/
sockjs_http.erl
122 lines (102 loc) · 4.1 KB
/
sockjs_http.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
-module(sockjs_http).
-export([path/1, method/1, body/1, body_qs/1, header/2, jsessionid/1,
callback/1, peer/1]).
-export([reply/4, chunk_start/3, chunk/2, chunk_end/1]).
-export([hook_tcp_close/1, unhook_tcp_close/1, abruptly_kill/1]).
-include("sockjs_internal.hrl").
%% --------------------------------------------------------------------------
-spec path(req()) -> {string(), req()}.
path({cowboy, Req}) -> {Path, Req1} = cowboy_http_req:raw_path(Req),
{binary_to_list(Path), {cowboy, Req1}}.
-spec method(req()) -> {atom(), req()}.
method({cowboy, Req}) -> {Method, Req1} = cowboy_http_req:method(Req),
{Method, {cowboy, Req1}}.
-spec body(req()) -> {binary(), req()}.
body({cowboy, Req}) -> {ok, Body, Req1} = cowboy_http_req:body(Req),
{Body, {cowboy, Req1}}.
-spec body_qs(req()) -> {binary(), req()}.
body_qs(Req) ->
{H, Req1} = header('Content-Type', Req),
case H of
H when H =:= "text/plain" orelse H =:= "" ->
body(Req1);
_ ->
%% By default assume application/x-www-form-urlencoded
body_qs2(Req1)
end.
body_qs2({cowboy, Req}) ->
{BodyQS, Req1} = cowboy_http_req:body_qs(Req),
case proplists:get_value(<<"d">>, BodyQS) of
undefined ->
{<<>>, {cowboy, Req1}};
V ->
{V, {cowboy, Req1}}
end.
-spec header(atom(), req()) -> {nonempty_string() | undefined, req()}.
header(K, {cowboy, Req})->
{H, Req2} = cowboy_http_req:header(K, Req),
{V, Req3} = case H of
undefined ->
cowboy_http_req:header(atom_to_binary(K, utf8), Req2);
_ -> {H, Req2}
end,
case V of
undefined -> {undefined, {cowboy, Req3}};
_ -> {binary_to_list(V), {cowboy, Req3}}
end.
-spec jsessionid(req()) -> {nonempty_string() | undefined, req()}.
jsessionid({cowboy, Req}) ->
{C, Req2} = cowboy_http_req:cookie(<<"JSESSIONID">>, Req),
case C of
_ when is_binary(C) ->
{binary_to_list(C), {cowboy, Req2}};
undefined ->
{undefined, {cowboy, Req2}}
end.
-spec callback(req()) -> {nonempty_string() | undefined, req()}.
callback({cowboy, Req}) ->
{CB, Req1} = cowboy_http_req:qs_val(<<"c">>, Req),
case CB of
undefined -> {undefined, {cowboy, Req1}};
_ -> {binary_to_list(CB), {cowboy, Req1}}
end.
-spec peer(req()) -> {{inet:ip_address(), non_neg_integer()}, req()}.
peer({cowboy, Req}) ->
{P, Req1} = cowboy_http_req:peer(Req),
{P, {cowboy, Req1}}.
%% --------------------------------------------------------------------------
-spec reply(non_neg_integer(), headers(), iodata(), req()) -> req().
reply(Code, Headers, Body, {cowboy, Req}) ->
Body1 = iolist_to_binary(Body),
{ok, Req1} = cowboy_http_req:reply(Code, enbinary(Headers), Body1, Req),
{cowboy, Req1}.
-spec chunk_start(non_neg_integer(), headers(), req()) -> req().
chunk_start(Code, Headers, {cowboy, Req}) ->
{ok, Req1} = cowboy_http_req:chunked_reply(Code, enbinary(Headers), Req),
{cowboy, Req1}.
-spec chunk(iodata(), req()) -> {ok | error, req()}.
chunk(Chunk, {cowboy, Req} = R) ->
case cowboy_http_req:chunk(Chunk, Req) of
ok -> {ok, R};
{error, _E} -> {error, R}
%% This shouldn't happen too often, usually we
%% should catch tco socket closure before.
end.
-spec chunk_end(req()) -> req().
chunk_end({cowboy, _Req} = R) -> R.
enbinary(L) -> [{list_to_binary(K), list_to_binary(V)} || {K, V} <- L].
-spec hook_tcp_close(req()) -> req().
hook_tcp_close(R = {cowboy, Req}) ->
{ok, T, S} = cowboy_http_req:transport(Req),
T:setopts(S,[{active,once}]),
R.
-spec unhook_tcp_close(req()) -> req().
unhook_tcp_close(R = {cowboy, Req}) ->
{ok, T, S} = cowboy_http_req:transport(Req),
T:setopts(S,[{active,false}]),
R.
-spec abruptly_kill(req()) -> req().
abruptly_kill(R = {cowboy, Req}) ->
{ok, T, S} = cowboy_http_req:transport(Req),
T:shutdown(S, read_write),
R.