Security Plugin: set http status for URL rule match
[MonkeyD.git] / src / request.c
blob2ef544c07853175f4293f89f3d595f6c1c90b5c7
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 <sys/ioctl.h>
30 #include <time.h>
31 #include <netdb.h>
32 #include <sys/wait.h>
33 #include <signal.h>
34 #include <errno.h>
36 #include <string.h>
38 #include <arpa/inet.h>
39 #include <netinet/in.h>
40 #include <sys/types.h>
42 #include "request.h"
43 #include "monkey.h"
44 #include "http.h"
45 #include "http_status.h"
46 #include "string.h"
47 #include "str.h"
48 #include "config.h"
49 #include "scheduler.h"
50 #include "epoll.h"
51 #include "socket.h"
52 #include "utils.h"
53 #include "header.h"
54 #include "user.h"
55 #include "method.h"
56 #include "memory.h"
57 #include "socket.h"
58 #include "cache.h"
59 #include "clock.h"
60 #include "utils.h"
61 #include "plugin.h"
63 struct request *mk_request_parse(struct client_request *cr)
65 int i, end;
66 int blocks = 0;
67 struct request *cr_buf = 0, *cr_search = 0;
69 for (i = 0; i <= cr->body_pos_end; i++) {
70 /* Look for CRLFCRLF (\r\n\r\n), maybe some pipelining
71 * request can be involved.
73 end = mk_string_search(cr->body + i, mk_endblock.data) + i;
75 if (end < 0) {
76 return NULL;
79 /* Allocating request block */
80 cr_buf = mk_request_alloc();
82 /* We point the block with a mk_pointer */
83 cr_buf->body.data = cr->body + i;
84 cr_buf->body.len = end - i;
86 /* Method, previous catch in mk_http_pending_request */
87 if (i == 0) {
88 cr_buf->method = cr->first_method;
90 else {
91 cr_buf->method = mk_http_method_get(cr_buf->body.data);
93 cr_buf->next = NULL;
95 /* Looking for POST data */
96 if (cr_buf->method == HTTP_METHOD_POST) {
97 cr_buf->post_variables = mk_method_post_get_vars(cr->body,
98 end + mk_endblock.len);
99 if (cr_buf->post_variables.len >= 0) {
100 i += cr_buf->post_variables.len;
104 /* Increase index to the end of the current block */
105 i = (end + mk_endblock.len) - 1;
107 /* Link block */
108 if (!cr->request) {
109 cr->request = cr_buf;
111 else {
112 cr_search = cr->request;
113 while (cr_search) {
114 if (cr_search->next == NULL) {
115 cr_search->next = cr_buf;
116 break;
118 else {
119 cr_search = cr_search->next;
124 /* Update counter */
125 blocks++;
129 /* DEBUG BLOCKS
130 cr_search = cr->request;
131 while(cr_search){
132 printf("\n");
133 MK_TRACE("BLOCK INIT");
134 mk_pointer_print(cr_search->body);
135 MK_TRACE("BLOCK_END");
137 cr_search = cr_search->next;
141 /* Checking pipelining connection */
142 cr_search = cr->request;
143 if (blocks > 1) {
144 while (cr_search) {
145 /* Pipelining request must use GET or HEAD methods */
146 if (cr_search->method != HTTP_METHOD_GET &&
147 cr_search->method != HTTP_METHOD_HEAD) {
148 return NULL;
150 cr_search = cr_search->next;
153 cr->pipelined = TRUE;
156 return cr->request;
159 int mk_handler_read(int socket, struct client_request *cr)
161 int bytes;
162 int pending = 0;
163 int available = 0;
164 int ret;
165 int new_size;
166 char *tmp = 0;
168 /* Check amount of data reported */
169 ret = ioctl(socket, FIONREAD, &pending);
170 if (ret == -1) {
171 mk_request_client_remove(socket);
172 return -1;
175 /* Reallocate buffer size if pending data does not have space */
176 if (pending > 0 && (pending >= (cr->body_size - (cr->body_length - 1)))) {
177 /* check available space */
178 available = (cr->body_size - cr->body_length) + MK_REQUEST_CHUNK;
179 if (pending < available) {
180 new_size = cr->body_size + MK_REQUEST_CHUNK + 1;
182 else {
183 new_size = cr->body_size + pending + 1;
186 if (new_size > config->max_request_size) {
187 return -1;
190 tmp = mk_mem_realloc(cr->body, new_size);
191 if (tmp) {
192 cr->body = tmp;
193 cr->body_size = new_size;
195 else {
196 mk_request_client_remove(socket);
197 return -1;
201 /* Read content */
202 bytes = mk_socket_read(socket, cr->body + cr->body_length,
203 (cr->body_size - cr->body_length) );
205 if (bytes < 0) {
206 if (errno == EAGAIN) {
207 return 1;
209 else {
210 mk_request_client_remove(socket);
211 return -1;
214 if (bytes == 0) {
215 mk_request_client_remove(socket);
216 return -1;
219 if (bytes >= 0) {
220 cr->body_length += bytes;
221 cr->body[cr->body_length] = '\0';
224 return bytes;
227 int mk_handler_write(int socket, struct client_request *cr)
229 int bytes, final_status = 0;
230 struct request *sr;
233 * Get node from schedule list node which contains
234 * the information regarding to the current thread
236 if (!cr) {
237 return -1;
240 if (!cr->request) {
241 if (!mk_request_parse(cr)) {
242 return -1;
246 sr = cr->request;
247 while (sr) {
248 /* Request not processed also no plugin has take some action */
249 if (sr->bytes_to_send < 0 && !sr->handled_by) {
250 final_status = mk_request_process(cr, sr);
252 /* Request with data to send by static file sender */
253 else if (sr->bytes_to_send > 0 && !sr->handled_by) {
254 final_status = bytes = mk_http_send_file(cr, sr);
258 * If we got an error, we don't want to parse
259 * and send information for another pipelined request
261 if (final_status > 0) {
262 return final_status;
264 else if (final_status <= 0) {
265 /* STAGE_40, request has ended */
266 mk_plugin_stage_run(MK_PLUGIN_STAGE_40, cr->socket,
267 NULL, cr, sr);
268 switch (final_status) {
269 case EXIT_NORMAL:
270 case EXIT_ERROR:
271 if (sr->close_now == VAR_ON) {
272 return -1;
274 break;
275 case EXIT_ABORT:
276 return -1;
280 sr = sr->next;
283 /* If we are here, is because all pipelined request were
284 * processed successfully, let's return 0;
286 return 0;
289 int mk_request_process(struct client_request *cr, struct request *s_request)
291 int status = 0;
292 struct host *host;
294 status = mk_request_header_process(s_request);
295 if (status < 0) {
296 mk_header_set_http_status(s_request, M_CLIENT_BAD_REQUEST);
297 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request);
298 return EXIT_ABORT;
301 switch (s_request->method) {
302 case METHOD_NOT_ALLOWED:
303 mk_request_error(M_CLIENT_METHOD_NOT_ALLOWED, cr, s_request);
304 return EXIT_NORMAL;
305 case METHOD_NOT_FOUND:
306 mk_request_error(M_SERVER_NOT_IMPLEMENTED, cr, s_request);
307 return EXIT_NORMAL;
310 s_request->user_home = VAR_OFF;
312 /* Valid request URI? */
313 if (s_request->uri_processed == NULL) {
314 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request);
315 return EXIT_NORMAL;
317 if (s_request->uri_processed[0] != '/') {
318 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request);
319 return EXIT_NORMAL;
321 if (s_request->uri_processed[0] != '/') {
322 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request);
323 return EXIT_NORMAL;
326 /* HTTP/1.1 needs Host header */
327 if (!s_request->host.data && s_request->protocol == HTTP_PROTOCOL_11) {
328 mk_request_error(M_CLIENT_BAD_REQUEST, cr, s_request);
329 return EXIT_NORMAL;
332 /* Method not allowed ? */
333 if (s_request->method == METHOD_NOT_ALLOWED) {
334 mk_request_error(M_CLIENT_METHOD_NOT_ALLOWED, cr, s_request);
335 return EXIT_NORMAL;
338 /* Validating protocol version */
339 if (s_request->protocol == HTTP_PROTOCOL_UNKNOWN) {
340 mk_request_error(M_SERVER_HTTP_VERSION_UNSUP, cr, s_request);
341 return EXIT_ABORT;
344 if (s_request->host.data) {
345 host = mk_config_host_find(s_request->host);
346 if (host) {
347 s_request->host_conf = host;
349 else {
350 s_request->host_conf = config->hosts;
353 else {
354 s_request->host_conf = config->hosts;
357 /* is requesting an user home directory ? */
358 if (config->user_dir) {
359 if (strncmp(s_request->uri_processed,
360 mk_user_home.data, mk_user_home.len) == 0) {
361 if (mk_user_init(cr, s_request) != 0) {
362 return EXIT_NORMAL;
367 /* Handling method requested */
368 if (s_request->method == HTTP_METHOD_POST) {
369 if ((status = mk_method_post(cr, s_request)) == -1) {
370 return status;
374 /* Plugins Stage 20 */
375 int ret;
376 ret = mk_plugin_stage_run(MK_PLUGIN_STAGE_20, cr->socket, NULL,
377 cr, s_request);
379 if (ret == MK_PLUGIN_RET_CLOSE_CONX) {
380 #ifdef TRACE
381 MK_TRACE("STAGE 20 requested close conexion");
382 #endif
383 return EXIT_ABORT;
386 /* Normal HTTP process */
387 status = mk_http_init(cr, s_request);
389 #ifdef TRACE
390 MK_TRACE("HTTP Init returning %i", status);
391 #endif
393 return status;
396 /* Return a struct with method, URI , protocol version
397 and all static headers defined here sent in request */
398 int mk_request_header_process(struct request *sr)
400 int uri_init = 0, uri_end = 0;
401 char *query_init = 0;
402 int prot_init = 0, prot_end = 0, pos_sep = 0;
403 int fh_limit;
404 char *port = 0;
405 char *headers;
406 mk_pointer host;
408 /* Method */
409 sr->method_p = mk_http_method_check_str(sr->method);
411 /* Request URI */
412 uri_init = (index(sr->body.data, ' ') - sr->body.data) + 1;
413 fh_limit = (index(sr->body.data, '\n') - sr->body.data);
415 uri_end = mk_string_search_r(sr->body.data, ' ', fh_limit) - 1;
417 if (uri_end <= 0) {
418 #ifdef TRACE
419 MK_TRACE("Error, first header bad formed");
420 #endif
421 return -1;
424 prot_init = uri_end + 2;
426 if (uri_end < uri_init) {
427 return -1;
430 /* Query String */
431 query_init = index(sr->body.data + uri_init, '?');
432 if (query_init) {
433 int init, end;
435 init = (int) (query_init - (sr->body.data + uri_init)) + uri_init;
436 if (init <= uri_end) {
437 end = uri_end;
438 uri_end = init - 1;
440 sr->query_string = mk_pointer_create(sr->body.data,
441 init + 1, end + 1);
445 /* Request URI Part 2 */
446 sr->uri = mk_pointer_create(sr->body.data, uri_init, uri_end + 1);
448 if (sr->uri.len < 1) {
449 return -1;
452 /* HTTP Version */
453 prot_end = fh_limit - 1;
454 if (prot_init == prot_end) {
455 return -1;
458 if (prot_end != prot_init && prot_end > 0) {
459 sr->protocol = mk_http_protocol_check(sr->body.data + prot_init,
460 prot_end - prot_init);
461 sr->protocol_p = mk_http_protocol_check_str(sr->protocol);
464 headers = sr->body.data + prot_end + mk_crlf.len;
466 /* URI processed */
467 sr->uri_processed = mk_utils_hexuri_to_ascii(sr->uri);
469 if (!sr->uri_processed) {
470 sr->uri_processed = mk_pointer_to_buf(sr->uri);
471 sr->uri_twin = VAR_ON;
474 /* Creating table of content (index) for request headers */
475 int toc_len = MK_KNOWN_HEADERS;
476 int headers_len = sr->body.len - (prot_end + mk_crlf.len);
478 struct header_toc *toc = mk_request_header_toc_create(toc_len);
479 mk_request_header_toc_parse(toc, toc_len, headers, headers_len);
481 /* Host */
482 host = mk_request_header_find(toc, toc_len, headers, mk_rh_host);
484 if (host.data) {
485 if ((pos_sep = mk_string_char_search(host.data, ':', host.len)) >= 0) {
486 sr->host.data = host.data;
487 sr->host.len = pos_sep;
489 port = mk_string_copy_substr(host.data, pos_sep + 1, host.len);
490 sr->port = atoi(port);
491 mk_mem_free(port);
493 else {
494 sr->host = host; /* maybe null */
495 sr->port = config->standard_port;
498 else {
499 sr->host.data = NULL;
502 /* Looking for headers */
503 sr->accept = mk_request_header_find(toc, toc_len, headers, mk_rh_accept);
504 sr->accept_charset = mk_request_header_find(toc, toc_len, headers,
505 mk_rh_accept_charset);
506 sr->accept_encoding = mk_request_header_find(toc, toc_len, headers,
507 mk_rh_accept_encoding);
510 sr->accept_language = mk_request_header_find(toc, toc_len, headers,
511 mk_rh_accept_language);
512 sr->cookies = mk_request_header_find(toc, toc_len, headers, mk_rh_cookie);
513 sr->connection = mk_request_header_find(toc, toc_len, headers,
514 mk_rh_connection);
515 sr->referer = mk_request_header_find(toc, toc_len, headers,
516 mk_rh_referer);
517 sr->user_agent = mk_request_header_find(toc, toc_len, headers,
518 mk_rh_user_agent);
519 sr->range = mk_request_header_find(toc, toc_len, headers, mk_rh_range);
520 sr->if_modified_since = mk_request_header_find(toc, toc_len, headers,
521 mk_rh_if_modified_since);
523 /* Default Keepalive is off */
524 if (sr->protocol == HTTP_PROTOCOL_10) {
525 sr->keep_alive = VAR_OFF;
526 sr->close_now = VAR_ON;
528 else if(sr->protocol == HTTP_PROTOCOL_11) {
529 sr->keep_alive = VAR_ON;
530 sr->close_now = VAR_OFF;
533 if (sr->connection.data) {
534 if (mk_string_casestr(sr->connection.data, "Keep-Alive")) {
535 sr->keep_alive = VAR_ON;
536 sr->close_now = VAR_OFF;
538 else if(mk_string_casestr(sr->connection.data, "Close")) {
539 sr->keep_alive = VAR_OFF;
540 sr->close_now = VAR_ON;
542 else {
543 /* Set as a non-valid connection header value */
544 sr->connection.len = 0;
548 return 0;
551 /* Return value of some variable sent in request */
552 mk_pointer mk_request_header_find(struct header_toc * toc, int toc_len,
553 char *request_body, mk_pointer header)
555 int i;
556 mk_pointer var;
558 var.data = NULL;
559 var.len = 0;
561 if (toc) {
562 for (i = 0; i < toc_len; i++) {
563 /* status = 1 means that the toc entry was already
564 * checked by monkey
566 if (toc[i].status == 1) {
567 continue;
570 if (!toc[i].init)
571 break;
573 if (strncasecmp(toc[i].init, header.data, header.len) == 0) {
574 var.data = toc[i].init + header.len + 1;
575 var.len = toc[i].end - var.data;
576 toc[i].status = 1;
577 return var;
582 return var;
585 /* Look for some index.xxx in pathfile */
586 mk_pointer mk_request_index(char *pathfile)
588 unsigned long len;
589 char *file_aux = 0;
590 mk_pointer f;
591 struct mk_string_line *aux_index;
593 mk_pointer_reset(&f);
595 aux_index = config->index_files;
597 while (aux_index) {
598 mk_string_build(&file_aux, &len, "%s%s",
599 pathfile, aux_index->val);
601 if (access(file_aux, F_OK) == 0) {
602 f.data = file_aux;
603 f.len = len;
604 return f;
606 mk_mem_free(file_aux);
607 aux_index = aux_index->next;
610 return f;
613 /* Send error responses */
614 void mk_request_error(int http_status, struct client_request *cr,
615 struct request *sr) {
616 char *aux_message = 0;
617 mk_pointer message, *page = 0;
618 long n;
620 switch (http_status) {
621 case M_CLIENT_BAD_REQUEST:
622 page = mk_request_set_default_page("Bad Request",
623 sr->uri,
624 sr->host_conf->host_signature);
625 break;
627 case M_CLIENT_FORBIDDEN:
628 page = mk_request_set_default_page("Forbidden",
629 sr->uri,
630 sr->host_conf->host_signature);
631 break;
633 case M_CLIENT_NOT_FOUND:
634 mk_string_build(&message.data, &message.len,
635 "The requested URL was not found on this server.");
636 page = mk_request_set_default_page("Not Found",
637 message,
638 sr->host_conf->host_signature);
639 mk_pointer_free(&message);
640 break;
642 case M_CLIENT_REQUEST_ENTITY_TOO_LARGE:
643 mk_string_build(&message.data, &message.len,
644 "The request entity is too large.");
645 page = mk_request_set_default_page("Entity too large",
646 message,
647 sr->host_conf->host_signature);
648 mk_pointer_free(&message);
649 break;
651 case M_CLIENT_METHOD_NOT_ALLOWED:
652 page = mk_request_set_default_page("Method Not Allowed",
653 sr->uri,
654 sr->host_conf->host_signature);
655 break;
657 case M_CLIENT_REQUEST_TIMEOUT:
658 case M_CLIENT_LENGTH_REQUIRED:
659 break;
661 case M_SERVER_NOT_IMPLEMENTED:
662 page = mk_request_set_default_page("Method Not Implemented",
663 sr->uri,
664 sr->host_conf->host_signature);
665 break;
667 case M_SERVER_INTERNAL_ERROR:
668 mk_string_build(&message.data, &message.len,
669 "Problems found running %s ", sr->uri);
670 page = mk_request_set_default_page("Internal Server Error",
671 message,
672 sr->host_conf->host_signature);
673 mk_pointer_free(&message);
674 break;
676 case M_SERVER_HTTP_VERSION_UNSUP:
677 mk_pointer_reset(&message);
678 page = mk_request_set_default_page("HTTP Version Not Supported",
679 message,
680 sr->host_conf->host_signature);
681 break;
684 mk_header_set_http_status(sr, http_status);
685 if (page) {
686 sr->headers->content_length = page->len;
689 sr->headers->location = NULL;
690 sr->headers->cgi = SH_NOCGI;
691 sr->headers->pconnections_left = 0;
692 sr->headers->last_modified = -1;
694 if (aux_message)
695 mk_mem_free(aux_message);
697 if (!page) {
698 mk_pointer_reset(&sr->headers->content_type);
700 else {
701 mk_pointer_set(&sr->headers->content_type, "text/html\r\n");
704 mk_header_send(cr->socket, cr, sr);
706 if (page && sr->method != HTTP_METHOD_HEAD) {
707 n = mk_socket_send(cr->socket, page->data, page->len);
708 mk_pointer_free(page);
709 mk_mem_free(page);
712 /* Turn off TCP_CORK */
713 mk_socket_set_cork_flag(cr->socket, TCP_CORK_OFF);
716 /* Build error page */
717 mk_pointer *mk_request_set_default_page(char *title, mk_pointer message,
718 char *signature)
720 char *temp;
721 mk_pointer *p;
723 p = mk_mem_malloc(sizeof(mk_pointer));
725 temp = mk_pointer_to_buf(message);
726 mk_string_build(&p->data, &p->len,
727 MK_REQUEST_DEFAULT_PAGE, title, temp, signature);
728 mk_mem_free(temp);
730 return p;
733 /* Create a memory allocation in order to handle the request data */
734 struct request *mk_request_alloc()
736 struct request *request = 0;
738 request = mk_mem_malloc(sizeof(struct request));
739 request->status = VAR_OFF; /* Request not processed yet */
740 request->close_now = VAR_OFF;
742 mk_pointer_reset(&request->body);
743 request->status = VAR_ON;
744 request->method = METHOD_NOT_FOUND;
746 mk_pointer_reset(&request->uri);
747 request->uri_processed = NULL;
748 request->uri_twin = VAR_OFF;
750 request->accept.data = NULL;
751 request->accept_language.data = NULL;
752 request->accept_encoding.data = NULL;
753 request->accept_charset.data = NULL;
754 request->content_length = 0;
755 request->content_type.data = NULL;
756 request->connection.data = NULL;
757 request->cookies.data = NULL;
758 request->host.data = NULL;
759 request->if_modified_since.data = NULL;
760 request->last_modified_since.data = NULL;
761 request->range.data = NULL;
762 request->referer.data = NULL;
763 request->resume.data = NULL;
764 request->user_agent.data = NULL;
766 request->post_variables.data = NULL;
768 request->user_uri = NULL;
769 mk_pointer_reset(&request->query_string);
771 request->file_info = NULL;
772 request->virtual_user = NULL;
773 request->script_filename = NULL;
774 mk_pointer_reset(&request->real_path);
775 request->host_conf = config->hosts;
777 request->loop = 0;
778 request->bytes_to_send = -1;
779 request->bytes_offset = 0;
780 request->fd_file = -1;
782 /* Response Headers */
783 request->headers = mk_header_create();
785 /* Plugin handler */
786 request->handled_by = NULL;
788 return request;
791 void mk_request_free_list(struct client_request *cr)
793 struct request *sr = 0, *before = 0;
795 /* sr = last node */
796 #ifdef TRACE
797 MK_TRACE("Free struct client_request [FD %i]", cr->socket);
798 #endif
800 while (cr->request) {
801 sr = before = cr->request;
803 while (sr->next) {
804 sr = sr->next;
807 if (sr != cr->request) {
808 while (before->next != sr) {
809 before = before->next;
811 before->next = NULL;
813 else {
814 cr->request = NULL;
816 mk_request_free(sr);
818 cr->request = NULL;
821 void mk_request_free(struct request *sr)
823 if (sr->fd_file > 0) {
824 close(sr->fd_file);
826 if (sr->headers) {
827 mk_mem_free(sr->headers->location);
828 mk_mem_free(sr->headers);
831 mk_pointer_reset(&sr->body);
832 mk_pointer_reset(&sr->uri);
834 if (sr->uri_twin == VAR_ON) {
835 mk_mem_free(sr->uri_processed);
838 mk_pointer_free(&sr->post_variables);
839 mk_mem_free(sr->user_uri);
840 mk_pointer_reset(&sr->query_string);
842 mk_mem_free(sr->file_info);
843 mk_mem_free(sr->virtual_user);
844 mk_mem_free(sr->script_filename);
845 mk_pointer_free(&sr->real_path);
846 mk_mem_free(sr);
849 /* Create a client request struct and put it on the
850 * main list
852 struct client_request *mk_request_client_create(int socket)
854 struct request_idx *request_index;
855 struct client_request *cr;
856 struct sched_connection *sc;
858 sc = mk_sched_get_connection(NULL, socket);
859 cr = mk_mem_malloc(sizeof(struct client_request));
861 if (!sc) {
862 #ifdef TRACE
863 MK_TRACE("FAILED SOCKET: %i", socket);
864 #endif
865 exit(1);
868 /* IPv4 Address */
869 cr->ipv4 = &sc->ipv4;
871 cr->pipelined = FALSE;
872 cr->counter_connections = 0;
873 cr->socket = socket;
874 cr->status = MK_REQUEST_STATUS_INCOMPLETE;
875 cr->request = NULL;
877 /* creation time in unix time */
878 cr->init_time = sc->arrive_time;
880 cr->next = NULL;
881 cr->body = mk_mem_malloc(MK_REQUEST_CHUNK);
883 /* Buffer size based in Chunk bytes */
884 cr->body_size = MK_REQUEST_CHUNK;
885 /* Current data length */
886 cr->body_length = 0;
888 cr->body_pos_end = -1;
889 cr->first_method = HTTP_METHOD_UNKNOWN;
891 /* Add this request to the thread request list */
892 request_index = mk_sched_get_request_index();
893 if (!request_index->first) {
894 request_index->first = request_index->last = cr;
896 else {
897 request_index->last->next = cr;
898 request_index->last = cr;
901 /* Set again the global list */
902 mk_sched_set_request_index(request_index);
904 return cr;
907 struct client_request *mk_request_client_get(int socket)
909 struct request_idx *request_index;
910 struct client_request *cr = NULL;
912 request_index = mk_sched_get_request_index();
913 cr = request_index->first;
914 while (cr != NULL) {
915 if (cr->socket == socket) {
916 break;
918 cr = cr->next;
921 return cr;
925 * From thread sched_list_node "list", remove the client_request
926 * struct information
928 void mk_request_client_remove(int socket)
930 struct request_idx *request_index;
931 struct client_request *cr, *aux;
933 request_index = mk_sched_get_request_index();
934 cr = request_index->first;
936 while (cr) {
937 if (cr->socket == socket) {
938 if (cr == request_index->first) {
939 request_index->first = cr->next;
941 else {
942 aux = request_index->first;
943 while (aux->next != cr) {
944 aux = aux->next;
946 aux->next = cr->next;
947 if (!aux->next) {
948 request_index->last = aux;
951 break;
953 cr = cr->next;
956 mk_mem_free(cr->body);
957 mk_mem_free(cr);
959 /* Update thread index */
960 mk_sched_set_request_index(request_index);
963 struct header_toc *mk_request_header_toc_create(int len)
965 int i;
966 struct header_toc *p;
968 p = (struct header_toc *) mk_cache_get(mk_cache_header_toc);
970 for (i = 0; i < len; i++) {
971 p[i].init = NULL;
972 p[i].end = NULL;
973 p[i].status = 0;
975 return p;
978 void mk_request_header_toc_parse(struct header_toc *toc, int toc_len, char *data, int len)
980 char *p, *l = 0;
981 int i;
983 p = data;
984 for (i = 0; i < toc_len && p && l < data + len; i++) {
985 l = strstr(p, MK_CRLF);
986 if (l) {
987 toc[i].init = p;
988 toc[i].end = l;
989 p = l + mk_crlf.len;
991 else {
992 break;
997 void mk_request_ka_next(struct client_request *cr)
999 bzero(cr->body, sizeof(cr->body));
1000 cr->first_method = -1;
1001 cr->body_pos_end = -1;
1002 cr->body_length = 0;
1003 cr->counter_connections++;
1005 /* Update data for scheduler */
1006 cr->init_time = log_current_utime;
1007 cr->status = MK_REQUEST_STATUS_INCOMPLETE;