Forward Port: Force validation of initial slash in request URI
[MonkeyD.git] / src / request.c
blob3eff30b7f1b6df6fefea24050f99ccb21cd3e7d8
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2010, Eduardo Silva P. <edsiper@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include <netdb.h>
31 #include <sys/wait.h>
32 #include <signal.h>
33 #include <errno.h>
35 #include <string.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <sys/types.h>
41 #include "request.h"
42 #include "monkey.h"
43 #include "http.h"
44 #include "http_status.h"
45 #include "string.h"
46 #include "str.h"
47 #include "config.h"
48 #include "scheduler.h"
49 #include "epoll.h"
50 #include "socket.h"
51 #include "utils.h"
52 #include "header.h"
53 #include "user.h"
54 #include "method.h"
55 #include "memory.h"
56 #include "socket.h"
57 #include "cache.h"
58 #include "clock.h"
59 #include "utils.h"
60 #include "plugin.h"
62 struct request *mk_request_parse(struct client_request *cr)
64 int i, end;
65 int blocks = 0;
66 struct request *cr_buf = 0, *cr_search = 0;
68 for (i = 0; i <= cr->body_pos_end; i++) {
69 /* Look for CRLFCRLF (\r\n\r\n), maybe some pipelining
70 * request can be involved.
72 end = mk_string_search(cr->body + i, mk_endblock.data) + i;
74 if (end < 0) {
75 return NULL;
78 /* Allocating request block */
79 cr_buf = mk_request_alloc();
81 /* We point the block with a mk_pointer */
82 cr_buf->body.data = cr->body + i;
83 cr_buf->body.len = end - i;
85 /* Method, previous catch in mk_http_pending_request */
86 if (i == 0) {
87 cr_buf->method = cr->first_method;
89 else {
90 cr_buf->method = mk_http_method_get(cr_buf->body.data);
92 cr_buf->next = NULL;
94 /* Looking for POST data */
95 if (cr_buf->method == HTTP_METHOD_POST) {
96 cr_buf->post_variables = mk_method_post_get_vars(cr->body,
97 end + mk_endblock.len);
98 if (cr_buf->post_variables.len >= 0) {
99 i += cr_buf->post_variables.len;
103 /* Increase index to the end of the current block */
104 i = (end + mk_endblock.len) - 1;
106 /* Link block */
107 if (!cr->request) {
108 cr->request = cr_buf;
110 else {
111 cr_search = cr->request;
112 while (cr_search) {
113 if (cr_search->next == NULL) {
114 cr_search->next = cr_buf;
115 break;
117 else {
118 cr_search = cr_search->next;
123 /* Update counter */
124 blocks++;
128 /* DEBUG BLOCKS
129 cr_search = cr->request;
130 while(cr_search){
131 printf("\n");
132 MK_TRACE("BLOCK INIT");
133 mk_pointer_print(cr_search->body);
134 MK_TRACE("BLOCK_END");
136 cr_search = cr_search->next;
140 /* Checking pipelining connection */
141 cr_search = cr->request;
142 if (blocks > 1) {
143 while (cr_search) {
144 /* Pipelining request must use GET or HEAD methods */
145 if (cr_search->method != HTTP_METHOD_GET &&
146 cr_search->method != HTTP_METHOD_HEAD) {
147 return NULL;
149 cr_search = cr_search->next;
152 cr->pipelined = TRUE;
155 return cr->request;
158 int mk_handler_read(int socket, struct client_request *cr)
160 int bytes;
162 bytes = mk_socket_read(socket, (void *)cr->body + cr->body_length, MAX_REQUEST_BODY - cr->body_length);
164 if (bytes < 0) {
165 if (errno == EAGAIN) {
166 return 1;
168 else {
169 mk_request_client_remove(socket);
170 return -1;
173 if (bytes == 0) {
174 mk_request_client_remove(socket);
175 return -1;
178 if (bytes > 0) {
179 cr->body_length += bytes;
180 cr->body[cr->body_length] = '\0';
183 return bytes;
186 int mk_handler_write(int socket, struct client_request *cr)
188 int bytes, final_status = 0;
189 struct request *sr;
192 * Get node from schedule list node which contains
193 * the information regarding to the current thread
195 if (!cr) {
196 return -1;
199 if (!cr->request) {
200 if (!mk_request_parse(cr)) {
201 return -1;
205 sr = cr->request;
206 while (sr) {
207 /* Request not processed also no plugin has take some action */
208 if (sr->bytes_to_send < 0 && !sr->handled_by) {
209 final_status = mk_request_process(cr, sr);
211 /* Request with data to send by static file sender */
212 else if (sr->bytes_to_send > 0 && !sr->handled_by) {
213 final_status = bytes = mk_http_send_file(cr, sr);
217 * If we got an error, we don't want to parse
218 * and send information for another pipelined request
220 if (final_status > 0) {
221 return final_status;
223 else if (final_status <= 0) {
224 /* STAGE_40, request has ended */
225 mk_plugin_stage_run(MK_PLUGIN_STAGE_40, cr->socket,
226 NULL, cr, sr);
227 switch (final_status) {
228 case EXIT_NORMAL:
229 case EXIT_ERROR:
230 if (sr->close_now == VAR_ON) {
231 return -1;
233 break;
234 case EXIT_ABORT:
235 return -1;
239 sr = sr->next;
242 /* If we are here, is because all pipelined request were
243 * processed successfully, let's return 0;
245 return 0;
248 int mk_request_process(struct client_request *cr, struct request *s_request)
250 int status = 0;
251 struct host *host;
253 status = mk_request_header_process(s_request);
254 if (status < 0) {
255 mk_header_set_http_status(s_request, M_CLIENT_BAD_REQUEST);
256 return EXIT_ABORT;
259 switch (s_request->method) {
260 case METHOD_NOT_ALLOWED:
261 mk_request_error(M_CLIENT_METHOD_NOT_ALLOWED, cr, s_request, 1);
262 return EXIT_NORMAL;
263 case METHOD_NOT_FOUND:
264 mk_request_error(M_SERVER_NOT_IMPLEMENTED, cr, s_request, 1);
265 return EXIT_NORMAL;
268 s_request->user_home = VAR_OFF;
270 /* Valid request URI? */
271 if (s_request->uri_processed == NULL) {
272 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request, 1);
273 return EXIT_NORMAL;
275 if (s_request->uri_processed[0] != '/') {
276 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request, 1);
277 return EXIT_NORMAL;
280 /* HTTP/1.1 needs Host header */
281 if (!s_request->host.data && s_request->protocol == HTTP_PROTOCOL_11) {
282 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request, 1);
283 return EXIT_NORMAL;
286 /* Method not allowed ? */
287 if (s_request->method == METHOD_NOT_ALLOWED) {
288 mk_request_error(M_CLIENT_METHOD_NOT_ALLOWED, cr, s_request, 1);
289 return EXIT_NORMAL;
292 /* Validating protocol version */
293 if (s_request->protocol == HTTP_PROTOCOL_UNKNOWN) {
294 mk_request_error(M_SERVER_HTTP_VERSION_UNSUP, cr, s_request, 1);
295 return EXIT_NORMAL;
298 if (s_request->host.data) {
299 host = mk_config_host_find(s_request->host);
300 if (host) {
301 s_request->host_conf = host;
303 else {
304 s_request->host_conf = config->hosts;
307 else {
308 s_request->host_conf = config->hosts;
311 /* is requesting an user home directory ? */
312 if (config->user_dir) {
313 if (strncmp(s_request->uri_processed,
314 mk_user_home.data, mk_user_home.len) == 0) {
315 if (mk_user_init(cr, s_request) != 0) {
316 return EXIT_NORMAL;
321 /* Handling method requested */
322 if (s_request->method == HTTP_METHOD_POST) {
323 if ((status = mk_method_post(cr, s_request)) == -1) {
324 return status;
328 /* Plugins Stage 20 */
329 int ret;
330 ret = mk_plugin_stage_run(MK_PLUGIN_STAGE_20, cr->socket, NULL,
331 cr, s_request);
333 if (ret == MK_PLUGIN_RET_CLOSE_CONX) {
334 #ifdef TRACE
335 MK_TRACE("STAGE 20 requested close conexion");
336 #endif
337 return EXIT_ABORT;
340 /* Normal HTTP process */
341 status = mk_http_init(cr, s_request);
343 #ifdef TRACE
344 MK_TRACE("HTTP Init returning %i", status);
345 #endif
347 return status;
350 /* Return a struct with method, URI , protocol version
351 and all static headers defined here sent in request */
352 int mk_request_header_process(struct request *sr)
354 int uri_init = 0, uri_end = 0;
355 char *query_init = 0;
356 int prot_init = 0, prot_end = 0, pos_sep = 0;
357 int fh_limit;
358 char *port = 0;
359 char *headers;
360 mk_pointer host;
362 /* Method */
363 sr->method_p = mk_http_method_check_str(sr->method);
365 /* Request URI */
366 uri_init = (index(sr->body.data, ' ') - sr->body.data) + 1;
367 fh_limit = (index(sr->body.data, '\n') - sr->body.data);
369 uri_end = mk_string_search_r(sr->body.data, ' ', fh_limit) - 1;
371 if (uri_end <= 0) {
372 return -1;
375 prot_init = uri_end + 2;
377 if (uri_end < uri_init) {
378 return -1;
381 /* Query String */
382 query_init = index(sr->body.data + uri_init, '?');
383 if (query_init) {
384 int init, end;
386 init = (int) (query_init - (sr->body.data + uri_init)) + uri_init;
387 if (init <= uri_end) {
388 end = uri_end;
389 uri_end = init - 1;
391 sr->query_string = mk_pointer_create(sr->body.data,
392 init + 1, end + 1);
396 /* Request URI Part 2 */
397 sr->uri = mk_pointer_create(sr->body.data, uri_init, uri_end + 1);
399 if (sr->uri.len < 1) {
400 return -1;
404 /* HTTP Version */
405 prot_end = fh_limit - 1;
406 if (prot_end != prot_init && prot_end > 0) {
407 sr->protocol = mk_http_protocol_check(sr->body.data + prot_init,
408 prot_end - prot_init);
409 sr->protocol_p = mk_http_protocol_check_str(sr->protocol);
412 headers = sr->body.data + prot_end + mk_crlf.len;
414 /* URI processed */
415 sr->uri_processed = mk_utils_hexuri_to_ascii(sr->uri);
417 if (!sr->uri_processed) {
418 sr->uri_processed = mk_pointer_to_buf(sr->uri);
419 sr->uri_twin = VAR_ON;
422 /* Creating table of content (index) for request headers */
423 int toc_len = MK_KNOWN_HEADERS;
424 int headers_len = sr->body.len - (prot_end + mk_crlf.len);
426 struct header_toc *toc = mk_request_header_toc_create(toc_len);
427 mk_request_header_toc_parse(toc, toc_len, headers, headers_len);
429 /* Host */
430 host = mk_request_header_find(toc, toc_len, headers, mk_rh_host);
432 if (host.data) {
433 if ((pos_sep = mk_string_char_search(host.data, ':', host.len)) >= 0) {
434 sr->host.data = host.data;
435 sr->host.len = pos_sep;
437 port = mk_string_copy_substr(host.data, pos_sep + 1, host.len);
438 sr->port = atoi(port);
439 mk_mem_free(port);
441 else {
442 sr->host = host; /* maybe null */
443 sr->port = config->standard_port;
446 else {
447 sr->host.data = NULL;
450 /* Looking for headers */
451 sr->accept = mk_request_header_find(toc, toc_len, headers, mk_rh_accept);
452 sr->accept_charset = mk_request_header_find(toc, toc_len, headers,
453 mk_rh_accept_charset);
454 sr->accept_encoding = mk_request_header_find(toc, toc_len, headers,
455 mk_rh_accept_encoding);
458 sr->accept_language = mk_request_header_find(toc, toc_len, headers,
459 mk_rh_accept_language);
460 sr->cookies = mk_request_header_find(toc, toc_len, headers, mk_rh_cookie);
461 sr->connection = mk_request_header_find(toc, toc_len, headers,
462 mk_rh_connection);
463 sr->referer = mk_request_header_find(toc, toc_len, headers,
464 mk_rh_referer);
465 sr->user_agent = mk_request_header_find(toc, toc_len, headers,
466 mk_rh_user_agent);
467 sr->range = mk_request_header_find(toc, toc_len, headers, mk_rh_range);
468 sr->if_modified_since = mk_request_header_find(toc, toc_len, headers,
469 mk_rh_if_modified_since);
471 /* Default Keepalive is off */
472 if (sr->protocol == HTTP_PROTOCOL_10) {
473 sr->keep_alive = VAR_OFF;
474 sr->close_now = VAR_ON;
476 else if(sr->protocol == HTTP_PROTOCOL_11) {
477 sr->keep_alive = VAR_ON;
478 sr->close_now = VAR_OFF;
481 if (sr->connection.data) {
482 if (mk_string_casestr(sr->connection.data, "Keep-Alive")) {
483 sr->keep_alive = VAR_ON;
484 sr->close_now = VAR_OFF;
486 else if(mk_string_casestr(sr->connection.data, "Close")) {
487 sr->keep_alive = VAR_OFF;
488 sr->close_now = VAR_ON;
490 else {
491 /* Set as a non-valid connection header value */
492 sr->connection.len = 0;
496 return 0;
499 /* Return value of some variable sent in request */
500 mk_pointer mk_request_header_find(struct header_toc * toc, int toc_len,
501 char *request_body, mk_pointer header)
503 int i;
504 mk_pointer var;
506 var.data = NULL;
507 var.len = 0;
509 if (toc) {
510 for (i = 0; i < toc_len; i++) {
511 /* status = 1 means that the toc entry was already
512 * checked by monkey
514 if (toc[i].status == 1) {
515 continue;
518 if (!toc[i].init)
519 break;
521 if (strncasecmp(toc[i].init, header.data, header.len) == 0) {
522 var.data = toc[i].init + header.len + 1;
523 var.len = toc[i].end - var.data;
524 toc[i].status = 1;
525 return var;
530 return var;
533 /* Look for some index.xxx in pathfile */
534 mk_pointer mk_request_index(char *pathfile)
536 unsigned long len;
537 char *file_aux = 0;
538 mk_pointer f;
539 struct indexfile *aux_index;
541 mk_pointer_reset(&f);
543 aux_index = first_index;
545 while (aux_index) {
546 mk_string_build(&file_aux, &len, "%s%s",
547 pathfile, aux_index->indexname);
549 if (access(file_aux, F_OK) == 0) {
550 f.data = file_aux;
551 f.len = len;
552 return f;
554 mk_mem_free(file_aux);
555 aux_index = aux_index->next;
558 return f;
561 /* Send error responses */
562 void mk_request_error(int http_status, struct client_request *cr,
563 struct request *sr, int debug){
564 char *aux_message = 0;
565 mk_pointer message, *page = 0;
566 long n;
568 switch (http_status) {
569 case M_CLIENT_BAD_REQUEST:
570 page = mk_request_set_default_page("Bad Request",
571 sr->uri,
572 sr->host_conf->host_signature);
573 break;
575 case M_CLIENT_FORBIDDEN:
576 page = mk_request_set_default_page("Forbidden",
577 sr->uri,
578 sr->host_conf->host_signature);
579 break;
581 case M_CLIENT_NOT_FOUND:
582 mk_string_build(&message.data, &message.len,
583 "The requested URL was not found on this server.");
584 page = mk_request_set_default_page("Not Found",
585 message,
586 sr->host_conf->host_signature);
587 mk_pointer_free(&message);
588 break;
590 case M_CLIENT_METHOD_NOT_ALLOWED:
591 page = mk_request_set_default_page("Method Not Allowed",
592 sr->uri,
593 sr->host_conf->host_signature);
594 break;
596 case M_CLIENT_REQUEST_TIMEOUT:
597 case M_CLIENT_LENGTH_REQUIRED:
598 break;
600 case M_SERVER_NOT_IMPLEMENTED:
601 page = mk_request_set_default_page("Method Not Implemented",
602 sr->uri,
603 sr->host_conf->host_signature);
604 break;
606 case M_SERVER_INTERNAL_ERROR:
607 mk_string_build(&message.data, &message.len,
608 "Problems found running %s ", sr->uri);
609 page = mk_request_set_default_page("Internal Server Error",
610 message,
611 sr->host_conf->host_signature);
612 //s_log->error_msg = request_error_msg_500;
614 mk_pointer_free(&message);
615 break;
617 case M_SERVER_HTTP_VERSION_UNSUP:
618 mk_pointer_reset(&message);
619 page = mk_request_set_default_page("HTTP Version Not Supported",
620 message,
621 sr->host_conf->host_signature);
622 //s_log->error_msg = request_error_msg_505;
623 break;
626 //s_log->final_response = num_error;
628 mk_header_set_http_status(sr, http_status);
629 if (page) {
630 sr->headers->content_length = page->len;
633 sr->headers->location = NULL;
634 sr->headers->cgi = SH_NOCGI;
635 sr->headers->pconnections_left = 0;
636 mk_pointer_reset(&sr->headers->last_modified);
638 if (aux_message)
639 mk_mem_free(aux_message);
641 if (!page) {
642 mk_pointer_reset(&sr->headers->content_type);
644 else {
645 mk_pointer_set(&sr->headers->content_type, "text/html\r\n");
648 mk_header_send(cr->socket, cr, sr);
650 if (debug == 1) {
651 n = write(cr->socket, page->data, page->len);
652 mk_pointer_free(page);
653 mk_mem_free(page);
657 /* Build error page */
658 mk_pointer *mk_request_set_default_page(char *title, mk_pointer message,
659 char *signature)
661 char *temp;
662 mk_pointer *p;
664 p = mk_mem_malloc(sizeof(mk_pointer));
666 temp = mk_pointer_to_buf(message);
667 mk_string_build(&p->data, &p->len,
668 MK_REQUEST_DEFAULT_PAGE, title, temp, signature);
669 mk_mem_free(temp);
671 return p;
674 /* Create a memory allocation in order to handle the request data */
675 struct request *mk_request_alloc()
677 struct request *request = 0;
679 request = mk_mem_malloc(sizeof(struct request));
680 request->status = VAR_OFF; /* Request not processed yet */
681 request->close_now = VAR_OFF;
683 mk_pointer_reset(&request->body);
684 request->status = VAR_ON;
685 request->method = METHOD_NOT_FOUND;
687 mk_pointer_reset(&request->uri);
688 request->uri_processed = NULL;
689 request->uri_twin = VAR_OFF;
691 request->accept.data = NULL;
692 request->accept_language.data = NULL;
693 request->accept_encoding.data = NULL;
694 request->accept_charset.data = NULL;
695 request->content_length = 0;
696 request->content_type.data = NULL;
697 request->connection.data = NULL;
698 request->cookies.data = NULL;
699 request->host.data = NULL;
700 request->if_modified_since.data = NULL;
701 request->last_modified_since.data = NULL;
702 request->range.data = NULL;
703 request->referer.data = NULL;
704 request->resume.data = NULL;
705 request->user_agent.data = NULL;
707 request->post_variables.data = NULL;
709 request->user_uri = NULL;
710 mk_pointer_reset(&request->query_string);
712 request->file_info = NULL;
713 request->virtual_user = NULL;
714 request->script_filename = NULL;
715 mk_pointer_reset(&request->real_path);
716 request->host_conf = config->hosts;
718 request->loop = 0;
719 request->bytes_to_send = -1;
720 request->bytes_offset = 0;
721 request->fd_file = -1;
723 /* Response Headers */
724 request->headers = mk_header_create();
726 /* Plugin handler */
727 request->handled_by = NULL;
729 return request;
732 void mk_request_free_list(struct client_request *cr)
734 struct request *sr = 0, *before = 0;
736 /* sr = last node */
737 #ifdef TRACE
738 MK_TRACE("Free struct client_request [FD %i]", cr->socket);
739 #endif
741 while (cr->request) {
742 sr = before = cr->request;
744 while (sr->next) {
745 sr = sr->next;
748 if (sr != cr->request) {
749 while (before->next != sr) {
750 before = before->next;
752 before->next = NULL;
754 else {
755 cr->request = NULL;
757 mk_request_free(sr);
759 cr->request = NULL;
762 void mk_request_free(struct request *sr)
764 if (sr->fd_file > 0) {
765 close(sr->fd_file);
767 if (sr->headers) {
768 mk_mem_free(sr->headers->location);
769 mk_pointer_free(&sr->headers->last_modified);
770 mk_mem_free(sr->headers);
772 if (sr->headers->content_length >= 0) {
773 mk_pointer_free(&sr->headers->content_length_p);
777 mk_pointer_reset(&sr->body);
778 mk_pointer_reset(&sr->uri);
780 if (sr->uri_twin == VAR_ON) {
781 mk_mem_free(sr->uri_processed);
784 mk_pointer_free(&sr->post_variables);
785 mk_mem_free(sr->user_uri);
786 mk_pointer_reset(&sr->query_string);
788 mk_mem_free(sr->file_info);
789 mk_mem_free(sr->virtual_user);
790 mk_mem_free(sr->script_filename);
791 mk_pointer_free(&sr->real_path);
792 mk_mem_free(sr);
795 /* Create a client request struct and put it on the
796 * main list
798 struct client_request *mk_request_client_create(int socket)
800 struct request_idx *request_index;
801 struct client_request *cr;
802 struct sched_connection *sc;
804 sc = mk_sched_get_connection(NULL, socket);
805 cr = mk_mem_malloc(sizeof(struct client_request));
807 /* IPv4 Address */
808 cr->ipv4 = &sc->ipv4;
810 cr->pipelined = FALSE;
811 cr->counter_connections = 0;
812 cr->socket = socket;
813 cr->status = MK_REQUEST_STATUS_INCOMPLETE;
814 cr->request = NULL;
816 /* creation time in unix time */
817 cr->init_time = sc->arrive_time;
819 cr->next = NULL;
820 cr->body = mk_mem_malloc(MAX_REQUEST_BODY);
821 cr->body_length = 0;
822 cr->body_pos_end = -1;
823 cr->first_method = HTTP_METHOD_UNKNOWN;
825 /* Add this request to the thread request list */
826 request_index = mk_sched_get_request_index();
827 if (!request_index->first) {
828 request_index->first = request_index->last = cr;
830 else {
831 request_index->last->next = cr;
832 request_index->last = cr;
835 /* Set again the global list */
836 mk_sched_set_request_index(request_index);
838 return cr;
841 struct client_request *mk_request_client_get(int socket)
843 struct request_idx *request_index;
844 struct client_request *cr = NULL;
846 request_index = mk_sched_get_request_index();
847 cr = request_index->first;
848 while (cr != NULL) {
849 if (cr->socket == socket) {
850 break;
852 cr = cr->next;
855 return cr;
859 * From thread sched_list_node "list", remove the client_request
860 * struct information
862 void mk_request_client_remove(int socket)
864 struct request_idx *request_index;
865 struct client_request *cr, *aux;
867 request_index = mk_sched_get_request_index();
868 cr = request_index->first;
870 while (cr) {
871 if (cr->socket == socket) {
872 if (cr == request_index->first) {
873 request_index->first = cr->next;
875 else {
876 aux = request_index->first;
877 while (aux->next != cr) {
878 aux = aux->next;
880 aux->next = cr->next;
881 if (!aux->next) {
882 request_index->last = aux;
885 break;
887 cr = cr->next;
890 mk_mem_free(cr->body);
891 mk_mem_free(cr);
893 /* Update thread index */
894 mk_sched_set_request_index(request_index);
897 struct header_toc *mk_request_header_toc_create(int len)
899 int i;
900 struct header_toc *p;
902 p = (struct header_toc *) pthread_getspecific(mk_cache_header_toc);
904 for (i = 0; i < len; i++) {
905 p[i].init = NULL;
906 p[i].end = NULL;
907 p[i].status = 0;
909 return p;
912 void mk_request_header_toc_parse(struct header_toc *toc, int toc_len, char *data, int len)
914 char *p, *l = 0;
915 int i;
917 p = data;
918 for (i = 0; i < toc_len && p && l < data + len; i++) {
919 l = strstr(p, MK_CRLF);
920 if (l) {
921 toc[i].init = p;
922 toc[i].end = l;
923 p = l + mk_crlf.len;
925 else {
926 break;
931 void mk_request_ka_next(struct client_request *cr)
933 bzero(cr->body, sizeof(cr->body));
934 cr->first_method = -1;
935 cr->body_pos_end = -1;
936 cr->body_length = 0;
937 cr->counter_connections++;
939 /* Update data for scheduler */
940 cr->init_time = log_current_utime;
941 cr->status = MK_REQUEST_STATUS_INCOMPLETE;