예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
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;
}
예제 #5
0
파일: server.c 프로젝트: Dstray/RPRobot
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;
}
예제 #6
0
파일: Parser.cpp 프로젝트: 0x7f/httpp
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;
}
예제 #7
0
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);
}
예제 #8
0
파일: aw_session.c 프로젝트: gkmail/AtomWeb
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;
}
예제 #9
0
/* 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(&current, "\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(&current, "\r\n\r\n");
    printf("headers:%s\n",headers);
     
    return send_response(resource, confd);
}
예제 #10
0
/*
 * 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;
    }
}
예제 #11
0
// 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);
}
예제 #12
0
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;
}
예제 #13
0
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;

}
예제 #14
0
 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 );
     }
 }
예제 #15
0
파일: http.c 프로젝트: sequenced/wsd
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);
}
예제 #16
0
/** @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;
}
예제 #17
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;
	}
}
예제 #18
0
파일: http.c 프로젝트: mr-xiangxu/sws
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);
}