@@ -167,16 +167,8 @@ instance ToJSON Double where
167167 toJSON = realFloatToJSON
168168 {-# INLINE toJSON #-}
169169
170−realFloatToJSON :: RealFloat a => a -> Value
171−realFloatToJSON d
172− | isNaN d || isInfinite d = Null
173− | otherwise = Number $ Scientific.fromFloatDigits d
174−{-# INLINE realFloatToJSON #-}
175−
176170instance FromJSON Double where
177− parseJSON (Number s) = pure $ realToFrac s
178− parseJSON Null = pure (0/0)
179− parseJSON v = typeMismatch "Double" v
171+ parseJSON = parseFractional "Double"
180172 {-# INLINE parseJSON #-}
181173
182174instance ToJSON Number where
@@ -195,9 +187,7 @@ instance ToJSON Float where
195187 {-# INLINE toJSON #-}
196188
197189instance FromJSON Float where
198− parseJSON (Number s) = pure $ realToFrac s
199− parseJSON Null = pure (0/0)
200− parseJSON v = typeMismatch "Float" v
190+ parseJSON = parseFractional "Float"
201191 {-# INLINE parseJSON #-}
202192
203193instance ToJSON (Ratio Integer) where
@@ -225,19 +215,19 @@ instance ToJSON Int where
225215 {-# INLINE toJSON #-}
226216
227217instance FromJSON Int where
228− parseJSON = parseIntegral
218+ parseJSON = parseIntegral "Int"
229219 {-# INLINE parseJSON #-}
230220
231−parseIntegral :: Integral a => Value -> Parser a
232−parseIntegral = withScientific "Integral" $ pure . floor
233−{-# INLINE parseIntegral #-}
234−
235221instance ToJSON Integer where
236222 toJSON = Number . fromInteger
237223 {-# INLINE toJSON #-}
238224
225+-- | /WARNING:/ Only parse Integers from trusted input since an
226+-- attacker could easily fill up the memory of the target system by
227+-- specifying a scientific number with a big exponent like
228+-- @1e1000000000@.
239229instance FromJSON Integer where
240− parseJSON = parseIntegral
230+ parseJSON = withScientific "Integral" $ pure . floor
241231 {-# INLINE parseJSON #-}
242232
243233instance ToJSON Int8 where
@@ -245,7 +235,7 @@ instance ToJSON Int8 where
245235 {-# INLINE toJSON #-}
246236
247237instance FromJSON Int8 where
248− parseJSON = parseIntegral
238+ parseJSON = parseIntegral "Int8"
249239 {-# INLINE parseJSON #-}
250240
251241instance ToJSON Int16 where
@@ -253,7 +243,7 @@ instance ToJSON Int16 where
253243 {-# INLINE toJSON #-}
254244
255245instance FromJSON Int16 where
256− parseJSON = parseIntegral
246+ parseJSON = parseIntegral "Int16"
257247 {-# INLINE parseJSON #-}
258248
259249instance ToJSON Int32 where
@@ -261,7 +251,7 @@ instance ToJSON Int32 where
261251 {-# INLINE toJSON #-}
262252
263253instance FromJSON Int32 where
264− parseJSON = parseIntegral
254+ parseJSON = parseIntegral "Int32"
265255 {-# INLINE parseJSON #-}
266256
267257instance ToJSON Int64 where
@@ -269,7 +259,7 @@ instance ToJSON Int64 where
269259 {-# INLINE toJSON #-}
270260
271261instance FromJSON Int64 where
272− parseJSON = parseIntegral
262+ parseJSON = parseIntegral "Int64"
273263 {-# INLINE parseJSON #-}
274264
275265instance ToJSON Word where
@@ -277,7 +267,7 @@ instance ToJSON Word where
277267 {-# INLINE toJSON #-}
278268
279269instance FromJSON Word where
280− parseJSON = parseIntegral
270+ parseJSON = parseIntegral "Word"
281271 {-# INLINE parseJSON #-}
282272
283273instance ToJSON Word8 where
@@ -285,7 +275,7 @@ instance ToJSON Word8 where
285275 {-# INLINE toJSON #-}
286276
287277instance FromJSON Word8 where
288− parseJSON = parseIntegral
278+ parseJSON = parseIntegral "Word8"
289279 {-# INLINE parseJSON #-}
290280
291281instance ToJSON Word16 where
@@ -293,7 +283,7 @@ instance ToJSON Word16 where
293283 {-# INLINE toJSON #-}
294284
295285instance FromJSON Word16 where
296− parseJSON = parseIntegral
286+ parseJSON = parseIntegral "Word16"
297287 {-# INLINE parseJSON #-}
298288
299289instance ToJSON Word32 where
@@ -301,7 +291,7 @@ instance ToJSON Word32 where
301291 {-# INLINE toJSON #-}
302292
303293instance FromJSON Word32 where
304− parseJSON = parseIntegral
294+ parseJSON = parseIntegral "Word32"
305295 {-# INLINE parseJSON #-}
306296
307297instance ToJSON Word64 where
@@ -309,7 +299,7 @@ instance ToJSON Word64 where
309299 {-# INLINE toJSON #-}
310300
311301instance FromJSON Word64 where
312− parseJSON = parseIntegral
302+ parseJSON = parseIntegral "Word64"
313303 {-# INLINE parseJSON #-}
314304
315305instance ToJSON Text where
@@ -788,6 +778,12 @@ typeMismatch expected actual =
788778 Bool _ -> "Boolean"
789779 Null -> "Null"
790780
781+realFloatToJSON :: RealFloat a => a -> Value
782+realFloatToJSON d
783+ | isNaN d || isInfinite d = Null
784+ | otherwise = Number $ Scientific.fromFloatDigits d
785+{-# INLINE realFloatToJSON #-}
786+
791787scientificToNumber :: Scientific -> Number
792788scientificToNumber s
793789 | e < 0 = D $ realToFrac s
@@ -796,3 +792,25 @@ scientificToNumber s
796792 e = Scientific.base10Exponent s
797793 c = Scientific.coefficient s
798794{-# INLINE scientificToNumber #-}
795+
796+parseFractional :: Fractional a => String -> Value -> Parser a
797+parseFractional _ (Number s) = pure $ scientificToFractional s
798+parseFractional _ Null = pure (0/0)
799+parseFractional expected v = typeMismatch expected v
800+{-# INLINE parseFractional #-}
801+
802+-- | Convert an /untrusted/ scientific value to a fractional.
803+scientificToFractional :: Fractional a => Scientific -> a
804+scientificToFractional s = realToFrac s
805+ -- TODO: Using realToFrac is unsafe here. Do something similar as
806+ -- scientificToIntegral. The following might work but I'm not sure
807+ -- this doesn't introduce rounding errors:
808+ --
809+ -- fromInteger c * 10 ^ e
810+ -- where
811+ -- e = Scientific.base10Exponent s
812+ -- c = Scientific.coefficient s
813+
814+parseIntegral :: Integral a => String -> Value -> Parser a
815+parseIntegral expected = withScientific expected $ pure . floor
816+{-# INLINE parseIntegral #-}