http_status http_server::http_request_state::parse_message_line(const char* line) // Parse the next line. { VLOG("parse_message_line: '%s'\n", line); http_status status = HTTP_BAD_REQUEST; switch (m_request_state) { default: case PARSE_DONE: assert(0); break; case PARSE_START_LINE: status = parse_request_line(line); if (status < 400) { // Move on to the rest of the header. m_request_state = PARSE_HEADER; } break; case PARSE_HEADER: status = parse_header_line(line); break; } return status; }
parse_status parse_request(std::istream& src, request& req) { wrapper w = {src, req}; try { parse_status result = parse_request_line(w); if(result != PARSE_SUCCESS) { return result; } result = parse_header_fields(w); if(result != PARSE_SUCCESS) { return result; } } catch(std::bad_alloc& e) { return PARSE_FAILURE; } return PARSE_SUCCESS; }
int parse_request(struct buf *bufp) { char *p; p = bufp->parse_p; //dbprintf("parse_request:\n\trbuf left to parse:\n%s\n", p); // count request number based on CRLF2 while ((p = strstr(p, CRLF2)) != NULL && p < bufp->rbuf_tail) { ++(bufp->rbuf_req_count); p += strlen(CRLF2); bufp->parse_p = p; } // parse every request while (bufp->rbuf_req_count != 0) { dbprintf("parse_request: request count %d\n", bufp->rbuf_req_count); // calloc http_req if (bufp->req_fully_received == 1) { //dbprintf("parse_request: start parsing new request\n"); bufp->http_req_p = (struct http_req *)calloc(1, sizeof(struct http_req)); bufp->req_fully_received = 0; bufp->req_line_header_received = 0; } // parse req parse_request_line(bufp); parse_request_headers(bufp); bufp->req_line_header_received = 1;// update parse_message_body(bufp); // set req_fully_received inside // if fully received, enqueue if (bufp->req_fully_received == 1) { dbprintf("parse_request: req fully received\n"); // update req_queue req_enqueue(bufp->req_queue_p, bufp->http_req_p); // update rbuf --(bufp->rbuf_req_count); bufp->rbuf_head = strstr(bufp->rbuf_head, CRLF2) + strlen(CRLF2); } else { // only POST can reach here dbprintf("parse_request: POST req not fully received yet, continue receiving\n"); break; // break out while loop } } return 0; }
ssize_t req_parse(req_t *req, const char *data, size_t len) { g_return_val_if_fail(req != NULL, -1); g_return_val_if_fail(data != NULL, -1); if (req_is_complete(req)) { g_warning("request already complete"); return 0; } if (strlen(data) < len) { // we have a null somewhere in the string req->state = STATE_INVALID; return -1; } /* request not complete, data looks good. * time to split and parse. */ ssize_t pos = 0; while (pos < len && !req_is_complete(req)) { ssize_t line_len; line_len = req_feed_line(req, data + pos, len - pos); if (line_len < 0) { // TODO better errors return -1; } pos += line_len; if (req->line_ready) { switch (req->state) { case STATE_INITIAL: if (parse_request_line(req, req->buf, req->buf_size) < 0) { return -1; } break; case STATE_IN_HEADER: if (req->buf_size == 0) { req->state = STATE_COMPLETE; } else if (parse_header_line(req, req->buf, req->buf_size) < 0) { return -1; } break; case STATE_COMPLETE: case STATE_INVALID: g_return_val_if_reached(-1); break; } g_free(req->buf); req->buf = NULL; req->buf_size = 0; req->line_ready = false; } } return pos; }
int parse_request(char* buf, int len, struct request* p_req) { CLEAR(p_req->req_line); p_req->h_buf.num = 0; int idx = 0; idx += parse_request_line(buf, len, &(p_req->req_line)); if (idx == -1) return -1; idx += parse_headers(buf + idx, len - idx, &(p_req->h_buf)); //idx = parse_message_body(buf[idx], len - idx); //TODO return idx; }
bool Parser::parse(std::istream& is, Request& request) { std::noskipws(is); Iterator it(is); bool ret = true; ret = ret && parse_request_line(it, request); ret = ret && parse_headers(it, request); ret = ret && match(it, '\r'); ret = ret && *it == '\n'; return ret; }
bool http_connection::read_request_line(unsigned fd, size_t& total) { io_result res; // If we had already processed the data in the input buffer... if (_M_inp == (off_t) _M_in.count()) { if ((res = read(fd, total)) == IO_ERROR) { return false; } else if (res == IO_NO_DATA_READ) { return true; } } do { parse_result parse_result = parse_request_line(); if (parse_result == PARSE_ERROR) { logger::instance().log(logger::LOG_DEBUG, "[http_connection::read_request_line] (fd %d) Invalid request line.", fd); _M_state = PREPARING_ERROR_PAGE_STATE; return true; } else if (parse_result == PARSING_COMPLETED) { parse_result = parse_headers(fd); if (parse_result == PARSE_ERROR) { _M_state = PREPARING_ERROR_PAGE_STATE; } else if (parse_result == PARSING_NOT_COMPLETED) { _M_state = READING_HEADERS_STATE; } else { _M_state = PROCESSING_REQUEST_STATE; } return true; } if (!_M_readable) { return true; } if ((res = read(fd, total)) == IO_ERROR) { return false; } else if (res == IO_NO_DATA_READ) { return true; } } while (true); }
AW_Result aw_session_run (AW_Session *sess) { AW_MethodFunc func; AW_Char *line; AW_Result r; AW_ASSERT(sess); if (!(line = get_line(sess))) { return AW_ERR_SYNTAX; } if ((r = parse_request_line(sess, line)) != AW_OK) return r; while (1) { if (!(line = get_line(sess))) { return AW_ERR_SYNTAX; } if (line[0] == 0) break; if ((r = parse_header_line(sess, line)) != AW_OK) return r; } func = sess->serv->methods[sess->method]; if (func) { r = func(sess, sess->method); } else { AW_ERROR(("do not support the method %d", sess->method)); r = AW_ERR_NOTSUPP; } return r; }
/* Given a HTTP message and the size of the message * Responds to the given socket with the approrpriate * HTTP response. The space allocated for message should * be at least 1 more than req_size */ status respond_to(char* buf, int confd) { char resource[BUFLEN+1], *resource_line, *headers, *current; int result; current = buf; /* Cut off the Resource line */ resource_line = strsep_str(¤t, "\r\n"); /* Get the resource, if error with parsing request line, send 400 response */ if ((result = parse_request_line(resource_line, resource)) != OK) { printf("Recieved badly formatted request line from connection %d\n",confd); return send_error(result, confd); } printf("request good\n"); headers = strsep_str(¤t, "\r\n\r\n"); printf("headers:%s\n",headers); return send_response(resource, confd); }
/* * forward_to_server - forward the http request to server * * this function is little bit long since it handles both GET and * non GET methods; * * it is hard to refactor since many variables need to be passed * * return -1 when all kinds of error * return 0 for GET method * return 1 when cache hit (not forward to server) * return 2 for non GET method */ int forward_to_server(int fd, int *to_server_fd, char *cache_id, void *cache_content, unsigned int *cache_length) { char buf[MAXLINE], request_buf[MAXLINE]; char method[MAXLINE], protocol[MAXLINE]; char host_port[MAXLINE]; char remote_host[MAXLINE], remote_port[MAXLINE], resource[MAXLINE]; char version[MAXLINE]; char origin_request_line[MAXLINE]; char origin_host_header[MAXLINE]; int has_user_agent_str = 0, has_accept_str = 0, has_accept_encoding_str = 0, has_connection_str = 0, has_proxy_connection_str = 0, has_host_str = 0; rio_t rio_client; strcpy(remote_host, ""); strcpy(remote_port, "80"); memset(cache_content, 0, MAX_OBJECT_SIZE); Rio_readinitb(&rio_client, fd); if (Rio_readlineb(&rio_client, buf, MAXLINE) == -1) { return -1; } // used incase dns lookup failed strcpy(origin_request_line, buf); if (parse_request_line(buf, method, protocol, host_port, resource, version) == -1) { return -1; } parse_host_port(host_port, remote_host, remote_port); if (strstr(method, "GET") != NULL) { // GET method // compose our request line strcpy(request_buf, method); strcat(request_buf, " "); strcat(request_buf, resource); strcat(request_buf, " "); strcat(request_buf, http_version_str); // process request header while (Rio_readlineb(&rio_client, buf, MAXLINE) != 0) { if (strcmp(buf, "\r\n") == 0) { break; } else if (strstr(buf, "User-Agent:") != NULL) { strcat(request_buf, user_agent_str); has_user_agent_str = 1; } else if (strstr(buf, "Accept-Encoding:") != NULL) { strcat(request_buf, accept_encoding_str); has_accept_encoding_str = 1; } else if (strstr(buf, "Accept:") != NULL) { strcat(request_buf, accept_str); has_accept_str = 1; } else if (strstr(buf, "Connection:") != NULL) { strcat(request_buf, connection_str); has_connection_str = 1; } else if (strstr(buf, "Proxy Connection:") != NULL) { strcat(request_buf, proxy_connection_str); has_proxy_connection_str = 1; } else if (strstr(buf, "Host:") != NULL) { strcpy(origin_host_header, buf); if (strlen(remote_host) < 1) { // if host not specified in request line // get host from host header sscanf(buf, "Host: %s", host_port); parse_host_port(host_port, remote_host, remote_port); } strcat(request_buf, buf); has_host_str = 1; } else { strcat(request_buf, buf); } } // if not sent, copy in out headers if (has_user_agent_str != 1) { strcat(request_buf, user_agent_str); } if (has_accept_encoding_str != 1) { strcat(request_buf, accept_encoding_str); } if (has_accept_str != 1) { strcat(request_buf, accept_str); } if (has_connection_str != 1) { strcat(request_buf, connection_str); } if (has_proxy_connection_str != 1) { strcat(request_buf, proxy_connection_str); } if (has_host_str != 1) { sprintf(buf, "Host: %s:%s\r\n", remote_host, remote_port); strcat(request_buf, buf); } strcat(request_buf, "\r\n"); if (strcmp(remote_host, "") == 0) { return -1; } // compose cache id strcpy(cache_id, method); strcat(cache_id, " "); strcat(cache_id, remote_host); strcat(cache_id, ":"); strcat(cache_id, remote_port); strcat(cache_id, resource); strcat(cache_id, " "); strcat(cache_id, version); // search in the cache if (read_cache_node_lru_sync(cache, cache_id, cache_content, cache_length) != -1) { // cache hit return 1; } // client to server *to_server_fd = Open_clientfd(remote_host, atoi(remote_port), origin_request_line, origin_host_header); if (*to_server_fd == -1) { return -1; } else if (*to_server_fd == -2) { // dns lookup failed, write our response page // caused by invalid host strcpy(buf, client_bad_request_str); Rio_writen(fd, buf, strlen(buf)); return -1; } if (Rio_writen(*to_server_fd, request_buf, strlen(request_buf)) == -1) { return -1; } return 0; } else { // non GET method unsigned int length = 0, size = 0; strcpy(request_buf, buf); while (strcmp(buf, "\r\n") != 0 && strlen(buf) > 0) { if (Rio_readlineb(&rio_client, buf, MAXLINE) == -1) { return -1; } if (strstr(buf, "Host:") != NULL) { strcpy(origin_host_header, buf); if (strlen(remote_host) < 1) { sscanf(buf, "Host: %s", host_port); parse_host_port(host_port, remote_host, remote_port); } } get_size(buf, &size); strcat(request_buf, buf); } if (strcmp(remote_host, "") == 0) { return -1; } *to_server_fd = Open_clientfd(remote_host, atoi(remote_port), origin_request_line, origin_host_header); if (*to_server_fd < 0) { return -1; } // write request line if (Rio_writen(*to_server_fd, request_buf, strlen(request_buf)) == -1) { return -1; } // write request body while (size > MAXLINE) { if ((length = Rio_readnb(&rio_client, buf, MAXLINE)) == -1) { return -1; } if (Rio_writen(*to_server_fd, buf, length) == -1) { return -1; } size -= MAXLINE; } if (size > 0) { if ((length = Rio_readnb(&rio_client, buf, size)) == -1) { return -1; } if (Rio_writen(*to_server_fd, buf, length) == -1) { return -1; } } return 2; } }
// start-line = Request-Line | Status-Line const char* parse_start_line(unsigned char** p) { if (!parse_request_line(p)) return NULL; return parse_status_line(p); }
apr_status_t modsecurity_tx_init(modsec_rec *msr) { const char *s = NULL; /* Register TX cleanup */ apr_pool_cleanup_register(msr->mp, msr, modsecurity_tx_cleanup, apr_pool_cleanup_null); /* Initialise C-L */ msr->request_content_length = -1; s = apr_table_get(msr->request_headers, "Content-Length"); if (s != NULL) { msr->request_content_length = strtol(s, NULL, 10); } /* Figure out whether this request has a body */ msr->reqbody_chunked = 0; msr->reqbody_should_exist = 0; if (msr->request_content_length == -1) { /* There's no C-L, but is chunked encoding used? */ char *transfer_encoding = (char *)apr_table_get(msr->request_headers, "Transfer-Encoding"); if ((transfer_encoding != NULL) && (strstr(transfer_encoding, "chunked") != NULL)) { msr->reqbody_should_exist = 1; msr->reqbody_chunked = 1; } } else { /* C-L found */ msr->reqbody_should_exist = 1; } /* Initialise C-T */ msr->request_content_type = NULL; s = apr_table_get(msr->request_headers, "Content-Type"); if (s != NULL) { msr->request_content_type = s; } /* Decide what to do with the request body. */ if ((msr->request_content_type != NULL) && (strncasecmp(msr->request_content_type, "application/x-www-form-urlencoded", 33) == 0)) { /* Always place POST requests with "application/x-www-form-urlencoded" payloads in memory. */ msr->msc_reqbody_storage = MSC_REQBODY_MEMORY; msr->msc_reqbody_spilltodisk = 1; msr->msc_reqbody_processor = "URLENCODED"; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "msc reqbody processor change to URLENCODED"); } else { /* In all other cases, try using the memory first but switch over to disk for larger bodies. */ msr->msc_reqbody_storage = MSC_REQBODY_MEMORY; msr->msc_reqbody_spilltodisk = 1; /* If the C-L is known and there's more data than our limit go to disk straight away. */ if ((msr->request_content_length != -1) && (msr->request_content_length > msr->txcfg->reqbody_inmemory_limit)) { msr->msc_reqbody_storage = MSC_REQBODY_DISK; } if (msr->request_content_type != NULL) { if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) == 0) { msr->msc_reqbody_processor = "MULTIPART"; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "msc reqbody processor change to MULTIPART"); } else if (strncasecmp(msr->request_content_type, "text/xml", 8) == 0) { msr->msc_reqbody_processor = "XML"; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "msc reqbody processor change to XML"); } } } /* Check if we are forcing buffering, then use memory only. */ if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) { msr->msc_reqbody_storage = MSC_REQBODY_MEMORY; msr->msc_reqbody_spilltodisk = 0; } /* Initialise arguments */ msr->arguments = apr_table_make(msr->mp, 32); if (msr->arguments == NULL) { return -1; } if (msr->query_string != NULL) { int invalid_count = 0; /* 查询串参数解析 */ if (parse_arguments(msr, msr->query_string, strlen(msr->query_string), msr->txcfg->argument_separator, "QUERY_STRING", msr->arguments, &invalid_count) < 0) { msr_log(msr, 1, "Initialisation: Error occurred while parsing QUERY_STRING arguments."); return -1; } if (invalid_count) { msr->urlencoded_error = 1; } } if (msr->request_uri != NULL) { /* request_uri解析 */ msr->request_uri = (const char *)parse_uri(msr->mp, msr->request_uri); if (msr->request_uri == NULL) { msr_log(msr, 1, "Initialisation: Error occurred while parsing REQUEST_URI arguments."); return -1; } } if (msr->request_line != NULL) { /* request_line解析 */ msr->request_line = (const char *)parse_request_line(msr->mp, msr->request_line); if (msr->request_line == NULL) { msr_log(msr, 1, "Initialisation: Error occurred while parsing REQUEST_LINE arguments."); return -1; } } msr->arguments_to_sanitize = apr_table_make(msr->mp, 16); if (msr->arguments_to_sanitize == NULL) { return -1; } msr->request_headers_to_sanitize = apr_table_make(msr->mp, 16); if (msr->request_headers_to_sanitize == NULL) { return -1; } msr->response_headers_to_sanitize = apr_table_make(msr->mp, 16); if (msr->response_headers_to_sanitize == NULL) { return -1; } msr->pattern_to_sanitize = apr_table_make(msr->mp, 32); if (msr->pattern_to_sanitize == NULL) { return -1; } /* Initialise cookies */ msr->request_cookies = apr_table_make(msr->mp, 5); if (msr->request_cookies == NULL) { return -1; } /* Initialize matched vars */ msr->matched_vars = apr_table_make(msr->mp, 8); if (msr->matched_vars == NULL) { return -1; } apr_table_clear(msr->matched_vars); /* Locate the cookie headers and parse them */ /* 解析请求cookie */ if (parse_request_cookie(msr) == -1) { return -1; } /* Collections. */ msr->tx_vars = apr_table_make(msr->mp, 32); if (msr->tx_vars == NULL) { return -1; } msr->geo_vars = apr_table_make(msr->mp, 8); if (msr->geo_vars == NULL) { return -1; } msr->collections_original = apr_table_make(msr->mp, 8); if (msr->collections_original == NULL) { return -1; } msr->collections = apr_table_make(msr->mp, 8); if (msr->collections == NULL) { return -1; } msr->collections_dirty = apr_table_make(msr->mp, 8); if (msr->collections_dirty == NULL) { return -1; } /* Other */ msr->tcache = NULL; msr->tcache_items = 0; /* 初始化变量缓存内存池 */ #ifdef VAR_FETCH_CACHE if (apr_pool_create(&msr->var_fetch_cache_mptmp, msr->mp) != APR_SUCCESS) { return -1; } apr_pool_tag(msr->var_fetch_cache_mptmp, "varfetchcache"); #endif msr->matched_rules = apr_array_make(msr->mp, 16, sizeof(void *)); if (msr->matched_rules == NULL) { return -1; } msr->matched_var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (msr->matched_var == NULL) { return -1; } msr->highest_severity = 255; /* high, invalid value */ msr->removed_rules = apr_array_make(msr->mp, 16, sizeof(char *)); if (msr->removed_rules == NULL) { return -1; } msr->removed_rules_tag = apr_array_make(msr->mp, 16, sizeof(char *)); if (msr->removed_rules_tag == NULL) { return -1; } return 1; }
void parse_request(TNCServer self, char *request, HTTPRequestData *request_data) { request_data->status_code = 200; char *request_line; char *saveptr_line; struct stat fileinfo; request_line = strtok_r(request, "\n", &saveptr_line); parse_request_line(self, request_data, request_line); if(! (request_data->flags & HTTPRequestData_flags_get_error_page)) { request_data->file_to_serve = open(request_data->file_info.path, O_RDONLY); if(-1 == request_data->file_to_serve) { request_data->status_code = 404; request_data->flags |= HTTPRequestData_flags_get_error_page; } else { fstat(request_data->file_to_serve, &fileinfo); if(S_ISREG(fileinfo.st_mode)) { TNCJob *close_file = TNCJob_new_close(request_data->file_to_serve); request_data->status_code = 200; TNCList_push_back( request_data->cleanup_jobs, close_file ); } else { request_data->status_code = 403; request_data->flags |= HTTPRequestData_flags_get_error_page; } } } if(request_data->flags & HTTPRequestData_flags_get_error_page) { switch (request_data->status_code) { #define TNC_XM(STATCODE, STATBRIEF, STATDESC) \ case STATCODE: \ pthread_once(&once_control_##STATCODE, init_errorpage_##STATCODE); \ request_data->file_to_serve = errorpage_fd_##STATCODE; \ break; #include "httpstatus.x.h" #undef TNC_XM } fstat(request_data->file_to_serve, &fileinfo); request_data->file_info.mimetype = strdup("text/html"); request_data->file_info.encoding = strdup("UTF-8"); } else { request_data->file_info.mimetype = get_shell_output(COMMAND_MIMETYPE, request_data->file_info.path); request_data->file_info.encoding = get_shell_output(COMMAND_ENCODING, request_data->file_info.path); } TNCList_push_back( request_data->cleanup_jobs, TNCJob_new_free(request_data->file_info.mimetype) ); TNCList_push_back( request_data->cleanup_jobs, TNCJob_new_free(request_data->file_info.encoding) ); request_data->file_info.last_edit = fileinfo.st_mtime; request_data->file_info.size = (size_t) fileinfo.st_size; while(! (request_data->flags & HTTPRequestData_flags_stop_parsing)) { HTTPRequestHeader header; request_line = strtok_r(NULL, CRLF, &saveptr_line); if(!request_line) break; header.field_name = strsep(&request_line, ":"); if(!header.field_name) continue; header.field_content = request_line; if(!header.field_content) continue; while(isspace(*header.field_content)) ++header.field_content; parse_header(self, request_data, &header); } return; }
void SessionImpl::parse_request( const asio::error_code& error, const shared_ptr< Session > session, const function< void ( const shared_ptr< Session > ) >& callback ) try { if ( error ) { throw runtime_error( error.message( ) ); } istream stream( m_buffer.get( ) ); const auto items = parse_request_line( stream ); const auto uri = Uri::parse( "http://localhost" + items.at( "path" ) ); m_request = make_shared< Request >( ); m_request->m_pimpl->m_path = Uri::decode( uri.get_path( ) ); m_request->m_pimpl->m_method = items.at( "method" ); m_request->m_pimpl->m_version = stod( items.at( "version" ) ); m_request->m_pimpl->m_headers = parse_request_headers( stream ); m_request->m_pimpl->m_query_parameters = uri.get_query_parameters( ); callback( session ); } catch ( const int status_code ) { runtime_error re( m_settings->get_status_message( status_code ) ); failure( session, status_code, re ); } catch ( const regex_error& re ) { failure( session, 500, re ); } catch ( const runtime_error& re ) { failure( session, 400, re ); } catch ( const exception& ex ) { failure( session, 500, ex ); } catch ( ... ) { auto cex = current_exception( ); if ( cex not_eq nullptr ) { try { rethrow_exception( cex ); } catch ( const exception& ex ) { failure( session, 500, ex ); } catch ( ... ) { runtime_error re( "Internal Server Error" ); failure( session, 500, re ); } } else { runtime_error re( "Internal Server Error" ); failure( session, 500, re ); } }
int http_recv(sk_t *sk) { AN(skb_rdsz(sk->recvbuf)); if (!has_rnrn_termination(sk->recvbuf)) { wsd_errno = WSD_EINPUT; return (-1); } int rv; chunk_t tok; memset(&tok, 0, sizeof(chunk_t)); rv = http_header_tok(&sk->recvbuf->data[sk->recvbuf->rdpos], &tok); if (0 > rv) { if (LOG_VVERBOSE <= wsd_cfg->verbose) { printf("\t%s: errno=%d\n", __func__, errno); } goto error; } http_req_t hreq; memset(&hreq, 0, sizeof(http_req_t)); /* Parse status line, see whether or not it's a request ... */ if (0 > parse_request_line(&tok, &hreq)) { if (LOG_VVERBOSE <= wsd_cfg->verbose) { printf("\t%s: errno=%d\n", __func__, errno); } if (0 == skb_put_str(sk->sendbuf, HTTP_400)) { sk->close_on_write = 1; } goto error; } /* ... validate request line ... */ if (!is_valid_req_line(&hreq)) { if (0 == skb_put_str(sk->sendbuf, HTTP_400)) { sk->close_on_write = 1; } goto error; } /* ... tokenise and parse header fields ... */ while (0 < http_header_tok(NULL, &tok)) { if (0 > parse_header_field(&tok, &hreq)) { if (LOG_VVERBOSE <= wsd_cfg->verbose) { printf("\t%s: errno=%d\n", __func__, errno); } if (0 == skb_put_str(sk->sendbuf, HTTP_400)) { sk->close_on_write = 1; } goto error; } } /* ... and finally, validate HTTP protocol fields. */ if (!is_valid_host_header_field(&hreq)) { if (LOG_VVERBOSE <= wsd_cfg->verbose) { printf("\t%s: invalid host header field\n", __func__); } /* * Implementing as MUST; see RFC7230, section 5.4 and * RFC6455, section 4.1 */ if (0 == skb_put_str(sk->sendbuf, HTTP_400)) { sk->close_on_write = 1; } goto error; } if (!is_valid_upgrade_header_field(&hreq)) { if (LOG_VVERBOSE <= wsd_cfg->verbose) { printf("\t%s: invalid upgrade header field\n", __func__); } if (0 == skb_put_str(sk->sendbuf, HTTP_400)) { sk->close_on_write = 1; } goto error; } if (!is_valid_connection_header_field(&hreq)) { if (LOG_VVERBOSE <= wsd_cfg->verbose) { printf("\t%s: invalid connection header field\n", __func__); } if (0 == skb_put_str(sk->sendbuf, HTTP_400)) { sk->close_on_write = 1; } goto error; } skb_reset(sk->recvbuf); return sk->proto->decode_handshake(sk, &hreq); error: skb_reset(sk->recvbuf); wsd_errno = WSD_EBADREQ; if (sk->close_on_write) { turn_off_events(sk, EPOLLIN); if (!(sk->events & EPOLLOUT)) { turn_on_events(sk, EPOLLOUT); } } return (-1); }
/** @brief Parse and response to request from a client * * @return 0 if the connection should be kept alive. -1 if the connection * should be closed. */ int http_parse(http_client_t *client) { int ret, i; char line[MAXBUF]; char* buf; if (client->status == C_IDLE) { /* A new request, parse request line */ ret = client_readline(client, line); if (strlen(line) == 0) return 0; log_msg(L_HTTP_DEBUG, "%s\n", line); if (ret == 0) return 0; /* The length of a line exceed MAXBUF */ if (ret < 0) { log_error("A line in request is too long"); return end_request(client, BAD_REQUEST); } if (client->req != NULL) free(client->req); client->req = new_request(); /* parse request line and store information in client->req */ if ((ret = parse_request_line(client->req, line)) > 0) return end_request(client, ret); /* Now start parsing header */ client->status = C_PHEADER; } /* * Read request headers. When finish reading request headers of a POST * request without error, client->req->content_length will be set * correspondingly. Thus client->req->content_length == -1 means the * request header section has not ended. */ while (client->status == C_PHEADER && client_readline(client, line) > 0) { log_msg(L_HTTP_DEBUG, "%s\n", line); if (strlen(line) == 0) { //Request header ends if (client->req->method == M_POST) { buf = get_request_header(client->req, "Content-Length"); if (buf == NULL) return end_request(client, LENGTH_REQUIRED); //validate content-length if (strlen(buf) == 0) return BAD_REQUEST; for (i = 0; i < strlen(buf); ++i) if (buf[i] < '0' || buf[i] >'9') //each char in range ['0', '9'] return end_request(client, BAD_REQUEST); client->req->content_length = atoi(buf); /* Now start receiving body */ client->status = C_PBODY; break; } if (client->req->method == M_GET) ret = handle_get(client); if (client->req->method == M_HEAD) ret = handle_head(client); if (ret != 0) return end_request(client, ret); else { /* The client signal a "Connection: Close" */ if (connection_close(client->req)) client->alive = 0; return ret; } } ret = parse_header(client->req, line); if (ret == -1) { log_msg(L_ERROR, "Bad request header format: %s\n", line); return end_request(client, BAD_REQUEST); } } /* * We've finished reading and parsing request header. Now, see if the body * of the request is ready. If so, copy data */ if (client->status == C_PBODY) { // Reveive complete body? if (client->in->datasize - client->in->pos >= client->req->content_length) { /* Let body points to corresponding memory in the input buffer */ client->req->body = client->in->buf + client->in->pos; client->in->pos += client->req->content_length; ret = handle_post(client); if (ret != 0) return end_request(client, ret); else { /* The client signal a "Connection: Close" */ if (connection_close(client->req)) client->alive = 0; return ret; } } /* Body not ready, next time then */ return 0; } return 0; }
void rq_add_line(request_t *h, const char *line) { size_t len = strlen(line); int res; switch (h->state) { case ST_START: res = parse_request_line(h, line); if (res == 0) { h->error = 1; return; } h->state = ST_HEADER; h->line[0] = '\0'; break; case ST_HEADER: if (len == 0) { h->done = 1; } if ( (len == 0) || ( (len > 0) && !isspace(line[0]) ) ) { if (strlen(h->line) > 0) { /* We have a full line of header, now we can analyze it. */ char *colon = strchr(h->line, ':'); size_t keylen; char *key; char *value; if (colon == NULL) { /* We didn't find a colon. */ h->error = 1; return; } keylen = colon - h->line; key = strndup(h->line, keylen); if (key == NULL) { /* Allocation error */ h->error = 1; return; } value = strdup(colon + 1); /* Now we have key and value, process them */ _process(h, key, value); } } if (len > 0) { if ( !isspace(line[0]) ) h->line[0] = '\0'; else line++; /* skip the starting space */ } if (len > 0) { int plen = strlen(h->line); int left = LINE_BUFFER_SIZE - plen - 1; char *to = h->line + plen; strncpy(to, line, left); } default: break; } }
void handle_request(SWS_REQUEST* req_ptr){ int fd = req_ptr->fd; int recv_size = 0; int req_index = 0; int is_request_line = TRUE; char read_buff[READ_BUFF_SIZE]; char req_buff[REQ_BUFF_SIZE]; char *rest; char *ifms_pos; char *ifms_end; //add read timeout struct sigaction sga; sga.sa_handler = read_timeout_handler; sigaction(SIGALRM, &sga, NULL); alarm(READ_TIMEOUT); memset(read_buff, 0, READ_BUFF_SIZE); memset(req_buff, 0, REQ_BUFF_SIZE); //read requesst for(;;){ if ((recv_size = recv(fd, read_buff, READ_BUFF_SIZE, 0)) > 0){ printf("read_buff : %s\n", read_buff); printf("req_buff : %s\n", req_buff); printf("recv_size : %d\n", recv_size); printf("req_index : %d\n", req_index); //add to request buff if (req_index + recv_size < REQ_BUFF_SIZE){ (void)memmove((void *)(req_buff+req_index), (void *)read_buff, recv_size); req_index += recv_size; }else{ //too long, bad request clientError(400, "Bad Request", req_ptr); } /* * parse request line first */ if (is_request_line && ( (rest = strstr(req_buff, "\015\012")) != NULL || (rest = strstr(req_buff, "\012")) != NULL)){ is_request_line = FALSE; // strncpy(req_ptr->request_line, req_buff, BUFF_SIZE); parse_request_line(req_buff, req_ptr); } if (req_ptr->is_simple){ break; } if ((strstr(req_buff, "\015\012\015\012") != NULL || strstr(req_buff, "\012\012") != NULL)){ break; } } /* peer shut down */ if ( recv_size == 0){ fprintf(stderr, "%s\n", "peer shut down"); break; } if ( recv_size < 0){ clientError(500, "Internal Server Error", req_ptr); break; } }//end of request parse //check the header /* Each header field consists of a name followed immediately by a colon (":"), a single space (SP) character, and the field value. Field names are case-insensitive. */ /* The If-Modified-Since request-header field is used with the `GET` method to make it conditional: if the requested resource has not been modified `since` the time specified in this field, a copy of the resource will not be returned from the server; instead, a 304 (not modified) response will be returned w, 3ithout any Entity-Body. */ if ( (ifms_pos = strstr(rest, "If-Modified-Since: ")) != NULL ){ ifms_pos += 19; if ( (ifms_end = strchr(rest, ' ')) != NULL || (ifms_end = strchr(rest, '\t')) != NULL ){ *ifms_end = '\0'; req_ptr->is_if_modified = 1; strncpy(req_ptr->if_modified_since, ifms_pos, 256); } } //check the method PrintRequest(req_ptr); if (req_ptr->method == METHOD_UNKNOWN){ clientError(400, "Bad Request", req_ptr); }else if (req_ptr->method == METHOD_UNIMPL){ clientError(501, "Not Implement", req_ptr); }else if (req_ptr->is_simple && req_ptr->method != METHOD_GET){ clientError(400, "Bad Request", req_ptr); } #ifndef DONT_CARE_VERSION //check http version if (req_ptr->version == HTTP_UNKNOWN){ clientError(505, "Version Not Supported", req_ptr); } #endif //check the request path process_request_path(req_ptr); close(req_ptr->fd); }