From 85973c178bdc78190ab5c45a7e0cd54c2b69c92f Mon Sep 17 00:00:00 2001 From: XIAO Tian Date: Tue, 27 Feb 2018 16:37:28 +0800 Subject: [PATCH 1/2] Add custom headers with websocket request Custom headers can be added with a websocket connect request using http_header elements, similar to HTTP requests. --- include/ts_websocket.hrl | 1 + src/lib/websocket.erl | 22 +++++++++++++++++--- src/test/ts_test_websocket.erl | 2 +- src/tsung/ts_websocket.erl | 13 ++++++++---- src/tsung_controller/ts_config_http.erl | 9 +++++++- src/tsung_controller/ts_config_websocket.erl | 3 ++- tsung-1.0.dtd | 2 +- 7 files changed, 41 insertions(+), 11 deletions(-) diff --git a/include/ts_websocket.hrl b/include/ts_websocket.hrl index 2683c07f5..8e3461f5d 100644 --- a/include/ts_websocket.hrl +++ b/include/ts_websocket.hrl @@ -33,6 +33,7 @@ frame = "binary", origin, % origin of websocket request subprotos = [], % subprotocols + headers = [], % additional headers data % websocket data }). diff --git a/src/lib/websocket.erl b/src/lib/websocket.erl index c42ff0b39..f505cd8ca 100644 --- a/src/lib/websocket.erl +++ b/src/lib/websocket.erl @@ -27,7 +27,7 @@ -vc('$Id$ '). -author('jzhihui521@gmail.com'). --export([get_handshake/5, check_handshake/2, encode_binary/1, encode_text/1, +-export([get_handshake/6, check_handshake/2, encode_binary/1, encode_text/1, encode_close/1, encode/2, decode/1]). -include("ts_profile.hrl"). @@ -37,7 +37,7 @@ %%%=================================================================== %%% API functions %%%=================================================================== -get_handshake(Host, Path, SubProtocol, Version, Origin) -> +get_handshake(Host, Path, SubProtocol, Version, Origin, Headers) -> {Key, Accept} = gen_accept_key(), Req = list_to_binary(["GET ", Path, " HTTP/1.1\r\n", "Host: ", Host ,"\r\n", @@ -48,7 +48,8 @@ get_handshake(Host, Path, SubProtocol, Version, Origin) -> _ -> Origin end, "\r\n", "Sec-WebSocket-Key: ", Key, "\r\n", - "Sec-WebSocket-Version: ", Version, "\r\n"]), + "Sec-WebSocket-Version: ", Version, "\r\n", + headers(Headers)]), SubProHeader = case SubProtocol of [] -> []; _ -> "Sec-WebSocket-Protocol: " ++ SubProtocol ++ "\r\n" @@ -196,3 +197,18 @@ parse_frame(<< 1:1, % FIN parse_payload(Opcode, MaskLengthAndPayload); parse_frame(_Data) -> more. + +% user defined headers +headers([]) -> []; +headers(Headers) -> + HeadersToIgnore = ["host", "upgrade", "connection", "origin", + "sec-websocket-key", "sec-websocket-version", + "sec-websocket-protocol"], + lists:foldl(fun({Name, Value}, Result) -> + case lists:member(string:to_lower(Name), HeadersToIgnore) of + true -> + Result; + _ -> + [Name, ": ", Value, ?CRLF | Result] + end + end, [], lists:reverse(Headers)). diff --git a/src/test/ts_test_websocket.erl b/src/test/ts_test_websocket.erl index 59b148869..5fa200425 100644 --- a/src/test/ts_test_websocket.erl +++ b/src/test/ts_test_websocket.erl @@ -29,7 +29,7 @@ test()->ok. handshake_test() -> - {_, Accept} = websocket:get_handshake("127.0.0.1", "/chat", [], 13, ""), + {_, Accept} = websocket:get_handshake("127.0.0.1", "/chat", [], 13, "", []), Response1 = ["HTTP/1.1 101 Switching Protocols\r\n", "Upgrade: websocket\r\n", "Connection: Upgrade\r\n", diff --git a/src/tsung/ts_websocket.erl b/src/tsung/ts_websocket.erl index a8667eee2..d4471204f 100644 --- a/src/tsung/ts_websocket.erl +++ b/src/tsung/ts_websocket.erl @@ -80,10 +80,11 @@ dump(A,B) -> %%---------------------------------------------------------------------- get_message(#websocket_request{type = connect, path = Path, subprotos = SubProtocol, version = Version, - origin = Origin}, + headers = Headers, origin = Origin}, State=#state_rcv{session = WebsocketSession}) -> {Request, Accept} = websocket:get_handshake(State#state_rcv.host, Path, - SubProtocol, Version, Origin), + SubProtocol, Version, Origin, + Headers), {Request, WebsocketSession#websocket_session{status = waiting_handshake, accept = Accept}}; get_message(#websocket_request{type = message, data = Data, frame = Frame}, @@ -175,9 +176,13 @@ add_dynparams(true, {DynVars, _S}, NewData = ts_search:subst(Data, DynVars), Param#websocket_request{data = NewData}; add_dynparams(true, {DynVars, _S}, - Param = #websocket_request{type = connect, path = Path}, + Param = #websocket_request{type = connect, path = Path, + headers = Headers}, _HostData) -> NewPath = ts_search:subst(Path, DynVars), - Param#websocket_request{path = NewPath}; + NewHeaders = lists:foldl(fun ({Name, Value}, Result) -> + [{Name, ts_search:subst(Value, DynVars)} | Result] + end, [], Headers), + Param#websocket_request{path = NewPath, headers = NewHeaders}; add_dynparams(_Bool, _DynData, Param, _HostData) -> Param#websocket_request{}. diff --git a/src/tsung_controller/ts_config_http.erl b/src/tsung_controller/ts_config_http.erl index f44cb0fb5..77b161423 100644 --- a/src/tsung_controller/ts_config_http.erl +++ b/src/tsung_controller/ts_config_http.erl @@ -32,7 +32,8 @@ -author('nicolas.niclausse@niclux.org'). -export([parse_config/2, parse_URL/1, set_port/1, set_scheme/1, - check_user_agent_sum/1, set_query/1, encode_ipv6_address/1]). + check_user_agent_sum/1, set_query/1, encode_ipv6_address/1, + parse_headers/2]). -include("ts_profile.hrl"). -include("ts_http.hrl"). @@ -209,6 +210,12 @@ get_previous_http_server(Ets, Id) -> [{_Key,PrevServ}] -> PrevServ end. +%%---------------------------------------------------------------------- +%% Func: parse_headers/2 +%% Args: Elements (list), Headers (list) +%% Returns: List +%% Purpose: parse http_header elements +%%---------------------------------------------------------------------- parse_headers([], Headers) -> Headers; parse_headers([Element = #xmlElement{name=http_header} | Tail], Headers) -> diff --git a/src/tsung_controller/ts_config_websocket.erl b/src/tsung_controller/ts_config_websocket.erl index ff5863a2d..77a90d12c 100644 --- a/src/tsung_controller/ts_config_websocket.erl +++ b/src/tsung_controller/ts_config_websocket.erl @@ -55,9 +55,10 @@ parse_config(Element = #xmlElement{name = websocket}, SubProtocols = ts_config:getAttr(string, Element#xmlElement.attributes, subprotocols, ""), Frame = ts_config:getAttr(string, Element#xmlElement.attributes, frame, "binary"), + Headers = ts_config_http:parse_headers(Element#xmlElement.content, []), Request = #websocket_request{data = ValRaw, type = Type, subprotos = SubProtocols, - origin = Origin, path = Path, frame = Frame}, + origin = Origin, path = Path, frame = Frame, headers = Headers}, Ack = case Type of message -> diff --git a/tsung-1.0.dtd b/tsung-1.0.dtd index 19ae9358e..8f0fba108 100644 --- a/tsung-1.0.dtd +++ b/tsung-1.0.dtd @@ -374,7 +374,7 @@ repeat | if | change_type | foreach | set_option | interaction | abort )*> certfile CDATA #IMPLIED dn CDATA #IMPLIED > - + Date: Sun, 3 Jun 2018 15:48:43 +0800 Subject: [PATCH 2/2] update doc for websocket http_header --- docs/conf-sessions.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/conf-sessions.rst b/docs/conf-sessions.rst index b569481cf..46e350cb3 100644 --- a/docs/conf-sessions.rst +++ b/docs/conf-sessions.rst @@ -889,6 +889,16 @@ If not set this defaults to the ``host`` value. +**New in 1.7.1**: You can also add any HTTP header now, as in: + +.. code-block:: xml + + + + + + + AMQP ^^^^^^^^^ .. _sec-session-amqp-label: