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 #include "protocol.h"
30
31 #include "session.h"
32 #include "httplistener.h"
33 #include "request.h"
34
35 #include "../util/pblock.h"
36 #include "../util/pool.h"
37 #include "../util/io.h"
38 #include "../util/util.h"
39 #include "../util/strbuf.h"
40
41 #define HTTP_SCHEME "http"
42 #define HTTPS_SCHEME "https"
43
44 void protocol_status(Session *sn, Request *rq,
int n,
const char *m) {
45 rq->status_num = n;
46
47 const char *msg = m ? m : protocol_status_message(n);
48
49 pb_param *pp = pblock_removekey(pb_key_status, rq->srvhdrs);
50 if (pp !=
NULL) {
51 param_free(pp);
52 }
53
54 pp = pblock_key_param_create(rq->srvhdrs, pb_key_status, msg, strlen(msg));
55 pblock_kpinsert(pb_key_status, pp, rq->srvhdrs);
56 }
57
58
59
60
61
62
63 NSAPI_PUBLIC const char * protocol_status_message (
int code)
64 {
65 WS_ASSERT(code >
0);
66
67 const char *r;
68
69 switch (code)
70 {
71 case PROTOCOL_CONTINUE :
72 r =
"Continue";
73 break;
74 case PROTOCOL_SWITCHING:
75 r =
"Switching Protocols";
76 break;
77 case PROTOCOL_OK:
78 r =
"OK";
79 break;
80 case PROTOCOL_CREATED:
81 r =
"Created";
82 break;
83 case PROTOCOL_ACCEPTED:
84 r =
"Accepted";
85 break;
86 case PROTOCOL_NONAUTHORITATIVE:
87 r =
"Non-Authoritative Information";
88 break;
89 case PROTOCOL_NO_CONTENT:
90
91
92
93
94 r =
"No Content";
95 break;
96 case PROTOCOL_RESET_CONTENT:
97 r =
"Reset Content";
98 break;
99 case PROTOCOL_PARTIAL_CONTENT:
100 r =
"Partial Content";
101 break;
102 case PROTOCOL_MULTI_STATUS:
103 r =
"Multi Status";
104 break;
105 case PROTOCOL_MULTIPLE_CHOICES:
106 r =
"Multiple Choices";
107 break;
108 case PROTOCOL_MOVED_PERMANENTLY:
109 r =
"Moved Permanently";
110 break;
111 case PROTOCOL_REDIRECT:
112 r =
"Moved Temporarily";
113 break;
114 case PROTOCOL_SEE_OTHER:
115 r =
"See Other";
116 break;
117 case PROTOCOL_NOT_MODIFIED:
118 r =
"Use local copy";
119 break;
120 case PROTOCOL_USE_PROXY:
121 r =
"Use Proxy";
122 break;
123 case PROTOCOL_TEMPORARY_REDIRECT:
124 r =
"Temporary Redirect";
125 break;
126 case PROTOCOL_BAD_REQUEST:
127 r =
"Bad request";
128 break;
129 case PROTOCOL_UNAUTHORIZED:
130 r =
"Unauthorized";
131 break;
132 case PROTOCOL_PAYMENT_REQUIRED:
133 r =
"Payment Required";
134 break;
135 case PROTOCOL_FORBIDDEN:
136 r =
"Forbidden";
137 break;
138 case PROTOCOL_NOT_FOUND:
139 r =
"Not found";
140 break;
141 case PROTOCOL_METHOD_NOT_ALLOWED:
142 r =
"Method Not Allowed";
143 break;
144 case PROTOCOL_NOT_ACCEPTABLE:
145 r =
"Not Acceptable";
146 break;
147 case PROTOCOL_PROXY_UNAUTHORIZED:
148 r =
"Proxy Authentication Required";
149 break;
150 case PROTOCOL_REQUEST_TIMEOUT:
151 r =
"Request Timeout";
152 break;
153 case PROTOCOL_CONFLICT:
154 r =
"Conflict";
155 break;
156 case PROTOCOL_GONE:
157 r =
"Gone";
158 break;
159 case PROTOCOL_LENGTH_REQUIRED:
160 r =
"Length Required";
161 break;
162 case PROTOCOL_PRECONDITION_FAIL:
163 r =
"Precondition Failed";
164 break;
165 case PROTOCOL_ENTITY_TOO_LARGE:
166 r =
"Request Entity Too Large";
167 break;
168 case PROTOCOL_URI_TOO_LARGE:
169 r =
"Request-URI Too Large";
170 break;
171 case PROTOCOL_UNSUPPORTED_MEDIA_TYPE:
172 r =
"Unsupported Media Type";
173 break;
174 case PROTOCOL_REQUESTED_RANGE_NOT_SATISFIABLE:
175 r =
"Requested range not satisfiable";
176 break;
177 case PROTOCOL_EXPECTATION_FAILED:
178 r =
"Expectation Failed";
179 break;
180 case PROTOCOL_LOCKED:
181 r =
"Locked";
182 break;
183 case PROTOCOL_FAILED_DEPENDENCY:
184 r =
"Failed Dependency";
185 break;
186 case PROTOCOL_SERVER_ERROR:
187 r =
"Server Error";
188 break;
189 case PROTOCOL_NOT_IMPLEMENTED:
190 r =
"Not Implemented";
191 break;
192 case PROTOCOL_BAD_GATEWAY:
193 r =
"Bad Gateway";
194 break;
195 case PROTOCOL_SERVICE_UNAVAILABLE:
196 r =
"Service Unavailable";
197 break;
198 case PROTOCOL_GATEWAY_TIMEOUT:
199 r =
"Gateway Timeout";
200 break;
201 case PROTOCOL_VERSION_NOT_SUPPORTED:
202 r =
"HTTP Version Not Supported";
203 break;
204 case PROTOCOL_INSUFFICIENT_STORAGE:
205 r =
"Insufficient Storage";
206 break;
207 default:
208 switch (code /
100)
209 {
210 case 1:
211 r =
"Information";
212 break;
213 case 2:
214 r =
"Success";
215 break;
216 case 3:
217 r =
"Redirect";
218 break;
219 case 4:
220 r =
"Client error";
221 break;
222 case 5:
223 r =
"Server error";
224 break;
225 default:
226 r =
"Unknown reason";
227 break;
228 }
229 break;
230 }
231
232 return r;
233 }
234
235
236 void add_http_status_line(
sbuf_t *out,
pool_handle_t *pool, Request *rq) {
237 sbuf_write(out,
"HTTP/1.1 ",
9);
238
239 char *status_code_str = pool_malloc(pool,
8);
240 int sc_len = snprintf(status_code_str,
8,
"%d ", rq->status_num);
241 sbuf_write(out, status_code_str, sc_len);
242
243 char *scmsg = pblock_findkeyval(pb_key_status, rq->srvhdrs);
244 if(scmsg ==
NULL) {
245 scmsg =
"OK";
246 }
247 sbuf_write(out, scmsg, strlen(scmsg));
248
249 sbuf_write(out,
"\r\n",
2);
250 }
251
252 void add_http_response_header(
sbuf_t *out, Request *rq) {
253 pblock *h = rq->srvhdrs;
254 pb_entry *p;
255
256 for(
int i=
0;i<h->hsize;i++) {
257 p = h->ht[i];
258 while(p !=
NULL) {
259
260 const pb_key *key =
PARAM_KEY(p->param);
261 if (key == pb_key_status || key == pb_key_server || key == pb_key_date) {
262
263 p = p->next;
264 continue;
265 }
266
267
268 char *name = p->param->name;
269 char *value = p->param->value;
270
271
272 size_t name_len = strlen(name);
273 if(name[
0] >
90) {
274
275
276
277
278 sbuf_put(out, name[
0]-
32);
279 if(name_len >
1) {
280 sbuf_write(out, name+
1, name_len-
1);
281 }
282 }
else {
283
284 sbuf_write(out, name, name_len);
285 }
286
287 sbuf_write(out,
": ",
2);
288 sbuf_write(out, value, strlen(value));
289 sbuf_write(out,
"\r\n",
2);
290
291 p = p->next;
292 }
293 }
294 }
295
296 int http_start_response(Session *sn, Request *rq) {
297 Connection *conn = ((NSAPISession*)sn)->connection;
298
299 if(rq->status_num == -
1) {
300 protocol_status(sn, rq,
200,
"OK");
301 }
302
303
304
305
306
307
308
309 sbuf_t *out = sbuf_new(
512);
310
311
312 add_http_status_line(out, sn->pool, rq);
313
314
315 struct tm mtms;
316 struct tm *mtm = system_gmtime(&rq->req_start, &mtms);
317 char date[
HTTP_DATE_LEN +
1];
318 strftime(date,
HTTP_DATE_LEN,
HTTP_DATE_FMT, mtm);
319 sbuf_write(out,
"Date: ",
6);
320 sbuf_write(out, date, strlen(date));
321 sbuf_write(out,
"\r\n",
2);
322
323
324 sbuf_write(out,
"Server: webserver\r\n",
19);
325
326
327 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->srvhdrs);
328 char *enc = pblock_findkeyval(pb_key_transfer_encoding, rq->srvhdrs);
329 if(ctlen && enc) {
330 pblock_removekey(pb_key_transfer_encoding, rq->srvhdrs);
331 }
332 if(!ctlen) {
333
334 if(!enc) {
335 pblock_kvinsert(
336 pb_key_transfer_encoding,
337 "chunked",
338 7,
339 rq->srvhdrs);
340 }
else if(strcmp(enc,
"chunked")) {
341 pblock_removekey(pb_key_transfer_encoding, rq->srvhdrs);
342 pblock_kvinsert(
343 pb_key_transfer_encoding,
344 "chunked",
345 7,
346 rq->srvhdrs);
347 }
348
349
350 HttpStream *stream = (HttpStream*)sn->csd;
351 stream->chunked_enc =
1;
352 rq->rq_attr.chunked =
1;
353 }
354
355
356 add_http_response_header(out, rq);
357
358
359 if(rq->rq_attr.keep_alive) {
360 sbuf_write(out,
"Connection: keep-alive\r\n",
24);
361 pblock_kvinsert(pb_key_connection,
"keep-alive",
10, rq->srvhdrs);
362 }
else {
363 sbuf_write(out,
"Connection: close\r\n",
19);
364 pblock_kvinsert(pb_key_connection,
"close",
5, rq->srvhdrs);
365 }
366
367
368
369 sbuf_write(out,
"\r\n",
2);
370
371
372 conn->write(conn, out->ptr, out->length);
373 sbuf_free(out);
374
375 rq->senthdrs =
1;
376
377 return 0;
378 }
379
380 int request_header(
char *name,
char **value, Session *sn, Request *rq) {
381 const pb_key *key = pblock_key(name);
382 pb_param *pp = pblock_findkey(key, rq->headers);
383 if(pp !=
NULL) {
384 *value = pp->value;
385 return REQ_PROCEED;
386 }
else {
387
388 *value =
NULL;
389 return REQ_NOACTION;
390 }
391 }
392
393 char *http_uri2url(
const char *prefix,
const char *suffix) {
394
395 return NULL;
396 }
397
398 char *http_uri2url_dynamic(
const char *prefix,
const char *suffix,
399 Session *sn, Request *rq)
400 {
401
402 return NULL;
403 }
404
405 void http_get_scheme_host_port(
406 Session *sn,
407 Request *rq,
408 char **scheme,
409 char **host,
410 uint16_t *port)
411 {
412 Connection *con = ((NSAPISession*)sn)->connection;
413
414 if(con->ssl) {
415 *scheme =
HTTPS_SCHEME;
416 }
else {
417 *scheme =
HTTP_SCHEME;
418 }
419
420 NSAPIRequest *request = (NSAPIRequest*)rq;
421
422 if(request->host) {
423 *host = request->host;
424 }
else {
425 *host =
"localhost";
426 }
427
428 *port = request->port;
429
430 }
431