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(CxBuffer *out,
pool_handle_t *pool, Request *rq) {
237 cxBufferWrite(
"HTTP/1.1 ",
1,
9, out);
238
239 char status_code_str[
8];
240 int sc_len = snprintf(status_code_str,
8,
"%d ", rq->status_num);
241 cxBufferWrite(status_code_str,
1, sc_len, out);
242
243 char *scmsg = pblock_findkeyval(pb_key_status, rq->srvhdrs);
244 if(scmsg ==
NULL) {
245 scmsg =
"OK";
246 }
247 cxBufferWrite(scmsg,
1, strlen(scmsg), out);
248
249 cxBufferWrite(
"\r\n",
1,
2, out);
250 }
251
252 void add_http_response_header(CxBuffer *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 cxBufferPut(out, name[
0]-
32);
279 if(name_len >
1) {
280 cxBufferWrite(name+
1,
1, name_len-
1, out);
281 }
282 }
else {
283
284 cxBufferWrite(name,
1, name_len, out);
285 }
286
287 cxBufferWrite(
": ",
1,
2, out);
288 cxBufferWrite(value,
1, strlen(value), out);
289 cxBufferWrite(
"\r\n",
1,
2, out);
290
291 p = p->next;
292 }
293 }
294 }
295
296 struct HttpResponseWriter {
297 Session *sn;
298 Request *rq;
299 CxBuffer buf;
300 };
301
302 HttpResponseWriter *http_create_response(Session *sn, Request *rq) {
303 HttpResponseWriter *writer = pool_malloc(sn->pool,
sizeof(HttpResponseWriter));
304 if(!writer) {
305 return NULL;
306 }
307 if(cxBufferInit(&writer->buf,
NULL,
512, pool_allocator(sn->pool),
CX_BUFFER_AUTO_EXTEND|
CX_BUFFER_FREE_CONTENTS)) {
308 pool_free(sn->pool, writer);
309 return NULL;
310 }
311 writer->sn = sn;
312 writer->rq = rq;
313
314 if(rq->status_num == -
1) {
315 protocol_status(sn, rq,
200,
"OK");
316 }
317
318
319 add_http_status_line(&writer->buf, sn->pool, rq);
320
321
322 struct tm mtms;
323 struct tm *mtm = system_gmtime(&rq->req_start, &mtms);
324 char date[
HTTP_DATE_LEN +
1];
325 strftime(date,
HTTP_DATE_LEN,
HTTP_DATE_FMT, mtm);
326 cxBufferWrite(
"Date: ",
1,
6, &writer->buf);
327 cxBufferWrite(date,
1, strlen(date), &writer->buf);
328 cxBufferWrite(
"\r\n",
1,
2, &writer->buf);
329
330
331 cxBufferWrite(
"Server: webserver\r\n",
1,
19, &writer->buf);
332
333
334 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->srvhdrs);
335 char *enc = pblock_findkeyval(pb_key_transfer_encoding, rq->srvhdrs);
336 if(ctlen && enc) {
337 pblock_removekey(pb_key_transfer_encoding, rq->srvhdrs);
338 }
339 if(!ctlen) {
340
341 if(!enc) {
342 pblock_kvinsert(
343 pb_key_transfer_encoding,
344 "chunked",
345 7,
346 rq->srvhdrs);
347 }
else if(strcmp(enc,
"chunked")) {
348 pblock_removekey(pb_key_transfer_encoding, rq->srvhdrs);
349 pblock_kvinsert(
350 pb_key_transfer_encoding,
351 "chunked",
352 7,
353 rq->srvhdrs);
354 }
355
356
357 httpstream_enable_chunked_write(sn->csd);
358 rq->rq_attr.chunked =
1;
359 }
360
361
362 add_http_response_header(&writer->buf, rq);
363
364
365 if(rq->rq_attr.keep_alive) {
366 cxBufferWrite(
"Connection: keep-alive\r\n",
1,
24, &writer->buf);
367 pblock_kvinsert(pb_key_connection,
"keep-alive",
10, rq->srvhdrs);
368 }
else {
369 cxBufferWrite(
"Connection: close\r\n",
1,
19, &writer->buf);
370 pblock_kvinsert(pb_key_connection,
"close",
5, rq->srvhdrs);
371 }
372
373
374 cxBufferWrite(
"\r\n",
1,
2,& writer->buf);
375
376
377 writer->buf.pos =
0;
378
379 return writer;
380 }
381
382 int http_send_response(HttpResponseWriter *writer) {
383 Connection *conn = ((NSAPISession*)writer->sn)->connection;
384 CxBuffer *buf = &writer->buf;
385
386
387 int ret =
0;
388 while(buf->pos < buf->size) {
389 int w = conn->write(conn, buf->space + buf->pos, buf->size - buf->pos);
390 if(w <=
0) {
391 if(conn->ssl) {
392 if(conn->ssl_error ==
SSL_ERROR_WANT_WRITE) {
393 return 1;
394 }
395 }
else {
396 if(errno ==
EWOULDBLOCK) {
397 return 1;
398 }
399 }
400 ret = -
1;
401 break;
402 }
403 buf->pos += w;
404 }
405
406 if(ret ==
0) {
407 writer->rq->senthdrs =
1;
408 }
409
410 cxBufferDestroy(buf);
411 pool_free(writer->sn->pool, writer);
412
413 return ret;
414 }
415
416
417 int http_start_response(Session *sn, Request *rq) {
418 HttpResponseWriter *writer = http_create_response(sn, rq);
419 if(!writer) {
420 return 1;
421 }
422
423 return http_send_response(writer);
424 }
425
426 int http_send_continue(Session *sn) {
427 NSAPISession *s = (NSAPISession*)sn;
428 cxstring msg =
CX_STR(
"HTTP/1.1 100 Continue\r\n\r\n");
429 int w = s->connection->write(s->connection, msg.ptr, msg.length);
430 if(w != msg.length) {
431 return 1;
432 }
433 return 0;
434 }
435
436 int request_header(
char *name,
char **value, Session *sn, Request *rq) {
437 const pb_key *key = pblock_key(name);
438 pb_param *pp = pblock_findkey(key, rq->headers);
439 if(pp !=
NULL) {
440 *value = pp->value;
441 return REQ_PROCEED;
442 }
else {
443
444 *value =
NULL;
445 return REQ_NOACTION;
446 }
447 }
448
449 char *http_uri2url(
const char *prefix,
const char *suffix) {
450
451 return NULL;
452 }
453
454 char *http_uri2url_dynamic(
const char *prefix,
const char *suffix,
455 Session *sn, Request *rq)
456 {
457
458 return NULL;
459 }
460
461 void http_get_scheme_host_port(
462 Session *sn,
463 Request *rq,
464 char **scheme,
465 char **host,
466 uint16_t *port)
467 {
468 Connection *con = ((NSAPISession*)sn)->connection;
469
470 if(con->ssl) {
471 *scheme =
HTTPS_SCHEME;
472 }
else {
473 *scheme =
HTTP_SCHEME;
474 }
475
476 NSAPIRequest *request = (NSAPIRequest*)rq;
477
478 if(request->host) {
479 *host = request->host;
480 }
else {
481 *host =
"localhost";
482 }
483
484 *port = request->port;
485
486 }
487