From 28186a68d0c023987fe7334b0326fb6c87f9447c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Thu, 16 May 2013 12:56:01 +0200 Subject: Make the HTTP version type more practical Now instead of {1, 1} we have 'HTTP/1.1', and instead of {1, 0} we have 'HTTP/1.0'. This is more efficient, easier to read in crash logs, and clearer in the code. --- src/cowboy_client.erl | 18 ++++++++++-------- src/cowboy_http.erl | 8 +------- src/cowboy_protocol.erl | 8 ++++---- src/cowboy_req.erl | 18 +++++++++--------- 4 files changed, 24 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/cowboy_client.erl b/src/cowboy_client.erl index 4d958b1..faee904 100644 --- a/src/cowboy_client.erl +++ b/src/cowboy_client.erl @@ -40,7 +40,7 @@ timeout = 5000 :: timeout(), %% @todo Configurable. buffer = <<>> :: binary(), connection = keepalive :: keepalive | close, - version = {1, 1} :: cowboy_http:version(), + version = 'HTTP/1.1' :: cowboy_http:version(), response_body = undefined :: undefined | non_neg_integer() }). @@ -91,7 +91,7 @@ request(Method, URL, Headers, Body, Client=#client{ wait -> connect(Transport, Host, Port, Client); request -> {ok, Client} end, - VersionBin = cowboy_http:version_to_binary(Version), + VersionBin = atom_to_binary(Version, latin1), %% @todo do keepalive too, allow override... Headers2 = [ {<<"host">>, FullHost}, @@ -173,7 +173,7 @@ stream_status(Client=#client{state=State, buffer=Buffer}) when State =:= request -> case binary:split(Buffer, <<"\r\n">>) of [Line, Rest] -> - parse_status(Client#client{state=response, buffer=Rest}, Line); + parse_version(Client#client{state=response, buffer=Rest}, Line); _ -> case recv(Client) of {ok, Data} -> @@ -184,11 +184,13 @@ stream_status(Client=#client{state=State, buffer=Buffer}) end end. -parse_status(Client, << "HTTP/", High, ".", Low, " ", - S3, S2, S1, " ", StatusStr/binary >>) - when High >= $0, High =< $9, Low >= $0, Low =< $9, - S3 >= $0, S3 =< $9, S2 >= $0, S2 =< $9, S1 >= $0, S1 =< $9 -> - Version = {High - $0, Low - $0}, +parse_version(Client, << "HTTP/1.1 ", Rest/binary >>) -> + parse_status(Client, Rest, 'HTTP/1.1'); +parse_version(Client, << "HTTP/1.0 ", Rest/binary >>) -> + parse_status(Client, Rest, 'HTTP/1.0'). + +parse_status(Client, << S3, S2, S1, " ", StatusStr/binary >>, Version) + when S3 >= $0, S3 =< $9, S2 >= $0, S2 =< $9, S1 >= $0, S1 =< $9 -> Status = (S3 - $0) * 100 + (S2 - $0) * 10 + S1 - $0, {ok, Status, StatusStr, Client#client{version=Version}}. diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index fc08716..2da211d 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -46,14 +46,13 @@ %% Interpretation. -export([cookie_to_iodata/3]). --export([version_to_binary/1]). -export([urldecode/1]). -export([urldecode/2]). -export([urlencode/1]). -export([urlencode/2]). -export([x_www_form_urlencoded/1]). --type version() :: {Major::non_neg_integer(), Minor::non_neg_integer()}. +-type version() :: 'HTTP/1.1' | 'HTTP/1.0'. -type headers() :: [{binary(), iodata()}]. -type status() :: non_neg_integer() | binary(). @@ -1001,11 +1000,6 @@ cookie_to_iodata(Name, Value, Opts) -> [Name, <<"=">>, Value, <<"; Version=1">>, MaxAgeBin, DomainBin, PathBin, SecureBin, HttpOnlyBin]. -%% @doc Convert an HTTP version tuple to its binary form. --spec version_to_binary(version()) -> binary(). -version_to_binary({1, 1}) -> <<"HTTP/1.1">>; -version_to_binary({1, 0}) -> <<"HTTP/1.0">>. - %% @doc Decode a URL encoded binary. %% @equiv urldecode(Bin, crash) -spec urldecode(binary()) -> binary(). diff --git a/src/cowboy_protocol.erl b/src/cowboy_protocol.erl index 09dc9d7..7c80bfd 100644 --- a/src/cowboy_protocol.erl +++ b/src/cowboy_protocol.erl @@ -242,9 +242,9 @@ skip_uri_fragment(<< C, Rest/bits >>, S, M, P, Q) -> end. parse_version(<< "HTTP/1.1\r\n", Rest/bits >>, S, M, P, Q) -> - parse_header(Rest, S, M, P, Q, {1, 1}, []); + parse_header(Rest, S, M, P, Q, 'HTTP/1.1', []); parse_version(<< "HTTP/1.0\r\n", Rest/bits >>, S, M, P, Q) -> - parse_header(Rest, S, M, P, Q, {1, 0}, []); + parse_header(Rest, S, M, P, Q, 'HTTP/1.0', []); parse_version(_, State, _, _, _) -> error_terminate(505, State). @@ -411,7 +411,7 @@ parse_hd_value(<<>>, S, M, P, Q, V, H, N, SoFar) -> request(B, State=#state{transport=Transport}, M, P, Q, Version, Headers) -> case lists:keyfind(<<"host">>, 1, Headers) of - false when Version =:= {1, 1} -> + false when Version =:= 'HTTP/1.1' -> error_terminate(400, State); false -> request(B, State, M, P, Q, Version, Headers, @@ -583,7 +583,7 @@ error_terminate(Code, State=#state{socket=Socket, transport=Transport, {cowboy_req, resp_sent} -> ok after 0 -> _ = cowboy_req:reply(Code, cowboy_req:new(Socket, Transport, - undefined, <<"GET">>, <<>>, <<>>, {1, 1}, [], <<>>, + undefined, <<"GET">>, <<>>, <<>>, 'HTTP/1.1', [], <<>>, undefined, <<>>, false, Compress, OnResponse)), ok end, diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl index 4e321ee..cbed01f 100644 --- a/src/cowboy_req.erl +++ b/src/cowboy_req.erl @@ -133,7 +133,7 @@ %% Request. pid = undefined :: pid(), method = <<"GET">> :: binary(), - version = {1, 1} :: cowboy_http:version(), + version = 'HTTP/1.1' :: cowboy_http:version(), peer = undefined :: undefined | {inet:ip_address(), inet:port_number()}, host = undefined :: undefined | binary(), host_info = undefined :: undefined | cowboy_router:tokens(), @@ -193,7 +193,7 @@ new(Socket, Transport, Peer, Method, Path, Query, method=Method, path=Path, qs=Query, version=Version, headers=Headers, host=Host, port=Port, buffer=Buffer, resp_compress=Compress, onresponse=OnResponse}, - case CanKeepalive and (Version =:= {1, 1}) of + case CanKeepalive and (Version =:= 'HTTP/1.1') of false -> Req#http_req{connection=close}; true -> @@ -605,7 +605,7 @@ stream_body(MaxLength, Req=#http_req{body_state=waiting, version=Version, {ok, ExpectHeader, Req1} = parse_header(<<"expect">>, Req), case ExpectHeader of [<<"100-continue">>] -> - HTTPVer = cowboy_http:version_to_binary(Version), + HTTPVer = atom_to_binary(Version, latin1), Transport:send(Socket, << HTTPVer/binary, " ", (status(100))/binary, "\r\n\r\n" >>); undefined -> @@ -935,7 +935,7 @@ reply(Status, Headers, Body, Req=#http_req{ method=Method, resp_compress=Compress, resp_state=waiting, resp_headers=RespHeaders}) -> HTTP11Headers = case Version of - {1, 1} -> [{<<"connection">>, atom_to_connection(Connection)}]; + 'HTTP/1.1' -> [{<<"connection">>, atom_to_connection(Connection)}]; _ -> [] end, Req3 = case Body of @@ -961,7 +961,7 @@ reply(Status, Headers, Body, Req=#http_req{ BodyFun(ChunkFun), %% Terminate the chunked body for HTTP/1.1 only. _ = case Version of - {1, 0} -> ok; + 'HTTP/1.0' -> ok; _ -> Transport:send(Socket, <<"0\r\n\r\n">>) end; true -> ok @@ -1055,7 +1055,7 @@ chunked_reply(Status, Headers, Req) -> -spec chunk(iodata(), req()) -> ok | {error, atom()}. chunk(_Data, #http_req{method= <<"HEAD">>}) -> ok; -chunk(Data, #http_req{socket=Socket, transport=Transport, version={1, 0}}) -> +chunk(Data, #http_req{socket=Socket, transport=Transport, version='HTTP/1.0'}) -> Transport:send(Socket, Data); chunk(Data, #http_req{socket=Socket, transport=Transport, resp_state=chunks}) -> Transport:send(Socket, [integer_to_list(iolist_size(Data), 16), @@ -1086,7 +1086,7 @@ ensure_response(Req=#http_req{resp_state=waiting}, Status) -> %% Terminate the chunked body for HTTP/1.1 only. ensure_response(#http_req{method= <<"HEAD">>, resp_state=chunks}, _) -> ok; -ensure_response(#http_req{version={1, 0}, resp_state=chunks}, _) -> +ensure_response(#http_req{version='HTTP/1.0', resp_state=chunks}, _) -> ok; ensure_response(#http_req{socket=Socket, transport=Transport, resp_state=chunks}, _) -> @@ -1207,7 +1207,7 @@ chunked_response(Status, Headers, Req=#http_req{ resp_state=waiting, resp_headers=RespHeaders}) -> RespConn = response_connection(Headers, Connection), HTTP11Headers = case Version of - {1, 1} -> [ + 'HTTP/1.1' -> [ {<<"connection">>, atom_to_connection(Connection)}, {<<"transfer-encoding">>, <<"chunked">>}]; _ -> [] @@ -1239,7 +1239,7 @@ response(Status, Headers, RespHeaders, DefaultHeaders, Body, Req=#http_req{ end, ReplyType = case Req2#http_req.resp_state of waiting -> - HTTPVer = cowboy_http:version_to_binary(Version), + HTTPVer = atom_to_binary(Version, latin1), StatusLine = << HTTPVer/binary, " ", (status(Status))/binary, "\r\n" >>, HeaderLines = [[Key, <<": ">>, Value, <<"\r\n">>] -- cgit v1.2.3