diff --git a/Makefile b/Makefile index dd69e53c..4cb0ff26 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,7 @@ LIB_SOURCES = src/libhttp.c \ src/httplib_log_access.c \ src/httplib_master_thread.c \ src/httplib_mkcol.c \ + src/httplib_parse_http_message.c \ src/httplib_parse_net.c \ src/httplib_prepare_cgi_environment.c \ src/httplib_process_new_connection.c \ diff --git a/src/httplib_parse_http_message.c b/src/httplib_parse_http_message.c new file mode 100644 index 00000000..3edcfa02 --- /dev/null +++ b/src/httplib_parse_http_message.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +/* + * int XX_httplib_parse_http_message( char *buf, int len, struct mg_request_info *ri ); + * + * The function XX_httplib_parse_http_message() parses an HTTP request and + * fills in the mg_request_info structure. This function modifies the buffer by + * NUL terminating HTTP request components, header names and header values. + * Parameters: + * buf (in/out) pointer to the HTTP header to parse and split + * len (in) length of the HTTP header buffer + * ri (out) parsed header as a mg_request_info structure + * The parameters buf and ri must be valid pointers (not NULL) with a length + * larger than zero. On error the function return a negative value, otherwise + * the length of the request is returned. + */ + +int XX_httplib_parse_http_message( char *buf, int len, struct mg_request_info *ri ) { + + int is_request; + int request_length; + char *start_line; + + request_length = XX_httplib_get_request_len(buf, len); + + if (request_length > 0) { + /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr, + * remote_port */ + ri->remote_user = ri->request_method = ri->request_uri = + ri->http_version = NULL; + ri->num_headers = 0; + + buf[request_length - 1] = '\0'; + + /* RFC says that all initial whitespaces should be ingored */ + while (*buf != '\0' && isspace(*(unsigned char *)buf)) { + buf++; + } + start_line = XX_httplib_skip(&buf, "\r\n"); + ri->request_method = XX_httplib_skip(&start_line, " "); + ri->request_uri = XX_httplib_skip(&start_line, " "); + ri->http_version = start_line; + + /* HTTP message could be either HTTP request: + * "GET / HTTP/1.0 ..." + * or a HTTP response: + * "HTTP/1.0 200 OK ..." + * otherwise it is invalid. + */ + is_request = XX_httplib_is_valid_http_method(ri->request_method); + if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) + || (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { + /* Not a valid request or response: invalid */ + return -1; + } + if (is_request) ri->http_version += 5; + if (XX_httplib_parse_http_headers(&buf, ri) < 0) { + /* Error while parsing headers */ + return -1; + } + } + return request_length; + +} /* XX_httplib_parse_http_message */ diff --git a/src/libhttp-private.h b/src/libhttp-private.h index b605637a..d5b51783 100644 --- a/src/libhttp-private.h +++ b/src/libhttp-private.h @@ -927,6 +927,7 @@ void XX_httplib_interpret_uri( struct mg_connection *conn, char *filename, size_ int XX_httplib_is_authorized_for_put( struct mg_connection *conn ); int XX_httplib_is_not_modified( const struct mg_connection *conn, const struct file *filep ); int XX_httplib_is_put_or_delete_method( const struct mg_connection *conn ); +int XX_httplib_is_valid_http_method( const char *method ); int XX_httplib_is_valid_port( unsigned long port ); int XX_httplib_is_websocket_protocol( const struct mg_connection *conn ); int XX_httplib_join_thread( pthread_t threadid ); @@ -980,6 +981,7 @@ int XX_httplib_set_throttle( const char *spec, uint32_t remote_ip, const char int XX_httplib_set_uid_option( struct mg_context *ctx ); int XX_httplib_should_decode_url( const struct mg_connection *conn ); int XX_httplib_should_keep_alive( const struct mg_connection *conn ); +char * XX_httplib_skip( char **buf, const char *delimiters ); void XX_httplib_snprintf( const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt), ... ) PRINTF_ARGS(5, 6); void XX_httplib_sockaddr_to_string(char *buf, size_t len, const union usa *usa ); pid_t XX_httplib_spawn_process( struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin[2], int fdout[2], int fderr[2], const char *dir ); diff --git a/src/libhttp.c b/src/libhttp.c index 2b7dff16..868da798 100644 --- a/src/libhttp.c +++ b/src/libhttp.c @@ -1290,10 +1290,11 @@ static char * skip_quoted(char **buf, const char *delimiters, const char *whites /* Simplified version of skip_quoted without quote char * and whitespace == delimiters */ -static char * skip(char **buf, const char *delimiters) { +char *XX_httplib_skip( char **buf, const char *delimiters ) { - return skip_quoted(buf, delimiters, delimiters, 0); -} + return skip_quoted( buf, delimiters, delimiters, 0 ); + +} /* XX_httplib_skip */ /* Return HTTP header value, or NULL if not found. */ @@ -5251,7 +5252,7 @@ int XX_httplib_parse_http_headers( char **buf, struct mg_request_info *ri ) { } /* XX_httplib_parse_http_headers */ -static int is_valid_http_method(const char *method) { +int XX_httplib_is_valid_http_method( const char *method ) { return !strcmp(method, "GET") /* HTTP (RFC 2616) */ || !strcmp(method, "POST") /* HTTP (RFC 2616) */ @@ -5276,62 +5277,5 @@ static int is_valid_http_method(const char *method) { /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */ || !strcmp(method, "PATCH"); /* PATCH method (RFC 5789) */ -} - -/* Parse HTTP request, fill in mg_request_info structure. - * This function modifies the buffer by NUL-terminating - * HTTP request components, header names and header values. - * Parameters: - * buf (in/out): pointer to the HTTP header to parse and split - * len (in): length of HTTP header buffer - * re (out): parsed header as mg_request_info - * buf and ri must be valid pointers (not NULL), len>0. - * Returns <0 on error. */ -int XX_httplib_parse_http_message( char *buf, int len, struct mg_request_info *ri ) { - - int is_request; - int request_length; - char *start_line; - - request_length = XX_httplib_get_request_len(buf, len); - - if (request_length > 0) { - /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr, - * remote_port */ - ri->remote_user = ri->request_method = ri->request_uri = - ri->http_version = NULL; - ri->num_headers = 0; - - buf[request_length - 1] = '\0'; - - /* RFC says that all initial whitespaces should be ingored */ - while (*buf != '\0' && isspace(*(unsigned char *)buf)) { - buf++; - } - start_line = skip(&buf, "\r\n"); - ri->request_method = skip(&start_line, " "); - ri->request_uri = skip(&start_line, " "); - ri->http_version = start_line; - - /* HTTP message could be either HTTP request: - * "GET / HTTP/1.0 ..." - * or a HTTP response: - * "HTTP/1.0 200 OK ..." - * otherwise it is invalid. - */ - is_request = is_valid_http_method(ri->request_method); - if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) - || (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { - /* Not a valid request or response: invalid */ - return -1; - } - if (is_request) ri->http_version += 5; - if (XX_httplib_parse_http_headers(&buf, ri) < 0) { - /* Error while parsing headers */ - return -1; - } - } - return request_length; - -} /* XX_httplib_parse_http_message */ +} /* XX_httplib_is_valid_http_method */