Browse Source

Parse the settings payload directly in cow_http_hd:parse_http2_settings/1

Loïc Hoguin 9 years ago
parent
commit
b5d5d674b1
2 changed files with 29 additions and 23 deletions
  1. 28 22
      src/cow_http2.erl
  2. 1 1
      src/cow_http_hd.erl

+ 28 - 22
src/cow_http2.erl

@@ -16,6 +16,7 @@
 
 
 %% Parsing.
 %% Parsing.
 -export([parse/1]).
 -export([parse/1]).
+-export([parse_settings_payload/1]).
 
 
 %% Building.
 %% Building.
 -export([data/3]).
 -export([data/3]).
@@ -163,7 +164,7 @@ parse(<< _:24, 4:8, _:7, 1:1, _:1, 0:31, _/bits >>) ->
 parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, _/bits >>) when Len rem 6 =/= 0 ->
 parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, _/bits >>) when Len rem 6 =/= 0 ->
 	{connection_error, frame_size_error, 'SETTINGS frames MUST have a length multiple of 6. (RFC7540 6.5)'};
 	{connection_error, frame_size_error, 'SETTINGS frames MUST have a length multiple of 6. (RFC7540 6.5)'};
 parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, Rest/bits >>) when byte_size(Rest) >= Len ->
 parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, Rest/bits >>) when byte_size(Rest) >= Len ->
-	parse_settings(Rest, Len, #{});
+	parse_settings_payload(Rest, Len, #{});
 parse(<< _:24, 4:8, _/bits >>) ->
 parse(<< _:24, 4:8, _/bits >>) ->
 	{connection_error, protocol_error, 'SETTINGS frames MUST NOT be associated with a stream. (RFC7540 6.5)'};
 	{connection_error, protocol_error, 'SETTINGS frames MUST NOT be associated with a stream. (RFC7540 6.5)'};
 %%
 %%
@@ -256,38 +257,43 @@ parse_error_code(12) -> inadequate_security;
 parse_error_code(13) -> http_1_1_required;
 parse_error_code(13) -> http_1_1_required;
 parse_error_code(_) -> unknown_error.
 parse_error_code(_) -> unknown_error.
 
 
-parse_settings(Rest, 0, Settings) ->
+parse_settings_payload(SettingsPayload) ->
+	{ok, {settings, Settings}, <<>>}
+		= parse_settings_payload(SettingsPayload, byte_size(SettingsPayload), #{}),
+	Settings.
+
+parse_settings_payload(Rest, 0, Settings) ->
 	{ok, {settings, Settings}, Rest};
 	{ok, {settings, Settings}, Rest};
 %% SETTINGS_HEADER_TABLE_SIZE.
 %% SETTINGS_HEADER_TABLE_SIZE.
-parse_settings(<< 1:16, Value:32, Rest/bits >>, Len, Settings) ->
-	parse_settings(Rest, Len - 6, Settings#{header_table_size => Value});
+parse_settings_payload(<< 1:16, Value:32, Rest/bits >>, Len, Settings) ->
+	parse_settings_payload(Rest, Len - 6, Settings#{header_table_size => Value});
 %% SETTINGS_ENABLE_PUSH.
 %% SETTINGS_ENABLE_PUSH.
-parse_settings(<< 2:16, 0:32, Rest/bits >>, Len, Settings) ->
-	parse_settings(Rest, Len - 6, Settings#{enable_push => false});
-parse_settings(<< 2:16, 1:32, Rest/bits >>, Len, Settings) ->
-	parse_settings(Rest, Len - 6, Settings#{enable_push => true});
-parse_settings(<< 2:16, _:32, _/bits >>, _, _) ->
+parse_settings_payload(<< 2:16, 0:32, Rest/bits >>, Len, Settings) ->
+	parse_settings_payload(Rest, Len - 6, Settings#{enable_push => false});
+parse_settings_payload(<< 2:16, 1:32, Rest/bits >>, Len, Settings) ->
+	parse_settings_payload(Rest, Len - 6, Settings#{enable_push => true});
+parse_settings_payload(<< 2:16, _:32, _/bits >>, _, _) ->
 	{connection_error, protocol_error, 'The SETTINGS_ENABLE_PUSH value MUST be 0 or 1. (RFC7540 6.5.2)'};
 	{connection_error, protocol_error, 'The SETTINGS_ENABLE_PUSH value MUST be 0 or 1. (RFC7540 6.5.2)'};
 %% SETTINGS_MAX_CONCURRENT_STREAMS.
 %% SETTINGS_MAX_CONCURRENT_STREAMS.
-parse_settings(<< 3:16, Value:32, Rest/bits >>, Len, Settings) ->
-	parse_settings(Rest, Len - 6, Settings#{max_concurrent_streams => Value});
+parse_settings_payload(<< 3:16, Value:32, Rest/bits >>, Len, Settings) ->
+	parse_settings_payload(Rest, Len - 6, Settings#{max_concurrent_streams => Value});
 %% SETTINGS_INITIAL_WINDOW_SIZE.
 %% SETTINGS_INITIAL_WINDOW_SIZE.
-parse_settings(<< 4:16, Value:32, _/bits >>, _, _) when Value > 16#7fffffff ->
+parse_settings_payload(<< 4:16, Value:32, _/bits >>, _, _) when Value > 16#7fffffff ->
 	{connection_error, flow_control_error, 'The maximum SETTINGS_INITIAL_WINDOW_SIZE value is 0x7fffffff. (RFC7540 6.5.2)'};
 	{connection_error, flow_control_error, 'The maximum SETTINGS_INITIAL_WINDOW_SIZE value is 0x7fffffff. (RFC7540 6.5.2)'};
-parse_settings(<< 4:16, Value:32, Rest/bits >>, Len, Settings) ->
-	parse_settings(Rest, Len - 6, Settings#{initial_window_size => Value});
+parse_settings_payload(<< 4:16, Value:32, Rest/bits >>, Len, Settings) ->
+	parse_settings_payload(Rest, Len - 6, Settings#{initial_window_size => Value});
 %% SETTINGS_MAX_FRAME_SIZE.
 %% SETTINGS_MAX_FRAME_SIZE.
-parse_settings(<< 5:16, Value:32, _/bits >>, _, _) when Value =< 16#3fff ->
+parse_settings_payload(<< 5:16, Value:32, _/bits >>, _, _) when Value =< 16#3fff ->
 	{connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be > 0x3fff. (RFC7540 6.5.2)'};
 	{connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be > 0x3fff. (RFC7540 6.5.2)'};
-parse_settings(<< 5:16, Value:32, Rest/bits >>, Len, Settings) when Value =< 16#ffffff ->
-	parse_settings(Rest, Len - 6, Settings#{max_frame_size => Value});
-parse_settings(<< 5:16, _:32, _/bits >>, _, _) ->
+parse_settings_payload(<< 5:16, Value:32, Rest/bits >>, Len, Settings) when Value =< 16#ffffff ->
+	parse_settings_payload(Rest, Len - 6, Settings#{max_frame_size => Value});
+parse_settings_payload(<< 5:16, _:32, _/bits >>, _, _) ->
 	{connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be =< 0xffffff. (RFC7540 6.5.2)'};
 	{connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be =< 0xffffff. (RFC7540 6.5.2)'};
 %% SETTINGS_MAX_HEADER_LIST_SIZE.
 %% SETTINGS_MAX_HEADER_LIST_SIZE.
-parse_settings(<< 6:16, Value:32, Rest/bits >>, Len, Settings) ->
-	parse_settings(Rest, Len - 6, Settings#{max_header_list_size => Value});
-parse_settings(<< _:48, Rest/bits >>, Len, Settings) ->
-	parse_settings(Rest, Len - 6, Settings).
+parse_settings_payload(<< 6:16, Value:32, Rest/bits >>, Len, Settings) ->
+	parse_settings_payload(Rest, Len - 6, Settings#{max_header_list_size => Value});
+parse_settings_payload(<< _:48, Rest/bits >>, Len, Settings) ->
+	parse_settings_payload(Rest, Len - 6, Settings).
 
 
 %% Building.
 %% Building.
 
 

+ 1 - 1
src/cow_http_hd.erl

@@ -1887,7 +1887,7 @@ horse_parse_host_ipv6_v4() ->
 
 
 -spec parse_http2_settings(binary()) -> binary().
 -spec parse_http2_settings(binary()) -> binary().
 parse_http2_settings(HTTP2Settings) ->
 parse_http2_settings(HTTP2Settings) ->
-	base64:decode(HTTP2Settings).
+	cow_http2:parse_settings_payload(base64:decode(HTTP2Settings)).
 
 
 %% @doc Parse the If-Match header.
 %% @doc Parse the If-Match header.