Skip to content

Commit

Permalink
fix query parameters with question marks
Browse files Browse the repository at this point in the history
According to RFC 3986:
> The query component is indicated by the first question mark ("?") character.
Therefore, following question marks should be disregarded.

This also makes the tests for query parameters check that those are parsed correctly.
  • Loading branch information
Johann150 authored and rawhat committed Jun 13, 2023
1 parent 95e1580 commit 2ce0076
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 18 deletions.
18 changes: 6 additions & 12 deletions src/mist/internal/http.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -224,16 +224,11 @@ pub fn parse_request(
|> bit_string.to_string
|> result.replace_error(InvalidPath),
)
let #(path, query) = case string.split(path, "?") {
[path] -> #(path, [])
[path, query_string] -> {
let query =
query_string
|> uri.parse_query
|> result.unwrap([])
#(path, query)
}
}
use parsed <- result.then(
uri.parse(path)
|> result.replace_error(InvalidPath),
)
let #(path, query) = #(parsed.path, parsed.query)
let req =
request.new()
|> request.set_scheme(case transport {
Expand All @@ -243,8 +238,7 @@ pub fn parse_request(
|> request.set_body(Unread(rest, socket))
|> request.set_method(method)
|> request.set_path(path)
|> request.set_query(query)
Ok(request.Request(..req, headers: map.to_list(headers)))
Ok(request.Request(..req, query: query, headers: map.to_list(headers)))
}
_ -> Error(DiscardPacket)
}
Expand Down
42 changes: 41 additions & 1 deletion test/http1_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import gleam/http/response.{Response}
import gleam/hackney
import gleam/string
import gleam/uri
import gleam/option.{Some}
import gleeunit/should
import scaffold.{
bitstring_response_should_equal, echo_handler, make_request, open_server,
Expand Down Expand Up @@ -35,6 +36,8 @@ pub fn set_up_echo_server_test_() {
it_rejects_large_requests,
it_supports_chunked_encoding,
it_supports_query_parameters,
it_handles_query_parameters_with_question_mark,
it_doesnt_mangle_query,
it_supports_expect_continue_header,
],
)
Expand Down Expand Up @@ -170,7 +173,44 @@ pub fn it_supports_query_parameters() {

let assert Ok(resp) = hackney.send(req)

let expected = get_default_response()
let expected =
get_default_response()
|> response.set_header("content-length", "61")
|> response.set_body(bit_builder.from_bit_string(<<
"something=123&another=true&a-complicated-one=is%20the%20thing":utf8,
>>))

string_response_should_equal(resp, expected)
}

pub fn it_handles_query_parameters_with_question_mark() {
let req =
make_request("/", "hello, world!")
|> request.set_method(http.Get)
|> request.set_query([#("?", "123")])

let assert Ok(resp) = hackney.send(req)

let expected =
get_default_response()
|> response.set_header("content-length", "5")
|> response.set_body(bit_builder.from_bit_string(<<"?=123":utf8>>))

string_response_should_equal(resp, expected)
}

pub fn it_doesnt_mangle_query() {
let req =
make_request("/", "hello, world!")
|> request.set_method(http.Get)
let req = request.Request(..req, query: Some("test"))

let assert Ok(resp) = hackney.send(req)

let expected =
get_default_response()
|> response.set_header("content-length", "4")
|> response.set_body(bit_builder.from_bit_string(<<"test":utf8>>))

string_response_should_equal(resp, expected)
}
Expand Down
19 changes: 14 additions & 5 deletions test/scaffold.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,33 @@ import mist/internal/http.{Chunked} as mhttp
import gleam/bit_string
import gleam/string
import gleam/iterator
import gleam/option
import gleam/int

pub fn echo_handler() -> Handler {
fn(req: request.Request(BitString)) {
let body =
req.query
|> option.map(bit_string.from_string)
|> option.unwrap(req.body)
|> bit_builder.from_bit_string
let length =
body
|> bit_builder.byte_size
|> int.to_string
let headers =
list.filter(
req.headers,
fn(p) {
case p {
#("transfer-encoding", "chunked") -> False
#("content-length", _) -> False
_ -> True
}
},
)
Response(
status: 200,
headers: headers,
body: bit_builder.from_bit_string(req.body),
)
|> list.prepend(#("content-length", length))
Response(status: 200, headers: headers, body: body)
}
}

Expand Down

0 comments on commit 2ce0076

Please sign in to comment.