long int mk_method_validate_content_length(const char *body, int body_len) { struct headers_toc toc; long int len; mk_pointer tmp; /* * obs: Table of Content (toc) is created when the full * request has arrived, this function cannot be used from * mk_http_pending_request(). */ mk_request_header_toc_parse(&toc, body, body_len); tmp = mk_request_header_get(&toc, mk_rh_content_length.data, mk_rh_content_length.len); if (!tmp.data) { int pos_header; int pos_crlf; char *str_cl; /* Pre-parsing mode: Check if content-length was sent */ pos_header = mk_string_search(body, RH_CONTENT_LENGTH, MK_STR_INSENSITIVE); if (pos_header <= 0) { return -1; } pos_crlf = mk_string_search(body + pos_header, MK_IOV_CRLF, MK_STR_SENSITIVE); if (pos_crlf <= 0) { return -1; } str_cl = mk_string_copy_substr(body + pos_header + mk_rh_content_length.len + 1, 0, pos_header + pos_crlf); len = strtol(str_cl, (char **) NULL, 10); mk_mem_free(str_cl); return len; } len = strtol(tmp.data, (char **) NULL, 10); return len; }
/* It parse data sent by POST or PUT methods */ int mk_method_parse_data(struct client_session *cs, struct session_request *sr) { mk_pointer tmp; long content_length_post = 0; content_length_post = mk_method_validate_content_length(cs->body, cs->body_length); /* Length Required */ if (content_length_post == -1) { mk_request_error(MK_CLIENT_LENGTH_REQUIRED, cs, sr); return -1; } /* Bad request */ if (content_length_post <= 0) { mk_request_error(MK_CLIENT_BAD_REQUEST, cs, sr); return -1; } /* Content length too large */ if (content_length_post >= cs->body_size) { mk_request_error(MK_CLIENT_REQUEST_ENTITY_TOO_LARGE, cs, sr); return -1; } tmp = mk_request_header_get(&sr->headers_toc, mk_rh_content_type.data, mk_rh_content_type.len); if (!tmp.data) { mk_request_error(MK_CLIENT_BAD_REQUEST, cs, sr); return -1; } sr->content_type = tmp; sr->content_length = content_length_post; return 0; }
/* Return a struct with method, URI , protocol version and all static headers defined here sent in request */ static int mk_request_header_process(struct session_request *sr) { int uri_init = 0, uri_end = 0; int query_init = 0; int prot_init = 0, prot_end = 0, pos_sep = 0; int fh_limit; char *headers; char *temp = 0; mk_ptr_t host; /* Method */ sr->method_p = mk_http_method_check_str(sr->method); /* Request URI */ temp = index(sr->body.data, ' '); if (mk_unlikely(!temp)) { MK_TRACE("Error, invalid first header"); return -1; } uri_init = (temp - sr->body.data) + 1; temp = index(sr->body.data, '\n'); if (mk_unlikely(!temp)) { MK_TRACE("Error, invalid header CRLF"); return -1; } fh_limit = (temp - sr->body.data); uri_end = mk_string_char_search_r(sr->body.data, ' ', fh_limit) - 1; if (mk_unlikely(uri_end <= 0)) { MK_TRACE("Error, first header bad formed"); return -1; } prot_init = uri_end + 2; if (mk_unlikely(uri_end < uri_init)) { return -1; } /* Query String */ query_init = mk_string_char_search(sr->body.data + uri_init, '?', prot_init); if (query_init > 0) { int init, end; init = query_init + uri_init; if (init <= uri_end) { end = uri_end; uri_end = init - 1; sr->query_string = mk_ptr_create(sr->body.data, init + 1, end + 1); } } /* Request URI Part 2 */ sr->uri = mk_ptr_create(sr->body.data, uri_init, uri_end + 1); if (mk_unlikely(sr->uri.len < 1)) { return -1; } /* HTTP Version */ prot_end = fh_limit - 1; if (mk_unlikely(prot_init == prot_end)) { return -1; } if (prot_end != prot_init && prot_end > 0) { sr->protocol = mk_http_protocol_check(sr->body.data + prot_init, prot_end - prot_init); sr->protocol_p = mk_http_protocol_check_str(sr->protocol); } headers = sr->body.data + prot_end + mk_crlf.len; /* * Process URI, if it contains ASCII encoded strings like '%20', * it will return a new memory buffer with the decoded string, otherwise * it returns NULL */ temp = mk_utils_url_decode(sr->uri); if (temp) { sr->uri_processed.data = temp; sr->uri_processed.len = strlen(temp); } else { sr->uri_processed.data = sr->uri.data; sr->uri_processed.len = sr->uri.len; } /* Creating Table of Content (index) for HTTP headers */ sr->headers_len = sr->body.len - (prot_end + mk_crlf.len); if (mk_request_header_toc_parse(&sr->headers_toc, headers, sr->headers_len) < 0) { MK_TRACE("Invalid headers"); return -1; } /* Host */ host = mk_request_header_get(&sr->headers_toc, mk_rh_host.data, mk_rh_host.len); if (host.data) { if ((pos_sep = mk_string_char_search_r(host.data, ':', host.len)) >= 0) { /* TCP port should not be higher than 65535 */ char *p; short int port_len, port_size = 6; char port[port_size]; /* just the host */ sr->host.data = host.data; sr->host.len = pos_sep; /* including the port */ sr->host_port = host; /* Port string length */ port_len = (host.len - pos_sep - 1); if (port_len >= port_size) { return -1; } /* Copy to buffer */ memcpy(port, host.data + pos_sep + 1, port_len); port[port_len] = '\0'; /* Validate that the input port is numeric */ p = port; while (*p) { if (!isdigit(*p)) return -1; p++; } /* Convert to base 10 */ errno = 0; sr->port = strtol(port, (char **) NULL, 10); if ((errno == ERANGE && (sr->port == LONG_MAX || sr->port == LONG_MIN)) || sr->port == 0) { return -1; } } else { sr->host = host; /* maybe null */ sr->port = config->standard_port; } } else { sr->host.data = NULL; } /* Looking for headers that ONLY Monkey uses */ sr->connection = mk_request_header_get(&sr->headers_toc, mk_rh_connection.data, mk_rh_connection.len); sr->range = mk_request_header_get(&sr->headers_toc, mk_rh_range.data, mk_rh_range.len); sr->if_modified_since = mk_request_header_get(&sr->headers_toc, mk_rh_if_modified_since.data, mk_rh_if_modified_since.len); /* Default Keepalive is off */ if (sr->protocol == MK_HTTP_PROTOCOL_10) { sr->keep_alive = MK_FALSE; sr->close_now = MK_TRUE; } else if(sr->protocol == MK_HTTP_PROTOCOL_11) { sr->keep_alive = MK_TRUE; sr->close_now = MK_FALSE; } if (sr->connection.data) { if (mk_string_search_n(sr->connection.data, "Keep-Alive", MK_STR_INSENSITIVE, sr->connection.len) >= 0) { sr->keep_alive = MK_TRUE; sr->close_now = MK_FALSE; } else if (mk_string_search_n(sr->connection.data, "Close", MK_STR_INSENSITIVE, sr->connection.len) >= 0) { sr->keep_alive = MK_FALSE; sr->close_now = MK_TRUE; } else { /* Set as a non-valid connection header value */ sr->connection.len = 0; } } return 0; }