diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index c40b74ece8d0..7094d67cb061 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -1080,7 +1080,9 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).
as atoms. Others are returned as strings. Strings of
unrecognized header fields are formatted with only
capital letters first and after hyphen characters, for
- example, "Sec-Websocket-Key".
+ example, "Sec-Websocket-Key". Header field names
+ are also returned in UnmodifiedField
+ as strings, without any conversion or formatting.
The protocol type http is only to be used for
the first line when an HttpRequest or an
HttpResponse is expected.
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 17e09f835b68..cf633b2f0145 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -1228,22 +1228,25 @@ static int http_request_erl(void* arg, const http_atom_t* meth,
}
static int
-http_header_erl(void* arg, const http_atom_t* name, const char* name_ptr,
- int name_len, const char* value_ptr, int value_len)
+http_header_erl(void* arg, const http_atom_t* name,
+ const char* name_ptr, int name_len,
+ const char* oname_ptr, int oname_len,
+ const char* value_ptr, int value_len)
{
struct packet_callback_args* pca = (struct packet_callback_args*) arg;
- Eterm bit_term, name_term, val_term;
+ Eterm bit_term, name_term, oname_term, val_term;
Uint sz = 6;
Eterm* hp;
#ifdef DEBUG
Eterm* hend;
#endif
- /* {http_header,Bit,Name,IValue,Value} */
+ /* {http_header,Bit,Name,Oname,Value} */
if (name == NULL) {
http_bld_string(pca, NULL, &sz, name_ptr, name_len);
}
+ http_bld_string(pca, NULL, &sz, oname_ptr, oname_len);
http_bld_string(pca, NULL, &sz, value_ptr, value_len);
hp = HAlloc(pca->p, sz);
@@ -1260,8 +1263,9 @@ http_header_erl(void* arg, const http_atom_t* name, const char* name_ptr,
name_term = http_bld_string(pca, &hp,NULL,name_ptr,name_len);
}
+ oname_term = http_bld_string(pca, &hp, NULL, oname_ptr, oname_len);
val_term = http_bld_string(pca, &hp, NULL, value_ptr, value_len);
- pca->res = TUPLE5(hp, am_http_header, bit_term, name_term, am_undefined, val_term);
+ pca->res = TUPLE5(hp, am_http_header, bit_term, name_term, oname_term, val_term);
ASSERT(hp+6==hend);
return 1;
}
diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c
index c0937aa5f24a..8f24725326e7 100644
--- a/erts/emulator/beam/packet_parser.c
+++ b/erts/emulator/beam/packet_parser.c
@@ -834,7 +834,9 @@ int packet_parse_http(const char* buf, int len, int* statep,
while (n && SP(ptr)) {
ptr++; n--;
}
- return pcb->http_header(arg, name, name_ptr, name_len,
+ return pcb->http_header(arg, name,
+ name_ptr, name_len,
+ buf, name_len,
ptr, n);
}
return -1;
diff --git a/erts/emulator/beam/packet_parser.h b/erts/emulator/beam/packet_parser.h
index 358d650804e0..b05623efec84 100644
--- a/erts/emulator/beam/packet_parser.h
+++ b/erts/emulator/beam/packet_parser.h
@@ -77,8 +77,10 @@ typedef int HttpResponseMessageFn(void* arg, int major, int minor, int status,
typedef int HttpRequestMessageFn(void* arg, const http_atom_t* meth, const char* meth_ptr,
int meth_len, const PacketHttpURI*, int major, int minor);
typedef int HttpEohMessageFn(void *arg);
-typedef int HttpHeaderMessageFn(void* arg, const http_atom_t* name, const char* name_ptr,
- int name_len, const char* value_ptr, int value_len);
+typedef int HttpHeaderMessageFn(void* arg, const http_atom_t* name,
+ const char* name_ptr, int name_len,
+ const char* oname_ptr, int oname_len,
+ const char* value_ptr, int value_len);
typedef int HttpErrorMessageFn(void* arg, const char* buf, int len);
typedef int SslTlsFn(void* arg, unsigned type, unsigned major, unsigned minor,
const char* data, int len, const char* prefix, int plen);
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 66ff8d84504c..8c10aa99334c 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -2574,16 +2574,18 @@ http_request_inetdrv(void* arg, const http_atom_t* meth, const char* meth_ptr,
}
static int
-http_header_inetdrv(void* arg, const http_atom_t* name, const char* name_ptr,
- int name_len, const char* value_ptr, int value_len)
+http_header_inetdrv(void* arg, const http_atom_t* name,
+ const char* name_ptr, int name_len,
+ const char* oname_ptr, int oname_len,
+ const char* value_ptr, int value_len)
{
tcp_descriptor* desc = (tcp_descriptor*) arg;
int i = 0;
- ErlDrvTermData spec[26];
+ ErlDrvTermData spec[27];
ErlDrvTermData caller = ERL_DRV_NIL;
if (desc->inet.active == INET_PASSIVE) {
- /* {inet_async,S,Ref,{ok,{http_header,Bit,Name,IValue,Value}} */
+ /* {inet_async,S,Ref,{ok,{http_header,Bit,Name,Oname,Value}} */
int req;
int aid;
@@ -2596,7 +2598,7 @@ http_header_inetdrv(void* arg, const http_atom_t* name, const char* name_ptr,
i = LOAD_ATOM(spec, i, am_ok);
}
else {
- /* {http, S, {http_header,Bit,Name,IValue,Value}} */
+ /* {http, S, {http_header,Bit,Name,Oname,Value}} */
i = LOAD_ATOM(spec, i, am_http);
i = LOAD_PORT(spec, i, desc->inet.dport);
}
@@ -2610,19 +2612,19 @@ http_header_inetdrv(void* arg, const http_atom_t* name, const char* name_ptr,
i = LOAD_INT(spec, i, 0);
i = http_load_string(desc, spec, i, name_ptr, name_len);
}
- i = LOAD_ATOM(spec, i, am_undefined);
+ i = http_load_string(desc, spec, i, oname_ptr, oname_len);
i = http_load_string(desc, spec, i, value_ptr, value_len);
i = LOAD_TUPLE(spec, i, 5);
if (desc->inet.active == INET_PASSIVE) {
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 4);
- ASSERT(i <= 26);
+ ASSERT(i <= 27);
return erl_drv_send_term(desc->inet.dport, caller, spec, i);
}
else {
i = LOAD_TUPLE(spec, i, 3);
- ASSERT(i <= 26);
+ ASSERT(i <= 27);
return erl_drv_output_term(desc->inet.dport, spec, i);
}
}
diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl
index d0f46167e426..099dfabcb686 100644
--- a/erts/emulator/test/decode_packet_SUITE.erl
+++ b/erts/emulator/test/decode_packet_SUITE.erl
@@ -301,8 +301,8 @@ http(Config) when is_list(Config) ->
StrA = list_to_atom(Str),
StrB = list_to_binary(Str),
Bin = <>,
- {ok, {http_header,N,StrA,undefined,Val}, Rest} = decode_pkt(httph,Bin),
- {ok, {http_header,N,StrA,undefined,ValB}, Rest} = decode_pkt(httph_bin,Bin),
+ {ok, {http_header,N,StrA,Str,Val}, Rest} = decode_pkt(httph,Bin),
+ {ok, {http_header,N,StrA,StrB,ValB}, Rest} = decode_pkt(httph_bin,Bin),
N + 1
end,
lists:foldl(HdrF, 1, http_hdr_strings()),
@@ -373,28 +373,40 @@ http_request(Msg) ->
{http_request, 'POST', {abs_path, "/invalid/url" }, {1,1}},
{http_request, 'POST', {abs_path,<<"/invalid/url">>}, {1,1}}},
{"Connection: close\r\n",
- {http_header,2,'Connection',undefined, "close"},
- {http_header,2,'Connection',undefined,<<"close">>}},
+ {http_header,2,'Connection', "Connection" , "close"},
+ {http_header,2,'Connection',<<"Connection">>,<<"close">>}},
{"User-Agent: perl post\r\n",
- {http_header,24,'User-Agent',undefined, "perl post"},
- {http_header,24,'User-Agent',undefined,<<"perl post">>}},
+ {http_header,24,'User-Agent', "User-Agent" , "perl post"},
+ {http_header,24,'User-Agent',<<"User-Agent">>,<<"perl post">>}},
{"Content-Length: 4\r\n",
- {http_header,38,'Content-Length',undefined, "4"},
- {http_header,38,'Content-Length',undefined,<<"4">>}},
+ {http_header,38,'Content-Length', "Content-Length" , "4"},
+ {http_header,38,'Content-Length',<<"Content-Length">>,<<"4">>}},
{"Content-Type: text/xml; charset=utf-8\r\n",
- {http_header,42,'Content-Type',undefined, "text/xml; charset=utf-8"},
- {http_header,42,'Content-Type',undefined,<<"text/xml; charset=utf-8">>}},
+ {http_header,42,'Content-Type', "Content-Type" , "text/xml; charset=utf-8"},
+ {http_header,42,'Content-Type',<<"Content-Type">>,<<"text/xml; charset=utf-8">>}},
{"Other-Field: with some text\r\n",
- {http_header,0, "Other-Field" ,undefined, "with some text"},
- {http_header,0,<<"Other-Field">>,undefined,<<"with some text">>}},
+ {http_header,0, "Other-Field" , "Other-Field" , "with some text"},
+ {http_header,0,<<"Other-Field">>,<<"Other-Field">>,<<"with some text">>}},
+ {"Content--Type: text/xml; charset=utf-8\r\n",
+ {http_header,0, "Content--type" , "Content--Type" , "text/xml; charset=utf-8"},
+ {http_header,0,<<"Content--type">>,<<"Content--Type">>,<<"text/xml; charset=utf-8">>}},
+ {"Content---Type: text/xml; charset=utf-8\r\n",
+ {http_header,0, "Content---Type" , "Content---Type" , "text/xml; charset=utf-8"},
+ {http_header,0,<<"Content---Type">>,<<"Content---Type">>,<<"text/xml; charset=utf-8">>}},
+ {"CONTENT-type: text/xml; charset=utf-8\r\n",
+ {http_header,42,'Content-Type', "CONTENT-type" , "text/xml; charset=utf-8"},
+ {http_header,42,'Content-Type',<<"CONTENT-type">>,<<"text/xml; charset=utf-8">>}},
+ {"OTHER-field: with some text\r\n",
+ {http_header,0, "Other-Field" , "OTHER-field" , "with some text"},
+ {http_header,0,<<"Other-Field">>,<<"OTHER-field">>,<<"with some text">>}},
{"Make-sure-a-LONG-HEaDer-fIeLd-is-fORMATTED-NicelY: with some text\r\n",
- {http_header,0, "Make-Sure-A-Long-Header-Field-Is-Formatted-Nicely" ,undefined, "with some text"},
- {http_header,0,<<"Make-Sure-A-Long-Header-Field-Is-Formatted-Nicely">>,undefined,<<"with some text">>}},
+ {http_header,0, "Make-Sure-A-Long-Header-Field-Is-Formatted-Nicely" , "Make-sure-a-LONG-HEaDer-fIeLd-is-fORMATTED-NicelY" , "with some text"},
+ {http_header,0,<<"Make-Sure-A-Long-Header-Field-Is-Formatted-Nicely">>,<<"Make-sure-a-LONG-HEaDer-fIeLd-is-fORMATTED-NicelY">>,<<"with some text">>}},
{"Multi-Line: Once upon a time in a land far far away,\r\n"
" there lived a princess imprisoned in the highest tower\r\n"
" of the most haunted castle.\r\n",
- {http_header,0, "Multi-Line" ,undefined, "Once upon a time in a land far far away,\r\n there lived a princess imprisoned in the highest tower\r\n of the most haunted castle."},
- {http_header,0,<<"Multi-Line">>,undefined,<<"Once upon a time in a land far far away,\r\n there lived a princess imprisoned in the highest tower\r\n of the most haunted castle.">>}},
+ {http_header,0, "Multi-Line" , "Multi-Line" , "Once upon a time in a land far far away,\r\n there lived a princess imprisoned in the highest tower\r\n of the most haunted castle."},
+ {http_header,0,<<"Multi-Line">>,<<"Multi-Line">>,<<"Once upon a time in a land far far away,\r\n there lived a princess imprisoned in the highest tower\r\n of the most haunted castle.">>}},
{"\r\n",
http_eoh,
http_eoh}],
@@ -410,17 +422,17 @@ http_response(Msg) ->
{http_response, {1,0}, 404, "Object Not Found"},
{http_response, {1,0}, 404, <<"Object Not Found">>}},
{"Server: inets/4.7.16\r\n",
- {http_header, 30, 'Server', undefined, "inets/4.7.16"},
- {http_header, 30, 'Server', undefined, <<"inets/4.7.16">>}},
+ {http_header, 30, 'Server', "Server" , "inets/4.7.16"},
+ {http_header, 30, 'Server', <<"Server">>, <<"inets/4.7.16">>}},
{"Date: Fri, 04 Jul 2008 17:16:22 GMT\r\n",
- {http_header, 3, 'Date', undefined, "Fri, 04 Jul 2008 17:16:22 GMT"},
- {http_header, 3, 'Date', undefined, <<"Fri, 04 Jul 2008 17:16:22 GMT">>}},
+ {http_header, 3, 'Date', "Date" , "Fri, 04 Jul 2008 17:16:22 GMT"},
+ {http_header, 3, 'Date', <<"Date">>, <<"Fri, 04 Jul 2008 17:16:22 GMT">>}},
{"Content-Type: text/html\r\n",
- {http_header, 42, 'Content-Type', undefined, "text/html"},
- {http_header, 42, 'Content-Type', undefined, <<"text/html">>}},
+ {http_header, 42, 'Content-Type', "Content-Type" , "text/html"},
+ {http_header, 42, 'Content-Type', <<"Content-Type">>, <<"text/html">>}},
{"Content-Length: 207\r\n",
- {http_header, 38, 'Content-Length', undefined, "207"},
- {http_header, 38, 'Content-Length', undefined, <<"207">>}},
+ {http_header, 38, 'Content-Length', "Content-Length" , "207"},
+ {http_header, 38, 'Content-Length', <<"Content-Length">>, <<"207">>}},
{"\r\n",
http_eoh,
http_eoh}],
@@ -548,7 +560,7 @@ otp_8536_do(N) ->
Bin = <>,
io:format("Bin='~p'\n",[Bin]),
- {ok,{http_header,0,Hdr2,undefined,Data2},<<"\r\n">>} = decode_pkt(httph_bin, Bin, []),
+ {ok,{http_header,0,Hdr2,Hdr2,Data2},<<"\r\n">>} = decode_pkt(httph_bin, Bin, []),
%% Do something to trash the C-stack, how about another decode_packet:
decode_pkt(httph_bin,<>, []),
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 869982c262f4..2c5b24ef7064 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -630,7 +630,7 @@ date() ->
HttpHeader :: {'http_header',
integer(),
HttpField,
- Reserved :: term(),
+ UnmodifiedField :: HttpString,
Value :: HttpString},
HttpError :: {'http_error', HttpString},
HttpMethod :: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE'
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index b79a51f02a61..03e77dd8633f 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -1130,7 +1130,7 @@ server_send_trailer(Socket, Trailer)->
client_http_decode_trailer_active(Socket) ->
receive
{ssl, Socket,
- {http_header,36,'Content-Encoding',undefined,"gzip"}} ->
+ {http_header,36,'Content-Encoding',"Content-Encoding","gzip"}} ->
ok;
Other1 ->
exit({?LINE, Other1})
@@ -1180,7 +1180,7 @@ packet_httph_bin_active(Config) when is_list(Config) ->
client_http_decode_trailer_bin_active(Socket) ->
receive
{ssl, Socket,
- {http_header,36,'Content-Encoding',undefined, <<"gzip">>}} ->
+ {http_header,36,'Content-Encoding',<<"Content-Encoding">>, <<"gzip">>}} ->
ok;
Other1 ->
exit({?LINE, Other1})
@@ -1232,7 +1232,7 @@ client_http_decode_trailer_active_once(Socket) ->
ssl:setopts(Socket, [{active, once}]),
receive
{ssl, Socket,
- {http_header,36,'Content-Encoding',undefined,"gzip"}} ->
+ {http_header,36,'Content-Encoding',"Content-Encoding","gzip"}} ->
ok;
Other1 ->
exit({?LINE, Other1})
@@ -1284,7 +1284,7 @@ client_http_decode_trailer_bin_active_once(Socket) ->
ssl:setopts(Socket, [{active, once}]),
receive
{ssl, Socket,
- {http_header,36,'Content-Encoding',undefined, <<"gzip">>}} ->
+ {http_header,36,'Content-Encoding',<<"Content-Encoding">>, <<"gzip">>}} ->
ok;
Other1 ->
exit({?LINE, Other1})
@@ -1335,7 +1335,7 @@ packet_httph_passive(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
client_http_decode_trailer_passive(Socket) ->
- {ok,{http_header,36,'Content-Encoding',undefined,"gzip"}} = ssl:recv(Socket, 0),
+ {ok,{http_header,36,'Content-Encoding',"Content-Encoding","gzip"}} = ssl:recv(Socket, 0),
{ok, http_eoh} = ssl:recv(Socket, 0),
ok.
@@ -1375,7 +1375,7 @@ packet_httph_bin_passive(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
client_http_decode_trailer_bin_passive(Socket) ->
- {ok,{http_header,36,'Content-Encoding',undefined,<<"gzip">>}} = ssl:recv(Socket, 0),
+ {ok,{http_header,36,'Content-Encoding',<<"Content-Encoding">>,<<"gzip">>}} = ssl:recv(Socket, 0),
{ok, http_eoh} = ssl:recv(Socket, 0),
ok.