/* * Check if the client request still has pending data. * * Return 0 when all parts of the expected data has arrived or -1 when * the connection is on a pending status due to HTTP spec. * * This function is called from request.c :: mk_handler_read(..) */ int mk_http_pending_request(struct client_session *cs) { int n; char *end; if (cs->body_length >= mk_endblock.len) { end = (cs->body + cs->body_length) - mk_endblock.len; } else { return -1; } /* try to match CRLF at the end of the request */ if (cs->body_pos_end < 0) { if (strncmp(end, mk_endblock.data, mk_endblock.len) == 0) { cs->body_pos_end = cs->body_length - mk_endblock.len; } else if ((n = mk_string_search(cs->body, mk_endblock.data, MK_STR_SENSITIVE)) >= 0 ) { cs->body_pos_end = n; } else { return -1; } } if (cs->first_method == MK_HTTP_METHOD_UNKNOWN) { cs->first_method = mk_http_method_get(cs->body); } if (cs->first_method == MK_HTTP_METHOD_POST || cs->first_method == MK_HTTP_METHOD_PUT) { if (cs->body_pos_end > 0) { int content_length; int current; current = cs->body_length - cs->body_pos_end - mk_endblock.len; content_length = mk_method_validate_content_length(cs->body, current); MK_TRACE("HTTP DATA %i/%i", current, content_length); if (content_length >= config->max_request_size) { return 0; } /* if first block has ended, we need to verify if exists * a previous block end, that will means that the POST * method has sent the whole information. * just for ref: pipelining is not allowed with POST */ if ((unsigned int) cs->body_pos_end == cs->body_length - mk_endblock.len) { /* Content-length is required, if is it not found, * we pass as successful in order to raise the error * later */ if (content_length <= 0) { cs->status = MK_REQUEST_STATUS_COMPLETED; return 0; } else { return -1; } } else { if (current < content_length) { return -1; } else { cs->status = MK_REQUEST_STATUS_COMPLETED; return 0; } } } else { return -1; } } cs->status = MK_REQUEST_STATUS_COMPLETED; return 0; }
static int mk_request_parse(struct client_session *cs) { int i, end; int blocks = 0; struct session_request *sr_node; struct mk_list *sr_list, *sr_head; for (i = 0; i <= cs->body_pos_end; i++) { /* * Pipelining can just exists in a persistent connection or * well known as KeepAlive, so if we are in keepalive mode * we should check if we have multiple request in our body buffer */ end = mk_string_search(cs->body + i, mk_endblock.data, MK_STR_SENSITIVE) + i; if (end < 0) { return -1; } /* Allocating request block */ if (blocks == 0) { sr_node = &cs->sr_fixed; memset(sr_node, '\0', sizeof(struct session_request)); } else { sr_node = mk_mem_malloc_z(sizeof(struct session_request)); } mk_request_init(sr_node); /* We point the block with a mk_ptr_t */ sr_node->body.data = cs->body + i; sr_node->body.len = end - i; /* Method, previous catch in mk_http_pending_request */ if (i == 0) { sr_node->method = cs->first_method; } else { sr_node->method = mk_http_method_get(sr_node->body.data); } /* Looking for POST data */ if (sr_node->method == MK_HTTP_METHOD_POST) { int offset; offset = end + mk_endblock.len; sr_node->data = mk_method_get_data(cs->body + offset, cs->body_length - offset); } /* Increase index to the end of the current block */ i = (end + mk_endblock.len) - 1; /* Link block */ mk_list_add(&sr_node->_head, &cs->request_list); /* Update counter */ blocks++; } /* DEBUG BLOCKS struct mk_list *head; struct session_request *entry; printf("\n*******************\n"); mk_list_foreach(head, &cs->request_list) { entry = mk_list_entry(head, struct session_request, _head); mk_ptr_print(entry->body); fflush(stdout); } */ /* Checking pipelining connection */ if (blocks > 1) { sr_list = &cs->request_list; mk_list_foreach(sr_head, sr_list) { sr_node = mk_list_entry(sr_head, struct session_request, _head); /* Pipelining request must use GET or HEAD methods */ if (sr_node->method != MK_HTTP_METHOD_GET && sr_node->method != MK_HTTP_METHOD_HEAD) { return -1; } }