Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

use tuple modules instead of parameterized modules

Erlang R16, coming soon, will do away with parameterized modules (see Issue
4 under http://www.erlang.org/news/35 for details). Change Mochiweb to use
tuple modules instead, since they will continue to be supported in R16 and
beyond. These changes are backward compatible, so current Mochiweb
applications should require only recompilation to continue working.
  • Loading branch information...
commit 6fef5148937671184fb2dda59256dd9653c34fd2 1 parent e1babc4
Steve Vinoski authored January 23, 2013
14  src/mochifmt_records.erl
@@ -9,11 +9,15 @@
9 9
 %%    M:format("{0.bar}", [#rec{bar=foo}]).
10 10
 %%    foo
11 11
 
12  
--module(mochifmt_records, [Recs]).
  12
+-module(mochifmt_records).
13 13
 -author('bob@mochimedia.com').
14  
--export([get_value/2]).
  14
+-export([new/1, get_value/3]).
15 15
 
16  
-get_value(Key, Rec) when is_tuple(Rec) and is_atom(element(1, Rec)) ->
  16
+new([{_Rec, RecFields}]=Recs) when is_list(RecFields) ->
  17
+    {?MODULE, Recs}.
  18
+
  19
+get_value(Key, Rec, {?MODULE, Recs})
  20
+  when is_tuple(Rec) and is_atom(element(1, Rec)) ->
17 21
     try begin
18 22
             Atom = list_to_existing_atom(Key),
19 23
             {_, Fields} = proplists:lookup(element(1, Rec), Recs),
@@ -21,8 +25,8 @@ get_value(Key, Rec) when is_tuple(Rec) and is_atom(element(1, Rec)) ->
21 25
         end
22 26
     catch error:_ -> mochifmt:get_value(Key, Rec)
23 27
     end;
24  
-get_value(Key, Args) ->
25  
-    mochifmt:get_value(Key, Args).
  28
+get_value(Key, Args, {?MODULE, _Recs}=THIS) ->
  29
+    mochifmt:get_value(Key, Args, THIS).
26 30
 
27 31
 get_rec_index(Atom, [Atom | _], Index) ->
28 32
     Index;
17  src/mochifmt_std.erl
@@ -3,23 +3,26 @@
3 3
 
4 4
 %% @doc Template module for a mochifmt formatter.
5 5
 
6  
--module(mochifmt_std, []).
  6
+-module(mochifmt_std).
7 7
 -author('bob@mochimedia.com').
8  
--export([format/2, get_value/2, format_field/2, get_field/2, convert_field/2]).
  8
+-export([new/0, format/3, get_value/3, format_field/3, get_field/3, convert_field/3]).
9 9
 
10  
-format(Format, Args) ->
  10
+new() ->
  11
+    {?MODULE}.
  12
+
  13
+format(Format, Args, {?MODULE}=THIS) ->
11 14
     mochifmt:format(Format, Args, THIS).
12 15
 
13  
-get_field(Key, Args) ->
  16
+get_field(Key, Args, {?MODULE}=THIS) ->
14 17
     mochifmt:get_field(Key, Args, THIS).
15 18
 
16  
-convert_field(Key, Args) ->
  19
+convert_field(Key, Args, {?MODULE}) ->
17 20
     mochifmt:convert_field(Key, Args).
18 21
 
19  
-get_value(Key, Args) ->
  22
+get_value(Key, Args, {?MODULE}) ->
20 23
     mochifmt:get_value(Key, Args).
21 24
 
22  
-format_field(Arg, Format) ->
  25
+format_field(Arg, Format, {?MODULE}=THIS) ->
23 26
     mochifmt:format_field(Arg, Format, THIS).
24 27
 
25 28
 %%
337  src/mochiweb_request.erl
@@ -3,7 +3,7 @@
3 3
 
4 4
 %% @doc MochiWeb HTTP Request abstraction.
5 5
 
6  
--module(mochiweb_request, [Socket, Method, RawPath, Version, Headers]).
  6
+-module(mochiweb_request).
7 7
 -author('bob@mochimedia.com').
8 8
 
9 9
 -include_lib("kernel/include/file.hrl").
@@ -11,17 +11,18 @@
11 11
 
12 12
 -define(QUIP, "Any of you quaids got a smint?").
13 13
 
14  
--export([get_header_value/1, get_primary_header_value/1, get/1, dump/0]).
15  
--export([send/1, recv/1, recv/2, recv_body/0, recv_body/1, stream_body/3]).
16  
--export([start_response/1, start_response_length/1, start_raw_response/1]).
17  
--export([respond/1, ok/1]).
18  
--export([not_found/0, not_found/1]).
19  
--export([parse_post/0, parse_qs/0]).
20  
--export([should_close/0, cleanup/0]).
21  
--export([parse_cookie/0, get_cookie_value/1]).
22  
--export([serve_file/2, serve_file/3]).
23  
--export([accepted_encodings/1]).
24  
--export([accepts_content_type/1, accepted_content_types/1]).
  14
+-export([new/5]).
  15
+-export([get_header_value/2, get_primary_header_value/2, get/2, dump/1]).
  16
+-export([send/2, recv/2, recv/3, recv_body/1, recv_body/2, stream_body/4]).
  17
+-export([start_response/2, start_response_length/2, start_raw_response/2]).
  18
+-export([respond/2, ok/2]).
  19
+-export([not_found/1, not_found/2]).
  20
+-export([parse_post/1, parse_qs/1]).
  21
+-export([should_close/1, cleanup/1]).
  22
+-export([parse_cookie/1, get_cookie_value/2]).
  23
+-export([serve_file/3, serve_file/4]).
  24
+-export([accepted_encodings/2]).
  25
+-export([accepts_content_type/2, accepted_content_types/2]).
25 26
 
26 27
 -define(SAVE_QS, mochiweb_request_qs).
27 28
 -define(SAVE_PATH, mochiweb_request_path).
@@ -37,6 +38,7 @@
37 38
 %% @type key() = atom() | string() | binary()
38 39
 %% @type value() = atom() | string() | binary() | integer()
39 40
 %% @type headers(). A mochiweb_headers structure.
  41
+%% @type request() = {mochiweb_request,[_Socket,_Method,_RawPath,_Version,_Headers]}
40 42
 %% @type response(). A mochiweb_response parameterized module instance.
41 43
 %% @type ioheaders() = headers() | [{key(), value()}].
42 44
 
@@ -46,50 +48,55 @@
46 48
 % Maximum recv_body() length of 1MB
47 49
 -define(MAX_RECV_BODY, (1024*1024)).
48 50
 
49  
-%% @spec get_header_value(K) -> undefined | Value
  51
+%% @spec new(Socket, Method, RawPath, Version, headers()) -> request()
  52
+%% @doc Create a new request instance.
  53
+new(Socket, Method, RawPath, Version, Headers) ->
  54
+    {?MODULE, [Socket, Method, RawPath, Version, Headers]}.
  55
+
  56
+%% @spec get_header_value(K, request()) -> undefined | Value
50 57
 %% @doc Get the value of a given request header.
51  
-get_header_value(K) ->
  58
+get_header_value(K, {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}) ->
52 59
     mochiweb_headers:get_value(K, Headers).
53 60
 
54  
-get_primary_header_value(K) ->
  61
+get_primary_header_value(K, {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}) ->
55 62
     mochiweb_headers:get_primary_value(K, Headers).
56 63
 
57 64
 %% @type field() = socket | scheme | method | raw_path | version | headers | peer | path | body_length | range
58 65
 
59  
-%% @spec get(field()) -> term()
  66
+%% @spec get(field(), request()) -> term()
60 67
 %% @doc Return the internal representation of the given field. If
61 68
 %%      <code>socket</code> is requested on a HTTPS connection, then
62 69
 %%      an ssl socket will be returned as <code>{ssl, SslSocket}</code>.
63 70
 %%      You can use <code>SslSocket</code> with the <code>ssl</code>
64 71
 %%      application, eg: <code>ssl:peercert(SslSocket)</code>.
65  
-get(socket) ->
  72
+get(socket, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
66 73
     Socket;
67  
-get(scheme) ->
  74
+get(scheme, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
68 75
     case mochiweb_socket:type(Socket) of
69 76
         plain ->
70 77
             http;
71 78
         ssl ->
72 79
             https
73 80
     end;
74  
-get(method) ->
  81
+get(method, {?MODULE, [_Socket, Method, _RawPath, _Version, _Headers]}) ->
75 82
     Method;
76  
-get(raw_path) ->
  83
+get(raw_path, {?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
77 84
     RawPath;
78  
-get(version) ->
  85
+get(version, {?MODULE, [_Socket, _Method, _RawPath, Version, _Headers]}) ->
79 86
     Version;
80  
-get(headers) ->
  87
+get(headers, {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}) ->
81 88
     Headers;
82  
-get(peer) ->
  89
+get(peer, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
83 90
     case mochiweb_socket:peername(Socket) of
84 91
         {ok, {Addr={10, _, _, _}, _Port}} ->
85  
-            case get_header_value("x-forwarded-for") of
  92
+            case get_header_value("x-forwarded-for", THIS) of
86 93
                 undefined ->
87 94
                     inet_parse:ntoa(Addr);
88 95
                 Hosts ->
89 96
                     string:strip(lists:last(string:tokens(Hosts, ",")))
90 97
             end;
91 98
         {ok, {{127, 0, 0, 1}, _Port}} ->
92  
-            case get_header_value("x-forwarded-for") of
  99
+            case get_header_value("x-forwarded-for", THIS) of
93 100
                 undefined ->
94 101
                     "127.0.0.1";
95 102
                 Hosts ->
@@ -100,7 +107,7 @@ get(peer) ->
100 107
         {error, enotconn} ->
101 108
             exit(normal)
102 109
     end;
103  
-get(path) ->
  110
+get(path, {?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
104 111
     case erlang:get(?SAVE_PATH) of
105 112
         undefined ->
106 113
             {Path0, _, _} = mochiweb_util:urlsplit_path(RawPath),
@@ -110,35 +117,35 @@ get(path) ->
110 117
         Cached ->
111 118
             Cached
112 119
     end;
113  
-get(body_length) ->
  120
+get(body_length, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
114 121
     case erlang:get(?SAVE_BODY_LENGTH) of
115 122
         undefined ->
116  
-            BodyLength = body_length(),
  123
+            BodyLength = body_length(THIS),
117 124
             put(?SAVE_BODY_LENGTH, {cached, BodyLength}),
118 125
             BodyLength;
119 126
         {cached, Cached} ->
120 127
             Cached
121 128
     end;
122  
-get(range) ->
123  
-    case get_header_value(range) of
  129
+get(range, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  130
+    case get_header_value(range, THIS) of
124 131
         undefined ->
125 132
             undefined;
126 133
         RawRange ->
127 134
             mochiweb_http:parse_range_request(RawRange)
128 135
     end.
129 136
 
130  
-%% @spec dump() -> {mochiweb_request, [{atom(), term()}]}
  137
+%% @spec dump(request()) -> {mochiweb_request, [{atom(), term()}]}
131 138
 %% @doc Dump the internal representation to a "human readable" set of terms
132 139
 %%      for debugging/inspection purposes.
133  
-dump() ->
  140
+dump({?MODULE, [_Socket, Method, RawPath, Version, Headers]}) ->
134 141
     {?MODULE, [{method, Method},
135 142
                {version, Version},
136 143
                {raw_path, RawPath},
137 144
                {headers, mochiweb_headers:to_list(Headers)}]}.
138 145
 
139  
-%% @spec send(iodata()) -> ok
  146
+%% @spec send(iodata(), request()) -> ok
140 147
 %% @doc Send data over the socket.
141  
-send(Data) ->
  148
+send(Data, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
142 149
     case mochiweb_socket:send(Socket, Data) of
143 150
         ok ->
144 151
             ok;
@@ -146,16 +153,16 @@ send(Data) ->
146 153
             exit(normal)
147 154
     end.
148 155
 
149  
-%% @spec recv(integer()) -> binary()
  156
+%% @spec recv(integer(), request()) -> binary()
150 157
 %% @doc Receive Length bytes from the client as a binary, with the default
151 158
 %%      idle timeout.
152  
-recv(Length) ->
153  
-    recv(Length, ?IDLE_TIMEOUT).
  159
+recv(Length, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  160
+    recv(Length, ?IDLE_TIMEOUT, THIS).
154 161
 
155  
-%% @spec recv(integer(), integer()) -> binary()
  162
+%% @spec recv(integer(), integer(), request()) -> binary()
156 163
 %% @doc Receive Length bytes from the client as a binary, with the given
157 164
 %%      Timeout in msec.
158  
-recv(Length, Timeout) ->
  165
+recv(Length, Timeout, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
159 166
     case mochiweb_socket:recv(Socket, Length, Timeout) of
160 167
         {ok, Data} ->
161 168
             put(?SAVE_RECV, true),
@@ -164,12 +171,12 @@ recv(Length, Timeout) ->
164 171
             exit(normal)
165 172
     end.
166 173
 
167  
-%% @spec body_length() -> undefined | chunked | unknown_transfer_encoding | integer()
  174
+%% @spec body_length(request()) -> undefined | chunked | unknown_transfer_encoding | integer()
168 175
 %% @doc  Infer body length from transfer-encoding and content-length headers.
169  
-body_length() ->
170  
-    case get_header_value("transfer-encoding") of
  176
+body_length({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  177
+    case get_header_value("transfer-encoding", THIS) of
171 178
         undefined ->
172  
-            case get_header_value("content-length") of
  179
+            case get_header_value("content-length", THIS) of
173 180
                 undefined ->
174 181
                     undefined;
175 182
                 Length ->
@@ -182,16 +189,16 @@ body_length() ->
182 189
     end.
183 190
 
184 191
 
185  
-%% @spec recv_body() -> binary()
  192
+%% @spec recv_body(request()) -> binary()
186 193
 %% @doc Receive the body of the HTTP request (defined by Content-Length).
187 194
 %%      Will only receive up to the default max-body length of 1MB.
188  
-recv_body() ->
189  
-    recv_body(?MAX_RECV_BODY).
  195
+recv_body({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  196
+    recv_body(?MAX_RECV_BODY, THIS).
190 197
 
191  
-%% @spec recv_body(integer()) -> binary()
  198
+%% @spec recv_body(integer(), request()) -> binary()
192 199
 %% @doc Receive the body of the HTTP request (defined by Content-Length).
193 200
 %%      Will receive up to MaxBody bytes.
194  
-recv_body(MaxBody) ->
  201
+recv_body(MaxBody, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
195 202
     case erlang:get(?SAVE_BODY) of
196 203
         undefined ->
197 204
             % we could use a sane constant for max chunk size
@@ -205,17 +212,18 @@ recv_body(MaxBody) ->
205 212
                     true ->
206 213
                         {NewLength, [Bin | BinAcc]}
207 214
                     end
208  
-                end, {0, []}, MaxBody),
  215
+                end, {0, []}, MaxBody, THIS),
209 216
             put(?SAVE_BODY, Body),
210 217
             Body;
211 218
         Cached -> Cached
212 219
     end.
213 220
 
214  
-stream_body(MaxChunkSize, ChunkFun, FunState) ->
215  
-    stream_body(MaxChunkSize, ChunkFun, FunState, undefined).
  221
+stream_body(MaxChunkSize, ChunkFun, FunState, {?MODULE,[_Socket,_Method,_RawPath,_Version,_Headers]}=THIS) ->
  222
+    stream_body(MaxChunkSize, ChunkFun, FunState, undefined, THIS).
216 223
 
217  
-stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength) ->
218  
-    Expect = case get_header_value("expect") of
  224
+stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength,
  225
+            {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  226
+    Expect = case get_header_value("expect", THIS) of
219 227
                  undefined ->
220 228
                      undefined;
221 229
                  Value when is_list(Value) ->
@@ -223,12 +231,12 @@ stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength) ->
223 231
              end,
224 232
     case Expect of
225 233
         "100-continue" ->
226  
-            _ = start_raw_response({100, gb_trees:empty()}),
  234
+            _ = start_raw_response({100, gb_trees:empty()}, THIS),
227 235
             ok;
228 236
         _Else ->
229 237
             ok
230 238
     end,
231  
-    case body_length() of
  239
+    case body_length(THIS) of
232 240
         undefined ->
233 241
             undefined;
234 242
         {unknown_transfer_encoding, Unknown} ->
@@ -237,7 +245,7 @@ stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength) ->
237 245
             % In this case the MaxBody is actually used to
238 246
             % determine the maximum allowed size of a single
239 247
             % chunk.
240  
-            stream_chunked_body(MaxChunkSize, ChunkFun, FunState);
  248
+            stream_chunked_body(MaxChunkSize, ChunkFun, FunState, THIS);
241 249
         0 ->
242 250
             <<>>;
243 251
         Length when is_integer(Length) ->
@@ -245,60 +253,62 @@ stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength) ->
245 253
             MaxBodyLength when is_integer(MaxBodyLength), MaxBodyLength < Length ->
246 254
                 exit({body_too_large, content_length});
247 255
             _ ->
248  
-                stream_unchunked_body(Length, ChunkFun, FunState)
  256
+                stream_unchunked_body(Length, ChunkFun, FunState, THIS)
249 257
             end
250 258
     end.
251 259
 
252 260
 
253  
-%% @spec start_response({integer(), ioheaders()}) -> response()
  261
+%% @spec start_response({integer(), ioheaders()}, request()) -> response()
254 262
 %% @doc Start the HTTP response by sending the Code HTTP response and
255 263
 %%      ResponseHeaders. The server will set header defaults such as Server
256 264
 %%      and Date if not present in ResponseHeaders.
257  
-start_response({Code, ResponseHeaders}) ->
  265
+start_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
258 266
     HResponse = mochiweb_headers:make(ResponseHeaders),
259 267
     HResponse1 = mochiweb_headers:default_from_list(server_headers(),
260 268
                                                     HResponse),
261  
-    start_raw_response({Code, HResponse1}).
  269
+    start_raw_response({Code, HResponse1}, THIS).
262 270
 
263  
-%% @spec start_raw_response({integer(), headers()}) -> response()
  271
+%% @spec start_raw_response({integer(), headers()}, request()) -> response()
264 272
 %% @doc Start the HTTP response by sending the Code HTTP response and
265 273
 %%      ResponseHeaders.
266  
-start_raw_response({Code, ResponseHeaders}) ->
  274
+start_raw_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Method, _RawPath, Version, _Headers]}=THIS) ->
267 275
     F = fun ({K, V}, Acc) ->
268 276
                 [mochiweb_util:make_io(K), <<": ">>, V, <<"\r\n">> | Acc]
269 277
         end,
270 278
     End = lists:foldl(F, [<<"\r\n">>],
271 279
                       mochiweb_headers:to_list(ResponseHeaders)),
272  
-    send([make_version(Version), make_code(Code), <<"\r\n">> | End]),
  280
+    send([make_version(Version), make_code(Code), <<"\r\n">> | End], THIS),
273 281
     mochiweb:new_response({THIS, Code, ResponseHeaders}).
274 282
 
275 283
 
276  
-%% @spec start_response_length({integer(), ioheaders(), integer()}) -> response()
  284
+%% @spec start_response_length({integer(), ioheaders(), integer()}, request()) -> response()
277 285
 %% @doc Start the HTTP response by sending the Code HTTP response and
278 286
 %%      ResponseHeaders including a Content-Length of Length. The server
279 287
 %%      will set header defaults such as Server
280 288
 %%      and Date if not present in ResponseHeaders.
281  
-start_response_length({Code, ResponseHeaders, Length}) ->
  289
+start_response_length({Code, ResponseHeaders, Length},
  290
+                      {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
282 291
     HResponse = mochiweb_headers:make(ResponseHeaders),
283 292
     HResponse1 = mochiweb_headers:enter("Content-Length", Length, HResponse),
284  
-    start_response({Code, HResponse1}).
  293
+    start_response({Code, HResponse1}, THIS).
285 294
 
286  
-%% @spec respond({integer(), ioheaders(), iodata() | chunked | {file, IoDevice}}) -> response()
  295
+%% @spec respond({integer(), ioheaders(), iodata() | chunked | {file, IoDevice}}, request()) -> response()
287 296
 %% @doc Start the HTTP response with start_response, and send Body to the
288 297
 %%      client (if the get(method) /= 'HEAD'). The Content-Length header
289 298
 %%      will be set by the Body length, and the server will insert header
290 299
 %%      defaults.
291  
-respond({Code, ResponseHeaders, {file, IoDevice}}) ->
  300
+respond({Code, ResponseHeaders, {file, IoDevice}},
  301
+        {?MODULE, [_Socket, Method, _RawPath, _Version, _Headers]}=THIS) ->
292 302
     Length = mochiweb_io:iodevice_size(IoDevice),
293  
-    Response = start_response_length({Code, ResponseHeaders, Length}),
  303
+    Response = start_response_length({Code, ResponseHeaders, Length}, THIS),
294 304
     case Method of
295 305
         'HEAD' ->
296 306
             ok;
297 307
         _ ->
298  
-            mochiweb_io:iodevice_stream(fun send/1, IoDevice)
  308
+            mochiweb_io:iodevice_stream(fun send/2, IoDevice)
299 309
     end,
300 310
     Response;
301  
-respond({Code, ResponseHeaders, chunked}) ->
  311
+respond({Code, ResponseHeaders, chunked}, {?MODULE, [_Socket, Method, _RawPath, Version, _Headers]}=THIS) ->
302 312
     HResponse = mochiweb_headers:make(ResponseHeaders),
303 313
     HResponse1 = case Method of
304 314
                      'HEAD' ->
@@ -319,35 +329,35 @@ respond({Code, ResponseHeaders, chunked}) ->
319 329
                          put(?SAVE_FORCE_CLOSE, true),
320 330
                          HResponse
321 331
                  end,
322  
-    start_response({Code, HResponse1});
323  
-respond({Code, ResponseHeaders, Body}) ->
324  
-    Response = start_response_length({Code, ResponseHeaders, iolist_size(Body)}),
  332
+    start_response({Code, HResponse1}, THIS);
  333
+respond({Code, ResponseHeaders, Body}, {?MODULE, [_Socket, Method, _RawPath, _Version, _Headers]}=THIS) ->
  334
+    Response = start_response_length({Code, ResponseHeaders, iolist_size(Body)}, THIS),
325 335
     case Method of
326 336
         'HEAD' ->
327 337
             ok;
328 338
         _ ->
329  
-            send(Body)
  339
+            send(Body, THIS)
330 340
     end,
331 341
     Response.
332 342
 
333  
-%% @spec not_found() -> response()
  343
+%% @spec not_found(request()) -> response()
334 344
 %% @doc Alias for <code>not_found([])</code>.
335  
-not_found() ->
336  
-    not_found([]).
  345
+not_found({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  346
+    not_found([], THIS).
337 347
 
338  
-%% @spec not_found(ExtraHeaders) -> response()
  348
+%% @spec not_found(ExtraHeaders, request()) -> response()
339 349
 %% @doc Alias for <code>respond({404, [{"Content-Type", "text/plain"}
340 350
 %% | ExtraHeaders], &lt;&lt;"Not found."&gt;&gt;})</code>.
341  
-not_found(ExtraHeaders) ->
  351
+not_found(ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
342 352
     respond({404, [{"Content-Type", "text/plain"} | ExtraHeaders],
343  
-             <<"Not found.">>}).
  353
+             <<"Not found.">>}, THIS).
344 354
 
345  
-%% @spec ok({value(), iodata()} | {value(), ioheaders(), iodata() | {file, IoDevice}}) ->
  355
+%% @spec ok({value(), iodata()} | {value(), ioheaders(), iodata() | {file, IoDevice}}, request()) ->
346 356
 %%           response()
347 357
 %% @doc respond({200, [{"Content-Type", ContentType} | Headers], Body}).
348  
-ok({ContentType, Body}) ->
349  
-    ok({ContentType, [], Body});
350  
-ok({ContentType, ResponseHeaders, Body}) ->
  358
+ok({ContentType, Body}, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  359
+    ok({ContentType, [], Body}, THIS);
  360
+ok({ContentType, ResponseHeaders, Body}, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
351 361
     HResponse = mochiweb_headers:make(ResponseHeaders),
352 362
     case THIS:get(range) of
353 363
         X when (X =:= undefined orelse X =:= fail) orelse Body =:= chunked ->
@@ -356,7 +366,7 @@ ok({ContentType, ResponseHeaders, Body}) ->
356 366
             %% full response.
357 367
             HResponse1 = mochiweb_headers:enter("Content-Type", ContentType,
358 368
                                                 HResponse),
359  
-            respond({200, HResponse1, Body});
  369
+            respond({200, HResponse1, Body}, THIS);
360 370
         Ranges ->
361 371
             {PartList, Size} = range_parts(Body, Ranges),
362 372
             case PartList of
@@ -365,7 +375,7 @@ ok({ContentType, ResponseHeaders, Body}) ->
365 375
                                                         ContentType,
366 376
                                                         HResponse),
367 377
                     %% could be 416, for now we'll just return 200
368  
-                    respond({200, HResponse1, Body});
  378
+                    respond({200, HResponse1, Body}, THIS);
369 379
                 PartList ->
370 380
                     {RangeHeaders, RangeBody} =
371 381
                         mochiweb_multipart:parts_to_body(PartList, ContentType, Size),
@@ -373,33 +383,33 @@ ok({ContentType, ResponseHeaders, Body}) ->
373 383
                                    [{"Accept-Ranges", "bytes"} |
374 384
                                     RangeHeaders],
375 385
                                    HResponse),
376  
-                    respond({206, HResponse1, RangeBody})
  386
+                    respond({206, HResponse1, RangeBody}, THIS)
377 387
             end
378 388
     end.
379 389
 
380  
-%% @spec should_close() -> bool()
  390
+%% @spec should_close(request()) -> bool()
381 391
 %% @doc Return true if the connection must be closed. If false, using
382 392
 %%      Keep-Alive should be safe.
383  
-should_close() ->
  393
+should_close({?MODULE, [_Socket, _Method, _RawPath, Version, _Headers]}=THIS) ->
384 394
     ForceClose = erlang:get(?SAVE_FORCE_CLOSE) =/= undefined,
385 395
     DidNotRecv = erlang:get(?SAVE_RECV) =:= undefined,
386 396
     ForceClose orelse Version < {1, 0}
387 397
         %% Connection: close
388  
-        orelse get_header_value("connection") =:= "close"
  398
+        orelse get_header_value("connection", THIS) =:= "close"
389 399
         %% HTTP 1.0 requires Connection: Keep-Alive
390 400
         orelse (Version =:= {1, 0}
391  
-                andalso get_header_value("connection") =/= "Keep-Alive")
  401
+                andalso get_header_value("connection", THIS) =/= "Keep-Alive")
392 402
         %% unread data left on the socket, can't safely continue
393 403
         orelse (DidNotRecv
394  
-                andalso get_header_value("content-length") =/= undefined
395  
-                andalso list_to_integer(get_header_value("content-length")) > 0)
  404
+                andalso get_header_value("content-length", THIS) =/= undefined
  405
+                andalso list_to_integer(get_header_value("content-length", THIS)) > 0)
396 406
         orelse (DidNotRecv
397  
-                andalso get_header_value("transfer-encoding") =:= "chunked").
  407
+                andalso get_header_value("transfer-encoding", THIS) =:= "chunked").
398 408
 
399  
-%% @spec cleanup() -> ok
  409
+%% @spec cleanup(request()) -> ok
400 410
 %% @doc Clean up any junk in the process dictionary, required before continuing
401 411
 %%      a Keep-Alive request.
402  
-cleanup() ->
  412
+cleanup({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}) ->
403 413
     L = [?SAVE_QS, ?SAVE_PATH, ?SAVE_RECV, ?SAVE_BODY, ?SAVE_BODY_LENGTH,
404 414
          ?SAVE_POST, ?SAVE_COOKIE, ?SAVE_FORCE_CLOSE],
405 415
     lists:foreach(fun(K) ->
@@ -407,9 +417,9 @@ cleanup() ->
407 417
                   end, L),
408 418
     ok.
409 419
 
410  
-%% @spec parse_qs() -> [{Key::string(), Value::string()}]
  420
+%% @spec parse_qs(request()) -> [{Key::string(), Value::string()}]
411 421
 %% @doc Parse the query string of the URL.
412  
-parse_qs() ->
  422
+parse_qs({?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
413 423
     case erlang:get(?SAVE_QS) of
414 424
         undefined ->
415 425
             {_, QueryString, _} = mochiweb_util:urlsplit_path(RawPath),
@@ -420,17 +430,17 @@ parse_qs() ->
420 430
             Cached
421 431
     end.
422 432
 
423  
-%% @spec get_cookie_value(Key::string) -> string() | undefined
  433
+%% @spec get_cookie_value(Key::string, request()) -> string() | undefined
424 434
 %% @doc Get the value of the given cookie.
425  
-get_cookie_value(Key) ->
426  
-    proplists:get_value(Key, parse_cookie()).
  435
+get_cookie_value(Key, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  436
+    proplists:get_value(Key, parse_cookie(THIS)).
427 437
 
428  
-%% @spec parse_cookie() -> [{Key::string(), Value::string()}]
  438
+%% @spec parse_cookie(request()) -> [{Key::string(), Value::string()}]
429 439
 %% @doc Parse the cookie header.
430  
-parse_cookie() ->
  440
+parse_cookie({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
431 441
     case erlang:get(?SAVE_COOKIE) of
432 442
         undefined ->
433  
-            Cookies = case get_header_value("cookie") of
  443
+            Cookies = case get_header_value("cookie", THIS) of
434 444
                           undefined ->
435 445
                               [];
436 446
                           Value ->
@@ -442,17 +452,17 @@ parse_cookie() ->
442 452
             Cached
443 453
     end.
444 454
 
445  
-%% @spec parse_post() -> [{Key::string(), Value::string()}]
  455
+%% @spec parse_post(request()) -> [{Key::string(), Value::string()}]
446 456
 %% @doc Parse an application/x-www-form-urlencoded form POST. This
447 457
 %%      has the side-effect of calling recv_body().
448  
-parse_post() ->
  458
+parse_post({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
449 459
     case erlang:get(?SAVE_POST) of
450 460
         undefined ->
451  
-            Parsed = case recv_body() of
  461
+            Parsed = case recv_body(THIS) of
452 462
                          undefined ->
453 463
                              [];
454 464
                          Binary ->
455  
-                             case get_primary_header_value("content-type") of
  465
+                             case get_primary_header_value("content-type",THIS) of
456 466
                                  "application/x-www-form-urlencoded" ++ _ ->
457 467
                                      mochiweb_util:parse_qs(Binary);
458 468
                                  _ ->
@@ -465,37 +475,39 @@ parse_post() ->
465 475
             Cached
466 476
     end.
467 477
 
468  
-%% @spec stream_chunked_body(integer(), fun(), term()) -> term()
  478
+%% @spec stream_chunked_body(integer(), fun(), term(), request()) -> term()
469 479
 %% @doc The function is called for each chunk.
470 480
 %%      Used internally by read_chunked_body.
471  
-stream_chunked_body(MaxChunkSize, Fun, FunState) ->
472  
-    case read_chunk_length() of
  481
+stream_chunked_body(MaxChunkSize, Fun, FunState,
  482
+                    {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  483
+    case read_chunk_length(THIS) of
473 484
         0 ->
474  
-            Fun({0, read_chunk(0)}, FunState);
  485
+            Fun({0, read_chunk(0, THIS)}, FunState);
475 486
         Length when Length > MaxChunkSize ->
476  
-            NewState = read_sub_chunks(Length, MaxChunkSize, Fun, FunState),
477  
-            stream_chunked_body(MaxChunkSize, Fun, NewState);
  487
+            NewState = read_sub_chunks(Length, MaxChunkSize, Fun, FunState, THIS),
  488
+            stream_chunked_body(MaxChunkSize, Fun, NewState, THIS);
478 489
         Length ->
479  
-            NewState = Fun({Length, read_chunk(Length)}, FunState),
480  
-            stream_chunked_body(MaxChunkSize, Fun, NewState)
  490
+            NewState = Fun({Length, read_chunk(Length, THIS)}, FunState),
  491
+            stream_chunked_body(MaxChunkSize, Fun, NewState, THIS)
481 492
     end.
482 493
 
483  
-stream_unchunked_body(0, Fun, FunState) ->
  494
+stream_unchunked_body(0, Fun, FunState, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}) ->
484 495
     Fun({0, <<>>}, FunState);
485  
-stream_unchunked_body(Length, Fun, FunState) when Length > 0 ->
  496
+stream_unchunked_body(Length, Fun, FunState,
  497
+                      {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > 0 ->
486 498
     PktSize = case Length > ?RECBUF_SIZE of
487 499
         true ->
488 500
             ?RECBUF_SIZE;
489 501
         false ->
490 502
             Length
491 503
     end,
492  
-    Bin = recv(PktSize),
  504
+    Bin = recv(PktSize, THIS),
493 505
     NewState = Fun({PktSize, Bin}, FunState),
494  
-    stream_unchunked_body(Length - PktSize, Fun, NewState).
  506
+    stream_unchunked_body(Length - PktSize, Fun, NewState, THIS).
495 507
 
496  
-%% @spec read_chunk_length() -> integer()
  508
+%% @spec read_chunk_length(request()) -> integer()
497 509
 %% @doc Read the length of the next HTTP chunk.
498  
-read_chunk_length() ->
  510
+read_chunk_length({?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
499 511
     ok = mochiweb_socket:setopts(Socket, [{packet, line}]),
500 512
     case mochiweb_socket:recv(Socket, 0, ?IDLE_TIMEOUT) of
501 513
         {ok, Header} ->
@@ -509,10 +521,10 @@ read_chunk_length() ->
509 521
             exit(normal)
510 522
     end.
511 523
 
512  
-%% @spec read_chunk(integer()) -> Chunk::binary() | [Footer::binary()]
  524
+%% @spec read_chunk(integer(), request()) -> Chunk::binary() | [Footer::binary()]
513 525
 %% @doc Read in a HTTP chunk of the given length. If Length is 0, then read the
514 526
 %%      HTTP footers (as a list of binaries, since they're nominal).
515  
-read_chunk(0) ->
  527
+read_chunk(0, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
516 528
     ok = mochiweb_socket:setopts(Socket, [{packet, line}]),
517 529
     F = fun (F1, Acc) ->
518 530
                 case mochiweb_socket:recv(Socket, 0, ?IDLE_TIMEOUT) of
@@ -528,7 +540,7 @@ read_chunk(0) ->
528 540
     ok = mochiweb_socket:setopts(Socket, [{packet, raw}]),
529 541
     put(?SAVE_RECV, true),
530 542
     Footers;
531  
-read_chunk(Length) ->
  543
+read_chunk(Length, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
532 544
     case mochiweb_socket:recv(Socket, 2 + Length, ?IDLE_TIMEOUT) of
533 545
         {ok, <<Chunk:Length/binary, "\r\n">>} ->
534 546
             Chunk;
@@ -536,32 +548,34 @@ read_chunk(Length) ->
536 548
             exit(normal)
537 549
     end.
538 550
 
539  
-read_sub_chunks(Length, MaxChunkSize, Fun, FunState) when Length > MaxChunkSize ->
540  
-    Bin = recv(MaxChunkSize),
  551
+read_sub_chunks(Length, MaxChunkSize, Fun, FunState,
  552
+                {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > MaxChunkSize ->
  553
+    Bin = recv(MaxChunkSize, THIS),
541 554
     NewState = Fun({size(Bin), Bin}, FunState),
542  
-    read_sub_chunks(Length - MaxChunkSize, MaxChunkSize, Fun, NewState);
  555
+    read_sub_chunks(Length - MaxChunkSize, MaxChunkSize, Fun, NewState, THIS);
543 556
 
544  
-read_sub_chunks(Length, _MaxChunkSize, Fun, FunState) ->
545  
-    Fun({Length, read_chunk(Length)}, FunState).
  557
+read_sub_chunks(Length, _MaxChunkSize, Fun, FunState,
  558
+                {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  559
+    Fun({Length, read_chunk(Length, THIS)}, FunState).
546 560
 
547  
-%% @spec serve_file(Path, DocRoot) -> Response
  561
+%% @spec serve_file(Path, DocRoot, request()) -> Response
548 562
 %% @doc Serve a file relative to DocRoot.
549  
-serve_file(Path, DocRoot) ->
550  
-    serve_file(Path, DocRoot, []).
  563
+serve_file(Path, DocRoot, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  564
+    serve_file(Path, DocRoot, [], THIS).
551 565
 
552  
-%% @spec serve_file(Path, DocRoot, ExtraHeaders) -> Response
  566
+%% @spec serve_file(Path, DocRoot, ExtraHeaders, request()) -> Response
553 567
 %% @doc Serve a file relative to DocRoot.
554  
-serve_file(Path, DocRoot, ExtraHeaders) ->
  568
+serve_file(Path, DocRoot, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
555 569
     case mochiweb_util:safe_relative_path(Path) of
556 570
         undefined ->
557  
-            not_found(ExtraHeaders);
  571
+            not_found(ExtraHeaders, THIS);
558 572
         RelPath ->
559 573
             FullPath = filename:join([DocRoot, RelPath]),
560 574
             case filelib:is_dir(FullPath) of
561 575
                 true ->
562  
-                    maybe_redirect(RelPath, FullPath, ExtraHeaders);
  576
+                    maybe_redirect(RelPath, FullPath, ExtraHeaders, THIS);
563 577
                 false ->
564  
-                    maybe_serve_file(FullPath, ExtraHeaders)
  578
+                    maybe_serve_file(FullPath, ExtraHeaders, THIS)
565 579
             end
566 580
     end.
567 581
 
@@ -571,13 +585,14 @@ serve_file(Path, DocRoot, ExtraHeaders) ->
571 585
 directory_index(FullPath) ->
572 586
     filename:join([FullPath, "index.html"]).
573 587
 
574  
-maybe_redirect([], FullPath, ExtraHeaders) ->
575  
-    maybe_serve_file(directory_index(FullPath), ExtraHeaders);
  588
+maybe_redirect([], FullPath, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  589
+    maybe_serve_file(directory_index(FullPath), ExtraHeaders, THIS);
576 590
 
577  
-maybe_redirect(RelPath, FullPath, ExtraHeaders) ->
  591
+maybe_redirect(RelPath, FullPath, ExtraHeaders,
  592
+               {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}=THIS) ->
578 593
     case string:right(RelPath, 1) of
579 594
         "/" ->
580  
-            maybe_serve_file(directory_index(FullPath), ExtraHeaders);
  595
+            maybe_serve_file(directory_index(FullPath), ExtraHeaders, THIS);
581 596
         _   ->
582 597
             Host = mochiweb_headers:get_value("host", Headers),
583 598
             Location = "http://" ++ Host  ++ "/" ++ RelPath ++ "/",
@@ -592,16 +607,16 @@ maybe_redirect(RelPath, FullPath, ExtraHeaders) ->
592 607
             "<p>The document has moved <a href=\"">>,
593 608
             Bottom = <<">here</a>.</p></body></html>\n">>,
594 609
             Body = <<Top/binary, LocationBin/binary, Bottom/binary>>,
595  
-            respond({301, MoreHeaders, Body})
  610
+            respond({301, MoreHeaders, Body}, THIS)
596 611
     end.
597 612
 
598  
-maybe_serve_file(File, ExtraHeaders) ->
  613
+maybe_serve_file(File, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
599 614
     case file:read_file_info(File) of
600 615
         {ok, FileInfo} ->
601 616
             LastModified = httpd_util:rfc1123_date(FileInfo#file_info.mtime),
602  
-            case get_header_value("if-modified-since") of
  617
+            case get_header_value("if-modified-since", THIS) of
603 618
                 LastModified ->
604  
-                    respond({304, ExtraHeaders, ""});
  619
+                    respond({304, ExtraHeaders, ""}, THIS);
605 620
                 _ ->
606 621
                     case file:open(File, [raw, binary]) of
607 622
                         {ok, IoDevice} ->
@@ -609,15 +624,15 @@ maybe_serve_file(File, ExtraHeaders) ->
609 624
                             Res = ok({ContentType,
610 625
                                       [{"last-modified", LastModified}
611 626
                                        | ExtraHeaders],
612  
-                                      {file, IoDevice}}),
  627
+                                      {file, IoDevice}}, THIS),
613 628
                             ok = file:close(IoDevice),
614 629
                             Res;
615 630
                         _ ->
616  
-                            not_found(ExtraHeaders)
  631
+                            not_found(ExtraHeaders, THIS)
617 632
                     end
618 633
             end;
619 634
         {error, _} ->
620  
-            not_found(ExtraHeaders)
  635
+            not_found(ExtraHeaders, THIS)
621 636
     end.
622 637
 
623 638
 server_headers() ->
@@ -665,7 +680,7 @@ range_parts(Body0, Ranges) ->
665 680
         end,
666 681
     {lists:foldr(F, [], Ranges), Size}.
667 682
 
668  
-%% @spec accepted_encodings([encoding()]) -> [encoding()] | bad_accept_encoding_value
  683
+%% @spec accepted_encodings([encoding()], request()) -> [encoding()] | bad_accept_encoding_value
669 684
 %% @type encoding() = string().
670 685
 %%
671 686
 %% @doc Returns a list of encodings accepted by a request. Encodings that are
@@ -689,8 +704,8 @@ range_parts(Body0, Ranges) ->
689 704
 %%         accepted_encodings(["gzip", "deflate", "identity"]) ->
690 705
 %%            ["deflate", "gzip", "identity"]
691 706
 %%
692  
-accepted_encodings(SupportedEncodings) ->
693  
-    AcceptEncodingHeader = case get_header_value("Accept-Encoding") of
  707
+accepted_encodings(SupportedEncodings, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  708
+    AcceptEncodingHeader = case get_header_value("Accept-Encoding", THIS) of
694 709
         undefined ->
695 710
             "";
696 711
         Value ->
@@ -705,7 +720,7 @@ accepted_encodings(SupportedEncodings) ->
705 720
             )
706 721
     end.
707 722
 
708  
-%% @spec accepts_content_type(string() | binary()) -> boolean() | bad_accept_header
  723
+%% @spec accepts_content_type(string() | binary(), request()) -> boolean() | bad_accept_header
709 724
 %%
710 725
 %% @doc Determines whether a request accepts a given media type by analyzing its
711 726
 %%      "Accept" header.
@@ -727,9 +742,9 @@ accepted_encodings(SupportedEncodings) ->
727 742
 %%      5) For an "Accept" header with value "text/*; q=0.0, */*":
728 743
 %%         accepts_content_type("text/plain") -> false
729 744
 %%
730  
-accepts_content_type(ContentType1) ->
  745
+accepts_content_type(ContentType1, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
731 746
     ContentType = re:replace(ContentType1, "\\s", "", [global, {return, list}]),
732  
-    AcceptHeader = accept_header(),
  747
+    AcceptHeader = accept_header(THIS),
733 748
     case mochiweb_util:parse_qvalues(AcceptHeader) of
734 749
         invalid_qvalue_string ->
735 750
             bad_accept_header;
@@ -750,7 +765,7 @@ accepts_content_type(ContentType1) ->
750 765
             (not lists:member({SuperType, 0.0}, QList))
751 766
     end.
752 767
 
753  
-%% @spec accepted_content_types([string() | binary()]) -> [string()] | bad_accept_header
  768
+%% @spec accepted_content_types([string() | binary()], request()) -> [string()] | bad_accept_header
754 769
 %%
755 770
 %% @doc Filters which of the given media types this request accepts. This filtering
756 771
 %%      is performed by analyzing the "Accept" header. The returned list is sorted
@@ -776,11 +791,11 @@ accepts_content_type(ContentType1) ->
776 791
 %%         accepts_content_types(["application/json", "text/html"]) ->
777 792
 %%             ["text/html", "application/json"]
778 793
 %%
779  
-accepted_content_types(Types1) ->
  794
+accepted_content_types(Types1, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
780 795
     Types = lists:map(
781 796
         fun(T) -> re:replace(T, "\\s", "", [global, {return, list}]) end,
782 797
         Types1),
783  
-    AcceptHeader = accept_header(),
  798
+    AcceptHeader = accept_header(THIS),
784 799
     case mochiweb_util:parse_qvalues(AcceptHeader) of
785 800
         invalid_qvalue_string ->
786 801
             bad_accept_header;
@@ -816,8 +831,8 @@ accepted_content_types(Types1) ->
816 831
             [Type || {_Q, Type} <- lists:sort(SortFun, TypesQ)]
817 832
     end.
818 833
 
819  
-accept_header() ->
820  
-    case get_header_value("Accept") of
  834
+accept_header({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
  835
+    case get_header_value("Accept", THIS) of
821 836
         undefined ->
822 837
             "*/*";
823 838
         Value ->
44  src/mochiweb_response.erl
@@ -3,39 +3,47 @@
3 3
 
4 4
 %% @doc Response abstraction.
5 5
 
6  
--module(mochiweb_response, [Request, Code, Headers]).
  6
+-module(mochiweb_response).
7 7
 -author('bob@mochimedia.com').
8 8
 
9 9
 -define(QUIP, "Any of you quaids got a smint?").
10 10
 
11  
--export([get_header_value/1, get/1, dump/0]).
12  
--export([send/1, write_chunk/1]).
  11
+-export([new/3, get_header_value/2, get/2, dump/1]).
  12
+-export([send/2, write_chunk/2]).
13 13
 
14  
-%% @spec get_header_value(string() | atom() | binary()) -> string() | undefined
  14
+%% @type response() = {atom(), [Request, Code, Headers]}
  15
+
  16
+%% @spec new(Request, Code, Headers) -> response()
  17
+%% @doc Create a new mochiweb_response instance.
  18
+new(Request, Code, Headers) ->
  19
+    {?MODULE, [Request, Code, Headers]}.
  20
+
  21
+%% @spec get_header_value(string() | atom() | binary(), response()) ->
  22
+%%           string() | undefined
15 23
 %% @doc Get the value of the given response header.
16  
-get_header_value(K) ->
  24
+get_header_value(K, {?MODULE, [_Request, _Code, Headers]}) ->
17 25
     mochiweb_headers:get_value(K, Headers).
18 26
 
19  
-%% @spec get(request | code | headers) -> term()
  27
+%% @spec get(request | code | headers, response()) -> term()
20 28
 %% @doc Return the internal representation of the given field.
21  
-get(request) ->
  29
+get(request, {?MODULE, [Request, _Code, _Headers]}) ->
22 30
     Request;
23  
-get(code) ->
  31
+get(code, {?MODULE, [_Request, Code, _Headers]}) ->
24 32
     Code;
25  
-get(headers) ->
  33
+get(headers, {?MODULE, [_Request, _Code, Headers]}) ->
26 34
     Headers.
27 35
 
28  
-%% @spec dump() -> {mochiweb_request, [{atom(), term()}]}
  36
+%% @spec dump(response()) -> {mochiweb_request, [{atom(), term()}]}
29 37
 %% @doc Dump the internal representation to a "human readable" set of terms
30 38
 %%      for debugging/inspection purposes.
31  
-dump() ->
  39
+dump({?MODULE, [Request, Code, Headers]}) ->
32 40
     [{request, Request:dump()},
33 41
      {code, Code},
34 42
      {headers, mochiweb_headers:to_list(Headers)}].
35 43
 
36  
-%% @spec send(iodata()) -> ok
  44
+%% @spec send(iodata(), response()) -> ok
37 45
 %% @doc Send data over the socket if the method is not HEAD.
38  
-send(Data) ->
  46
+send(Data, {?MODULE, [Request, _Code, _Headers]}) ->
39 47
     case Request:get(method) of
40 48
         'HEAD' ->
41 49
             ok;
@@ -43,16 +51,16 @@ send(Data) ->
43 51
             Request:send(Data)
44 52
     end.
45 53
 
46  
-%% @spec write_chunk(iodata()) -> ok
  54
+%% @spec write_chunk(iodata(), response()) -> ok
47 55
 %% @doc Write a chunk of a HTTP chunked response. If Data is zero length,
48 56
 %%      then the chunked response will be finished.
49  
-write_chunk(Data) ->
50  
-    case Request:get(version) of
  57
+write_chunk(Data, {?MODULE, [Request, _Code, _Headers]}=THIS) ->
  58
+    case Request:get(version, THIS) of
51 59
         Version when Version >= {1, 1} ->
52 60
             Length = iolist_size(Data),
53  
-            send([io_lib:format("~.16b\r\n", [Length]), Data, <<"\r\n">>]);
  61
+            send([io_lib:format("~.16b\r\n", [Length]), Data, <<"\r\n">>], THIS);
54 62
         _ ->
55  
-            send(Data)
  63
+            send(Data, THIS)
56 64
     end.
57 65
 
58 66
 

0 notes on commit 6fef514

Please sign in to comment.
Something went wrong with that request. Please try again.