aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2018-09-17 11:36:39 +0200
committerLoïc Hoguin <[email protected]>2018-09-17 11:36:39 +0200
commit889f26865006095bab986113ba249632523cd414 (patch)
tree39360a06fb95c3fd6e0da317f1c726a9084d30ad
parentb1ca51bc78d9e974014e70b820c9296db4ecb4f1 (diff)
downloadcowlib-889f26865006095bab986113ba249632523cd414.tar.gz
cowlib-889f26865006095bab986113ba249632523cd414.tar.bz2
cowlib-889f26865006095bab986113ba249632523cd414.zip
Add cow_http:parse_request_line/1
-rw-r--r--src/cow_http.erl49
-rw-r--r--src/cow_http_hd.erl1
2 files changed, 49 insertions, 1 deletions
diff --git a/src/cow_http.erl b/src/cow_http.erl
index 0eccd16..5701b02 100644
--- a/src/cow_http.erl
+++ b/src/cow_http.erl
@@ -14,7 +14,7 @@
-module(cow_http).
-%% @todo parse_request_line
+-export([parse_request_line/1]).
-export([parse_status_line/1]).
-export([status_to_integer/1]).
-export([parse_headers/1]).
@@ -38,6 +38,53 @@
-include("cow_inline.hrl").
+%% @doc Parse the request line.
+
+-spec parse_request_line(binary()) -> {binary(), binary(), version(), binary()}.
+parse_request_line(Data) ->
+ {Pos, _} = binary:match(Data, <<"\r">>),
+ <<RequestLine:Pos/binary, "\r\n", Rest/bits>> = Data,
+ [Method, Target, Version0] = binary:split(RequestLine, <<$\s>>, [trim_all, global]),
+ Version = case Version0 of
+ <<"HTTP/1.1">> -> 'HTTP/1.1';
+ <<"HTTP/1.0">> -> 'HTTP/1.0'
+ end,
+ {Method, Target, Version, Rest}.
+
+-ifdef(TEST).
+parse_request_line_test_() ->
+ Tests = [
+ {<<"GET /path HTTP/1.0\r\nRest">>,
+ {<<"GET">>, <<"/path">>, 'HTTP/1.0', <<"Rest">>}},
+ {<<"GET /path HTTP/1.1\r\nRest">>,
+ {<<"GET">>, <<"/path">>, 'HTTP/1.1', <<"Rest">>}},
+ {<<"CONNECT proxy.example.org:1080 HTTP/1.1\r\nRest">>,
+ {<<"CONNECT">>, <<"proxy.example.org:1080">>, 'HTTP/1.1', <<"Rest">>}}
+ ],
+ [{V, fun() -> R = parse_request_line(V) end}
+ || {V, R} <- Tests].
+
+parse_request_line_error_test_() ->
+ Tests = [
+ <<>>,
+ <<"GET">>,
+ <<"GET /path\r\n">>,
+ <<"GET /path HTTP/1.1">>,
+ <<"GET /path HTTP/1.1\r">>,
+ <<"GET /path HTTP/1.1\n">>,
+ <<"GET /path HTTP/0.9\r\n">>,
+ <<"content-type: text/plain\r\n">>,
+ <<0:80, "\r\n">>
+ ],
+ [{V, fun() -> {'EXIT', _} = (catch parse_request_line(V)) end}
+ || V <- Tests].
+
+horse_parse_request_line_get_path() ->
+ horse:repeat(200000,
+ parse_request_line(<<"GET /path HTTP/1.1\r\n">>)
+ ).
+-endif.
+
%% @doc Parse the status line.
-spec parse_status_line(binary()) -> {version(), status(), binary(), binary()}.
diff --git a/src/cow_http_hd.erl b/src/cow_http_hd.erl
index 76d2d44..1e8faaf 100644
--- a/src/cow_http_hd.erl
+++ b/src/cow_http_hd.erl
@@ -858,6 +858,7 @@ horse_parse_allow() ->
-> {basic, binary(), binary()}
| {bearer, binary()}
| {digest, [{binary(), binary()}]}.
+%% @todo The token is case-insensitive. https://tools.ietf.org/html/rfc7235#section-2.1
parse_authorization(<<"Basic ", R/bits >>) ->
auth_basic(base64:decode(R), <<>>);
parse_authorization(<<"Bearer ", R/bits >>) when R =/= <<>> ->