Skip to content

Commit 783df3b

Browse files
authored
Merge pull request #29 from garyb/semicolon-in-query
Fix behaviour of semicolons in query parts
2 parents 30f87da + 7a770c9 commit 783df3b

File tree

4 files changed

+55
-26
lines changed

4 files changed

+55
-26
lines changed

src/Data/URI/Common.purs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Data.String as S
1212
import Data.String.Regex as RX
1313
import Data.String.Regex.Flags as RXF
1414
import Data.Unfoldable (replicateA)
15-
import Global (decodeURI, decodeURIComponent, encodeURIComponent)
15+
import Global (decodeURI, decodeURIComponent)
1616
import Partial.Unsafe (unsafePartial)
1717
import Text.Parsing.StringParser (ParseError(..), Parser(..), unParser)
1818
import Text.Parsing.StringParser.String (string)
@@ -44,21 +44,6 @@ parsePChar f
4444
parseUnreserved Parser String
4545
parseUnreserved = rxPat "[0-9a-z\\-\\._~]+"
4646

47-
parseFragmentOrQuery Parser String
48-
parseFragmentOrQuery = parsePChar decodePCTComponent <|> string "/" <|> string "?"
49-
50-
printFragmentOrQuery String String
51-
printFragmentOrQuery = S.joinWith "" <<< map printChar <<< S.split (S.Pattern "")
52-
where
53-
-- Fragments & queries have a bunch of characters that don't need escaping
54-
printChar String String
55-
printChar s
56-
| RX.test rxPrintable s = s
57-
| otherwise = encodeURIComponent s
58-
59-
rxPrintable RX.Regex
60-
rxPrintable = unsafePartial fromRight $ RX.regex "[$&+;=/?:@]" RXF.global
61-
6247
newtype PCTEncoded = PCTEncoded String
6348

6449
decodePCT PCTEncoded String

src/Data/URI/Fragment.purs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,31 @@ module Data.URI.Fragment (parser, print) where
22

33
import Prelude
44

5+
import Control.Alt ((<|>))
6+
import Data.Either (fromRight)
7+
import Data.String as S
8+
import Data.String.Regex as RX
9+
import Data.String.Regex.Flags as RXF
510
import Data.URI (Fragment(..))
6-
import Data.URI.Common (joinWith, parseFragmentOrQuery, printFragmentOrQuery)
11+
import Data.URI.Common (decodePCTComponent, joinWith, parsePChar)
12+
import Global (encodeURIComponent)
13+
import Partial.Unsafe (unsafePartial)
714
import Text.Parsing.StringParser (Parser)
815
import Text.Parsing.StringParser.Combinators (many)
16+
import Text.Parsing.StringParser.String (string)
917

1018
parser Parser Fragment
11-
parser = Fragment <<< joinWith "" <$> many parseFragmentOrQuery
19+
parser = Fragment <<< joinWith ""
20+
<$> many (parsePChar decodePCTComponent <|> string "/" <|> string "?")
1221

1322
print Fragment String
14-
print (Fragment f) = printFragmentOrQuery f
23+
print (Fragment f) = S.joinWith "" $ map printChar $ S.split (S.Pattern "") f
24+
where
25+
-- Fragments & queries have a bunch of characters that don't need escaping
26+
printChar String String
27+
printChar s
28+
| RX.test rxPrintable s = s
29+
| otherwise = encodeURIComponent s
30+
31+
rxPrintable RX.Regex
32+
rxPrintable = unsafePartial fromRight $ RX.regex "[&;$+=/?:@]" RXF.global

src/Data/URI/Query.purs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,31 @@ module Data.URI.Query (parser, print) where
33
import Prelude
44

55
import Control.Alt ((<|>))
6+
import Data.Either (fromRight)
67
import Data.List (List(..))
78
import Data.Maybe (Maybe(..))
9+
import Data.String as S
10+
import Data.String.Regex as RX
11+
import Data.String.Regex.Flags as RXF
812
import Data.Tuple (Tuple(..))
913
import Data.URI (Query(..))
10-
import Data.URI.Common (joinWith, parseFragmentOrQuery, printFragmentOrQuery, rxPat, wrapParser)
14+
import Data.URI.Common (joinWith, rxPat, wrapParser)
15+
import Global (decodeURIComponent, encodeURIComponent)
16+
import Partial.Unsafe (unsafePartial)
1117
import Text.Parsing.StringParser (Parser, try)
12-
import Text.Parsing.StringParser.Combinators (optionMaybe, sepBy, many)
18+
import Text.Parsing.StringParser.Combinators (optionMaybe, sepBy)
1319
import Text.Parsing.StringParser.String (string)
1420

1521
parser Parser Query
16-
parser = Query <$> (wrapParser parseParts $ try (joinWith "" <$> many parseFragmentOrQuery))
22+
parser = Query <$> wrapParser parseParts (try (rxPat "[^#]*"))
1723

1824
parseParts Parser (List (Tuple String (Maybe String)))
1925
parseParts = sepBy parsePart (string ";" <|> string "&")
2026

2127
parsePart Parser (Tuple String (Maybe String))
2228
parsePart = do
23-
key ← rxPat "[^=;&]+"
24-
value ← optionMaybe $ string "=" *> rxPat "[^;&]*"
29+
key ← decodeURIComponent <$> rxPat "[^=;&]+"
30+
value ← optionMaybe $ decodeURIComponent <$> (string "=" *> rxPat "[^;&]*")
2531
pure $ Tuple key value
2632

2733
print Query String
@@ -31,5 +37,19 @@ print (Query m) =
3137
items → "?" <> joinWith "&" (printPart <$> items)
3238
where
3339
printPart Tuple String (Maybe String) String
34-
printPart (Tuple k Nothing) = printFragmentOrQuery k
35-
printPart (Tuple k (Just v)) = printFragmentOrQuery k <> "=" <> printFragmentOrQuery v
40+
printPart (Tuple k Nothing) =
41+
printQueryPart k
42+
printPart (Tuple k (Just v)) =
43+
printQueryPart k <> "=" <> printQueryPart v
44+
45+
printQueryPart String String
46+
printQueryPart = S.joinWith "" <<< map printChar <<< S.split (S.Pattern "")
47+
where
48+
-- Fragments & queries have a bunch of characters that don't need escaping
49+
printChar String String
50+
printChar s
51+
| RX.test rxPrintable s = s
52+
| otherwise = encodeURIComponent s
53+
54+
rxPrintable RX.Regex
55+
rxPrintable = unsafePartial fromRight $ RX.regex "[$+=/?:@]" RXF.global

test/Main.purs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ main = runTest $ suite "Data.URI" do
450450
testPrintQuerySerializes
451451
(Query (Tuple "key1" Nothing : Tuple "key2" Nothing : Nil))
452452
"?key1&key2"
453+
testPrintQuerySerializes
454+
(Query (Tuple "key1" (Just "foo;bar") : Nil))
455+
"?key1=foo%3Bbar"
453456

454457
suite "Query.parser" do
455458
testParseQueryParses
@@ -461,6 +464,9 @@ main = runTest $ suite "Data.URI" do
461464
testParseQueryParses
462465
"key1=&key2="
463466
(Query (Tuple "key1" (Just "") : Tuple "key2" (Just "") : Nil))
467+
testParseQueryParses
468+
"key1=foo%3Bbar"
469+
(Query (Tuple "key1" (Just "foo;bar") : Nil))
464470

465471
suite "Common.match1From" do
466472
testMatch1FromMisses (regex "key1" noFlags) 0 ""

0 commit comments

Comments
 (0)