1 | /* |
2 | This file is part of Mtproto-proxy Library. |
3 | |
4 | Mtproto-proxy Library is free software: you can redistribute it and/or modify |
5 | it under the terms of the GNU Lesser General Public License as published by |
6 | the Free Software Foundation, either version 2 of the License, or |
7 | (at your option) any later version. |
8 | |
9 | Mtproto-proxy Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public License |
15 | along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | Copyright 2010-2012 Vkontakte Ltd |
18 | 2010-2012 Nikolai Durov |
19 | 2010-2012 Andrey Lopatin |
20 | 2012 Anton Maydell |
21 | |
22 | Copyright 2014-2016 Telegram Messenger Inc |
23 | 2015-2016 Vitaly Valtman |
24 | */ |
25 | |
26 | #define _FILE_OFFSET_BITS 64 |
27 | |
28 | #include <assert.h> |
29 | #include <string.h> |
30 | #include <stdio.h> |
31 | #include <stdlib.h> |
32 | #include <unistd.h> |
33 | |
34 | #include "crc32.h" |
35 | #include "kprintf.h" |
36 | #include "net/net-events.h" |
37 | #include "precise-time.h" |
38 | #include "net/net-connections.h" |
39 | #include "net/net-http-server.h" |
40 | |
41 | /* |
42 | * |
43 | * HTTP SERVER INTERFACE |
44 | * |
45 | */ |
46 | |
47 | #define SERVER_VERSION "MTProxy/1.0" |
48 | |
49 | int http_connections; |
50 | long long http_queries, , http_queries_size; |
51 | |
52 | char * = "" ; |
53 | |
54 | int hts_std_wakeup (connection_job_t c); |
55 | int hts_parse_execute (connection_job_t c); |
56 | int hts_std_alarm (connection_job_t c); |
57 | int hts_do_wakeup (connection_job_t c); |
58 | int hts_init_accepted (connection_job_t c); |
59 | int hts_close_connection (connection_job_t c, int who); |
60 | int hts_write_packet (connection_job_t C, struct raw_message *raw); |
61 | |
62 | conn_type_t ct_http_server = { |
63 | .magic = CONN_FUNC_MAGIC, |
64 | .title = "http_server" , |
65 | .flags = C_RAWMSG, |
66 | .accept = net_accept_new_connections, |
67 | .init_accepted = hts_init_accepted, |
68 | .parse_execute = hts_parse_execute, |
69 | .close = hts_close_connection, |
70 | .init_outbound = server_failed, |
71 | .connected = server_failed, |
72 | .wakeup = hts_std_wakeup, |
73 | .alarm = hts_std_alarm, |
74 | .write_packet = hts_write_packet |
75 | }; |
76 | |
77 | enum http_query_parse_state { |
78 | htqp_start, |
79 | htqp_readtospace, |
80 | htqp_readtocolon, |
81 | htqp_readint, |
82 | htqp_skipspc, |
83 | htqp_skiptoeoln, |
84 | htqp_skipspctoeoln, |
85 | htqp_eoln, |
86 | htqp_wantlf, |
87 | htqp_wantlastlf, |
88 | htqp_linestart, |
89 | htqp_fatal, |
90 | htqp_done |
91 | }; |
92 | |
93 | int hts_default_execute (connection_job_t c, struct raw_message *raw, int op); |
94 | |
95 | struct http_server_functions default_http_server = { |
96 | .execute = hts_default_execute, |
97 | .ht_wakeup = hts_do_wakeup, |
98 | .ht_alarm = hts_do_wakeup |
99 | }; |
100 | |
101 | int hts_default_execute (connection_job_t c, struct raw_message *raw, int op) { |
102 | struct hts_data *D = HTS_DATA(c); |
103 | |
104 | vkprintf (1, "http_server: op=%d, header_size=%d\n" , op, D->header_size); |
105 | |
106 | switch (op) { |
107 | |
108 | case htqt_empty: |
109 | break; |
110 | |
111 | case htqt_get: |
112 | case htqt_post: |
113 | case htqt_head: |
114 | case htqt_options: |
115 | |
116 | default: |
117 | D->query_flags |= QF_ERROR; |
118 | break; |
119 | } |
120 | |
121 | return D->data_size >= 0 ? -413 : -501; |
122 | } |
123 | |
124 | int hts_init_accepted (connection_job_t c) { |
125 | http_connections++; |
126 | return 0; |
127 | } |
128 | |
129 | int hts_close_connection (connection_job_t c, int who) { |
130 | http_connections--; |
131 | |
132 | if (HTS_FUNC(c)->ht_close != NULL) { |
133 | HTS_FUNC(c)->ht_close (c, who); |
134 | } |
135 | |
136 | return cpu_server_close_connection (c, who); |
137 | } |
138 | |
139 | static inline char *http_get_error_msg_text (int *code) { |
140 | /* the most frequent case */ |
141 | if (*code == 200) { |
142 | return "OK" ; |
143 | } |
144 | switch (*code) { |
145 | /* python generated from old array */ |
146 | case 201: return "Created" ; |
147 | case 202: return "Accepted" ; |
148 | case 204: return "No Content" ; |
149 | case 206: return "Partial Content" ; |
150 | case 301: return "Moved Permanently" ; |
151 | case 302: return "Found" ; |
152 | case 303: return "See Other" ; |
153 | case 304: return "Not Modified" ; |
154 | case 307: return "Temporary Redirect" ; |
155 | case 400: return "Bad Request" ; |
156 | case 403: return "Forbidden" ; |
157 | case 404: return "Not Found" ; |
158 | case 405: return "Method Not Allowed" ; |
159 | case 406: return "Not Acceptable" ; |
160 | case 408: return "Request Timeout" ; |
161 | case 411: return "Length Required" ; |
162 | case 413: return "Request Entity Too Large" ; |
163 | case 414: return "Request URI Too Long" ; |
164 | case 418: return "I'm a teapot" ; |
165 | case 429: return "Too Many Requests" ; |
166 | case 501: return "Not Implemented" ; |
167 | case 502: return "Bad Gateway" ; |
168 | case 503: return "Service Unavailable" ; |
169 | default: *code = 500; |
170 | } |
171 | return "Internal Server Error" ; |
172 | } |
173 | |
174 | static char error_text_pattern[] = |
175 | "<html>\r\n" |
176 | "<head><title>%d %s</title></head>\r\n" |
177 | "<body bgcolor=\"white\">\r\n" |
178 | "<center><h1>%d %s</h1></center>\r\n" |
179 | "<hr><center>" SERVER_VERSION "</center>\r\n" |
180 | "</body>\r\n" |
181 | "</html>\r\n" ; |
182 | |
183 | int write_http_error_raw (connection_job_t C, struct raw_message *raw, int code) { |
184 | if (code == 204) { |
185 | write_basic_http_header_raw (C, raw, code, 0, -1, 0, 0); |
186 | return 0; |
187 | } else { |
188 | static char buff[1024]; |
189 | char *ptr = buff; |
190 | const char *error_message = http_get_error_msg_text (&code); |
191 | ptr += sprintf (ptr, error_text_pattern, code, error_message, code, error_message); |
192 | write_basic_http_header_raw (C, raw, code, 0, ptr - buff, 0, 0); |
193 | assert (rwm_push_data (raw, buff, ptr - buff) == ptr - buff); |
194 | return ptr - buff; |
195 | } |
196 | } |
197 | |
198 | int write_http_error (connection_job_t C, int code) { |
199 | struct raw_message *raw = calloc (sizeof (*raw), 1); |
200 | rwm_init (raw, 0); |
201 | int r = write_http_error_raw (C, raw, code); |
202 | |
203 | mpq_push_w (CONN_INFO(C)->out_queue, raw, 0); |
204 | job_signal (JOB_REF_CREATE_PASS (C), JS_RUN); |
205 | |
206 | return r; |
207 | } |
208 | |
209 | int hts_write_packet (connection_job_t C, struct raw_message *raw) { |
210 | rwm_union (&CONN_INFO(C)->out, raw); |
211 | return 0; |
212 | } |
213 | |
214 | |
215 | int hts_parse_execute (connection_job_t C) { |
216 | struct connection_info *c = CONN_INFO (C); |
217 | |
218 | struct hts_data *D = HTS_DATA(C); |
219 | char *ptr, *ptr_s, *ptr_e; |
220 | int len; |
221 | long long tt; |
222 | |
223 | D->parse_state = htqp_start; |
224 | |
225 | struct raw_message raw; |
226 | rwm_clone (&raw, &c->in); |
227 | |
228 | while (c->status == conn_working && !c->pending_queries && raw.total_bytes) { |
229 | if (c->flags & (C_ERROR | C_STOPPARSE)) { |
230 | break; |
231 | } |
232 | |
233 | len = rwm_get_block_ptr_bytes (&raw); |
234 | assert (len > 0); |
235 | ptr = ptr_s = rwm_get_block_ptr (&raw); |
236 | ptr_e = ptr + len; |
237 | |
238 | assert (ptr); |
239 | |
240 | while (ptr < ptr_e && D->parse_state != htqp_done) { |
241 | switch (D->parse_state) { |
242 | case htqp_start: |
243 | //fprintf (stderr, "htqp_start: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
244 | memset (D, 0, offsetof (struct hts_data, query_seqno)); |
245 | D->query_seqno++; |
246 | D->query_type = htqt_none; |
247 | D->data_size = -1; |
248 | D->parse_state = htqp_readtospace; |
249 | |
250 | case htqp_readtospace: |
251 | //fprintf (stderr, "htqp_readtospace: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
252 | while (ptr < ptr_e && ((unsigned) *ptr > ' ')) { |
253 | if (D->wlen < 15) { |
254 | D->word[D->wlen] = *ptr; |
255 | } |
256 | D->wlen++; |
257 | ptr++; |
258 | } |
259 | if (D->wlen > 4096) { |
260 | D->parse_state = htqp_fatal; |
261 | break; |
262 | } |
263 | if (ptr == ptr_e) { |
264 | break; |
265 | } |
266 | D->parse_state = htqp_skipspc; |
267 | D->query_words++; |
268 | if (D->query_words == 1) { |
269 | D->query_type = htqt_error; |
270 | if (D->wlen == 3 && !memcmp (D->word, "GET" , 3)) { |
271 | D->query_type = htqt_get; |
272 | } else if (D->wlen == 4) { |
273 | if (!memcmp (D->word, "HEAD" , 4)) { |
274 | D->query_type = htqt_head; |
275 | } else if (!memcmp (D->word, "POST" , 4)) { |
276 | D->query_type = htqt_post; |
277 | } |
278 | } else if (D->wlen == 7 && !memcmp (D->word, "OPTIONS" , 7)) { |
279 | D->query_type = htqt_options; |
280 | } |
281 | if (D->query_type == htqt_error) { |
282 | D->parse_state = htqp_skiptoeoln; |
283 | D->query_flags |= QF_ERROR; |
284 | } |
285 | } else if (D->query_words == 2) { |
286 | D->uri_offset = D->header_size; |
287 | D->uri_size = D->wlen; |
288 | if (!D->wlen) { |
289 | D->parse_state = htqp_skiptoeoln; |
290 | D->query_flags |= QF_ERROR; |
291 | } |
292 | } else if (D->query_words == 3) { |
293 | D->parse_state = htqp_skipspctoeoln; |
294 | if (D->wlen != 0) { |
295 | /* HTTP/x.y */ |
296 | if (D->wlen != 8) { |
297 | D->parse_state = htqp_skiptoeoln; |
298 | D->query_flags |= QF_ERROR; |
299 | } else { |
300 | if (!memcmp (D->word, "HTTP/1.0" , 8)) { |
301 | D->http_ver = HTTP_V10; |
302 | } else if (!memcmp (D->word, "HTTP/1.1" , 8)) { |
303 | D->http_ver = HTTP_V11; |
304 | } else { |
305 | D->parse_state = htqp_skiptoeoln; |
306 | D->query_flags |= QF_ERROR; |
307 | } |
308 | } |
309 | } else { |
310 | D->http_ver = HTTP_V09; |
311 | } |
312 | } else { |
313 | assert (D->query_flags & (QF_HOST | QF_CONNECTION)); |
314 | if (D->wlen) { |
315 | if (D->query_flags & QF_HOST) { |
316 | D->host_offset = D->header_size; |
317 | D->host_size = D->wlen; |
318 | } else if (D->wlen == 10 && !strncasecmp (D->word, "keep-alive" , 10)) { |
319 | D->query_flags |= QF_KEEPALIVE; |
320 | } |
321 | } |
322 | D->query_flags &= ~(QF_HOST | QF_CONNECTION); |
323 | D->parse_state = htqp_skipspctoeoln; |
324 | } |
325 | D->header_size += D->wlen; |
326 | break; |
327 | |
328 | case htqp_skipspc: |
329 | case htqp_skipspctoeoln: |
330 | //fprintf (stderr, "htqp_skipspc[toeoln]: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
331 | while (D->header_size < MAX_HTTP_HEADER_SIZE && ptr < ptr_e && (*ptr == ' ' || (*ptr == '\t' && D->query_words >= 8))) { |
332 | D->header_size++; |
333 | ptr++; |
334 | } |
335 | if (D->header_size >= MAX_HTTP_HEADER_SIZE) { |
336 | D->parse_state = htqp_fatal; |
337 | break; |
338 | } |
339 | if (ptr == ptr_e) { |
340 | break; |
341 | } |
342 | if (D->parse_state == htqp_skipspctoeoln) { |
343 | D->parse_state = htqp_eoln; |
344 | break; |
345 | } |
346 | if (D->query_words < 3) { |
347 | D->wlen = 0; |
348 | D->parse_state = htqp_readtospace; |
349 | } else { |
350 | assert (D->query_words >= 4); |
351 | if (D->query_flags & QF_DATASIZE) { |
352 | if (D->data_size != -1) { |
353 | D->parse_state = htqp_skiptoeoln; |
354 | D->query_flags |= QF_ERROR; |
355 | } else { |
356 | D->parse_state = htqp_readint; |
357 | D->data_size = 0; |
358 | } |
359 | } else if (D->query_flags & (QF_HOST | QF_CONNECTION)) { |
360 | D->wlen = 0; |
361 | D->parse_state = htqp_readtospace; |
362 | } else { |
363 | D->parse_state = htqp_skiptoeoln; |
364 | } |
365 | } |
366 | break; |
367 | |
368 | case htqp_readtocolon: |
369 | //fprintf (stderr, "htqp_readtocolon: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
370 | while (ptr < ptr_e && *ptr != ':' && *ptr > ' ') { |
371 | if (D->wlen < 15) { |
372 | D->word[D->wlen] = *ptr; |
373 | } |
374 | D->wlen++; |
375 | ptr++; |
376 | } |
377 | if (D->wlen > 4096) { |
378 | D->parse_state = htqp_fatal; |
379 | break; |
380 | } |
381 | if (ptr == ptr_e) { |
382 | break; |
383 | } |
384 | |
385 | if (*ptr != ':') { |
386 | D->header_size += D->wlen; |
387 | D->parse_state = htqp_skiptoeoln; |
388 | D->query_flags |= QF_ERROR; |
389 | break; |
390 | } |
391 | |
392 | ptr++; |
393 | |
394 | if (D->wlen == 4 && !strncasecmp (D->word, "host" , 4)) { |
395 | D->query_flags |= QF_HOST; |
396 | } else if (D->wlen == 10 && !strncasecmp (D->word, "connection" , 10)) { |
397 | D->query_flags |= QF_CONNECTION; |
398 | } else if (D->wlen == 14 && !strncasecmp (D->word, "content-length" , 14)) { |
399 | D->query_flags |= QF_DATASIZE; |
400 | } else { |
401 | D->query_flags &= ~(QF_HOST | QF_DATASIZE | QF_CONNECTION); |
402 | } |
403 | |
404 | D->header_size += D->wlen + 1; |
405 | D->parse_state = htqp_skipspc; |
406 | break; |
407 | |
408 | case htqp_readint: |
409 | //fprintf (stderr, "htqp_readint: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
410 | |
411 | tt = D->data_size; |
412 | while (ptr < ptr_e && *ptr >= '0' && *ptr <= '9') { |
413 | if (tt >= 0x7fffffffL / 10) { |
414 | D->query_flags |= QF_ERROR; |
415 | D->parse_state = htqp_skiptoeoln; |
416 | break; |
417 | } |
418 | tt = tt * 10 + (*ptr - '0'); |
419 | ptr++; |
420 | D->header_size++; |
421 | D->query_flags &= ~QF_DATASIZE; |
422 | } |
423 | |
424 | D->data_size = tt; |
425 | if (ptr == ptr_e) { |
426 | break; |
427 | } |
428 | |
429 | if (D->query_flags & QF_DATASIZE) { |
430 | D->query_flags |= QF_ERROR; |
431 | D->parse_state = htqp_skiptoeoln; |
432 | } else { |
433 | D->parse_state = htqp_skipspctoeoln; |
434 | } |
435 | break; |
436 | |
437 | case htqp_skiptoeoln: |
438 | //fprintf (stderr, "htqp_skiptoeoln: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
439 | |
440 | while (D->header_size < MAX_HTTP_HEADER_SIZE && ptr < ptr_e && (*ptr != '\r' && *ptr != '\n')) { |
441 | D->header_size++; |
442 | ptr++; |
443 | } |
444 | if (D->header_size >= MAX_HTTP_HEADER_SIZE) { |
445 | D->parse_state = htqp_fatal; |
446 | break; |
447 | } |
448 | if (ptr == ptr_e) { |
449 | break; |
450 | } |
451 | |
452 | D->parse_state = htqp_eoln; |
453 | |
454 | case htqp_eoln: |
455 | |
456 | if (ptr == ptr_e) { |
457 | break; |
458 | } |
459 | if (*ptr == '\r') { |
460 | ptr++; |
461 | D->header_size++; |
462 | } |
463 | D->parse_state = htqp_wantlf; |
464 | |
465 | case htqp_wantlf: |
466 | //fprintf (stderr, "htqp_wantlf: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
467 | |
468 | if (ptr == ptr_e) { |
469 | break; |
470 | } |
471 | if (++D->query_words < 8) { |
472 | D->query_words = 8; |
473 | if (D->query_flags & QF_ERROR) { |
474 | D->parse_state = htqp_fatal; |
475 | break; |
476 | } |
477 | } |
478 | |
479 | if (D->http_ver <= HTTP_V09) { |
480 | D->parse_state = htqp_wantlastlf; |
481 | break; |
482 | } |
483 | |
484 | if (*ptr != '\n') { |
485 | D->query_flags |= QF_ERROR; |
486 | D->parse_state = htqp_skiptoeoln; |
487 | break; |
488 | } |
489 | |
490 | ptr++; |
491 | D->header_size++; |
492 | |
493 | D->parse_state = htqp_linestart; |
494 | |
495 | case htqp_linestart: |
496 | //fprintf (stderr, "htqp_linestart: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
497 | |
498 | if (ptr == ptr_e) { |
499 | break; |
500 | } |
501 | |
502 | if (!D->first_line_size) { |
503 | D->first_line_size = D->header_size; |
504 | } |
505 | |
506 | if (*ptr == '\r') { |
507 | ptr++; |
508 | D->header_size++; |
509 | D->parse_state = htqp_wantlastlf; |
510 | break; |
511 | } |
512 | if (*ptr == '\n') { |
513 | D->parse_state = htqp_wantlastlf; |
514 | break; |
515 | } |
516 | |
517 | if (D->query_flags & QF_ERROR) { |
518 | D->parse_state = htqp_skiptoeoln; |
519 | } else { |
520 | D->wlen = 0; |
521 | D->parse_state = htqp_readtocolon; |
522 | } |
523 | break; |
524 | |
525 | case htqp_wantlastlf: |
526 | //fprintf (stderr, "htqp_wantlastlf: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
527 | |
528 | if (ptr == ptr_e) { |
529 | break; |
530 | } |
531 | if (*ptr != '\n') { |
532 | D->parse_state = htqp_fatal; |
533 | break; |
534 | } |
535 | ptr++; |
536 | D->header_size++; |
537 | |
538 | if (!D->first_line_size) { |
539 | D->first_line_size = D->header_size; |
540 | } |
541 | |
542 | D->parse_state = htqp_done; |
543 | |
544 | case htqp_done: |
545 | //fprintf (stderr, "htqp_done: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
546 | break; |
547 | |
548 | case htqp_fatal: |
549 | //fprintf (stderr, "htqp_fatal: ptr=%p (%.8s), hsize=%d, qf=%d, words=%d\n", ptr, ptr, D->header_size, D->query_flags, D->query_words); |
550 | D->query_flags |= QF_ERROR; |
551 | D->parse_state = htqp_done; |
552 | break; |
553 | |
554 | default: |
555 | assert (0); |
556 | } |
557 | } |
558 | |
559 | len = ptr - ptr_s; |
560 | assert (rwm_skip_data (&raw, len) == len); |
561 | |
562 | if (D->parse_state == htqp_done) { |
563 | if (D->header_size >= MAX_HTTP_HEADER_SIZE) { |
564 | D->query_flags |= QF_ERROR; |
565 | } |
566 | if (!(D->query_flags & QF_ERROR)) { |
567 | if (!HTS_FUNC(C)->execute) { |
568 | HTS_FUNC(C)->execute = hts_default_execute; |
569 | } |
570 | |
571 | int res; |
572 | if (D->query_type == htqt_post && D->data_size < 0) { |
573 | // assert (rwm_skip_data (&c->in, D->header_size) == D->header_size); |
574 | res = -411; |
575 | } else if (D->query_type != htqt_post && D->data_size > 0) { |
576 | res = -413; |
577 | } else { |
578 | int bytes = D->header_size; |
579 | if (D->query_type == htqt_post) { |
580 | bytes += D->data_size; |
581 | } |
582 | struct raw_message r; |
583 | rwm_clone (&r, &c->in); |
584 | if (bytes < c->in.total_bytes) { |
585 | rwm_trunc (&r, bytes); |
586 | } |
587 | |
588 | res = HTS_FUNC(C)->execute (C, &r, D->query_type); |
589 | rwm_free (&r); |
590 | } |
591 | http_queries++; |
592 | http_queries_size += D->header_size + D->data_size; |
593 | if (res > 0) { |
594 | //c->status = conn_reading_query; |
595 | rwm_free (&raw); |
596 | return res; // need more bytes |
597 | } else { |
598 | assert (rwm_skip_data (&c->in, D->header_size) == D->header_size); |
599 | if (res == SKIP_ALL_BYTES || !res) { |
600 | if (D->data_size > 0) { |
601 | int x = c->in.total_bytes; |
602 | int y = x > D->data_size ? D->data_size : x; |
603 | assert (rwm_skip_data (&c->in, y) == y); |
604 | if (y < x) { |
605 | D->parse_state = htqp_start; |
606 | return y - x; |
607 | } |
608 | } |
609 | } else { |
610 | if (res == -413) { |
611 | D->query_flags &= ~QF_KEEPALIVE; |
612 | } |
613 | write_http_error (C, -res); |
614 | D->query_flags &= ~QF_ERROR; |
615 | } |
616 | } |
617 | } else { |
618 | //fprintf (stderr, "[parse error]\n"); |
619 | assert (rwm_skip_data (&c->in, D->header_size) == D->header_size); |
620 | http_bad_headers++; |
621 | } |
622 | if (D->query_flags & QF_ERROR) { |
623 | D->query_flags &= ~QF_KEEPALIVE; |
624 | write_http_error (C, 400); |
625 | } |
626 | if (!c->pending_queries && !(D->query_flags & QF_KEEPALIVE)) { |
627 | connection_write_close (C); |
628 | D->parse_state = -1; |
629 | return 0; |
630 | } |
631 | D->parse_state = htqp_start; |
632 | rwm_free (&raw); |
633 | rwm_clone (&raw, &c->in); |
634 | } |
635 | } |
636 | |
637 | rwm_free (&raw); |
638 | return NEED_MORE_BYTES; |
639 | } |
640 | |
641 | |
642 | int hts_std_wakeup (connection_job_t c) { |
643 | if (HTS_FUNC(c)->ht_wakeup) { |
644 | HTS_FUNC(c)->ht_wakeup (c); |
645 | } |
646 | CONN_INFO(c)->generation = new_conn_generation (); |
647 | return 0; |
648 | } |
649 | |
650 | int hts_std_alarm (connection_job_t c) { |
651 | if (HTS_FUNC(c)->ht_alarm) { |
652 | HTS_FUNC(c)->ht_alarm (c); |
653 | } |
654 | CONN_INFO(c)->generation = new_conn_generation (); |
655 | return 0; |
656 | } |
657 | |
658 | int hts_do_wakeup (connection_job_t c) { |
659 | //struct hts_data *D = HTS_DATA(c); |
660 | assert (0); |
661 | return 0; |
662 | } |
663 | |
664 | /* |
665 | * |
666 | * USEFUL HTTP FUNCTIONS |
667 | * |
668 | */ |
669 | |
670 | #define HTTP_DATE_LEN 29 |
671 | char now_date_string[] = "Thu, 01 Jan 1970 00:00:00 GMT" ; |
672 | int now_date_utime; |
673 | |
674 | static char months [] = "JanFebMarAprMayJunJulAugSepOctNovDecGlk" ; |
675 | static char dows [] = "SunMonTueWedThuFriSatEar" ; |
676 | |
677 | |
678 | int dd [] = |
679 | {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
680 | |
681 | void gen_http_date (char date_buffer[29], int time) { |
682 | int day, mon, year, hour, min, sec, xd, i, dow; |
683 | if (time < 0) time = 0; |
684 | sec = time % 60; |
685 | time /= 60; |
686 | min = time % 60; |
687 | time /= 60; |
688 | hour = time % 24; |
689 | time /= 24; |
690 | dow = (time + 4) % 7; |
691 | xd = time % (365 * 3 + 366); |
692 | time /= (365 * 3 + 366); |
693 | year = time * 4 + 1970; |
694 | if (xd >= 365) { |
695 | year++; |
696 | xd -= 365; |
697 | if (xd >= 365) { |
698 | year++; |
699 | xd -= 365; |
700 | if (xd >= 366) { |
701 | year++; |
702 | xd -= 366; |
703 | } |
704 | } |
705 | } |
706 | if (year & 3) { |
707 | dd[1] = 28; |
708 | } else { |
709 | dd[1] = 29; |
710 | } |
711 | |
712 | for (i = 0; i < 12; i++) { |
713 | if (xd < dd[i]) { |
714 | break; |
715 | } |
716 | xd -= dd[i]; |
717 | } |
718 | |
719 | day = xd + 1; |
720 | mon = i; |
721 | assert (day >= 1 && day <= 31 && mon >=0 && mon <= 11 && |
722 | year >= 1970 && year <= 2039); |
723 | |
724 | sprintf (date_buffer, "%.3s, %.2d %.3s %d %.2d:%.2d:%.2d GM" , |
725 | dows + dow * 3, day, months + mon * 3, year, |
726 | hour, min, sec); |
727 | date_buffer[28] = 'T'; |
728 | } |
729 | |
730 | int gen_http_time (char *date_buffer, int *time) { |
731 | char dow[4]; |
732 | char month[4]; |
733 | char tz[16]; |
734 | int i, year, mon, day, hour, min, sec; |
735 | int argc = sscanf (date_buffer, "%3s, %d %3s %d %d:%d:%d %15s" , dow, &day, month, &year, &hour, &min, &sec, tz); |
736 | if (argc != 8) { |
737 | return (argc > 0) ? -argc : -8; |
738 | } |
739 | for (mon = 0; mon < 12; mon++) { |
740 | if (!memcmp (months + mon * 3, month, 3)) { |
741 | break; |
742 | } |
743 | } |
744 | if (mon == 12) { |
745 | return -11; |
746 | } |
747 | if (year < 1970 || year > 2039) { |
748 | return -12; |
749 | } |
750 | if (hour < 0 || hour >= 24) { |
751 | return -13; |
752 | } |
753 | if (min < 0 || min >= 60) { |
754 | return -14; |
755 | } |
756 | if (sec < 0 || sec >= 60) { |
757 | return -15; |
758 | } |
759 | if (strcmp (tz, "GMT" )) { |
760 | return -16; |
761 | } |
762 | int d = (year - 1970) * 365 + ((year - 1969) >> 2) + (day - 1); |
763 | if (!(year & 3) && mon >= 2) { |
764 | d++; |
765 | } |
766 | dd[1] = 28; |
767 | for (i = 0; i < mon; i++) { |
768 | d += dd[i]; |
769 | } |
770 | *time = (((d * 24 + hour) * 60 + min) * 60) + sec; |
771 | return 0; |
772 | } |
773 | |
774 | char *cur_http_date (void) { |
775 | if (now_date_utime != now) { |
776 | gen_http_date (now_date_string, now_date_utime = now); |
777 | } |
778 | return now_date_string; |
779 | } |
780 | |
781 | int (const char *, const int , char *buffer, int b_len, const char *arg_name, const int arg_len) { |
782 | const char *where = qHeaders; |
783 | const char *where_end = where + qHeadersLen; |
784 | while (where < where_end) { |
785 | const char *start = where; |
786 | while (where < where_end && (*where != ':' && *where != '\n')) { |
787 | ++where; |
788 | } |
789 | if (where == where_end) { |
790 | buffer[0] = 0; |
791 | return -1; |
792 | } |
793 | if (*where == ':') { |
794 | if (arg_len == where - start && !strncasecmp (arg_name, start, arg_len)) { |
795 | where++; |
796 | while (where < where_end && (*where == 9 || *where == 32)) { |
797 | where++; |
798 | } |
799 | start = where; |
800 | while (where < where_end && *where != '\r' && *where != '\n') { |
801 | ++where; |
802 | } |
803 | while (where > start && (where[-1] == ' ' || where[-1] == 9)) { |
804 | where--; |
805 | } |
806 | b_len--; |
807 | if (where - start < b_len) { |
808 | b_len = where - start; |
809 | } |
810 | memcpy (buffer, start, b_len); |
811 | buffer[b_len] = 0; |
812 | return b_len; |
813 | } |
814 | ++where; |
815 | } |
816 | while (where < where_end && *where != '\n') { |
817 | ++where; |
818 | } |
819 | if (where < where_end) { |
820 | ++where; |
821 | } |
822 | } |
823 | buffer[0] = 0; |
824 | return -1; |
825 | } |
826 | |
827 | static char [] = |
828 | "HTTP/1.1 %d %s\r\n" |
829 | "Server: " SERVER_VERSION "\r\n" |
830 | "Date: %s\r\n" |
831 | "Content-Type: %.256s\r\n" |
832 | "Connection: %s\r\n%.1024s%.1024s" ; |
833 | |
834 | int (connection_job_t C, struct raw_message *raw, int code, int date, int len, const char *, const char *content_type) { |
835 | struct hts_data *D = HTS_DATA(C); |
836 | |
837 | if (D->http_ver >= HTTP_V10 || D->http_ver == 0) { |
838 | #define B_SZ 4096 |
839 | static char buff[B_SZ], date_buff[32]; |
840 | char *ptr = buff; |
841 | const char *error_message = http_get_error_msg_text (&code); |
842 | if (date) { |
843 | gen_http_date (date_buff, date); |
844 | } |
845 | ptr += snprintf (ptr, B_SZ - 64, header_pattern, code, error_message, |
846 | date ? date_buff : cur_http_date(), |
847 | content_type ? content_type : "text/html" , |
848 | (D->query_flags & QF_KEEPALIVE) ? "keep-alive" : "close" , |
849 | (D->query_flags & QF_EXTRA_HEADERS) && extra_http_response_headers ? extra_http_response_headers : "" , |
850 | add_header ?: "" ); |
851 | D->query_flags &= ~QF_EXTRA_HEADERS; |
852 | assert (ptr < buff + B_SZ - 64); |
853 | if (len >= 0) { |
854 | ptr += sprintf (ptr, "Content-Length: %d\r\n" , len); |
855 | } |
856 | |
857 | ptr += sprintf (ptr, "\r\n" ); |
858 | |
859 | assert (rwm_push_data (raw, buff, ptr - buff) == ptr - buff); |
860 | return ptr - buff; |
861 | } |
862 | |
863 | return 0; |
864 | } |
865 | |
866 | void http_flush (connection_job_t C, struct raw_message *raw) { |
867 | if (raw) { |
868 | mpq_push_w (CONN_INFO(C)->out_queue, raw, 0); |
869 | } |
870 | struct hts_data *D = HTS_DATA(C); |
871 | if (!CONN_INFO(C)->pending_queries && !(D->query_flags & QF_KEEPALIVE)) { |
872 | connection_write_close (C); |
873 | D->parse_state = -1; |
874 | } |
875 | job_signal (JOB_REF_CREATE_PASS (C), JS_RUN); |
876 | } |
877 | |
878 | //int write_basic_http_header (connection_job_t C, struct raw_message *raw, int code, int date, int len, const char *add_header, const char *content_type) { |
879 | |
880 | |
881 | /* |
882 | * |
883 | * END (HTTP SERVER) |
884 | * |
885 | */ |
886 | |
887 | |