Skip to content

Commit b5ba408

Browse files
authored
Stack safety (#65)
* Ignore node_modules * Add test that causes a stack overflow * Use stack safe `many`/`some` * Update CHANGELOG.md * Add explicit lists dependency
1 parent 041e717 commit b5ba408

16 files changed

+55
-36
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
output
77
generated-docs
88
bower_components
9+
node_modules

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Breaking changes:
99
New features:
1010

1111
Bugfixes:
12+
- Made all parsers stack safe on long input (#63 by @garyb)
1213

1314
Other improvements:
1415

spago.dhall

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
, "gen"
1414
, "integers"
1515
, "js-uri"
16+
, "lists"
1617
, "maybe"
1718
, "newtype"
1819
, "parsing"

src/URI/Common.purs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@ import Prelude
1717
import Control.Alt ((<|>))
1818
import Control.Monad.Except (throwError)
1919
import Control.Monad.State (get)
20-
import Data.Array as Array
2120
import Data.Either (Either(..), either)
2221
import Data.Generic.Rep (class Generic)
22+
import Data.List as List
2323
import Data.Maybe (fromJust)
2424
import Data.Newtype (class Newtype, un)
2525
import Data.Show.Generic (genericShow)
26-
import Data.String (joinWith) as String
2726
import Data.String.CodeUnits (singleton) as String
2827
import Data.String.NonEmpty (NonEmptyString)
28+
import Data.String.NonEmpty (joinWith, toString, unsafeFromString) as NES
2929
import Data.String.NonEmpty.CodeUnits (singleton) as NES
30-
import Data.String.NonEmpty (unsafeFromString, toString) as NES
3130
import JSURI (decodeURIComponent, encodeURIComponent)
3231
import Partial.Unsafe (unsafePartial)
3332
import Text.Parsing.Parser (ParseError(..), ParseState(..), Parser, ParserT(..), runParser)
@@ -93,11 +92,11 @@ printEncoded ∷ Parser String Char → String → String
9392
printEncoded p s = either (const s) identity (runParser s parse)
9493
where
9594
parse Parser String String
96-
parse = (String.joinWith "" <$> Array.many (simpleChar <|> encodedChar)) <* eof
97-
simpleChar Parser String String
98-
simpleChar = String.singleton <$> p
99-
encodedChar Parser String String
100-
encodedChar = unsafePartial fromJust <<< encodeURIComponent <<< String.singleton <$> anyChar
95+
parse = (NES.joinWith "" <$> List.manyRec (simpleChar <|> encodedChar)) <* eof
96+
simpleChar Parser String NonEmptyString
97+
simpleChar = NES.singleton <$> p
98+
encodedChar Parser String NonEmptyString
99+
encodedChar = unsafePartial (NES.unsafeFromString <<< fromJust) <<< encodeURIComponent <<< String.singleton <$> anyChar
101100

102101
-- | A version of [`printEncoded`](#v:printEncoded) that operates on non-empty
103102
-- | strings.

src/URI/Extra/QueryPairs.purs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import Data.Array as Array
2323
import Data.Bifunctor (bimap)
2424
import Data.Either (Either)
2525
import Data.Generic.Rep (class Generic)
26+
import Data.List as List
2627
import Data.Maybe (Maybe(..), fromJust)
2728
import Data.Show.Generic (genericShow)
2829
import Data.String as String
@@ -78,10 +79,10 @@ parsePart
7879
Parser String (Tuple k (Maybe v))
7980
parsePart parseK parseV = do
8081
key ← wrapParser (parseK <<< Key) $
81-
NES.joinWith "" <$> Array.some (NES.singleton <$> keyPartChar <|> pctEncoded)
82+
NES.joinWith "" <$> List.someRec (NES.singleton <$> keyPartChar <|> pctEncoded)
8283
value ← wrapParser (traverse (parseV <<< Value)) $ optionMaybe do
8384
_ ← char '='
84-
NES.joinWith "" <$> Array.many (NES.singleton <$> valuePartChar <|> pctEncoded)
85+
NES.joinWith "" <$> List.manyRec (NES.singleton <$> valuePartChar <|> pctEncoded)
8586
pure $ Tuple key value
8687

8788
-- | A printer for key/value pairs style query string.

src/URI/Fragment.purs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ module URI.Fragment
1212
import Prelude
1313

1414
import Control.Alt ((<|>))
15-
import Data.Array as Array
15+
import Data.List as List
1616
import Data.Maybe (fromJust)
17-
import Data.String.NonEmpty.CodeUnits (singleton) as NES
1817
import Data.String.NonEmpty (joinWith) as NES
18+
import Data.String.NonEmpty.CodeUnits (singleton) as NES
1919
import JSURI (decodeURIComponent)
2020
import Partial.Unsafe (unsafePartial)
2121
import Text.Parsing.Parser (Parser)
@@ -75,7 +75,7 @@ parser ∷ Parser String Fragment
7575
parser =
7676
char '#' *>
7777
(Fragment <<< NES.joinWith ""
78-
<$> Array.many (pctEncoded <|> NES.singleton <$> fragmentChar))
78+
<$> List.manyRec (pctEncoded <|> NES.singleton <$> fragmentChar))
7979

8080
-- | A printer for the fragment component of a URI. Will print the value with
8181
-- | a `'#'` prefix.

src/URI/Host/IPv6Address.purs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ module URI.Host.IPv6Address
88
import Prelude
99

1010
import Control.Alt ((<|>))
11-
import Data.Array as Array
12-
import Data.String.CodeUnits as String
11+
import Data.List as List
12+
import Data.String.NonEmpty as NES
13+
import Data.String.NonEmpty.CodeUnits as NESCU
1314
import Text.Parsing.Parser (Parser)
1415
import Text.Parsing.Parser.Combinators ((<?>))
1516
import Text.Parsing.Parser.String (char)
@@ -34,7 +35,7 @@ unsafeToString (IPv6Address s) = "[" <> s <> "]"
3435
parser Parser String IPv6Address
3536
parser =
3637
IPv6Address
37-
<$> (char '[' *> (String.fromCharArray <$> Array.some ipv6Char) <* char ']')
38+
<$> (char '[' *> (NES.joinWith "" <$> List.someRec (NESCU.singleton <$> ipv6Char)) <* char ']')
3839
<?> "IPv6 address"
3940
where
4041
ipv6Char Parser String Char

src/URI/Path.purs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Prelude
44

55
import Data.Array as Array
66
import Data.Generic.Rep (class Generic)
7+
import Data.List as List
78
import Data.Show.Generic (genericShow)
89
import Data.String as String
910
import Text.Parsing.Parser (Parser)
@@ -26,7 +27,7 @@ instance showPath ∷ Show Path where show = genericShow
2627

2728
-- | A parser for a _path-abempty_ URI component.
2829
parser Parser String Path
29-
parser = Path <$> Array.many (char '/' *> parseSegment)
30+
parser = Path <<< Array.fromFoldable <$> List.manyRec (char '/' *> parseSegment)
3031

3132
-- | A printer for a _path-abempty_ URI component.
3233
print Path String

src/URI/Path/Absolute.purs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Prelude
44

55
import Data.Array as Array
66
import Data.Generic.Rep (class Generic)
7+
import Data.List as List
78
import Data.Maybe (Maybe(..))
89
import Data.Show.Generic (genericShow)
910
import Data.String as String
@@ -36,7 +37,11 @@ parse = do
3637
_ ← char '/'
3738
optionMaybe parseSegmentNZ >>= case _ of
3839
Just head →
39-
PathAbsolute <<< Just <<< Tuple head <$> Array.many (char '/' *> parseSegment)
40+
PathAbsolute
41+
<<< Just
42+
<<< Tuple head
43+
<<< Array.fromFoldable
44+
<$> List.manyRec (char '/' *> parseSegment)
4045
Nothing
4146
pure (PathAbsolute Nothing)
4247

src/URI/Path/NoScheme.purs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Prelude
44

55
import Data.Array as Array
66
import Data.Generic.Rep (class Generic)
7+
import Data.List as List
78
import Data.Show.Generic (genericShow)
89
import Data.String as String
910
import Data.Tuple (Tuple(..))
@@ -27,8 +28,8 @@ instance showPathNoScheme ∷ Show PathNoScheme where show = genericShow
2728
parse Parser String PathNoScheme
2829
parse = do
2930
head ← parseSegmentNZNC
30-
tail ← Array.many (char '/' *> parseSegment)
31-
pure (PathNoScheme (Tuple head tail))
31+
tail ← List.manyRec (char '/' *> parseSegment)
32+
pure (PathNoScheme (Tuple head (Array.fromFoldable tail)))
3233

3334
-- | A printer for a _path-noscheme_ URI component.
3435
print PathNoScheme String

0 commit comments

Comments
 (0)