void mk_mem_pointers_init() { /* Short server response headers */ mk_pointer_set(&mk_header_short_date, MK_HEADER_SHORT_DATE); mk_pointer_set(&mk_header_short_location, MK_HEADER_SHORT_LOCATION); mk_pointer_set(&mk_header_short_ct, MK_HEADER_SHORT_CT); /* Request vars */ mk_pointer_set(&mk_crlf, MK_CRLF); mk_pointer_set(&mk_endblock, MK_ENDBLOCK); /* Client headers */ mk_pointer_set(&mk_rh_accept, RH_ACCEPT); mk_pointer_set(&mk_rh_accept_charset, RH_ACCEPT_CHARSET); mk_pointer_set(&mk_rh_accept_encoding, RH_ACCEPT_ENCODING); mk_pointer_set(&mk_rh_accept_language, RH_ACCEPT_LANGUAGE); mk_pointer_set(&mk_rh_connection, RH_CONNECTION); mk_pointer_set(&mk_rh_cookie, RH_COOKIE); mk_pointer_set(&mk_rh_content_length, RH_CONTENT_LENGTH); mk_pointer_set(&mk_rh_content_range, RH_CONTENT_RANGE); mk_pointer_set(&mk_rh_content_type, RH_CONTENT_TYPE); mk_pointer_set(&mk_rh_if_modified_since, RH_IF_MODIFIED_SINCE); mk_pointer_set(&mk_rh_host, RH_HOST); mk_pointer_set(&mk_rh_last_modified, RH_LAST_MODIFIED); mk_pointer_set(&mk_rh_last_modified_since, RH_LAST_MODIFIED_SINCE); mk_pointer_set(&mk_rh_referer, RH_REFERER); mk_pointer_set(&mk_rh_range, RH_RANGE); mk_pointer_set(&mk_rh_user_agent, RH_USER_AGENT); /* Server response normal headers */ mk_pointer_set(&mk_header_conn_ka, MK_HEADER_CONN_KA); mk_pointer_set(&mk_header_conn_close, MK_HEADER_CONN_CLOSE); mk_pointer_set(&mk_header_content_length, MK_HEADER_CONTENT_LENGTH); mk_pointer_set(&mk_header_content_encoding, MK_HEADER_CONTENT_ENCODING); mk_pointer_set(&mk_header_accept_ranges, MK_HEADER_ACCEPT_RANGES); mk_pointer_set(&mk_header_te_chunked, MK_HEADER_TE_CHUNKED); mk_pointer_set(&mk_header_last_modified, MK_HEADER_LAST_MODIFIED); mk_http_status_list_init(); mk_iov_separators_init(); /* Server */ mk_pointer_set(&mk_monkey_protocol, HTTP_PROTOCOL_11_STR); /* HTTP */ mk_pointer_set(&mk_http_method_get_p, HTTP_METHOD_GET_STR); mk_pointer_set(&mk_http_method_post_p, HTTP_METHOD_POST_STR); mk_pointer_set(&mk_http_method_head_p, HTTP_METHOD_HEAD_STR); mk_pointer_set(&mk_http_method_put_p, HTTP_METHOD_PUT_STR); mk_pointer_set(&mk_http_method_delete_p, HTTP_METHOD_DELETE_STR); mk_pointer_reset(&mk_http_method_null_p); mk_pointer_set(&mk_http_protocol_09_p, HTTP_PROTOCOL_09_STR); mk_pointer_set(&mk_http_protocol_10_p, HTTP_PROTOCOL_10_STR); mk_pointer_set(&mk_http_protocol_11_p, HTTP_PROTOCOL_11_STR); mk_pointer_reset(&mk_http_protocol_null_p); }
void mk_header_response_reset(struct response_headers *header) { header->status = 0; header->sent = MK_FALSE; header->ranges[0] = -1; header->ranges[1] = -1; header->content_length = -1; header->connection = 0; header->transfer_encoding = -1; header->last_modified = -1; header->cgi = SH_NOCGI; mk_pointer_reset(&header->content_type); mk_pointer_reset(&header->content_encoding); header->location = NULL; header->_extra_rows = NULL; }
/* Create a memory allocation in order to handle the request data */ static void mk_request_init(struct session_request *request) { request->status = MK_FALSE; /* Request not processed yet */ request->close_now = MK_FALSE; mk_pointer_reset(&request->body); request->status = MK_TRUE; request->method = HTTP_METHOD_UNKNOWN; mk_pointer_reset(&request->uri); request->uri_processed.data = NULL; request->content_length = 0; request->content_type.data = NULL; request->connection.data = NULL; request->host.data = NULL; request->if_modified_since.data = NULL; request->last_modified_since.data = NULL; request->range.data = NULL; request->data.data = NULL; mk_pointer_reset(&request->query_string); request->file_info.size = -1; request->virtual_user = NULL; request->keep_alive = MK_FALSE; mk_pointer_reset(&request->real_path); request->host_conf = config->hosts; request->loop = 0; request->bytes_to_send = -1; request->bytes_offset = 0; request->fd_file = -1; /* Response Headers */ mk_header_response_reset(&request->headers); /* Plugin handler */ request->handled_by = NULL; /* Headers TOC */ request->headers_toc.length = 0; }
mk_pointer mk_pointer_create(char *buf, long init, long end) { mk_pointer p; mk_pointer_reset(&p); p.data = buf + init; if (init != end) { p.len = (end - init); } else { p.len = 1; } return p; }
int mk_http_directory_redirect_check(struct client_session *cs, struct session_request *sr) { int port_redirect = 0; char *host; char *location = 0; char *real_location = 0; unsigned long len; /* * We have to check if exist an slash to the end of * this string, if doesn't exist we send a redirection header */ if (sr->uri_processed.data[sr->uri_processed.len - 1] == '/') { return 0; } host = mk_pointer_to_buf(sr->host); /* * Add ending slash to the location string */ location = mk_mem_malloc(sr->uri_processed.len + 2); memcpy(location, sr->uri_processed.data, sr->uri_processed.len); location[sr->uri_processed.len] = '/'; location[sr->uri_processed.len + 1] = '\0'; /* FIXME: should we done something similar for SSL = 443 */ if (sr->host.data && sr->port > 0) { if (sr->port != config->standard_port) { port_redirect = sr->port; } } if (port_redirect > 0) { mk_string_build(&real_location, &len, "%s://%s:%i%s", config->transport, host, port_redirect, location); } else { mk_string_build(&real_location, &len, "%s://%s%s", config->transport, host, location); } #ifdef TRACE MK_TRACE("Redirecting to '%s'", real_location); #endif mk_mem_free(host); mk_header_set_http_status(sr, MK_REDIR_MOVED); sr->headers.content_length = 0; mk_pointer_reset(&sr->headers.content_type); sr->headers.location = real_location; sr->headers.cgi = SH_NOCGI; sr->headers.pconnections_left = (config->max_keep_alive_request - cs->counter_connections); mk_header_send(cs->socket, cs, sr); mk_socket_set_cork_flag(cs->socket, TCP_CORK_OFF); /* * we do not free() real_location * as it's freed by iov */ mk_mem_free(location); sr->headers.location = NULL; return -1; }
int mk_http_init(struct client_session *cs, struct session_request *sr) { int ret; int bytes = 0; struct mimetype *mime; MK_TRACE("HTTP Protocol Init"); /* Request to root path of the virtualhost in question */ if (sr->uri_processed.len == 1 && sr->uri_processed.data[0] == '/') { sr->real_path.data = sr->host_conf->documentroot.data; sr->real_path.len = sr->host_conf->documentroot.len; } /* Compose real path */ if (sr->user_home == MK_FALSE) { int len; len = sr->host_conf->documentroot.len + sr->uri_processed.len; if (len < MK_PATH_BASE) { memcpy(sr->real_path_static, sr->host_conf->documentroot.data, sr->host_conf->documentroot.len); memcpy(sr->real_path_static + sr->host_conf->documentroot.len, sr->uri_processed.data, sr->uri_processed.len); sr->real_path_static[len] = '\0'; sr->real_path.data = sr->real_path_static; sr->real_path.len = len; } else { ret = mk_buffer_cat(&sr->real_path, sr->host_conf->documentroot.data, sr->host_conf->documentroot.len, sr->uri_processed.data, sr->uri_processed.len); if (ret < 0) { MK_TRACE("Error composing real path"); return EXIT_ERROR; } } } /* Check backward directory request */ if (memmem(sr->uri_processed.data, sr->uri_processed.len, HTTP_DIRECTORY_BACKWARD, sizeof(HTTP_DIRECTORY_BACKWARD) - 1)) { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } if (mk_file_get_info(sr->real_path.data, &sr->file_info) != 0) { /* if the resource requested doesn't exists, let's * check if some plugin would like to handle it */ MK_TRACE("No file, look for handler plugin"); ret = mk_plugin_stage_run(MK_PLUGIN_STAGE_30, cs->socket, NULL, cs, sr); if (ret == MK_PLUGIN_RET_CLOSE_CONX) { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } else if (ret == MK_PLUGIN_RET_CONTINUE) { return MK_PLUGIN_RET_CONTINUE; } else if (ret == MK_PLUGIN_RET_END) { return EXIT_NORMAL; } if (sr->file_info.exists == MK_FALSE) { return mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr); } else { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } } /* is it a valid directory ? */ if (sr->file_info.is_directory == MK_TRUE) { /* Send redirect header if end slash is not found */ if (mk_http_directory_redirect_check(cs, sr) == -1) { MK_TRACE("Directory Redirect"); /* Redirect has been sent */ return -1; } /* looking for a index file */ mk_pointer index_file; char tmppath[MAX_PATH]; index_file = mk_request_index(sr->real_path.data, tmppath, MAX_PATH); if (index_file.data) { if (sr->real_path.data != sr->real_path_static) { mk_pointer_free(&sr->real_path); sr->real_path = index_file; sr->real_path.data = strdup(index_file.data); } /* If it's static, and still fits */ else if (index_file.len < MK_PATH_BASE) { memcpy(sr->real_path_static, index_file.data, index_file.len); sr->real_path_static[index_file.len] = '\0'; sr->real_path.len = index_file.len; } /* It was static, but didn't fit */ else { sr->real_path = index_file; sr->real_path.data = strdup(index_file.data); } mk_file_get_info(sr->real_path.data, &sr->file_info); } } /* Check symbolic link file */ if (sr->file_info.is_link == MK_TRUE) { if (config->symlink == MK_FALSE) { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } else { int n; char linked_file[MAX_PATH]; n = readlink(sr->real_path.data, linked_file, MAX_PATH); if (n < 0) { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } } } /* Plugin Stage 30: look for handlers for this request */ ret = mk_plugin_stage_run(MK_PLUGIN_STAGE_30, cs->socket, NULL, cs, sr); MK_TRACE("[FD %i] STAGE_30 returned %i", cs->socket, ret); switch (ret) { case MK_PLUGIN_RET_CONTINUE: return MK_PLUGIN_RET_CONTINUE; case MK_PLUGIN_RET_CLOSE_CONX: if (sr->headers.status > 0) { return mk_request_error(sr->headers.status, cs, sr); } else { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } case MK_PLUGIN_RET_END: return EXIT_NORMAL; } /* * Monkey listen for PUT and DELETE methods in addition to GET, POST and * HEAD, but it does not care about them, so if any plugin did not worked * on it, Monkey will return error 501 (501 Not Implemented). */ if (sr->method == HTTP_METHOD_PUT || sr->method == HTTP_METHOD_DELETE || sr->method == HTTP_METHOD_UNKNOWN) { return mk_request_error(MK_SERVER_NOT_IMPLEMENTED, cs, sr); } /* read permissions and check file */ if (sr->file_info.read_access == MK_FALSE) { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } /* Matching MimeType */ mime = mk_mimetype_find(&sr->real_path); if (!mime) { mime = mimetype_default; } if (sr->file_info.is_directory == MK_TRUE) { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } /* get file size */ if (sr->file_info.size < 0) { return mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr); } /* counter connections */ sr->headers.pconnections_left = (int) (config->max_keep_alive_request - cs->counter_connections); sr->headers.last_modified = sr->file_info.last_modification; if (sr->if_modified_since.data && sr->method == HTTP_METHOD_GET) { time_t date_client; /* Date sent by client */ time_t date_file_server; /* Date server file */ date_client = mk_utils_gmt2utime(sr->if_modified_since.data); date_file_server = sr->file_info.last_modification; if (date_file_server <= date_client && date_client > 0 && date_client <= log_current_utime) { mk_header_set_http_status(sr, MK_NOT_MODIFIED); mk_header_send(cs->socket, cs, sr); return EXIT_NORMAL; } } mk_header_set_http_status(sr, MK_HTTP_OK); sr->headers.location = NULL; /* Object size for log and response headers */ sr->headers.content_length = sr->file_info.size; sr->headers.real_length = sr->file_info.size; /* Process methods */ if (sr->method == HTTP_METHOD_GET || sr->method == HTTP_METHOD_HEAD) { sr->headers.content_type = mime->type; /* Range */ if (sr->range.data != NULL && config->resume == MK_TRUE) { if (mk_http_range_parse(sr) < 0) { return mk_request_error(MK_CLIENT_BAD_REQUEST, cs, sr); } if (sr->headers.ranges[0] >= 0 || sr->headers.ranges[1] >= 0) { mk_header_set_http_status(sr, MK_HTTP_PARTIAL); } } } else { /* without content-type */ mk_pointer_reset(&sr->headers.content_type); } /* Open file */ if (sr->file_info.size > 0) { sr->fd_file = open(sr->real_path.data, sr->file_info.flags_read_only); if (sr->fd_file == -1) { MK_TRACE("open() failed"); return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } } /* Send headers */ mk_header_send(cs->socket, cs, sr); if (sr->headers.content_length == 0) { return 0; } /* Send file content*/ if (sr->method == HTTP_METHOD_GET || sr->method == HTTP_METHOD_POST) { /* Calc bytes to send & offset */ if (mk_http_range_set(sr, sr->file_info.size) != 0) { return mk_request_error(MK_CLIENT_BAD_REQUEST, cs, sr); } bytes = mk_http_send_file(cs, sr); } return bytes; }