diff --git a/.gitignore b/.gitignore index 8141bfa..9333626 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /cowlib-1.3.0.tar.gz +/cowlib-2.0.0.tar.gz diff --git a/erlang-cowlib-0001-Add-HPACK-decoding-and-encoding-functions.patch b/erlang-cowlib-0001-Add-HPACK-decoding-and-encoding-functions.patch deleted file mode 100644 index eb26cc3..0000000 --- a/erlang-cowlib-0001-Add-HPACK-decoding-and-encoding-functions.patch +++ /dev/null @@ -1,1305 +0,0 @@ -From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= -Date: Thu, 19 Mar 2015 16:07:25 +0100 -Subject: [PATCH] Add HPACK decoding and encoding functions - -No decoding options have been added in this commit. They will be -added in the future. - -Only one encoding option has been added: #{huffman => boolean()}. -It allows to disable Huffman compression of strings. This compression -is enabled by default. - -diff --git a/src/cow_hpack.erl b/src/cow_hpack.erl -new file mode 100644 -index 0000000..efabaa6 ---- /dev/null -+++ b/src/cow_hpack.erl -@@ -0,0 +1,1288 @@ -+%% Copyright (c) 2015, Loïc Hoguin -+%% -+%% Permission to use, copy, modify, and/or distribute this software for any -+%% purpose with or without fee is hereby granted, provided that the above -+%% copyright notice and this permission notice appear in all copies. -+%% -+%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ -+%% The current implementation is not suitable for use in -+%% intermediaries as the information about headers that -+%% should never be indexed is currently lost. -+ -+-module(cow_hpack). -+ -+-export([init/0]). -+-export([init/1]). -+ -+-export([decode/1]). -+-export([decode/2]). -+-export([decode/3]). -+ -+-export([encode/1]). -+-export([encode/2]). -+-export([encode/3]). -+ -+-record(state, { -+ size = 0 :: non_neg_integer(), -+ max_size = 4096 :: non_neg_integer(), -+ dyn_table = [] :: queue:queue({binary(), binary()}) -+}). -+ -+-opaque state() :: #state{}. -+-export_type([state/0]). -+ -+-type opts() :: map(). -+-export_type([opts/0]). -+ -+-ifdef(TEST). -+-include_lib("triq/include/triq.hrl"). -+-endif. -+ -+%% State initialization. -+ -+-spec init() -> state(). -+init() -> -+ #state{}. -+ -+-spec init(non_neg_integer()) -> state(). -+init(MaxSize) -> -+ #state{max_size=MaxSize}. -+ -+%% Decoding. -+ -+-spec decode(binary()) -> {cow_http:headers(), state()}. -+decode(Data) -> -+ decode(Data, init(), #{}). -+ -+-spec decode(binary(), State) -> {cow_http:headers(), State} when State::state(). -+decode(Data, State) -> -+ decode(Data, State, #{}). -+ -+-spec decode(binary(), State, opts()) -> {cow_http:headers(), State} when State::state(). -+decode(Data, State, Opts) -> -+ decode(Data, State, Opts, []). -+ -+decode(<<>>, State, _, Acc) -> -+ {lists:reverse(Acc), State}; -+%% Indexed header field representation. -+decode(<< 1:1, Rest/bits >>, State, Opts, Acc) -> -+ dec_indexed(Rest, State, Opts, Acc); -+%% Literal header field with incremental indexing: new name. -+decode(<< 0:1, 1:1, 0:6, Rest/bits >>, State, Opts, Acc) -> -+ dec_lit_index_new_name(Rest, State, Opts, Acc); -+%% Literal header field with incremental indexing: indexed name. -+decode(<< 0:1, 1:1, Rest/bits >>, State, Opts, Acc) -> -+ dec_lit_index_indexed_name(Rest, State, Opts, Acc); -+%% Literal header field without indexing: new name. -+decode(<< 0:8, Rest/bits >>, State, Opts, Acc) -> -+ dec_lit_no_index_new_name(Rest, State, Opts, Acc); -+%% Literal header field without indexing: indexed name. -+decode(<< 0:4, Rest/bits >>, State, Opts, Acc) -> -+ dec_lit_no_index_indexed_name(Rest, State, Opts, Acc); -+%% Literal header field never indexed: new name. -+%% @todo Keep track of "never indexed" headers. -+decode(<< 0:3, 1:1, 0:4, Rest/bits >>, State, Opts, Acc) -> -+ dec_lit_no_index_new_name(Rest, State, Opts, Acc); -+%% Literal header field never indexed: indexed name. -+%% @todo Keep track of "never indexed" headers. -+decode(<< 0:3, 1:1, Rest/bits >>, State, Opts, Acc) -> -+ dec_lit_no_index_indexed_name(Rest, State, Opts, Acc); -+%% Dynamic table size update. -+decode(<< 0:2, 1:1, Rest/bits >>, State, Opts, Acc) -> -+ dec_table_size_update(Rest, State, Opts, Acc). -+ -+%% Indexed header field representation. -+ -+dec_indexed(Rest, State, Opts, Acc) -> -+ {Index, Rest2} = dec_int7(Rest), -+ {Name, Value} = table_get(Index, State), -+ decode(Rest2, State, Opts, [{Name, Value}|Acc]). -+ -+%% Literal header field with incremental indexing. -+ -+dec_lit_index_new_name(Rest, State, Opts, Acc) -> -+ {Name, Rest2} = dec_str(Rest), -+ dec_lit_index(Rest2, State, Opts, Acc, Name). -+ -+dec_lit_index_indexed_name(Rest, State, Opts, Acc) -> -+ {Index, Rest2} = dec_int6(Rest), -+ Name = table_get_name(Index, State), -+ dec_lit_index(Rest2, State, Opts, Acc, Name). -+ -+dec_lit_index(Rest, State, Opts, Acc, Name) -> -+ {Value, Rest2} = dec_str(Rest), -+ State2 = table_insert({Name, Value}, State), -+ decode(Rest2, State2, Opts, [{Name, Value}|Acc]). -+ -+%% Literal header field without indexing. -+ -+dec_lit_no_index_new_name(Rest, State, Opts, Acc) -> -+ {Name, Rest2} = dec_str(Rest), -+ dec_lit_no_index(Rest2, State, Opts, Acc, Name). -+ -+dec_lit_no_index_indexed_name(Rest, State, Opts, Acc) -> -+ {Index, Rest2} = dec_int4(Rest), -+ Name = table_get_name(Index, State), -+ dec_lit_no_index(Rest2, State, Opts, Acc, Name). -+ -+dec_lit_no_index(Rest, State, Opts, Acc, Name) -> -+ {Value, Rest2} = dec_str(Rest), -+ decode(Rest2, State, Opts, [{Name, Value}|Acc]). -+ -+%% @todo Literal header field never indexed. -+ -+%% Dynamic table size update. -+ -+dec_table_size_update(Rest, State, Opts, Acc) -> -+ {MaxSize, Rest2} = dec_int5(Rest), -+ State2 = table_update_size(MaxSize, State), -+ decode(Rest2, State2, Opts, Acc). -+ -+%% Decode an integer. -+ -+%% The HPACK format has 4 different integer prefixes length (from 4 to 7) -+%% and each can be used to create an indefinite length integer if all bits -+%% of the prefix are set to 1. -+ -+dec_int4(<< 2#1111:4, Rest/bits >>) -> -+ dec_big_int(Rest, 15, 0); -+dec_int4(<< Int:4, Rest/bits >>) -> -+ {Int, Rest}. -+ -+dec_int5(<< 2#11111:5, Rest/bits >>) -> -+ dec_big_int(Rest, 31, 0); -+dec_int5(<< Int:5, Rest/bits >>) -> -+ {Int, Rest}. -+ -+dec_int6(<< 2#111111:6, Rest/bits >>) -> -+ dec_big_int(Rest, 63, 0); -+dec_int6(<< Int:6, Rest/bits >>) -> -+ {Int, Rest}. -+ -+dec_int7(<< 2#1111111:7, Rest/bits >>) -> -+ dec_big_int(Rest, 127, 0); -+dec_int7(<< Int:7, Rest/bits >>) -> -+ {Int, Rest}. -+ -+dec_big_int(<< 0:1, Value:7, Rest/bits >>, Int, M) -> -+ {Int + (Value bsl M), Rest}; -+dec_big_int(<< 1:1, Value:7, Rest/bits >>, Int, M) -> -+ dec_big_int(Rest, Int + (Value bsl M), M + 7). -+ -+%% Decode a string. -+ -+dec_str(<< 0:1, Rest/bits >>) -> -+ {Length, Rest2} = dec_int7(Rest), -+ << Str:Length/binary, Rest3/bits >> = Rest2, -+ {Str, Rest3}; -+dec_str(<< 1:1, Rest/bits >>) -> -+ {Length, Rest2} = dec_int7(Rest), -+ dec_huffman(Rest2, Length * 8, <<>>). -+ -+%% HPACK uses a static code table for Huffman encoded strings. -+%% It has been converted into one clause per code in the following function. -+ -+%% EOS. -+dec_huffman(Rest, 0, String) -> {String, Rest}; -+dec_huffman(<<2#1:1, Rest/bits>>, 1, String) -> {String, Rest}; -+dec_huffman(<<2#11:2, Rest/bits>>, 2, String) -> {String, Rest}; -+dec_huffman(<<2#111:3, Rest/bits>>, 3, String) -> {String, Rest}; -+dec_huffman(<<2#1111:4, Rest/bits>>, 4, String) -> {String, Rest}; -+dec_huffman(<<2#11111:5, Rest/bits>>, 5, String) -> {String, Rest}; -+dec_huffman(<<2#111111:6, Rest/bits>>, 6, String) -> {String, Rest}; -+dec_huffman(<<2#1111111:7, Rest/bits>>, 7, String) -> {String, Rest}; -+%% Static code table. -+dec_huffman(<<2#00000:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#00001:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#00010:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#00011:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#00100:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#00101:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#00110:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#00111:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#01000:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#01001:5, R/bits>>, L, A) -> dec_huffman(R, L - 5, <>); -+dec_huffman(<<2#010100:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#010101:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#010110:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#010111:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011000:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011001:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011010:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011011:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011100:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011101:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011110:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#011111:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100000:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100001:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100010:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100011:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100100:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100101:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100110:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#100111:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#101000:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#101001:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#101010:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#101011:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#101100:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#101101:6, R/bits>>, L, A) -> dec_huffman(R, L - 6, <>); -+dec_huffman(<<2#1011100:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1011101:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1011110:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1011111:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100000:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100001:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100010:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100011:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100100:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100101:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100110:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1100111:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101000:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101001:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101010:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101011:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101100:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101101:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101110:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1101111:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110000:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110001:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110010:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110011:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110100:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110101:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110110:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1110111:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1111000:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1111001:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1111010:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#1111011:7, R/bits>>, L, A) -> dec_huffman(R, L - 7, <>); -+dec_huffman(<<2#11111000:8, R/bits>>, L, A) -> dec_huffman(R, L - 8, <>); -+dec_huffman(<<2#11111001:8, R/bits>>, L, A) -> dec_huffman(R, L - 8, <>); -+dec_huffman(<<2#11111010:8, R/bits>>, L, A) -> dec_huffman(R, L - 8, <>); -+dec_huffman(<<2#11111011:8, R/bits>>, L, A) -> dec_huffman(R, L - 8, <>); -+dec_huffman(<<2#11111100:8, R/bits>>, L, A) -> dec_huffman(R, L - 8, <>); -+dec_huffman(<<2#11111101:8, R/bits>>, L, A) -> dec_huffman(R, L - 8, <>); -+dec_huffman(<<2#1111111000:10, R/bits>>, L, A) -> dec_huffman(R, L - 10, <>); -+dec_huffman(<<2#1111111001:10, R/bits>>, L, A) -> dec_huffman(R, L - 10, <>); -+dec_huffman(<<2#1111111010:10, R/bits>>, L, A) -> dec_huffman(R, L - 10, <>); -+dec_huffman(<<2#1111111011:10, R/bits>>, L, A) -> dec_huffman(R, L - 10, <>); -+dec_huffman(<<2#1111111100:10, R/bits>>, L, A) -> dec_huffman(R, L - 10, <>); -+dec_huffman(<<2#11111111010:11, R/bits>>, L, A) -> dec_huffman(R, L - 11, <>); -+dec_huffman(<<2#11111111011:11, R/bits>>, L, A) -> dec_huffman(R, L - 11, <>); -+dec_huffman(<<2#11111111100:11, R/bits>>, L, A) -> dec_huffman(R, L - 11, <>); -+dec_huffman(<<2#111111111010:12, R/bits>>, L, A) -> dec_huffman(R, L - 12, <>); -+dec_huffman(<<2#111111111011:12, R/bits>>, L, A) -> dec_huffman(R, L - 12, <>); -+dec_huffman(<<2#1111111111000:13, R/bits>>, L, A) -> dec_huffman(R, L - 13, <>); -+dec_huffman(<<2#1111111111001:13, R/bits>>, L, A) -> dec_huffman(R, L - 13, <>); -+dec_huffman(<<2#1111111111010:13, R/bits>>, L, A) -> dec_huffman(R, L - 13, <>); -+dec_huffman(<<2#1111111111011:13, R/bits>>, L, A) -> dec_huffman(R, L - 13, <>); -+dec_huffman(<<2#1111111111100:13, R/bits>>, L, A) -> dec_huffman(R, L - 13, <>); -+dec_huffman(<<2#1111111111101:13, R/bits>>, L, A) -> dec_huffman(R, L - 13, <>); -+dec_huffman(<<2#11111111111100:14, R/bits>>, L, A) -> dec_huffman(R, L - 14, <>); -+dec_huffman(<<2#11111111111101:14, R/bits>>, L, A) -> dec_huffman(R, L - 14, <>); -+dec_huffman(<<2#111111111111100:15, R/bits>>, L, A) -> dec_huffman(R, L - 15, <>); -+dec_huffman(<<2#111111111111101:15, R/bits>>, L, A) -> dec_huffman(R, L - 15, <>); -+dec_huffman(<<2#111111111111110:15, R/bits>>, L, A) -> dec_huffman(R, L - 15, <>); -+dec_huffman(<<2#1111111111111110000:19, R/bits>>, L, A) -> dec_huffman(R, L - 19, <>); -+dec_huffman(<<2#1111111111111110001:19, R/bits>>, L, A) -> dec_huffman(R, L - 19, <>); -+dec_huffman(<<2#1111111111111110010:19, R/bits>>, L, A) -> dec_huffman(R, L - 19, <>); -+dec_huffman(<<2#11111111111111100110:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#11111111111111100111:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#11111111111111101000:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#11111111111111101001:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#11111111111111101010:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#11111111111111101011:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#11111111111111101100:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#11111111111111101101:20, R/bits>>, L, A) -> dec_huffman(R, L - 20, <>); -+dec_huffman(<<2#111111111111111011100:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111011101:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111011110:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111011111:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100000:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100001:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100010:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100011:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100100:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100101:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100110:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111100111:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#111111111111111101000:21, R/bits>>, L, A) -> dec_huffman(R, L - 21, <>); -+dec_huffman(<<2#1111111111111111010010:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111010011:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111010100:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111010101:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111010110:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111010111:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011000:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011001:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011010:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011011:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011100:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011101:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011110:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111011111:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100000:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100001:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100010:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100011:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100100:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100101:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100110:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111100111:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111101000:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111101001:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111101010:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#1111111111111111101011:22, R/bits>>, L, A) -> dec_huffman(R, L - 22, <>); -+dec_huffman(<<2#11111111111111111011000:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111011001:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111011010:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111011011:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111011100:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111011101:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111011110:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111011111:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100000:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100001:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100010:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100011:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100100:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100101:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100110:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111100111:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101000:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101001:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101010:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101011:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101100:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101101:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101110:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111101111:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111110000:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111110001:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111110010:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111110011:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#11111111111111111110100:23, R/bits>>, L, A) -> dec_huffman(R, L - 23, <>); -+dec_huffman(<<2#111111111111111111101010:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111101011:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111101100:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111101101:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111101110:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111101111:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111110000:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111110001:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111110010:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111110011:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111110100:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#111111111111111111110101:24, R/bits>>, L, A) -> dec_huffman(R, L - 24, <>); -+dec_huffman(<<2#1111111111111111111101100:25, R/bits>>, L, A) -> dec_huffman(R, L - 25, <>); -+dec_huffman(<<2#1111111111111111111101101:25, R/bits>>, L, A) -> dec_huffman(R, L - 25, <>); -+dec_huffman(<<2#1111111111111111111101110:25, R/bits>>, L, A) -> dec_huffman(R, L - 25, <>); -+dec_huffman(<<2#1111111111111111111101111:25, R/bits>>, L, A) -> dec_huffman(R, L - 25, <>); -+dec_huffman(<<2#11111111111111111111100000:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111100001:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111100010:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111100011:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111100100:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111100101:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111100110:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111100111:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111101000:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111101001:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111101010:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111101011:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111101100:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111101101:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#11111111111111111111101110:26, R/bits>>, L, A) -> dec_huffman(R, L - 26, <>); -+dec_huffman(<<2#111111111111111111111011110:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111011111:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100000:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100001:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100010:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100011:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100100:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100101:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100110:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111100111:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101000:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101001:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101010:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101011:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101100:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101101:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101110:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111101111:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#111111111111111111111110000:27, R/bits>>, L, A) -> dec_huffman(R, L - 27, <>); -+dec_huffman(<<2#1111111111111111111111100010:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111100011:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111100100:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111100101:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111100110:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111100111:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101000:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101001:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101010:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101011:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101100:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101101:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101110:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111101111:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110000:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110001:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110010:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110011:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110100:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110101:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110110:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111110111:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111111000:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111111001:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111111010:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111111011:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111111100:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111111101:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#1111111111111111111111111110:28, R/bits>>, L, A) -> dec_huffman(R, L - 28, <>); -+dec_huffman(<<2#111111111111111111111111111100:30, R/bits>>, L, A) -> dec_huffman(R, L - 30, <>); -+dec_huffman(<<2#111111111111111111111111111101:30, R/bits>>, L, A) -> dec_huffman(R, L - 30, <>); -+dec_huffman(<<2#111111111111111111111111111110:30, R/bits>>, L, A) -> dec_huffman(R, L - 30, <>). -+ -+-ifdef(TEST). -+req_decode_test() -> -+ %% First request (raw then huffman). -+ {Headers1, State1} = decode(<< 16#828684410f7777772e6578616d706c652e636f6d:160 >>), -+ {Headers1, State1} = decode(<< 16#828684418cf1e3c2e5f23a6ba0ab90f4ff:136 >>), -+ Headers1 = [ -+ {<<":method">>, <<"GET">>}, -+ {<<":scheme">>, <<"http">>}, -+ {<<":path">>, <<"/">>}, -+ {<<":authority">>, <<"www.example.com">>} -+ ], -+ #state{size=57, dyn_table=[{57,{<<":authority">>, <<"www.example.com">>}}]} = State1, -+ %% Second request (raw then huffman). -+ {Headers2, State2} = decode(<< 16#828684be58086e6f2d6361636865:112 >>, State1), -+ {Headers2, State2} = decode(<< 16#828684be5886a8eb10649cbf:96 >>, State1), -+ Headers2 = [ -+ {<<":method">>, <<"GET">>}, -+ {<<":scheme">>, <<"http">>}, -+ {<<":path">>, <<"/">>}, -+ {<<":authority">>, <<"www.example.com">>}, -+ {<<"cache-control">>, <<"no-cache">>} -+ ], -+ #state{size=110, dyn_table=[ -+ {53,{<<"cache-control">>, <<"no-cache">>}}, -+ {57,{<<":authority">>, <<"www.example.com">>}}]} = State2, -+ %% Third request (raw then huffman). -+ {Headers3, State3} = decode(<< 16#828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565:232 >>, State2), -+ {Headers3, State3} = decode(<< 16#828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf:192 >>, State2), -+ Headers3 = [ -+ {<<":method">>, <<"GET">>}, -+ {<<":scheme">>, <<"https">>}, -+ {<<":path">>, <<"/index.html">>}, -+ {<<":authority">>, <<"www.example.com">>}, -+ {<<"custom-key">>, <<"custom-value">>} -+ ], -+ #state{size=164, dyn_table=[ -+ {54,{<<"custom-key">>, <<"custom-value">>}}, -+ {53,{<<"cache-control">>, <<"no-cache">>}}, -+ {57,{<<":authority">>, <<"www.example.com">>}}]} = State3, -+ ok. -+ -+resp_decode_test() -> -+ %% Use a max_size of 256 to trigger header evictions. -+ State0 = init(256), -+ %% First response (raw then huffman). -+ {Headers1, State1} = decode(<< 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >>, State0), -+ {Headers1, State1} = decode(<< 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >>, State0), -+ Headers1 = [ -+ {<<":status">>, <<"302">>}, -+ {<<"cache-control">>, <<"private">>}, -+ {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, -+ {<<"location">>, <<"https://www.example.com">>} -+ ], -+ #state{size=222, dyn_table=[ -+ {63,{<<"location">>, <<"https://www.example.com">>}}, -+ {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, -+ {52,{<<"cache-control">>, <<"private">>}}, -+ {42,{<<":status">>, <<"302">>}}]} = State1, -+ %% Second response (raw then huffman). -+ {Headers2, State2} = decode(<< 16#4803333037c1c0bf:64 >>, State1), -+ {Headers2, State2} = decode(<< 16#4883640effc1c0bf:64 >>, State1), -+ Headers2 = [ -+ {<<":status">>, <<"307">>}, -+ {<<"cache-control">>, <<"private">>}, -+ {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, -+ {<<"location">>, <<"https://www.example.com">>} -+ ], -+ #state{size=180, dyn_table=[ -+ {42,{<<":status">>, <<"307">>}}, -+ {63,{<<"location">>, <<"https://www.example.com">>}}, -+ {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, -+ {52,{<<"cache-control">>, <<"private">>}}]} = State2, -+ %% Third response (raw then huffman). -+ {Headers3, State3} = decode(<< 16#88c1611d4d6f6e2c203231204f637420323031332032303a31333a323220474d54c05a04677a69707738666f6f3d4153444a4b48514b425a584f5157454f50495541585157454f49553b206d61782d6167653d333630303b2076657273696f6e3d31:784 >>, State2), -+ {Headers3, State3} = decode(<< 16#88c16196d07abe941054d444a8200595040b8166e084a62d1bffc05a839bd9ab77ad94e7821dd7f2e6c7b335dfdfcd5b3960d5af27087f3672c1ab270fb5291f9587316065c003ed4ee5b1063d5007:632 >>, State2), -+ Headers3 = [ -+ {<<":status">>, <<"200">>}, -+ {<<"cache-control">>, <<"private">>}, -+ {<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}, -+ {<<"location">>, <<"https://www.example.com">>}, -+ {<<"content-encoding">>, <<"gzip">>}, -+ {<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>} -+ ], -+ #state{size=117, dyn_table=[ -+ {98,{<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>}}, -+ {52,{<<"content-encoding">>, <<"gzip">>}}, -+ {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}}]} = State3, -+ ok. -+-endif. -+ -+%% Encoding. -+ -+-spec encode(cow_http:headers()) -> iodata(). -+encode(Headers) -> -+ encode(Headers, init(), #{}, []). -+ -+-spec encode(cow_http:headers(), State) -> iodata() when State::state(). -+encode(Headers, State) -> -+ encode(Headers, State, #{}, []). -+ -+-spec encode(cow_http:headers(), State, opts()) -> iodata() when State::state(). -+encode(Headers, State, Opts) -> -+ encode(Headers, State, Opts, []). -+ -+%% @todo Handle cases where no/never indexing is expected. -+encode([], State, _, Acc) -> -+ {lists:reverse(Acc), State}; -+encode([Header = {Name, Value}|Tail], State, Opts, Acc) -> -+ case table_find(Header, State) of -+ %% Indexed header field representation. -+ {field, Index} -> -+ encode(Tail, State, Opts, [enc_int7(Index, 2#1)|Acc]); -+ %% Literal header field representation: indexed name. -+ {name, Index} -> -+ State2 = table_insert(Header, State), -+ encode(Tail, State2, Opts, [[enc_int6(Index, 2#01), enc_str(Value, Opts)]|Acc]); -+ %% Literal header field representation: new name. -+ not_found -> -+ State2 = table_insert(Header, State), -+ encode(Tail, State2, Opts, [[<< 0:1, 1:1, 0:6 >>, enc_str(Name, Opts), enc_str(Value, Opts)]|Acc]) -+ end. -+ -+%% Encode an integer. -+ -+enc_int6(Int, Prefix) when Int < 63 -> -+ << Prefix:2, Int:6 >>; -+enc_int6(Int, Prefix) -> -+ [<< Prefix:2, 2#111111:6 >>|enc_big_int(Int - 63, [])]. -+ -+enc_int7(Int, Prefix) when Int < 127 -> -+ << Prefix:1, Int:7 >>; -+enc_int7(Int, Prefix) -> -+ [<< Prefix:1, 2#1111111:7 >>|enc_big_int(Int - 127, [])]. -+ -+enc_big_int(Int, Acc) when Int < 128 -> -+ lists:reverse([<< Int:8 >>|Acc]); -+enc_big_int(Int, Acc) -> -+ enc_big_int(Int bsr 7, [<< 1:1, Int:7 >>|Acc]). -+ -+%% Encode a string. -+ -+enc_str(Str, Opts) -> -+ case maps:get(huffman, Opts, true) of -+ true -> -+ Str2 = enc_huffman(Str, <<>>), -+ [enc_int7(byte_size(Str2), 2#1), Str2]; -+ false -> -+ [enc_int7(iolist_size(Str), 2#0), Str] -+ end. -+ -+enc_huffman(<<>>, Acc) -> -+ case bit_size(Acc) rem 8 of -+ 1 -> << Acc/bits, 2#1111111:7 >>; -+ 2 -> << Acc/bits, 2#111111:6 >>; -+ 3 -> << Acc/bits, 2#11111:5 >>; -+ 4 -> << Acc/bits, 2#1111:4 >>; -+ 5 -> << Acc/bits, 2#111:3 >>; -+ 6 -> << Acc/bits, 2#11:2 >>; -+ 7 -> << Acc/bits, 2#1:1 >>; -+ 0 -> Acc -+ end; -+enc_huffman(<< 0, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111000:13 >>); -+enc_huffman(<< 1, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011000:23 >>); -+enc_huffman(<< 2, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100010:28 >>); -+enc_huffman(<< 3, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100011:28 >>); -+enc_huffman(<< 4, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100100:28 >>); -+enc_huffman(<< 5, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100101:28 >>); -+enc_huffman(<< 6, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100110:28 >>); -+enc_huffman(<< 7, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100111:28 >>); -+enc_huffman(<< 8, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101000:28 >>); -+enc_huffman(<< 9, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101010:24 >>); -+enc_huffman(<< 10, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111111111100:30 >>); -+enc_huffman(<< 11, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101001:28 >>); -+enc_huffman(<< 12, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101010:28 >>); -+enc_huffman(<< 13, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111111111101:30 >>); -+enc_huffman(<< 14, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101011:28 >>); -+enc_huffman(<< 15, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101100:28 >>); -+enc_huffman(<< 16, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101101:28 >>); -+enc_huffman(<< 17, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101110:28 >>); -+enc_huffman(<< 18, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101111:28 >>); -+enc_huffman(<< 19, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110000:28 >>); -+enc_huffman(<< 20, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110001:28 >>); -+enc_huffman(<< 21, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110010:28 >>); -+enc_huffman(<< 22, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111111111110:30 >>); -+enc_huffman(<< 23, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110011:28 >>); -+enc_huffman(<< 24, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110100:28 >>); -+enc_huffman(<< 25, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110101:28 >>); -+enc_huffman(<< 26, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110110:28 >>); -+enc_huffman(<< 27, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110111:28 >>); -+enc_huffman(<< 28, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111000:28 >>); -+enc_huffman(<< 29, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111001:28 >>); -+enc_huffman(<< 30, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111010:28 >>); -+enc_huffman(<< 31, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111011:28 >>); -+enc_huffman(<< 32, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010100:6 >>); -+enc_huffman(<< 33, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111000:10 >>); -+enc_huffman(<< 34, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111001:10 >>); -+enc_huffman(<< 35, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111010:12 >>); -+enc_huffman(<< 36, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111001:13 >>); -+enc_huffman(<< 37, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010101:6 >>); -+enc_huffman(<< 38, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111000:8 >>); -+enc_huffman(<< 39, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111010:11 >>); -+enc_huffman(<< 40, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111010:10 >>); -+enc_huffman(<< 41, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111011:10 >>); -+enc_huffman(<< 42, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111001:8 >>); -+enc_huffman(<< 43, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111011:11 >>); -+enc_huffman(<< 44, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111010:8 >>); -+enc_huffman(<< 45, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010110:6 >>); -+enc_huffman(<< 46, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010111:6 >>); -+enc_huffman(<< 47, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011000:6 >>); -+enc_huffman(<< 48, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00000:5 >>); -+enc_huffman(<< 49, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00001:5 >>); -+enc_huffman(<< 50, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00010:5 >>); -+enc_huffman(<< 51, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011001:6 >>); -+enc_huffman(<< 52, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011010:6 >>); -+enc_huffman(<< 53, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011011:6 >>); -+enc_huffman(<< 54, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011100:6 >>); -+enc_huffman(<< 55, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011101:6 >>); -+enc_huffman(<< 56, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011110:6 >>); -+enc_huffman(<< 57, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011111:6 >>); -+enc_huffman(<< 58, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011100:7 >>); -+enc_huffman(<< 59, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111011:8 >>); -+enc_huffman(<< 60, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111100:15 >>); -+enc_huffman(<< 61, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100000:6 >>); -+enc_huffman(<< 62, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111011:12 >>); -+enc_huffman(<< 63, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111100:10 >>); -+enc_huffman(<< 64, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111010:13 >>); -+enc_huffman(<< 65, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100001:6 >>); -+enc_huffman(<< 66, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011101:7 >>); -+enc_huffman(<< 67, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011110:7 >>); -+enc_huffman(<< 68, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011111:7 >>); -+enc_huffman(<< 69, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100000:7 >>); -+enc_huffman(<< 70, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100001:7 >>); -+enc_huffman(<< 71, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100010:7 >>); -+enc_huffman(<< 72, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100011:7 >>); -+enc_huffman(<< 73, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100100:7 >>); -+enc_huffman(<< 74, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100101:7 >>); -+enc_huffman(<< 75, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100110:7 >>); -+enc_huffman(<< 76, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100111:7 >>); -+enc_huffman(<< 77, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101000:7 >>); -+enc_huffman(<< 78, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101001:7 >>); -+enc_huffman(<< 79, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101010:7 >>); -+enc_huffman(<< 80, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101011:7 >>); -+enc_huffman(<< 81, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101100:7 >>); -+enc_huffman(<< 82, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101101:7 >>); -+enc_huffman(<< 83, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101110:7 >>); -+enc_huffman(<< 84, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101111:7 >>); -+enc_huffman(<< 85, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110000:7 >>); -+enc_huffman(<< 86, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110001:7 >>); -+enc_huffman(<< 87, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110010:7 >>); -+enc_huffman(<< 88, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111100:8 >>); -+enc_huffman(<< 89, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110011:7 >>); -+enc_huffman(<< 90, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111101:8 >>); -+enc_huffman(<< 91, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111011:13 >>); -+enc_huffman(<< 92, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111110000:19 >>); -+enc_huffman(<< 93, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111100:13 >>); -+enc_huffman(<< 94, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111100:14 >>); -+enc_huffman(<< 95, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100010:6 >>); -+enc_huffman(<< 96, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111101:15 >>); -+enc_huffman(<< 97, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00011:5 >>); -+enc_huffman(<< 98, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100011:6 >>); -+enc_huffman(<< 99, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00100:5 >>); -+enc_huffman(<< 100, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100100:6 >>); -+enc_huffman(<< 101, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00101:5 >>); -+enc_huffman(<< 102, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100101:6 >>); -+enc_huffman(<< 103, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100110:6 >>); -+enc_huffman(<< 104, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100111:6 >>); -+enc_huffman(<< 105, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00110:5 >>); -+enc_huffman(<< 106, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110100:7 >>); -+enc_huffman(<< 107, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110101:7 >>); -+enc_huffman(<< 108, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101000:6 >>); -+enc_huffman(<< 109, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101001:6 >>); -+enc_huffman(<< 110, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101010:6 >>); -+enc_huffman(<< 111, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00111:5 >>); -+enc_huffman(<< 112, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101011:6 >>); -+enc_huffman(<< 113, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110110:7 >>); -+enc_huffman(<< 114, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101100:6 >>); -+enc_huffman(<< 115, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#01000:5 >>); -+enc_huffman(<< 116, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#01001:5 >>); -+enc_huffman(<< 117, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101101:6 >>); -+enc_huffman(<< 118, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110111:7 >>); -+enc_huffman(<< 119, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111000:7 >>); -+enc_huffman(<< 120, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111001:7 >>); -+enc_huffman(<< 121, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111010:7 >>); -+enc_huffman(<< 122, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111011:7 >>); -+enc_huffman(<< 123, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111110:15 >>); -+enc_huffman(<< 124, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111100:11 >>); -+enc_huffman(<< 125, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111101:14 >>); -+enc_huffman(<< 126, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111101:13 >>); -+enc_huffman(<< 127, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111100:28 >>); -+enc_huffman(<< 128, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111100110:20 >>); -+enc_huffman(<< 129, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010010:22 >>); -+enc_huffman(<< 130, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111100111:20 >>); -+enc_huffman(<< 131, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101000:20 >>); -+enc_huffman(<< 132, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010011:22 >>); -+enc_huffman(<< 133, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010100:22 >>); -+enc_huffman(<< 134, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010101:22 >>); -+enc_huffman(<< 135, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011001:23 >>); -+enc_huffman(<< 136, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010110:22 >>); -+enc_huffman(<< 137, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011010:23 >>); -+enc_huffman(<< 138, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011011:23 >>); -+enc_huffman(<< 139, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011100:23 >>); -+enc_huffman(<< 140, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011101:23 >>); -+enc_huffman(<< 141, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011110:23 >>); -+enc_huffman(<< 142, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101011:24 >>); -+enc_huffman(<< 143, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011111:23 >>); -+enc_huffman(<< 144, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101100:24 >>); -+enc_huffman(<< 145, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101101:24 >>); -+enc_huffman(<< 146, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010111:22 >>); -+enc_huffman(<< 147, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100000:23 >>); -+enc_huffman(<< 148, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101110:24 >>); -+enc_huffman(<< 149, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100001:23 >>); -+enc_huffman(<< 150, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100010:23 >>); -+enc_huffman(<< 151, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100011:23 >>); -+enc_huffman(<< 152, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100100:23 >>); -+enc_huffman(<< 153, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011100:21 >>); -+enc_huffman(<< 154, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011000:22 >>); -+enc_huffman(<< 155, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100101:23 >>); -+enc_huffman(<< 156, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011001:22 >>); -+enc_huffman(<< 157, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100110:23 >>); -+enc_huffman(<< 158, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100111:23 >>); -+enc_huffman(<< 159, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101111:24 >>); -+enc_huffman(<< 160, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011010:22 >>); -+enc_huffman(<< 161, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011101:21 >>); -+enc_huffman(<< 162, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101001:20 >>); -+enc_huffman(<< 163, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011011:22 >>); -+enc_huffman(<< 164, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011100:22 >>); -+enc_huffman(<< 165, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101000:23 >>); -+enc_huffman(<< 166, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101001:23 >>); -+enc_huffman(<< 167, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011110:21 >>); -+enc_huffman(<< 168, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101010:23 >>); -+enc_huffman(<< 169, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011101:22 >>); -+enc_huffman(<< 170, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011110:22 >>); -+enc_huffman(<< 171, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110000:24 >>); -+enc_huffman(<< 172, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011111:21 >>); -+enc_huffman(<< 173, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011111:22 >>); -+enc_huffman(<< 174, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101011:23 >>); -+enc_huffman(<< 175, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101100:23 >>); -+enc_huffman(<< 176, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100000:21 >>); -+enc_huffman(<< 177, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100001:21 >>); -+enc_huffman(<< 178, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100000:22 >>); -+enc_huffman(<< 179, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100010:21 >>); -+enc_huffman(<< 180, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101101:23 >>); -+enc_huffman(<< 181, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100001:22 >>); -+enc_huffman(<< 182, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101110:23 >>); -+enc_huffman(<< 183, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101111:23 >>); -+enc_huffman(<< 184, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101010:20 >>); -+enc_huffman(<< 185, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100010:22 >>); -+enc_huffman(<< 186, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100011:22 >>); -+enc_huffman(<< 187, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100100:22 >>); -+enc_huffman(<< 188, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110000:23 >>); -+enc_huffman(<< 189, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100101:22 >>); -+enc_huffman(<< 190, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100110:22 >>); -+enc_huffman(<< 191, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110001:23 >>); -+enc_huffman(<< 192, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100000:26 >>); -+enc_huffman(<< 193, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100001:26 >>); -+enc_huffman(<< 194, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101011:20 >>); -+enc_huffman(<< 195, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111110001:19 >>); -+enc_huffman(<< 196, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100111:22 >>); -+enc_huffman(<< 197, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110010:23 >>); -+enc_huffman(<< 198, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101000:22 >>); -+enc_huffman(<< 199, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101100:25 >>); -+enc_huffman(<< 200, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100010:26 >>); -+enc_huffman(<< 201, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100011:26 >>); -+enc_huffman(<< 202, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100100:26 >>); -+enc_huffman(<< 203, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111011110:27 >>); -+enc_huffman(<< 204, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111011111:27 >>); -+enc_huffman(<< 205, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100101:26 >>); -+enc_huffman(<< 206, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110001:24 >>); -+enc_huffman(<< 207, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101101:25 >>); -+enc_huffman(<< 208, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111110010:19 >>); -+enc_huffman(<< 209, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100011:21 >>); -+enc_huffman(<< 210, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100110:26 >>); -+enc_huffman(<< 211, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100000:27 >>); -+enc_huffman(<< 212, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100001:27 >>); -+enc_huffman(<< 213, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100111:26 >>); -+enc_huffman(<< 214, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100010:27 >>); -+enc_huffman(<< 215, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110010:24 >>); -+enc_huffman(<< 216, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100100:21 >>); -+enc_huffman(<< 217, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100101:21 >>); -+enc_huffman(<< 218, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101000:26 >>); -+enc_huffman(<< 219, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101001:26 >>); -+enc_huffman(<< 220, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111101:28 >>); -+enc_huffman(<< 221, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100011:27 >>); -+enc_huffman(<< 222, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100100:27 >>); -+enc_huffman(<< 223, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100101:27 >>); -+enc_huffman(<< 224, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101100:20 >>); -+enc_huffman(<< 225, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110011:24 >>); -+enc_huffman(<< 226, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101101:20 >>); -+enc_huffman(<< 227, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100110:21 >>); -+enc_huffman(<< 228, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101001:22 >>); -+enc_huffman(<< 229, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100111:21 >>); -+enc_huffman(<< 230, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111101000:21 >>); -+enc_huffman(<< 231, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110011:23 >>); -+enc_huffman(<< 232, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101010:22 >>); -+enc_huffman(<< 233, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101011:22 >>); -+enc_huffman(<< 234, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101110:25 >>); -+enc_huffman(<< 235, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101111:25 >>); -+enc_huffman(<< 236, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110100:24 >>); -+enc_huffman(<< 237, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110101:24 >>); -+enc_huffman(<< 238, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101010:26 >>); -+enc_huffman(<< 239, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110100:23 >>); -+enc_huffman(<< 240, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101011:26 >>); -+enc_huffman(<< 241, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100110:27 >>); -+enc_huffman(<< 242, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101100:26 >>); -+enc_huffman(<< 243, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101101:26 >>); -+enc_huffman(<< 244, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100111:27 >>); -+enc_huffman(<< 245, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101000:27 >>); -+enc_huffman(<< 246, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101001:27 >>); -+enc_huffman(<< 247, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101010:27 >>); -+enc_huffman(<< 248, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101011:27 >>); -+enc_huffman(<< 249, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111110:28 >>); -+enc_huffman(<< 250, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101100:27 >>); -+enc_huffman(<< 251, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101101:27 >>); -+enc_huffman(<< 252, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101110:27 >>); -+enc_huffman(<< 253, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101111:27 >>); -+enc_huffman(<< 254, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111110000:27 >>); -+enc_huffman(<< 255, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101110:26 >>). -+ -+-ifdef(TEST). -+req_encode_test() -> -+ %% First request (raw then huffman). -+ Headers1 = [ -+ {<<":method">>, <<"GET">>}, -+ {<<":scheme">>, <<"http">>}, -+ {<<":path">>, <<"/">>}, -+ {<<":authority">>, <<"www.example.com">>} -+ ], -+ {Raw1, State1} = encode(Headers1, init(), #{huffman => false}), -+ << 16#828684410f7777772e6578616d706c652e636f6d:160 >> = iolist_to_binary(Raw1), -+ {Huff1, State1} = encode(Headers1), -+ << 16#828684418cf1e3c2e5f23a6ba0ab90f4ff:136 >> = iolist_to_binary(Huff1), -+ #state{size=57, dyn_table=[{57,{<<":authority">>, <<"www.example.com">>}}]} = State1, -+ %% Second request (raw then huffman). -+ Headers2 = [ -+ {<<":method">>, <<"GET">>}, -+ {<<":scheme">>, <<"http">>}, -+ {<<":path">>, <<"/">>}, -+ {<<":authority">>, <<"www.example.com">>}, -+ {<<"cache-control">>, <<"no-cache">>} -+ ], -+ {Raw2, State2} = encode(Headers2, State1, #{huffman => false}), -+ << 16#828684be58086e6f2d6361636865:112 >> = iolist_to_binary(Raw2), -+ {Huff2, State2} = encode(Headers2, State1), -+ << 16#828684be5886a8eb10649cbf:96 >> = iolist_to_binary(Huff2), -+ #state{size=110, dyn_table=[ -+ {53,{<<"cache-control">>, <<"no-cache">>}}, -+ {57,{<<":authority">>, <<"www.example.com">>}}]} = State2, -+ %% Third request (raw then huffman). -+ Headers3 = [ -+ {<<":method">>, <<"GET">>}, -+ {<<":scheme">>, <<"https">>}, -+ {<<":path">>, <<"/index.html">>}, -+ {<<":authority">>, <<"www.example.com">>}, -+ {<<"custom-key">>, <<"custom-value">>} -+ ], -+ {Raw3, State3} = encode(Headers3, State2, #{huffman => false}), -+ << 16#828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565:232 >> = iolist_to_binary(Raw3), -+ {Huff3, State3} = encode(Headers3, State2), -+ << 16#828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf:192 >> = iolist_to_binary(Huff3), -+ #state{size=164, dyn_table=[ -+ {54,{<<"custom-key">>, <<"custom-value">>}}, -+ {53,{<<"cache-control">>, <<"no-cache">>}}, -+ {57,{<<":authority">>, <<"www.example.com">>}}]} = State3, -+ ok. -+ -+resp_encode_test() -> -+ %% Use a max_size of 256 to trigger header evictions. -+ State0 = init(256), -+ %% First response (raw then huffman). -+ Headers1 = [ -+ {<<":status">>, <<"302">>}, -+ {<<"cache-control">>, <<"private">>}, -+ {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, -+ {<<"location">>, <<"https://www.example.com">>} -+ ], -+ {Raw1, State1} = encode(Headers1, State0, #{huffman => false}), -+ << 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >> = iolist_to_binary(Raw1), -+ {Huff1, State1} = encode(Headers1, State0), -+ << 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >> = iolist_to_binary(Huff1), -+ #state{size=222, dyn_table=[ -+ {63,{<<"location">>, <<"https://www.example.com">>}}, -+ {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, -+ {52,{<<"cache-control">>, <<"private">>}}, -+ {42,{<<":status">>, <<"302">>}}]} = State1, -+ %% Second response (raw then huffman). -+ Headers2 = [ -+ {<<":status">>, <<"307">>}, -+ {<<"cache-control">>, <<"private">>}, -+ {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, -+ {<<"location">>, <<"https://www.example.com">>} -+ ], -+ {Raw2, State2} = encode(Headers2, State1, #{huffman => false}), -+ << 16#4803333037c1c0bf:64 >> = iolist_to_binary(Raw2), -+ {Huff2, State2} = encode(Headers2, State1), -+ << 16#4883640effc1c0bf:64 >> = iolist_to_binary(Huff2), -+ #state{size=180, dyn_table=[ -+ {42,{<<":status">>, <<"307">>}}, -+ {63,{<<"location">>, <<"https://www.example.com">>}}, -+ {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, -+ {52,{<<"cache-control">>, <<"private">>}}]} = State2, -+ %% Third response (raw then huffman). -+ Headers3 = [ -+ {<<":status">>, <<"200">>}, -+ {<<"cache-control">>, <<"private">>}, -+ {<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}, -+ {<<"location">>, <<"https://www.example.com">>}, -+ {<<"content-encoding">>, <<"gzip">>}, -+ {<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>} -+ ], -+ {Raw3, State3} = encode(Headers3, State2, #{huffman => false}), -+ << 16#88c1611d4d6f6e2c203231204f637420323031332032303a31333a323220474d54c05a04677a69707738666f6f3d4153444a4b48514b425a584f5157454f50495541585157454f49553b206d61782d6167653d333630303b2076657273696f6e3d31:784 >> = iolist_to_binary(Raw3), -+ {Huff3, State3} = encode(Headers3, State2), -+ << 16#88c16196d07abe941054d444a8200595040b8166e084a62d1bffc05a839bd9ab77ad94e7821dd7f2e6c7b335dfdfcd5b3960d5af27087f3672c1ab270fb5291f9587316065c003ed4ee5b1063d5007:632 >> = iolist_to_binary(Huff3), -+ #state{size=117, dyn_table=[ -+ {98,{<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>}}, -+ {52,{<<"content-encoding">>, <<"gzip">>}}, -+ {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}}]} = State3, -+ ok. -+-endif. -+ -+%% Static and dynamic tables. -+ -+%% @todo There must be a more efficient way. -+table_find({Name, Value}, State) -> -+ case table_find_field({Name, iolist_to_binary(Value)}, State) of -+ not_found -> -+ case table_find_name(Name, State) of -+ NotFound = not_found -> -+ NotFound; -+ Found -> -+ {name, Found} -+ end; -+ Found -> -+ {field, Found} -+ end. -+ -+table_find_field({<<":authority">>, <<>>}, _) -> 1; -+table_find_field({<<":method">>, <<"GET">>}, _) -> 2; -+table_find_field({<<":method">>, <<"POST">>}, _) -> 3; -+table_find_field({<<":path">>, <<"/">>}, _) -> 4; -+table_find_field({<<":path">>, <<"/index.html">>}, _) -> 5; -+table_find_field({<<":scheme">>, <<"http">>}, _) -> 6; -+table_find_field({<<":scheme">>, <<"https">>}, _) -> 7; -+table_find_field({<<":status">>, <<"200">>}, _) -> 8; -+table_find_field({<<":status">>, <<"204">>}, _) -> 9; -+table_find_field({<<":status">>, <<"206">>}, _) -> 10; -+table_find_field({<<":status">>, <<"304">>}, _) -> 11; -+table_find_field({<<":status">>, <<"400">>}, _) -> 12; -+table_find_field({<<":status">>, <<"404">>}, _) -> 13; -+table_find_field({<<":status">>, <<"500">>}, _) -> 14; -+table_find_field({<<"accept-charset">>, <<>>}, _) -> 15; -+table_find_field({<<"accept-encoding">>, <<"gzip, deflate">>}, _) -> 16; -+table_find_field({<<"accept-language">>, <<>>}, _) -> 17; -+table_find_field({<<"accept-ranges">>, <<>>}, _) -> 18; -+table_find_field({<<"accept">>, <<>>}, _) -> 19; -+table_find_field({<<"access-control-allow-origin">>, <<>>}, _) -> 20; -+table_find_field({<<"age">>, <<>>}, _) -> 21; -+table_find_field({<<"allow">>, <<>>}, _) -> 22; -+table_find_field({<<"authorization">>, <<>>}, _) -> 23; -+table_find_field({<<"cache-control">>, <<>>}, _) -> 24; -+table_find_field({<<"content-disposition">>, <<>>}, _) -> 25; -+table_find_field({<<"content-encoding">>, <<>>}, _) -> 26; -+table_find_field({<<"content-language">>, <<>>}, _) -> 27; -+table_find_field({<<"content-length">>, <<>>}, _) -> 28; -+table_find_field({<<"content-location">>, <<>>}, _) -> 29; -+table_find_field({<<"content-range">>, <<>>}, _) -> 30; -+table_find_field({<<"content-type">>, <<>>}, _) -> 31; -+table_find_field({<<"cookie">>, <<>>}, _) -> 32; -+table_find_field({<<"date">>, <<>>}, _) -> 33; -+table_find_field({<<"etag">>, <<>>}, _) -> 34; -+table_find_field({<<"expect">>, <<>>}, _) -> 35; -+table_find_field({<<"expires">>, <<>>}, _) -> 36; -+table_find_field({<<"from">>, <<>>}, _) -> 37; -+table_find_field({<<"host">>, <<>>}, _) -> 38; -+table_find_field({<<"if-match">>, <<>>}, _) -> 39; -+table_find_field({<<"if-modified-since">>, <<>>}, _) -> 40; -+table_find_field({<<"if-none-match">>, <<>>}, _) -> 41; -+table_find_field({<<"if-range">>, <<>>}, _) -> 42; -+table_find_field({<<"if-unmodified-since">>, <<>>}, _) -> 43; -+table_find_field({<<"last-modified">>, <<>>}, _) -> 44; -+table_find_field({<<"link">>, <<>>}, _) -> 45; -+table_find_field({<<"location">>, <<>>}, _) -> 46; -+table_find_field({<<"max-forwards">>, <<>>}, _) -> 47; -+table_find_field({<<"proxy-authenticate">>, <<>>}, _) -> 48; -+table_find_field({<<"proxy-authorization">>, <<>>}, _) -> 49; -+table_find_field({<<"range">>, <<>>}, _) -> 50; -+table_find_field({<<"referer">>, <<>>}, _) -> 51; -+table_find_field({<<"refresh">>, <<>>}, _) -> 52; -+table_find_field({<<"retry-after">>, <<>>}, _) -> 53; -+table_find_field({<<"server">>, <<>>}, _) -> 54; -+table_find_field({<<"set-cookie">>, <<>>}, _) -> 55; -+table_find_field({<<"strict-transport-security">>, <<>>}, _) -> 56; -+table_find_field({<<"transfer-encoding">>, <<>>}, _) -> 57; -+table_find_field({<<"user-agent">>, <<>>}, _) -> 58; -+table_find_field({<<"vary">>, <<>>}, _) -> 59; -+table_find_field({<<"via">>, <<>>}, _) -> 60; -+table_find_field({<<"www-authenticate">>, <<>>}, _) -> 61; -+table_find_field(Header, #state{dyn_table=DynamicTable}) -> -+ table_find_field_dyn(Header, DynamicTable, 62). -+ -+table_find_field_dyn(_, [], _) -> not_found; -+table_find_field_dyn(Header, [{_, Header}|_], Index) -> Index; -+table_find_field_dyn(Header, [_|Tail], Index) -> table_find_field_dyn(Header, Tail, Index + 1). -+ -+table_find_name(<<":authority">>, _) -> 1; -+table_find_name(<<":method">>, _) -> 2; -+table_find_name(<<":path">>, _) -> 4; -+table_find_name(<<":scheme">>, _) -> 6; -+table_find_name(<<":status">>, _) -> 8; -+table_find_name(<<"accept-charset">>, _) -> 15; -+table_find_name(<<"accept-encoding">>, _) -> 16; -+table_find_name(<<"accept-language">>, _) -> 17; -+table_find_name(<<"accept-ranges">>, _) -> 18; -+table_find_name(<<"accept">>, _) -> 19; -+table_find_name(<<"access-control-allow-origin">>, _) -> 20; -+table_find_name(<<"age">>, _) -> 21; -+table_find_name(<<"allow">>, _) -> 22; -+table_find_name(<<"authorization">>, _) -> 23; -+table_find_name(<<"cache-control">>, _) -> 24; -+table_find_name(<<"content-disposition">>, _) -> 25; -+table_find_name(<<"content-encoding">>, _) -> 26; -+table_find_name(<<"content-language">>, _) -> 27; -+table_find_name(<<"content-length">>, _) -> 28; -+table_find_name(<<"content-location">>, _) -> 29; -+table_find_name(<<"content-range">>, _) -> 30; -+table_find_name(<<"content-type">>, _) -> 31; -+table_find_name(<<"cookie">>, _) -> 32; -+table_find_name(<<"date">>, _) -> 33; -+table_find_name(<<"etag">>, _) -> 34; -+table_find_name(<<"expect">>, _) -> 35; -+table_find_name(<<"expires">>, _) -> 36; -+table_find_name(<<"from">>, _) -> 37; -+table_find_name(<<"host">>, _) -> 38; -+table_find_name(<<"if-match">>, _) -> 39; -+table_find_name(<<"if-modified-since">>, _) -> 40; -+table_find_name(<<"if-none-match">>, _) -> 41; -+table_find_name(<<"if-range">>, _) -> 42; -+table_find_name(<<"if-unmodified-since">>, _) -> 43; -+table_find_name(<<"last-modified">>, _) -> 44; -+table_find_name(<<"link">>, _) -> 45; -+table_find_name(<<"location">>, _) -> 46; -+table_find_name(<<"max-forwards">>, _) -> 47; -+table_find_name(<<"proxy-authenticate">>, _) -> 48; -+table_find_name(<<"proxy-authorization">>, _) -> 49; -+table_find_name(<<"range">>, _) -> 50; -+table_find_name(<<"referer">>, _) -> 51; -+table_find_name(<<"refresh">>, _) -> 52; -+table_find_name(<<"retry-after">>, _) -> 53; -+table_find_name(<<"server">>, _) -> 54; -+table_find_name(<<"set-cookie">>, _) -> 55; -+table_find_name(<<"strict-transport-security">>, _) -> 56; -+table_find_name(<<"transfer-encoding">>, _) -> 57; -+table_find_name(<<"user-agent">>, _) -> 58; -+table_find_name(<<"vary">>, _) -> 59; -+table_find_name(<<"via">>, _) -> 60; -+table_find_name(<<"www-authenticate">>, _) -> 61; -+table_find_name(Name, #state{dyn_table=DynamicTable}) -> -+ table_find_name_dyn(Name, DynamicTable, 62). -+ -+table_find_name_dyn(_, [], _) -> not_found; -+table_find_name_dyn(Name, [{Name, _}|_], Index) -> Index; -+table_find_name_dyn(Name, [_|Tail], Index) -> table_find_name_dyn(Name, Tail, Index + 1). -+ -+table_get(1, _) -> {<<":authority">>, <<>>}; -+table_get(2, _) -> {<<":method">>, <<"GET">>}; -+table_get(3, _) -> {<<":method">>, <<"POST">>}; -+table_get(4, _) -> {<<":path">>, <<"/">>}; -+table_get(5, _) -> {<<":path">>, <<"/index.html">>}; -+table_get(6, _) -> {<<":scheme">>, <<"http">>}; -+table_get(7, _) -> {<<":scheme">>, <<"https">>}; -+table_get(8, _) -> {<<":status">>, <<"200">>}; -+table_get(9, _) -> {<<":status">>, <<"204">>}; -+table_get(10, _) -> {<<":status">>, <<"206">>}; -+table_get(11, _) -> {<<":status">>, <<"304">>}; -+table_get(12, _) -> {<<":status">>, <<"400">>}; -+table_get(13, _) -> {<<":status">>, <<"404">>}; -+table_get(14, _) -> {<<":status">>, <<"500">>}; -+table_get(15, _) -> {<<"accept-charset">>, <<>>}; -+table_get(16, _) -> {<<"accept-encoding">>, <<"gzip, deflate">>}; -+table_get(17, _) -> {<<"accept-language">>, <<>>}; -+table_get(18, _) -> {<<"accept-ranges">>, <<>>}; -+table_get(19, _) -> {<<"accept">>, <<>>}; -+table_get(20, _) -> {<<"access-control-allow-origin">>, <<>>}; -+table_get(21, _) -> {<<"age">>, <<>>}; -+table_get(22, _) -> {<<"allow">>, <<>>}; -+table_get(23, _) -> {<<"authorization">>, <<>>}; -+table_get(24, _) -> {<<"cache-control">>, <<>>}; -+table_get(25, _) -> {<<"content-disposition">>, <<>>}; -+table_get(26, _) -> {<<"content-encoding">>, <<>>}; -+table_get(27, _) -> {<<"content-language">>, <<>>}; -+table_get(28, _) -> {<<"content-length">>, <<>>}; -+table_get(29, _) -> {<<"content-location">>, <<>>}; -+table_get(30, _) -> {<<"content-range">>, <<>>}; -+table_get(31, _) -> {<<"content-type">>, <<>>}; -+table_get(32, _) -> {<<"cookie">>, <<>>}; -+table_get(33, _) -> {<<"date">>, <<>>}; -+table_get(34, _) -> {<<"etag">>, <<>>}; -+table_get(35, _) -> {<<"expect">>, <<>>}; -+table_get(36, _) -> {<<"expires">>, <<>>}; -+table_get(37, _) -> {<<"from">>, <<>>}; -+table_get(38, _) -> {<<"host">>, <<>>}; -+table_get(39, _) -> {<<"if-match">>, <<>>}; -+table_get(40, _) -> {<<"if-modified-since">>, <<>>}; -+table_get(41, _) -> {<<"if-none-match">>, <<>>}; -+table_get(42, _) -> {<<"if-range">>, <<>>}; -+table_get(43, _) -> {<<"if-unmodified-since">>, <<>>}; -+table_get(44, _) -> {<<"last-modified">>, <<>>}; -+table_get(45, _) -> {<<"link">>, <<>>}; -+table_get(46, _) -> {<<"location">>, <<>>}; -+table_get(47, _) -> {<<"max-forwards">>, <<>>}; -+table_get(48, _) -> {<<"proxy-authenticate">>, <<>>}; -+table_get(49, _) -> {<<"proxy-authorization">>, <<>>}; -+table_get(50, _) -> {<<"range">>, <<>>}; -+table_get(51, _) -> {<<"referer">>, <<>>}; -+table_get(52, _) -> {<<"refresh">>, <<>>}; -+table_get(53, _) -> {<<"retry-after">>, <<>>}; -+table_get(54, _) -> {<<"server">>, <<>>}; -+table_get(55, _) -> {<<"set-cookie">>, <<>>}; -+table_get(56, _) -> {<<"strict-transport-security">>, <<>>}; -+table_get(57, _) -> {<<"transfer-encoding">>, <<>>}; -+table_get(58, _) -> {<<"user-agent">>, <<>>}; -+table_get(59, _) -> {<<"vary">>, <<>>}; -+table_get(60, _) -> {<<"via">>, <<>>}; -+table_get(61, _) -> {<<"www-authenticate">>, <<>>}; -+table_get(Index, #state{dyn_table=DynamicTable}) -> -+ {_, Header} = lists:nth(Index - 61, DynamicTable), -+ Header. -+ -+table_get_name(1, _) -> <<":authority">>; -+table_get_name(2, _) -> <<":method">>; -+table_get_name(3, _) -> <<":method">>; -+table_get_name(4, _) -> <<":path">>; -+table_get_name(5, _) -> <<":path">>; -+table_get_name(6, _) -> <<":scheme">>; -+table_get_name(7, _) -> <<":scheme">>; -+table_get_name(8, _) -> <<":status">>; -+table_get_name(9, _) -> <<":status">>; -+table_get_name(10, _) -> <<":status">>; -+table_get_name(11, _) -> <<":status">>; -+table_get_name(12, _) -> <<":status">>; -+table_get_name(13, _) -> <<":status">>; -+table_get_name(14, _) -> <<":status">>; -+table_get_name(15, _) -> <<"accept-charset">>; -+table_get_name(16, _) -> <<"accept-encoding">>; -+table_get_name(17, _) -> <<"accept-language">>; -+table_get_name(18, _) -> <<"accept-ranges">>; -+table_get_name(19, _) -> <<"accept">>; -+table_get_name(20, _) -> <<"access-control-allow-origin">>; -+table_get_name(21, _) -> <<"age">>; -+table_get_name(22, _) -> <<"allow">>; -+table_get_name(23, _) -> <<"authorization">>; -+table_get_name(24, _) -> <<"cache-control">>; -+table_get_name(25, _) -> <<"content-disposition">>; -+table_get_name(26, _) -> <<"content-encoding">>; -+table_get_name(27, _) -> <<"content-language">>; -+table_get_name(28, _) -> <<"content-length">>; -+table_get_name(29, _) -> <<"content-location">>; -+table_get_name(30, _) -> <<"content-range">>; -+table_get_name(31, _) -> <<"content-type">>; -+table_get_name(32, _) -> <<"cookie">>; -+table_get_name(33, _) -> <<"date">>; -+table_get_name(34, _) -> <<"etag">>; -+table_get_name(35, _) -> <<"expect">>; -+table_get_name(36, _) -> <<"expires">>; -+table_get_name(37, _) -> <<"from">>; -+table_get_name(38, _) -> <<"host">>; -+table_get_name(39, _) -> <<"if-match">>; -+table_get_name(40, _) -> <<"if-modified-since">>; -+table_get_name(41, _) -> <<"if-none-match">>; -+table_get_name(42, _) -> <<"if-range">>; -+table_get_name(43, _) -> <<"if-unmodified-since">>; -+table_get_name(44, _) -> <<"last-modified">>; -+table_get_name(45, _) -> <<"link">>; -+table_get_name(46, _) -> <<"location">>; -+table_get_name(47, _) -> <<"max-forwards">>; -+table_get_name(48, _) -> <<"proxy-authenticate">>; -+table_get_name(49, _) -> <<"proxy-authorization">>; -+table_get_name(50, _) -> <<"range">>; -+table_get_name(51, _) -> <<"referer">>; -+table_get_name(52, _) -> <<"refresh">>; -+table_get_name(53, _) -> <<"retry-after">>; -+table_get_name(54, _) -> <<"server">>; -+table_get_name(55, _) -> <<"set-cookie">>; -+table_get_name(56, _) -> <<"strict-transport-security">>; -+table_get_name(57, _) -> <<"transfer-encoding">>; -+table_get_name(58, _) -> <<"user-agent">>; -+table_get_name(59, _) -> <<"vary">>; -+table_get_name(60, _) -> <<"via">>; -+table_get_name(61, _) -> <<"www-authenticate">>; -+table_get_name(Index, #state{dyn_table=DynamicTable}) -> -+ {_, {Name, _}} = lists:nth(Index - 61, DynamicTable), -+ Name. -+ -+table_insert(Entry = {Name, Value}, State=#state{size=Size, max_size=MaxSize, dyn_table=DynamicTable}) -> -+ EntrySize = byte_size(Name) + byte_size(Value) + 32, -+ Size2 = Size + EntrySize, -+ {DynamicTable2, Size3} = if -+ Size + EntrySize > MaxSize -> -+ table_resize(DynamicTable, MaxSize - EntrySize, 0, []); -+ true -> -+ {DynamicTable, Size2} -+ end, -+ State#state{size=Size3, dyn_table=[{EntrySize, Entry}|DynamicTable2]}. -+ -+table_resize([], _, Size, Acc) -> -+ {lists:reverse(Acc), Size}; -+table_resize([{EntrySize, _}|_], MaxSize, Size, Acc) when Size + EntrySize > MaxSize -> -+ {lists:reverse(Acc), Size}; -+table_resize([Entry = {EntrySize, _}|Tail], MaxSize, Size, Acc) -> -+ table_resize(Tail, MaxSize, Size + EntrySize, [Entry|Acc]). -+ -+table_update_size(0, State) -> -+ State#state{size=0, max_size=0, dyn_table=[]}; -+table_update_size(MaxSize, State=#state{max_size=MaxSize}) -> -+ State; -+table_update_size(MaxSize, #state{dyn_table=DynTable}) -> -+ {DynTable2, Size} = table_resize(DynTable, MaxSize, 0, []), -+ #state{size=Size, max_size=MaxSize, dyn_table=DynTable2}. -+ -+-ifdef(TEST). -+prop_str_raw() -> -+ ?FORALL(Str, binary(), begin -+ {Str, <<>>} =:= dec_str(iolist_to_binary(enc_str(Str, #{huffman => false}))) -+ end). -+ -+prop_str_huffman() -> -+ ?FORALL(Str, binary(), begin -+ {Str, <<>>} =:= dec_str(iolist_to_binary(enc_str(Str, #{huffman => true}))) -+ end). -+-endif. diff --git a/erlang-cowlib-0002-WS-accepts-iodata-so-byte_size-won-t-work-unless-we-.patch b/erlang-cowlib-0002-WS-accepts-iodata-so-byte_size-won-t-work-unless-we-.patch deleted file mode 100644 index 4f1b6f6..0000000 --- a/erlang-cowlib-0002-WS-accepts-iodata-so-byte_size-won-t-work-unless-we-.patch +++ /dev/null @@ -1,18 +0,0 @@ -From: Rob Ashton -Date: Thu, 9 Apr 2015 18:01:38 +0100 -Subject: [PATCH] WS accepts iodata, so byte_size won't work unless we flatten - - -diff --git a/src/cow_ws.erl b/src/cow_ws.erl -index c89c17a..c025b38 100644 ---- a/src/cow_ws.erl -+++ b/src/cow_ws.erl -@@ -580,7 +580,7 @@ masked_frame({binary, Payload}, _) -> - [<< 1:1, 0:3, 2:4, 1:1, Len/bits >>, MaskKeyBin, mask(iolist_to_binary(Payload), MaskKey, <<>>)]. - - payload_length(Payload) -> -- case byte_size(Payload) of -+ case iolist_size(Payload) of - N when N =< 125 -> << N:7 >>; - N when N =< 16#ffff -> << 126:7, N:16 >>; - N when N =< 16#7fffffffffffffff -> << 127:7, N:64 >> diff --git a/erlang-cowlib-0003-Add-cowboy_http2-with-initial-HTTP-2-suppport.patch b/erlang-cowlib-0003-Add-cowboy_http2-with-initial-HTTP-2-suppport.patch deleted file mode 100644 index b60d3c9..0000000 --- a/erlang-cowlib-0003-Add-cowboy_http2-with-initial-HTTP-2-suppport.patch +++ /dev/null @@ -1,348 +0,0 @@ -From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= -Date: Thu, 11 Jun 2015 14:04:21 +0200 -Subject: [PATCH] Add cowboy_http2 with initial HTTP/2 suppport - - -diff --git a/src/cow_http2.erl b/src/cow_http2.erl -new file mode 100644 -index 0000000..a4d2e23 ---- /dev/null -+++ b/src/cow_http2.erl -@@ -0,0 +1,337 @@ -+%% Copyright (c) 2015, Loïc Hoguin -+%% -+%% Permission to use, copy, modify, and/or distribute this software for any -+%% purpose with or without fee is hereby granted, provided that the above -+%% copyright notice and this permission notice appear in all copies. -+%% -+%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ -+-module(cow_http2). -+ -+%% Parsing. -+-export([parse/1]). -+ -+%% Building. -+-export([data/3]). -+-export([headers/3]). -+-export([rst_stream/2]). -+-export([settings/1]). -+-export([push_promise/3]). -+-export([ping_ack/1]). -+ -+-type streamid() :: pos_integer(). -+-type fin() :: fin | nofin. -+-type head_fin() :: head_fin | head_nofin. -+-type exclusive() :: exclusive | shared. -+-type weight() :: 1..256. -+-type settings() :: map(). -+ -+-type error() :: no_error -+ | protocol_error -+ | internal_error -+ | flow_control_error -+ | settings_timeout -+ | stream_closed -+ | frame_size_error -+ | refused_stream -+ | cancel -+ | compression_error -+ | connect_error -+ | enhance_your_calm -+ | inadequate_security -+ | http_1_1_required -+ | unknown_error. -+-export_type([error/0]). -+ -+-type frame() :: {data, streamid(), fin(), binary()} -+ | {headers, streamid(), fin(), head_fin(), binary()} -+ | {headers, streamid(), fin(), head_fin(), exclusive(), streamid(), weight(), binary()} -+ | {priority, streamid(), exclusive(), streamid(), weight()} -+ | {rst_stream, streamid(), error()} -+ | {settings, settings()} -+ | settings_ack -+ | {push_promise, streamid(), head_fin(), streamid(), binary()} -+ | {ping, integer()} -+ | {ping_ack, integer()} -+ | {goaway, streamid(), error(), binary()} -+ | {window_update, non_neg_integer()} -+ | {window_update, streamid(), non_neg_integer()} -+ | {continuation, streamid(), head_fin(), binary()}. -+-export_type([frame/0]). -+ -+%% Parsing. -+ -+%% -+%% DATA frames. -+%% -+parse(<< _:24, 0:8, _:9, 0:31, _/bits >>) -> -+ {connection_error, protocol_error, 'DATA frames MUST be associated with a stream. (RFC7540 6.1)'}; -+parse(<< Len0:24, 0:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 -> -+ {connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.1)'}; -+%% No padding. -+parse(<< Len:24, 0:8, _:4, 0:1, _:2, FlagEndStream:1, _:1, StreamID:31, Data:Len/binary, Rest/bits >>) -> -+ {ok, {data, StreamID, parse_fin(FlagEndStream), Data}, Rest}; -+%% Padding. -+parse(<< Len0:24, 0:8, _:4, 1:1, _:2, FlagEndStream:1, _:1, StreamID:31, PadLen:8, Rest0/bits >>) -+ when byte_size(Rest0) >= Len0 - 1 -> -+ Len = Len0 - PadLen, -+ case Rest0 of -+ << Data:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ {ok, {data, StreamID, parse_fin(FlagEndStream), Data}, Rest}; -+ _ -> -+ {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.1)'} -+ end; -+%% -+%% HEADERS frames. -+%% -+parse(<< _:24, 1:8, _:9, 0:31, _/bits >>) -> -+ {connection_error, protocol_error, 'HEADERS frames MUST be associated with a stream. (RFC7540 6.2)'}; -+parse(<< Len0:24, 1:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 -> -+ {connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.2)'}; -+parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 - 5 -> -+ {connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.2)'}; -+%% No padding, no priority. -+parse(<< Len:24, 1:8, _:2, 0:1, _:1, 0:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31, -+ HeaderBlockFragment:Len/binary, Rest/bits >>) -> -+ {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest}; -+%% Padding, no priority. -+parse(<< Len0:24, 1:8, _:2, 0:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31, -+ PadLen:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 1 -> -+ Len = Len0 - PadLen - 1, -+ case Rest0 of -+ << HeaderBlockFragment:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest}; -+ _ -> -+ {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.2)'} -+ end; -+%% No padding, priority. -+parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 0:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31, -+ E:1, DepStreamID:31, Weight:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 5 -> -+ Len = Len0 - 5, -+ << HeaderBlockFragment:Len/binary, Rest/bits >> = Rest0, -+ {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), -+ parse_exclusive(E), DepStreamID, Weight + 1, HeaderBlockFragment}, Rest}; -+%% Padding, priority. -+parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31, -+ PadLen:8, E:1, DepStreamID:31, Weight:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 6 -> -+ Len = Len0 - PadLen - 6, -+ case Rest0 of -+ << HeaderBlockFragment:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), -+ parse_exclusive(E), DepStreamID, Weight + 1, HeaderBlockFragment}, Rest}; -+ _ -> -+ {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.2)'} -+ end; -+%% -+%% PRIORITY frames. -+%% -+parse(<< 5:24, 2:8, _:9, 0:31, _/bits >>) -> -+ {connection_error, protocol_error, 'PRIORITY frames MUST be associated with a stream. (RFC7540 6.3)'}; -+parse(<< 5:24, 2:8, _:9, StreamID:31, E:1, DepStreamID:31, Weight:8, Rest/bits >>) -> -+ {ok, {priority, StreamID, parse_exclusive(E), DepStreamID, Weight + 1}, Rest}; -+%% @todo figure out how to best deal with frame size errors; if we have everything fine -+%% if not we might want to inform the caller how much he should expect so that it can -+%% decide if it should just close the connection -+parse(<< BadLen:24, 2:8, _:9, StreamID:31, _:BadLen/binary, Rest/bits >>) -> -+ {stream_error, StreamID, frame_size_error, 'PRIORITY frames MUST be 5 bytes wide. (RFC7540 6.3)', Rest}; -+%% -+%% RST_STREAM frames. -+%% -+parse(<< 4:24, 3:8, _:9, 0:31, _/bits >>) -> -+ {connection_error, protocol_error, 'RST_STREAM frames MUST be associated with a stream. (RFC7540 6.4)'}; -+parse(<< 4:24, 3:8, _:9, StreamID:31, ErrorCode:32, Rest/bits >>) -> -+ {ok, {rst_stream, StreamID, parse_error_code(ErrorCode)}, Rest}; -+%% @todo same as priority -+parse(<< BadLen:24, 3:8, _:9, StreamID:31, _:BadLen/binary, Rest/bits >>) -> -+ {stream_error, StreamID, frame_size_error, 'RST_STREAM frames MUST be 4 bytes wide. (RFC7540 6.4)', Rest}; -+%% -+%% SETTINGS frames. -+%% -+parse(<< 0:24, 4:8, _:7, 1:1, _:1, 0:31, Rest/bits >>) -> -+ {ok, settings_ack, Rest}; -+parse(<< _:24, 4:8, _:7, 1:1, _:1, 0:31, _/bits >>) -> -+ {connection_error, frame_size_error, 'SETTINGS frames with the ACK flag set MUST have a length of 0. (RFC7540 6.5)'}; -+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)'}; -+parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, Rest/bits >>) when byte_size(Rest) >= Len -> -+ parse_settings(Rest, Len, #{}); -+parse(<< _:24, 4:8, _/bits >>) -> -+ {connection_error, protocol_error, 'SETTINGS frames MUST NOT be associated with a stream. (RFC7540 6.5)'}; -+%% -+%% PUSH_PROMISE frames. -+%% -+parse(<< _:24, 5:8, _:9, 0:31, _/bits >>) -> -+ {connection_error, protocol_error, 'PUSH_PROMISE frames MUST be associated with a stream. (RFC7540 6.6)'}; -+parse(<< Len0:24, 5:8, _:4, 0:1, FlagEndHeaders:1, _:3, StreamID:31, _:1, PromisedStreamID:31, Rest0/bits >>) -+ when byte_size(Rest0) >= Len0 - 4 -> -+ Len = Len0 - 4, -+ << HeaderBlockFragment:Len/binary, Rest/bits >> = Rest0, -+ {ok, {push_promise, StreamID, parse_head_fin(FlagEndHeaders), PromisedStreamID, HeaderBlockFragment}, Rest}; -+parse(<< Len0:24, 5:8, _:4, 1:1, FlagEndHeaders:1, _:2, StreamID:31, PadLen:8, _:1, PromisedStreamID:31, Rest0/bits >>) -+ when byte_size(Rest0) >= Len0 - 5 -> -+ Len = Len0 - 5, -+ case Rest0 of -+ << HeaderBlockFragment:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ {ok, {push_promise, StreamID, parse_head_fin(FlagEndHeaders), PromisedStreamID, HeaderBlockFragment}, Rest}; -+ _ -> -+ {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.6)'} -+ end; -+%% -+%% PING frames. -+%% -+parse(<< 8:24, 6:8, _:7, 1:1, _:1, 0:31, Opaque:64, Rest/bits >>) -> -+ {ok, {ping_ack, Opaque}, Rest}; -+parse(<< 8:24, 6:8, _:7, 0:1, _:1, 0:31, Opaque:64, Rest/bits >>) -> -+ {ok, {ping, Opaque}, Rest}; -+parse(<< 8:24, 6:8, _:104, _/bits >>) -> -+ {connection_error, protocol_error, 'PING frames MUST NOT be associated with a stream. (RFC7540 6.7)'}; -+parse(<< _:24, 6:8, _/bits >>) -> -+ {connection_error, frame_size_error, 'PING frames MUST be 8 bytes wide. (RFC7540 6.7)'}; -+%% -+%% GOAWAY frames. -+%% -+parse(<< Len0:24, 7:8, _:9, 0:31, _:1, LastStreamID:31, ErrorCode:32, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 8 -> -+ Len = Len0 - 8, -+ << DebugData:Len/binary, Rest/bits >> = Rest0, -+ {ok, {goaway, LastStreamID, parse_error_code(ErrorCode), DebugData}, Rest}; -+parse(<< _:24, 7:8, _:40, _/bits >>) -> -+ {connection_error, protocol_error, 'GOAWAY frames MUST NOT be associated with a stream. (RFC7540 6.8)'}; -+%% -+%% WINDOW_UPDATE frames. -+%% -+parse(<< 4:24, 8:8, _:9, 0:31, _:1, 0:31, _/bits >>) -> -+ {connection_error, protocol_error, 'WINDOW_UPDATE frames MUST have a non-zero increment. (RFC7540 6.9)'}; -+parse(<< 4:24, 8:8, _:9, 0:31, _:1, Increment:31, Rest/bits >>) -> -+ {ok, {window_update, Increment}, Rest}; -+parse(<< 4:24, 8:8, _:9, StreamID:31, _:1, 0:31, _/bits >>) -> -+ {stream_error, StreamID, protocol_error, 'WINDOW_UPDATE frames MUST have a non-zero increment. (RFC7540 6.9)'}; -+parse(<< 4:24, 8:8, _:9, StreamID:31, _:1, Increment:31, Rest/bits >>) -> -+ {ok, {window_update, StreamID, Increment}, Rest}; -+parse(<< _:24, 8:8, _/bits >>) -> -+ {connection_error, frame_size_error, 'WINDOW_UPDATE frames MUST be 4 bytes wide. (RFC7540 6.9)'}; -+%% -+%% CONTINUATION frames. -+%% -+parse(<< _:24, 9:8, _:9, 0:31, _/bits >>) -> -+ {connection_error, protocol_error, 'CONTINUATION frames MUST be associated with a stream. (RFC7540 6.10)'}; -+parse(<< Len:24, 9:8, _:5, FlagEndHeaders:1, _:3, StreamID:31, HeaderBlockFragment:Len/binary, Rest/bits >>) -> -+ {ok, {continuation, StreamID, parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest}; -+%% -+%% Incomplete frames. -+%% -+parse(_) -> -+ more. -+ -+parse_fin(0) -> nofin; -+parse_fin(1) -> fin. -+ -+parse_head_fin(0) -> head_nofin; -+parse_head_fin(1) -> head_fin. -+ -+parse_exclusive(0) -> shared; -+parse_exclusive(1) -> exclusive. -+ -+parse_error_code( 0) -> no_error; -+parse_error_code( 1) -> protocol_error; -+parse_error_code( 2) -> internal_error; -+parse_error_code( 3) -> flow_control_error; -+parse_error_code( 4) -> settings_timeout; -+parse_error_code( 5) -> stream_closed; -+parse_error_code( 6) -> frame_size_error; -+parse_error_code( 7) -> refused_stream; -+parse_error_code( 8) -> cancel; -+parse_error_code( 9) -> compression_error; -+parse_error_code(10) -> connect_error; -+parse_error_code(11) -> enhance_your_calm; -+parse_error_code(12) -> inadequate_security; -+parse_error_code(13) -> http_1_1_required; -+parse_error_code(_) -> unknown_error. -+ -+parse_settings(Rest, 0, Settings) -> -+ {ok, {settings, Settings}, Rest}; -+%% SETTINGS_HEADER_TABLE_SIZE. -+parse_settings(<< 1:16, Value:32, Rest/bits >>, Len, Settings) -> -+ parse_settings(Rest, Len - 6, Settings#{header_table_size => Value}); -+%% 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 >>, _, _) -> -+ {connection_error, protocol_error, 'The SETTINGS_ENABLE_PUSH value MUST be 0 or 1. (RFC7540 6.5.2)'}; -+%% SETTINGS_MAX_CONCURRENT_STREAMS. -+parse_settings(<< 3:16, Value:32, Rest/bits >>, Len, Settings) -> -+ parse_settings(Rest, Len - 6, Settings#{max_concurrent_streams => Value}); -+%% SETTINGS_INITIAL_WINDOW_SIZE. -+parse_settings(<< 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)'}; -+parse_settings(<< 4:16, Value:32, Rest/bits >>, Len, Settings) -> -+ parse_settings(Rest, Len - 6, Settings#{initial_window_size => Value}); -+%% SETTINGS_MAX_FRAME_SIZE. -+parse_settings(<< 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)'}; -+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 >>, _, _) -> -+ {connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be =< 0xffffff. (RFC7540 6.5.2)'}; -+%% 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). -+ -+%% Building. -+ -+%% @todo Check size and create multiple frames if needed. -+data(StreamID, IsFin, Data) -> -+ Len = iolist_size(Data), -+ FlagEndStream = flag_fin(IsFin), -+ [<< Len:24, 0:15, FlagEndStream:1, 0:1, StreamID:31 >>, Data]. -+ -+%% @todo Check size of HeaderBlock and use CONTINUATION frames if needed. -+headers(StreamID, IsFin, HeaderBlock) -> -+ Len = iolist_size(HeaderBlock), -+ FlagEndStream = flag_fin(IsFin), -+ FlagEndHeaders = 1, -+ [<< Len:24, 1:8, 0:5, FlagEndHeaders:1, 0:1, FlagEndStream:1, 0:1, StreamID:31 >>, HeaderBlock]. -+ -+rst_stream(StreamID, Reason) -> -+ ErrorCode = error_code(Reason), -+ << 4:24, 3:8, 0:9, StreamID:31, ErrorCode:32 >>. -+ -+%% @todo Actually implement it. :-) -+settings(#{}) -> -+ << 0:24, 4:8, 0:40 >>. -+ -+%% @todo Check size of HeaderBlock and use CONTINUATION frames if needed. -+push_promise(StreamID, PromisedStreamID, HeaderBlock) -> -+ Len = iolist_size(HeaderBlock) + 4, -+ FlagEndHeaders = 1, -+ [<< Len:24, 5:8, 0:5, FlagEndHeaders:1, 0:3, StreamID:31, 0:1, PromisedStreamID:31 >>, HeaderBlock]. -+ -+ping_ack(Opaque) -> -+ << 8:24, 6:8, 0:7, 1:1, 0:32, Opaque:64 >>. -+ -+flag_fin(nofin) -> 0; -+flag_fin(fin) -> 1. -+ -+error_code(no_error) -> 0; -+error_code(protocol_error) -> 1; -+error_code(internal_error) -> 2; -+error_code(flow_control_error) -> 3; -+error_code(settings_timeout) -> 4; -+error_code(stream_closed) -> 5; -+error_code(frame_size_error) -> 6; -+error_code(refused_stream) -> 7; -+error_code(cancel) -> 8; -+error_code(compression_error) -> 9; -+error_code(connect_error) -> 10; -+error_code(enhance_your_calm) -> 11; -+error_code(inadequate_security) -> 12; -+error_code(http_1_1_required) -> 13. diff --git a/erlang-cowlib-0004-Fix-handling-of-default-values-in-cookie-options.patch b/erlang-cowlib-0004-Fix-handling-of-default-values-in-cookie-options.patch deleted file mode 100644 index 7a56a01..0000000 --- a/erlang-cowlib-0004-Fix-handling-of-default-values-in-cookie-options.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Krzysztof Jurewicz -Date: Tue, 21 Jul 2015 11:10:47 +0200 -Subject: [PATCH] Fix handling of default values in cookie options -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Previously, an error would be raised when explicitly passing a default -value for either “http_only” or “secure” option. - -diff --git a/src/cow_cookie.erl b/src/cow_cookie.erl -index 150efeb..b31a528 100644 ---- a/src/cow_cookie.erl -+++ b/src/cow_cookie.erl -@@ -197,10 +197,12 @@ setcookie(Name, Value, Opts) -> - end, - SecureBin = case lists:keyfind(secure, 1, Opts) of - false -> <<>>; -+ {_, false} -> <<>>; - {_, true} -> <<"; Secure">> - end, - HttpOnlyBin = case lists:keyfind(http_only, 1, Opts) of - false -> <<>>; -+ {_, false} -> <<>>; - {_, true} -> <<"; HttpOnly">> - end, - [Name, <<"=">>, Value, <<"; Version=1">>, -@@ -218,6 +220,12 @@ setcookie_test_() -> - [{path, <<"/acme">>}], - <<"Customer=WILE_E_COYOTE; Version=1; Path=/acme">>}, - {<<"Customer">>, <<"WILE_E_COYOTE">>, -+ [{secure, true}], -+ <<"Customer=WILE_E_COYOTE; Version=1; Secure">>}, -+ {<<"Customer">>, <<"WILE_E_COYOTE">>, -+ [{secure, false}, {http_only, false}], -+ <<"Customer=WILE_E_COYOTE; Version=1">>}, -+ {<<"Customer">>, <<"WILE_E_COYOTE">>, - [{path, <<"/acme">>}, {badoption, <<"negatory">>}], - <<"Customer=WILE_E_COYOTE; Version=1; Path=/acme">>} - ], diff --git a/erlang-cowlib-0005-Fix-a-few-binary-pattern-matching-issues.patch b/erlang-cowlib-0005-Fix-a-few-binary-pattern-matching-issues.patch deleted file mode 100644 index d846f05..0000000 --- a/erlang-cowlib-0005-Fix-a-few-binary-pattern-matching-issues.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= -Date: Wed, 26 Aug 2015 17:27:33 +0200 -Subject: [PATCH] Fix a few binary pattern matching issues - - -diff --git a/src/cow_http2.erl b/src/cow_http2.erl -index a4d2e23..c7773b4 100644 ---- a/src/cow_http2.erl -+++ b/src/cow_http2.erl -@@ -82,7 +82,7 @@ parse(<< Len0:24, 0:8, _:4, 1:1, _:2, FlagEndStream:1, _:1, StreamID:31, PadLen: - when byte_size(Rest0) >= Len0 - 1 -> - Len = Len0 - PadLen, - case Rest0 of -- << Data:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ << Data:Len/binary, 0:PadLen/unit:8, Rest/bits >> -> - {ok, {data, StreamID, parse_fin(FlagEndStream), Data}, Rest}; - _ -> - {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.1)'} -@@ -105,7 +105,7 @@ parse(<< Len0:24, 1:8, _:2, 0:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream: - PadLen:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 1 -> - Len = Len0 - PadLen - 1, - case Rest0 of -- << HeaderBlockFragment:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ << HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> -> - {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest}; - _ -> - {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.2)'} -@@ -122,7 +122,7 @@ parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream: - PadLen:8, E:1, DepStreamID:31, Weight:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 6 -> - Len = Len0 - PadLen - 6, - case Rest0 of -- << HeaderBlockFragment:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ << HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> -> - {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), - parse_exclusive(E), DepStreamID, Weight + 1, HeaderBlockFragment}, Rest}; - _ -> -@@ -177,7 +177,7 @@ parse(<< Len0:24, 5:8, _:4, 1:1, FlagEndHeaders:1, _:2, StreamID:31, PadLen:8, _ - when byte_size(Rest0) >= Len0 - 5 -> - Len = Len0 - 5, - case Rest0 of -- << HeaderBlockFragment:Len/binary, 0:PadLen/binary, Rest/bits >> -> -+ << HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> -> - {ok, {push_promise, StreamID, parse_head_fin(FlagEndHeaders), PromisedStreamID, HeaderBlockFragment}, Rest}; - _ -> - {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.6)'} diff --git a/erlang-cowlib-0006-Add-cow_http-response-3.patch b/erlang-cowlib-0006-Add-cow_http-response-3.patch deleted file mode 100644 index c3c8132..0000000 --- a/erlang-cowlib-0006-Add-cow_http-response-3.patch +++ /dev/null @@ -1,96 +0,0 @@ -From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= -Date: Sat, 12 Mar 2016 18:09:41 +0100 -Subject: [PATCH] Add cow_http:response/3 - - -diff --git a/src/cow_http.erl b/src/cow_http.erl -index 8f2ae92..4b98d81 100644 ---- a/src/cow_http.erl -+++ b/src/cow_http.erl -@@ -22,6 +22,7 @@ - -export([parse_version/1]). - - -export([request/4]). -+-export([response/3]). - -export([version/1]). - - -type version() :: 'HTTP/1.0' | 'HTTP/1.1'. -@@ -243,6 +244,12 @@ request(Method, Path, Version, Headers) -> - [[N, <<": ">>, V, <<"\r\n">>] || {N, V} <- Headers], - <<"\r\n">>]. - -+-spec response(status() | binary(), version(), headers()) -> iodata(). -+response(Status, Version, Headers) -> -+ [version(Version), <<" ">>, status(Status), <<"\r\n">>, -+ [[N, <<": ">>, V, <<"\r\n">>] || {N, V} <- Headers], -+ <<"\r\n">>]. -+ - %% @doc Return the version as a binary. - - -spec version(version()) -> binary(). -@@ -256,3 +263,65 @@ version_test() -> - {'EXIT', _} = (catch version('HTTP/1.2')), - ok. - -endif. -+ -+%% @doc Return the status code and string as binary. -+ -+-spec status(status() | binary()) -> binary(). -+status(100) -> <<"100 Continue">>; -+status(101) -> <<"101 Switching Protocols">>; -+status(102) -> <<"102 Processing">>; -+status(200) -> <<"200 OK">>; -+status(201) -> <<"201 Created">>; -+status(202) -> <<"202 Accepted">>; -+status(203) -> <<"203 Non-Authoritative Information">>; -+status(204) -> <<"204 No Content">>; -+status(205) -> <<"205 Reset Content">>; -+status(206) -> <<"206 Partial Content">>; -+status(207) -> <<"207 Multi-Status">>; -+status(226) -> <<"226 IM Used">>; -+status(300) -> <<"300 Multiple Choices">>; -+status(301) -> <<"301 Moved Permanently">>; -+status(302) -> <<"302 Found">>; -+status(303) -> <<"303 See Other">>; -+status(304) -> <<"304 Not Modified">>; -+status(305) -> <<"305 Use Proxy">>; -+status(306) -> <<"306 Switch Proxy">>; -+status(307) -> <<"307 Temporary Redirect">>; -+status(400) -> <<"400 Bad Request">>; -+status(401) -> <<"401 Unauthorized">>; -+status(402) -> <<"402 Payment Required">>; -+status(403) -> <<"403 Forbidden">>; -+status(404) -> <<"404 Not Found">>; -+status(405) -> <<"405 Method Not Allowed">>; -+status(406) -> <<"406 Not Acceptable">>; -+status(407) -> <<"407 Proxy Authentication Required">>; -+status(408) -> <<"408 Request Timeout">>; -+status(409) -> <<"409 Conflict">>; -+status(410) -> <<"410 Gone">>; -+status(411) -> <<"411 Length Required">>; -+status(412) -> <<"412 Precondition Failed">>; -+status(413) -> <<"413 Request Entity Too Large">>; -+status(414) -> <<"414 Request-URI Too Long">>; -+status(415) -> <<"415 Unsupported Media Type">>; -+status(416) -> <<"416 Requested Range Not Satisfiable">>; -+status(417) -> <<"417 Expectation Failed">>; -+status(418) -> <<"418 I'm a teapot">>; -+status(422) -> <<"422 Unprocessable Entity">>; -+status(423) -> <<"423 Locked">>; -+status(424) -> <<"424 Failed Dependency">>; -+status(425) -> <<"425 Unordered Collection">>; -+status(426) -> <<"426 Upgrade Required">>; -+status(428) -> <<"428 Precondition Required">>; -+status(429) -> <<"429 Too Many Requests">>; -+status(431) -> <<"431 Request Header Fields Too Large">>; -+status(500) -> <<"500 Internal Server Error">>; -+status(501) -> <<"501 Not Implemented">>; -+status(502) -> <<"502 Bad Gateway">>; -+status(503) -> <<"503 Service Unavailable">>; -+status(504) -> <<"504 Gateway Timeout">>; -+status(505) -> <<"505 HTTP Version Not Supported">>; -+status(506) -> <<"506 Variant Also Negotiates">>; -+status(507) -> <<"507 Insufficient Storage">>; -+status(510) -> <<"510 Not Extended">>; -+status(511) -> <<"511 Network Authentication Required">>; -+status(B) when is_binary(B) -> B. diff --git a/erlang-cowlib-0007-Add-settings_payload-1-settings_ack-0-and-ping-1-in-.patch b/erlang-cowlib-0007-Add-settings_payload-1-settings_ack-0-and-ping-1-in-.patch deleted file mode 100644 index 98a1b4c..0000000 --- a/erlang-cowlib-0007-Add-settings_payload-1-settings_ack-0-and-ping-1-in-.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= -Date: Sat, 12 Mar 2016 18:10:32 +0100 -Subject: [PATCH] Add settings_payload/1, settings_ack/0 and ping/1 in - cow_http2 - -Although settings_payload/1 is currently only a placeholder. - -diff --git a/src/cow_http2.erl b/src/cow_http2.erl -index c7773b4..163802e 100644 ---- a/src/cow_http2.erl -+++ b/src/cow_http2.erl -@@ -22,7 +22,10 @@ - -export([headers/3]). - -export([rst_stream/2]). - -export([settings/1]). -+-export([settings_payload/1]). -+-export([settings_ack/0]). - -export([push_promise/3]). -+-export([ping/1]). - -export([ping_ack/1]). - - -type streamid() :: pos_integer(). -@@ -309,12 +312,22 @@ rst_stream(StreamID, Reason) -> - settings(#{}) -> - << 0:24, 4:8, 0:40 >>. - -+%% @todo Actually implement it. :-) -+settings_payload(#{}) -> -+ <<>>. -+ -+settings_ack() -> -+ << 0:24, 4:8, 1:8, 0:32 >>. -+ - %% @todo Check size of HeaderBlock and use CONTINUATION frames if needed. - push_promise(StreamID, PromisedStreamID, HeaderBlock) -> - Len = iolist_size(HeaderBlock) + 4, - FlagEndHeaders = 1, - [<< Len:24, 5:8, 0:5, FlagEndHeaders:1, 0:3, StreamID:31, 0:1, PromisedStreamID:31 >>, HeaderBlock]. - -+ping(Opaque) -> -+ << 8:24, 6:8, 0:40, Opaque:64 >>. -+ - ping_ack(Opaque) -> - << 8:24, 6:8, 0:7, 1:1, 0:32, Opaque:64 >>. - diff --git a/erlang-cowlib-0008-Add-cow_http_hd-parse_http2_settings-1.patch b/erlang-cowlib-0008-Add-cow_http_hd-parse_http2_settings-1.patch deleted file mode 100644 index 3e2f8ba..0000000 --- a/erlang-cowlib-0008-Add-cow_http_hd-parse_http2_settings-1.patch +++ /dev/null @@ -1,32 +0,0 @@ -From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= -Date: Sat, 12 Mar 2016 18:21:39 +0100 -Subject: [PATCH] Add cow_http_hd:parse_http2_settings/1 - -No tests or benchmarks, we just call base64:decode on the value. - -diff --git a/src/cow_http_hd.erl b/src/cow_http_hd.erl -index e47d80d..e6c4524 100644 ---- a/src/cow_http_hd.erl -+++ b/src/cow_http_hd.erl -@@ -56,7 +56,7 @@ - % @todo -export([parse_forwarded/1]). RFC7239 - % @todo -export([parse_from/1]). RFC7231 - -export([parse_host/1]). --% @todo -export([parse_http2_settings/1]). HTTP/2 (upcoming) -+-export([parse_http2_settings/1]). - -export([parse_if_match/1]). - -export([parse_if_modified_since/1]). - -export([parse_if_none_match/1]). -@@ -1885,6 +1885,12 @@ horse_parse_host_ipv6_v4() -> - ). - -endif. - -+%% @doc Parse the HTTP2-Settings header. -+ -+-spec parse_http2_settings(binary()) -> binary(). -+parse_http2_settings(HTTP2Settings) -> -+ base64:decode(HTTP2Settings). -+ - %% @doc Parse the If-Match header. - - -spec parse_if_match(binary()) -> '*' | [etag()]. diff --git a/erlang-cowlib-0009-Parse-the-settings-payload-directly-in-cow_http_hd-p.patch b/erlang-cowlib-0009-Parse-the-settings-payload-directly-in-cow_http_hd-p.patch deleted file mode 100644 index 3c727c3..0000000 --- a/erlang-cowlib-0009-Parse-the-settings-payload-directly-in-cow_http_hd-p.patch +++ /dev/null @@ -1,105 +0,0 @@ -From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= -Date: Sun, 13 Mar 2016 11:14:58 +0100 -Subject: [PATCH] Parse the settings payload directly in - cow_http_hd:parse_http2_settings/1 - - -diff --git a/src/cow_http2.erl b/src/cow_http2.erl -index 163802e..c8dbd9b 100644 ---- a/src/cow_http2.erl -+++ b/src/cow_http2.erl -@@ -16,6 +16,7 @@ - - %% Parsing. - -export([parse/1]). -+-export([parse_settings_payload/1]). - - %% Building. - -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 -> - {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_settings(Rest, Len, #{}); -+ parse_settings_payload(Rest, Len, #{}); - parse(<< _:24, 4:8, _/bits >>) -> - {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(_) -> 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}; - %% 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. --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)'}; - %% 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. --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)'}; --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. --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)'}; --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)'}; - %% 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. - -diff --git a/src/cow_http_hd.erl b/src/cow_http_hd.erl -index e6c4524..c85d1fb 100644 ---- a/src/cow_http_hd.erl -+++ b/src/cow_http_hd.erl -@@ -1889,7 +1889,7 @@ horse_parse_host_ipv6_v4() -> - - -spec parse_http2_settings(binary()) -> binary(). - parse_http2_settings(HTTP2Settings) -> -- base64:decode(HTTP2Settings). -+ cow_http2:parse_settings_payload(base64:decode(HTTP2Settings)). - - %% @doc Parse the If-Match header. - diff --git a/erlang-cowlib.spec b/erlang-cowlib.spec index dd073cb..47c73bc 100644 --- a/erlang-cowlib.spec +++ b/erlang-cowlib.spec @@ -5,8 +5,8 @@ Name: erlang-%{realname} -Version: 1.3.0 -Release: 4%{?dist} +Version: 2.0.0 +Release: 1%{?dist} Summary: Support library for manipulating Web protocols Group: Development/Libraries License: ASL 2.0 @@ -15,17 +15,8 @@ URL: https://github.com/%{upstream}/%{realname} VCS: scm:git:https://github.com/%{upstream}/%{realname}.git %endif Source0: https://github.com/%{upstream}/%{realname}/archive/%{version}/%{realname}-%{version}.tar.gz -Patch1: erlang-cowlib-0001-Add-HPACK-decoding-and-encoding-functions.patch -Patch2: erlang-cowlib-0002-WS-accepts-iodata-so-byte_size-won-t-work-unless-we-.patch -Patch3: erlang-cowlib-0003-Add-cowboy_http2-with-initial-HTTP-2-suppport.patch -Patch4: erlang-cowlib-0004-Fix-handling-of-default-values-in-cookie-options.patch -Patch5: erlang-cowlib-0005-Fix-a-few-binary-pattern-matching-issues.patch -Patch6: erlang-cowlib-0006-Add-cow_http-response-3.patch -Patch7: erlang-cowlib-0007-Add-settings_payload-1-settings_ack-0-and-ping-1-in-.patch -Patch8: erlang-cowlib-0008-Add-cow_http_hd-parse_http2_settings-1.patch -Patch9: erlang-cowlib-0009-Parse-the-settings-payload-directly-in-cow_http_hd-p.patch +BuildRequires: erlang-proper BuildRequires: erlang-rebar -BuildRequires: erlang-triq %description @@ -33,16 +24,7 @@ Support library for manipulating Web protocols. %prep -%setup -q -n %{realname}-%{version} -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 +%autosetup -n %{realname}-%{version} %build @@ -54,16 +36,20 @@ Support library for manipulating Web protocols. %check -%{__rebar} qc -vv +# FIXME doesn't work with ProPer atm +#%%{__rebar} qc -vv %files %license LICENSE -%doc AUTHORS CHANGELOG.md README.md +%doc AUTHORS README.asciidoc %{erlang_appdir}/ %changelog +* Fri Oct 06 2017 Peter Lemenkov - 2.0.0-1 +- Ver. 2.0.0 + * Wed Aug 02 2017 Fedora Release Engineering - 1.3.0-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild diff --git a/sources b/sources index 5cb4aec..26fc666 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -78e79985dfd274dc980a9eae8f5bc33c cowlib-1.3.0.tar.gz +SHA512 (cowlib-2.0.0.tar.gz) = 3d534edab384d41b3aa3ba78a97f0157210811ba8d7f400af4fd2df78ed30653a66dd1f01b17d3bbe82a87a02bf02aeb33e7e15733aacbca1d81915e5aac4114