int mk_user_init(struct client_session *cs, struct session_request *sr) { int limit; const int offset = 2; /* The user is defined after the '/~' string, so offset = 2 */ const int user_len = 255; char user[user_len], *user_uri; struct passwd *s_user; if (sr->uri_processed.len <= 2) { return -1; } limit = mk_string_char_search(sr->uri_processed.data + offset, '/', sr->uri_processed.len); if (limit == -1) { limit = (sr->uri_processed.len) - offset; } if (limit + offset >= (user_len)) { return -1; } memcpy(user, sr->uri_processed.data + offset, limit); user[limit] = '\0'; MK_TRACE("user: '******'", user); /* Check system user */ if ((s_user = getpwnam(user)) == NULL) { mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr); return -1; } if (sr->uri_processed.len > (unsigned int) (offset+limit)) { user_uri = mk_mem_malloc(sr->uri_processed.len); if (!user_uri) { return -1; } memcpy(user_uri, sr->uri_processed.data + (offset + limit), sr->uri_processed.len - offset - limit); user_uri[sr->uri_processed.len - offset - limit] = '\0'; mk_string_build(&sr->real_path.data, &sr->real_path.len, "%s/%s%s", s_user->pw_dir, config->user_dir, user_uri); mk_mem_free(user_uri); } else { mk_string_build(&sr->real_path.data, &sr->real_path.len, "%s/%s", s_user->pw_dir, config->user_dir); } sr->user_home = MK_TRUE; return 0; }
/* 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; }
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, MK_HTTP_DIRECTORY_BACKWARD, sizeof(MK_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 requested resource doesn't exist, * 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) { if (sr->headers.status > 0) { return mk_request_error(sr->headers.status, cs, sr); } else { 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 if (sr->stage30_blocked == MK_FALSE) { 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 an index file */ mk_ptr_t index_file; char tmppath[MK_MAX_PATH]; index_file = mk_request_index(sr->real_path.data, tmppath, MK_MAX_PATH); if (index_file.data) { if (sr->real_path.data != sr->real_path_static) { mk_ptr_t_free(&sr->real_path); sr->real_path = index_file; sr->real_path.data = mk_string_dup(index_file.data); } /* If it's static and it 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 = mk_string_dup(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[MK_MAX_PATH]; n = readlink(sr->real_path.data, linked_file, MK_MAX_PATH); if (n < 0) { return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } } } /* Plugin Stage 30: look for handlers for this request */ if (sr->stage30_blocked == MK_FALSE) { 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 listens 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 == MK_HTTP_METHOD_PUT || sr->method == MK_HTTP_METHOD_DELETE || sr->method == MK_HTTP_METHOD_UNKNOWN) { return mk_request_error(MK_SERVER_NOT_IMPLEMENTED, cs, sr); } /* counter connections */ sr->headers.pconnections_left = (int) (config->max_keep_alive_request - cs->counter_connections); /* Set default value */ mk_header_set_http_status(sr, MK_HTTP_OK); sr->headers.location = NULL; sr->headers.content_length = 0; /* * For OPTIONS method, we let the plugin handle it and * return without any content. */ if (sr->method == MK_HTTP_METHOD_OPTIONS) { sr->headers.allow_methods.data = MK_HTTP_METHOD_AVAILABLE; sr->headers.allow_methods.len = strlen(MK_HTTP_METHOD_AVAILABLE); mk_ptr_t_reset(&sr->headers.content_type); mk_header_send(cs->socket, cs, sr); return EXIT_NORMAL; } else { mk_ptr_t_reset(&sr->headers.allow_methods); } /* 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); } sr->headers.last_modified = sr->file_info.last_modification; if (sr->if_modified_since.data && sr->method == MK_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; } } /* Object size for log and response headers */ sr->headers.content_length = sr->file_info.size; sr->headers.real_length = sr->file_info.size; /* Open file */ if (mk_likely(sr->file_info.size > 0)) { sr->fd_file = mk_vhost_open(sr); if (sr->fd_file == -1) { MK_TRACE("open() failed"); return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr); } sr->bytes_to_send = sr->file_info.size; } /* Process methods */ if (sr->method == MK_HTTP_METHOD_GET || sr->method == MK_HTTP_METHOD_HEAD) { sr->headers.content_type = mime->type; /* HTTP Ranges */ if (sr->range.data != NULL && config->resume == MK_TRUE) { if (mk_http_range_parse(sr) < 0) { sr->headers.ranges[0] = -1; sr->headers.ranges[1] = -1; 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); } /* Calc bytes to send & offset */ if (mk_http_range_set(sr, sr->file_info.size) != 0) { sr->headers.content_length = -1; sr->headers.ranges[0] = -1; sr->headers.ranges[1] = -1; return mk_request_error(MK_CLIENT_REQUESTED_RANGE_NOT_SATISF, cs, sr); } } } else { /* without content-type */ mk_ptr_t_reset(&sr->headers.content_type); } /* Send headers */ mk_header_send(cs->socket, cs, sr); if (mk_unlikely(sr->headers.content_length == 0)) { return 0; } /* Send file content */ if (sr->method == MK_HTTP_METHOD_GET || sr->method == MK_HTTP_METHOD_POST) { bytes = mk_http_send_file(cs, sr); } return bytes; }