static int mk_http_request_prepare(struct mk_http_session *cs, struct mk_http_request *sr) { int status = 0; char *temp; struct mk_list *hosts = &mk_config->hosts; struct mk_list *alias; struct mk_http_header *header; /* * 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; } /* Always assign the default vhost' */ sr->host_conf = mk_list_entry_first(hosts, struct host, _head); sr->user_home = MK_FALSE; /* Valid request URI? */ if (sr->uri_processed.data[0] != '/') { mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr); return MK_EXIT_OK; } /* Check if we have a Host header: Hostname ; port */ mk_http_point_header(&sr->host, &cs->parser, MK_HEADER_HOST); /* Header: Connection */ mk_http_point_header(&sr->connection, &cs->parser, MK_HEADER_CONNECTION); /* Header: Range */ mk_http_point_header(&sr->range, &cs->parser, MK_HEADER_RANGE); /* Header: If-Modified-Since */ mk_http_point_header(&sr->if_modified_since, &cs->parser, MK_HEADER_IF_MODIFIED_SINCE); /* HTTP/1.1 needs Host header */ if (!sr->host.data && sr->protocol == MK_HTTP_PROTOCOL_11) { mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr); return MK_EXIT_OK; } /* Should we close the session after this request ? */ mk_http_keepalive_check(cs, sr); /* Content Length */ header = &cs->parser.headers[MK_HEADER_CONTENT_LENGTH]; if (header->type == MK_HEADER_CONTENT_LENGTH) { sr->_content_length.data = header->val.data; sr->_content_length.len = header->val.len; } else { sr->_content_length.data = NULL; } /* Assign the first node alias */ alias = &sr->host_conf->server_names; sr->host_alias = mk_list_entry_first(alias, struct host_alias, _head); if (sr->host.data) { /* Set the given port */ if (cs->parser.header_host_port > 0) { sr->port = cs->parser.header_host_port; } /* Match the virtual host */ mk_vhost_get(sr->host, &sr->host_conf, &sr->host_alias); /* Check if this virtual host have some redirection */ if (sr->host_conf->header_redirect.data) { mk_header_set_http_status(sr, MK_REDIR_MOVED); sr->headers.location = mk_string_dup(sr->host_conf->header_redirect.data); sr->headers.content_length = 0; sr->headers.location = NULL; mk_header_prepare(cs, sr); return 0; } } /* Is requesting an user home directory ? */ if (mk_config->user_dir && sr->uri_processed.len > 2 && sr->uri_processed.data[1] == MK_USER_HOME) { if (mk_user_init(cs, sr) != 0) { mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr); return MK_EXIT_ABORT; } } /* Plugins Stage 20 */ int ret; ret = mk_plugin_stage_run_20(cs, sr); if (ret == MK_PLUGIN_RET_CLOSE_CONX) { MK_TRACE("STAGE 20 requested close conexion"); return MK_EXIT_ABORT; } /* Normal HTTP process */ status = mk_http_init(cs, sr); MK_TRACE("[FD %i] HTTP Init returning %i", cs->socket, status); return status; }
/* 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; }