Browse Source

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.
Loïc Hoguin 12 years ago
parent
commit
28186a68d0
5 changed files with 25 additions and 29 deletions
  1. 1 1
      guide/req.md
  2. 10 8
      src/cowboy_client.erl
  3. 1 7
      src/cowboy_http.erl
  4. 4 4
      src/cowboy_protocol.erl
  5. 9 9
      src/cowboy_req.erl

+ 1 - 1
guide/req.md

@@ -31,7 +31,7 @@ request object.
 The following access functions are defined in `cowboy_req`:
 The following access functions are defined in `cowboy_req`:
 
 
  *  `method/1`: the request method (`<<"GET">>`, `<<"POST">>`...)
  *  `method/1`: the request method (`<<"GET">>`, `<<"POST">>`...)
- *  `version/1`: the HTTP version (`{1,0}` or `{1,1}`)
+ *  `version/1`: the HTTP version (`'HTTP/1.0'` or `'HTTP/1.1'`)
  *  `peer/1`: the peer address and port number
  *  `peer/1`: the peer address and port number
  *  `host/1`: the hostname requested
  *  `host/1`: the hostname requested
  *  `host_info/1`: the result of the `[...]` match on the host
  *  `host_info/1`: the result of the `[...]` match on the host

+ 10 - 8
src/cowboy_client.erl

@@ -40,7 +40,7 @@
 	timeout = 5000 :: timeout(), %% @todo Configurable.
 	timeout = 5000 :: timeout(), %% @todo Configurable.
 	buffer = <<>> :: binary(),
 	buffer = <<>> :: binary(),
 	connection = keepalive :: keepalive | close,
 	connection = keepalive :: keepalive | close,
-	version = {1, 1} :: cowboy_http:version(),
+	version = 'HTTP/1.1' :: cowboy_http:version(),
 	response_body = undefined :: undefined | non_neg_integer()
 	response_body = undefined :: undefined | non_neg_integer()
 }).
 }).
 
 
@@ -91,7 +91,7 @@ request(Method, URL, Headers, Body, Client=#client{
 		wait -> connect(Transport, Host, Port, Client);
 		wait -> connect(Transport, Host, Port, Client);
 		request -> {ok, Client}
 		request -> {ok, Client}
 	end,
 	end,
-	VersionBin = cowboy_http:version_to_binary(Version),
+	VersionBin = atom_to_binary(Version, latin1),
 	%% @todo do keepalive too, allow override...
 	%% @todo do keepalive too, allow override...
 	Headers2 = [
 	Headers2 = [
 		{<<"host">>, FullHost},
 		{<<"host">>, FullHost},
@@ -173,7 +173,7 @@ stream_status(Client=#client{state=State, buffer=Buffer})
 		when State =:= request ->
 		when State =:= request ->
 	case binary:split(Buffer, <<"\r\n">>) of
 	case binary:split(Buffer, <<"\r\n">>) of
 		[Line, Rest] ->
 		[Line, Rest] ->
-			parse_status(Client#client{state=response, buffer=Rest}, Line);
+			parse_version(Client#client{state=response, buffer=Rest}, Line);
 		_ ->
 		_ ->
 			case recv(Client) of
 			case recv(Client) of
 				{ok, Data} ->
 				{ok, Data} ->
@@ -184,11 +184,13 @@ stream_status(Client=#client{state=State, buffer=Buffer})
 			end
 			end
 	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,
 	Status = (S3 - $0) * 100 + (S2 - $0) * 10 + S1 - $0,
 	{ok, Status, StatusStr, Client#client{version=Version}}.
 	{ok, Status, StatusStr, Client#client{version=Version}}.
 
 

+ 1 - 7
src/cowboy_http.erl

@@ -46,14 +46,13 @@
 
 
 %% Interpretation.
 %% Interpretation.
 -export([cookie_to_iodata/3]).
 -export([cookie_to_iodata/3]).
--export([version_to_binary/1]).
 -export([urldecode/1]).
 -export([urldecode/1]).
 -export([urldecode/2]).
 -export([urldecode/2]).
 -export([urlencode/1]).
 -export([urlencode/1]).
 -export([urlencode/2]).
 -export([urlencode/2]).
 -export([x_www_form_urlencoded/1]).
 -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 headers() :: [{binary(), iodata()}].
 -type status() :: non_neg_integer() | binary().
 -type status() :: non_neg_integer() | binary().
 
 
@@ -1001,11 +1000,6 @@ cookie_to_iodata(Name, Value, Opts) ->
 	[Name, <<"=">>, Value, <<"; Version=1">>,
 	[Name, <<"=">>, Value, <<"; Version=1">>,
 		MaxAgeBin, DomainBin, PathBin, SecureBin, HttpOnlyBin].
 		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.
 %% @doc Decode a URL encoded binary.
 %% @equiv urldecode(Bin, crash)
 %% @equiv urldecode(Bin, crash)
 -spec urldecode(binary()) -> binary().
 -spec urldecode(binary()) -> binary().

+ 4 - 4
src/cowboy_protocol.erl

@@ -242,9 +242,9 @@ skip_uri_fragment(<< C, Rest/bits >>, S, M, P, Q) ->
 	end.
 	end.
 
 
 parse_version(<< "HTTP/1.1\r\n", Rest/bits >>, S, M, P, Q) ->
 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_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, _, _, _) ->
 parse_version(_, State, _, _, _) ->
 	error_terminate(505, 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) ->
 request(B, State=#state{transport=Transport}, M, P, Q, Version, Headers) ->
 	case lists:keyfind(<<"host">>, 1, Headers) of
 	case lists:keyfind(<<"host">>, 1, Headers) of
-		false when Version =:= {1, 1} ->
+		false when Version =:= 'HTTP/1.1' ->
 			error_terminate(400, State);
 			error_terminate(400, State);
 		false ->
 		false ->
 			request(B, State, M, P, Q, Version, Headers,
 			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
 		{cowboy_req, resp_sent} -> ok
 	after 0 ->
 	after 0 ->
 		_ = cowboy_req:reply(Code, cowboy_req:new(Socket, Transport,
 		_ = cowboy_req:reply(Code, cowboy_req:new(Socket, Transport,
-			undefined, <<"GET">>, <<>>, <<>>, {1, 1}, [], <<>>,
+			undefined, <<"GET">>, <<>>, <<>>, 'HTTP/1.1', [], <<>>,
 			undefined, <<>>, false, Compress, OnResponse)),
 			undefined, <<>>, false, Compress, OnResponse)),
 		ok
 		ok
 	end,
 	end,

+ 9 - 9
src/cowboy_req.erl

@@ -133,7 +133,7 @@
 	%% Request.
 	%% Request.
 	pid = undefined :: pid(),
 	pid = undefined :: pid(),
 	method = <<"GET">> :: binary(),
 	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()},
 	peer = undefined :: undefined | {inet:ip_address(), inet:port_number()},
 	host = undefined :: undefined | binary(),
 	host = undefined :: undefined | binary(),
 	host_info = undefined :: undefined | cowboy_router:tokens(),
 	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,
 		method=Method, path=Path, qs=Query, version=Version,
 		headers=Headers, host=Host, port=Port, buffer=Buffer,
 		headers=Headers, host=Host, port=Port, buffer=Buffer,
 		resp_compress=Compress, onresponse=OnResponse},
 		resp_compress=Compress, onresponse=OnResponse},
-	case CanKeepalive and (Version =:= {1, 1}) of
+	case CanKeepalive and (Version =:= 'HTTP/1.1') of
 		false ->
 		false ->
 			Req#http_req{connection=close};
 			Req#http_req{connection=close};
 		true ->
 		true ->
@@ -605,7 +605,7 @@ stream_body(MaxLength, Req=#http_req{body_state=waiting, version=Version,
 	{ok, ExpectHeader, Req1} = parse_header(<<"expect">>, Req),
 	{ok, ExpectHeader, Req1} = parse_header(<<"expect">>, Req),
 	case ExpectHeader of
 	case ExpectHeader of
 		[<<"100-continue">>] ->
 		[<<"100-continue">>] ->
-			HTTPVer = cowboy_http:version_to_binary(Version),
+			HTTPVer = atom_to_binary(Version, latin1),
 			Transport:send(Socket,
 			Transport:send(Socket,
 				<< HTTPVer/binary, " ", (status(100))/binary, "\r\n\r\n" >>);
 				<< HTTPVer/binary, " ", (status(100))/binary, "\r\n\r\n" >>);
 		undefined ->
 		undefined ->
@@ -935,7 +935,7 @@ reply(Status, Headers, Body, Req=#http_req{
 		method=Method, resp_compress=Compress,
 		method=Method, resp_compress=Compress,
 		resp_state=waiting, resp_headers=RespHeaders}) ->
 		resp_state=waiting, resp_headers=RespHeaders}) ->
 	HTTP11Headers = case Version of
 	HTTP11Headers = case Version of
-		{1, 1} -> [{<<"connection">>, atom_to_connection(Connection)}];
+		'HTTP/1.1' -> [{<<"connection">>, atom_to_connection(Connection)}];
 		_ -> []
 		_ -> []
 	end,
 	end,
 	Req3 = case Body of
 	Req3 = case Body of
@@ -961,7 +961,7 @@ reply(Status, Headers, Body, Req=#http_req{
 					BodyFun(ChunkFun),
 					BodyFun(ChunkFun),
 					%% Terminate the chunked body for HTTP/1.1 only.
 					%% Terminate the chunked body for HTTP/1.1 only.
 					_ = case Version of
 					_ = case Version of
-						{1, 0} -> ok;
+						'HTTP/1.0' -> ok;
 						_ -> Transport:send(Socket, <<"0\r\n\r\n">>)
 						_ -> Transport:send(Socket, <<"0\r\n\r\n">>)
 					end;
 					end;
 				true -> ok
 				true -> ok
@@ -1055,7 +1055,7 @@ chunked_reply(Status, Headers, Req) ->
 -spec chunk(iodata(), req()) -> ok | {error, atom()}.
 -spec chunk(iodata(), req()) -> ok | {error, atom()}.
 chunk(_Data, #http_req{method= <<"HEAD">>}) ->
 chunk(_Data, #http_req{method= <<"HEAD">>}) ->
 	ok;
 	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);
 	Transport:send(Socket, Data);
 chunk(Data, #http_req{socket=Socket, transport=Transport, resp_state=chunks}) ->
 chunk(Data, #http_req{socket=Socket, transport=Transport, resp_state=chunks}) ->
 	Transport:send(Socket, [integer_to_list(iolist_size(Data), 16),
 	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.
 %% Terminate the chunked body for HTTP/1.1 only.
 ensure_response(#http_req{method= <<"HEAD">>, resp_state=chunks}, _) ->
 ensure_response(#http_req{method= <<"HEAD">>, resp_state=chunks}, _) ->
 	ok;
 	ok;
-ensure_response(#http_req{version={1, 0}, resp_state=chunks}, _) ->
+ensure_response(#http_req{version='HTTP/1.0', resp_state=chunks}, _) ->
 	ok;
 	ok;
 ensure_response(#http_req{socket=Socket, transport=Transport,
 ensure_response(#http_req{socket=Socket, transport=Transport,
 		resp_state=chunks}, _) ->
 		resp_state=chunks}, _) ->
@@ -1207,7 +1207,7 @@ chunked_response(Status, Headers, Req=#http_req{
 		resp_state=waiting, resp_headers=RespHeaders}) ->
 		resp_state=waiting, resp_headers=RespHeaders}) ->
 	RespConn = response_connection(Headers, Connection),
 	RespConn = response_connection(Headers, Connection),
 	HTTP11Headers = case Version of
 	HTTP11Headers = case Version of
-		{1, 1} -> [
+		'HTTP/1.1' -> [
 			{<<"connection">>, atom_to_connection(Connection)},
 			{<<"connection">>, atom_to_connection(Connection)},
 			{<<"transfer-encoding">>, <<"chunked">>}];
 			{<<"transfer-encoding">>, <<"chunked">>}];
 		_ -> []
 		_ -> []
@@ -1239,7 +1239,7 @@ response(Status, Headers, RespHeaders, DefaultHeaders, Body, Req=#http_req{
 	end,
 	end,
 	ReplyType = case Req2#http_req.resp_state of
 	ReplyType = case Req2#http_req.resp_state of
 		waiting ->
 		waiting ->
-			HTTPVer = cowboy_http:version_to_binary(Version),
+			HTTPVer = atom_to_binary(Version, latin1),
 			StatusLine = << HTTPVer/binary, " ",
 			StatusLine = << HTTPVer/binary, " ",
 				(status(Status))/binary, "\r\n" >>,
 				(status(Status))/binary, "\r\n" >>,
 			HeaderLines = [[Key, <<": ">>, Value, <<"\r\n">>]
 			HeaderLines = [[Key, <<": ">>, Value, <<"\r\n">>]