diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gun_http.erl | 44 | ||||
-rw-r--r-- | src/gun_spdy.erl | 30 |
2 files changed, 51 insertions, 23 deletions
diff --git a/src/gun_http.erl b/src/gun_http.erl index d29ca2d..620f8ae 100644 --- a/src/gun_http.erl +++ b/src/gun_http.erl @@ -135,7 +135,7 @@ handle_head(Data, State=#http_state{owner=Owner, version=ClientVersion, {101, {websocket, _, WsKey, WsExtensions, WsProtocols, WsOpts}} -> ws_handshake(Rest2, State, Headers, WsKey, WsExtensions, WsProtocols, WsOpts); _ -> - In = io_from_headers(Version, Headers), + In = response_io_from_headers(Version, Headers), IsFin = case In of head -> fin; _ -> nofin end, case IsAlive of false -> @@ -153,7 +153,7 @@ handle_head(Data, State=#http_state{owner=Owner, version=ClientVersion, Conn =:= close -> close; Version =:= 'HTTP/1.0' -> close; ClientVersion =:= 'HTTP/1.0' -> close; - true -> conn_from_headers(Headers) + true -> conn_from_headers(Version, Headers) end, %% We always reset in_state even if not chunked. if @@ -200,18 +200,14 @@ keepalive(State) -> request(State=#http_state{socket=Socket, transport=Transport, version=Version, out=head}, StreamRef, Method, Host, Port, Path, Headers) -> - Headers2 = case Version of - 'HTTP/1.0' -> lists:keydelete(<<"transfer-encoding">>, 1, Headers); - 'HTTP/1.1' -> Headers - end, + Headers2 = lists:keydelete(<<"transfer-encoding">>, 1, Headers), Headers3 = case lists:keymember(<<"host">>, 1, Headers) of false -> [{<<"host">>, [Host, $:, integer_to_binary(Port)]}|Headers2]; true -> Headers2 end, %% We use Headers2 because this is the smallest list. - Conn = conn_from_headers(Headers2), - %% @todo This should probably also check for content-type like SPDY. - Out = io_from_headers(Version, Headers2), + Conn = conn_from_headers(Version, Headers2), + Out = request_io_from_headers(Headers2), Transport:send(Socket, cow_http:request(Method, Path, Version, Headers3)), new_stream(State#http_state{connection=Conn, out=Out}, StreamRef). @@ -224,10 +220,10 @@ request(State=#http_state{socket=Socket, transport=Transport, version=Version, true -> Headers2 end, %% We use Headers2 because this is the smallest list. - Conn = conn_from_headers(Headers2), + Conn = conn_from_headers(Version, Headers2), Transport:send(Socket, [ cow_http:request(Method, Path, Version, [ - {<<"content-length">>, integer_to_list(iolist_size(Body))} + {<<"content-length">>, integer_to_binary(iolist_size(Body))} |Headers3]), Body]), new_stream(State#http_state{connection=Conn}, StreamRef). @@ -296,8 +292,10 @@ error_stream_not_found(State=#http_state{owner=Owner}) -> %% Headers information retrieval. -conn_from_headers(Headers) -> +conn_from_headers(Version, Headers) -> case lists:keyfind(<<"connection">>, 1, Headers) of + false when Version =:= 'HTTP/1.0' -> + close; false -> keepalive; {_, ConnHd} -> @@ -308,7 +306,20 @@ conn_from_headers(Headers) -> end end. -io_from_headers(Version, Headers) -> +request_io_from_headers(Headers) -> + case lists:keyfind(<<"content-length">>, 1, Headers) of + {_, <<"0">>} -> + head; + {_, Length} -> + {body, cow_http_hd:parse_content_length(Length)}; + _ -> + case lists:keymember(<<"content-type">>, 1, Headers) of + true -> body_chunked; + false -> head + end + end. + +response_io_from_headers(Version, Headers) -> case lists:keyfind(<<"content-length">>, 1, Headers) of {_, <<"0">>} -> head; @@ -369,9 +380,12 @@ ws_upgrade(State=#http_state{socket=Socket, transport=Transport, out=head}, {<<"sec-websocket-key">>, Key} |ExtHeaders ], + IsSecure = Transport:secure(), Headers3 = case lists:keymember(<<"host">>, 1, Headers) of - false -> [{<<"host">>, [Host, $:, integer_to_binary(Port)]}|Headers2]; - true -> Headers2 + true -> Headers2; + false when Port =:= 80, not IsSecure -> [{<<"host">>, Host}|Headers2]; + false when Port =:= 443, IsSecure -> [{<<"host">>, Host}|Headers2]; + false -> [{<<"host">>, [Host, $:, integer_to_binary(Port)]}|Headers2] end, Transport:send(Socket, cow_http:request(<<"GET">>, Path, 'HTTP/1.1', Headers3)), new_stream(State#http_state{connection=keepalive, out=head}, diff --git a/src/gun_spdy.erl b/src/gun_spdy.erl index fc2fb1b..7651584 100644 --- a/src/gun_spdy.erl +++ b/src/gun_spdy.erl @@ -189,30 +189,44 @@ keepalive(State=#spdy_state{socket=Socket, transport=Transport, Transport:send(Socket, cow_spdy:ping(PingID)), State#spdy_state{ping_id=PingID + 2}. -%% @todo Allow overriding the host when doing requests. +%% @todo Always https scheme? request(State=#spdy_state{socket=Socket, transport=Transport, zdef=Zdef, - stream_id=StreamID}, StreamRef, Method, Host, _Port, Path, Headers) -> - Out = false =/= lists:keyfind(<<"content-type">>, 1, Headers), + stream_id=StreamID}, StreamRef, Method, Host, Port, Path, Headers) -> + {Host2, Headers2} = prepare_request(Headers, Host, Port), + Out = (false =/= lists:keyfind(<<"content-type">>, 1, Headers2)) + orelse (false =/= lists:keyfind(<<"content-length">>, 1, Headers2)), Transport:send(Socket, cow_spdy:syn_stream(Zdef, StreamID, 0, not Out, false, 0, - Method, <<"https">>, Host, Path, <<"HTTP/1.1">>, Headers)), + Method, <<"https">>, Host2, Path, <<"HTTP/1.1">>, Headers2)), new_stream(StreamID, StreamRef, true, Out, <<"HTTP/1.1">>, State#spdy_state{stream_id=StreamID + 2}). %% @todo Handle Body > 16MB. (split it out into many frames) +%% @todo Always https scheme? request(State=#spdy_state{socket=Socket, transport=Transport, zdef=Zdef, - stream_id=StreamID}, StreamRef, Method, Host, _Port, Path, Headers, Body) -> - Headers2 = lists:keystore(<<"content-length">>, 1, Headers, - {<<"content-length">>, integer_to_list(iolist_size(Body))}), + stream_id=StreamID}, StreamRef, Method, Host, Port, Path, Headers, Body) -> + {Host2, Headers2} = prepare_request(Headers, Host, Port), + Headers3 = lists:keystore(<<"content-length">>, 1, Headers2, + {<<"content-length">>, integer_to_binary(iolist_size(Body))}), Transport:send(Socket, [ cow_spdy:syn_stream(Zdef, StreamID, 0, false, false, 0, - Method, <<"https">>, Host, Path, <<"HTTP/1.1">>, Headers2), + Method, <<"https">>, Host2, Path, <<"HTTP/1.1">>, Headers3), cow_spdy:data(StreamID, true, Body) ]), new_stream(StreamID, StreamRef, true, false, <<"HTTP/1.1">>, State#spdy_state{stream_id=StreamID + 2}). +prepare_request(Headers, Host, Port) -> + Headers2 = lists:keydelete(<<"keep-alive">>, 1, + lists:keydelete(<<"proxy-connection">>, 1, + lists:keydelete(<<"transfer-encoding">>, 1, + lists:keydelete(<<"connection">>, 1, Headers)))), + case lists:keytake(<<"host">>, 1, Headers2) of + false -> {[Host, $:, integer_to_binary(Port)], Headers2}; + {value, {_, Host1}, Headers3} -> {Host1, Headers3} + end. + data(State=#spdy_state{socket=Socket, transport=Transport}, StreamRef, IsFin, Data) -> case get_stream_by_ref(StreamRef, State) of |