From 9149b56418003bbf193b334ed6cf17b8dfe7e8d6 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Sat, 9 Feb 2019 16:11:41 -0500 Subject: [PATCH] [core] get_http_method_key() match by strlen first --- src/http_kv.c | 212 +++++++++++++++++++++++++------------------------- src/http_kv.h | 4 +- src/request.c | 7 +- 3 files changed, 112 insertions(+), 111 deletions(-) diff --git a/src/http_kv.c b/src/http_kv.c index 2ddbf7da..2eb29649 100644 --- a/src/http_kv.c +++ b/src/http_kv.c @@ -5,113 +5,115 @@ #include +#define CONST_LEN_STR(x) (unsigned int)sizeof(x)-1, (x) + typedef struct { int key; + unsigned int vlen; const char *value; - size_t vlen; } keyvalue; static const keyvalue http_versions[] = { - { HTTP_VERSION_1_1, CONST_STR_LEN("HTTP/1.1") }, - { HTTP_VERSION_1_0, CONST_STR_LEN("HTTP/1.0") }, - { HTTP_VERSION_UNSET, NULL, 0 } + { HTTP_VERSION_1_1, CONST_LEN_STR("HTTP/1.1") }, + { HTTP_VERSION_1_0, CONST_LEN_STR("HTTP/1.0") }, + { HTTP_VERSION_UNSET, 0, NULL } }; static const keyvalue http_methods[] = { - { HTTP_METHOD_GET, CONST_STR_LEN("GET") }, - { HTTP_METHOD_HEAD, CONST_STR_LEN("HEAD") }, - { HTTP_METHOD_POST, CONST_STR_LEN("POST") }, - { HTTP_METHOD_PUT, CONST_STR_LEN("PUT") }, - { HTTP_METHOD_DELETE, CONST_STR_LEN("DELETE") }, - { HTTP_METHOD_CONNECT, CONST_STR_LEN("CONNECT") }, - { HTTP_METHOD_OPTIONS, CONST_STR_LEN("OPTIONS") }, - { HTTP_METHOD_TRACE, CONST_STR_LEN("TRACE") }, - { HTTP_METHOD_ACL, CONST_STR_LEN("ACL") }, - { HTTP_METHOD_BASELINE_CONTROL, CONST_STR_LEN("BASELINE-CONTROL") }, - { HTTP_METHOD_BIND, CONST_STR_LEN("BIND") }, - { HTTP_METHOD_CHECKIN, CONST_STR_LEN("CHECKIN") }, - { HTTP_METHOD_CHECKOUT, CONST_STR_LEN("CHECKOUT") }, - { HTTP_METHOD_COPY, CONST_STR_LEN("COPY") }, - { HTTP_METHOD_LABEL, CONST_STR_LEN("LABEL") }, - { HTTP_METHOD_LINK, CONST_STR_LEN("LINK") }, - { HTTP_METHOD_LOCK, CONST_STR_LEN("LOCK") }, - { HTTP_METHOD_MERGE, CONST_STR_LEN("MERGE") }, - { HTTP_METHOD_MKACTIVITY, CONST_STR_LEN("MKACTIVITY") }, - { HTTP_METHOD_MKCALENDAR, CONST_STR_LEN("MKCALENDAR") }, - { HTTP_METHOD_MKCOL, CONST_STR_LEN("MKCOL") }, - { HTTP_METHOD_MKREDIRECTREF, CONST_STR_LEN("MKREDIRECTREF") }, - { HTTP_METHOD_MKWORKSPACE, CONST_STR_LEN("MKWORKSPACE") }, - { HTTP_METHOD_MOVE, CONST_STR_LEN("MOVE") }, - { HTTP_METHOD_ORDERPATCH, CONST_STR_LEN("ORDERPATCH") }, - { HTTP_METHOD_PATCH, CONST_STR_LEN("PATCH") }, - { HTTP_METHOD_PROPFIND, CONST_STR_LEN("PROPFIND") }, - { HTTP_METHOD_PROPPATCH, CONST_STR_LEN("PROPPATCH") }, - { HTTP_METHOD_REBIND, CONST_STR_LEN("REBIND") }, - { HTTP_METHOD_REPORT, CONST_STR_LEN("REPORT") }, - { HTTP_METHOD_SEARCH, CONST_STR_LEN("SEARCH") }, - { HTTP_METHOD_UNBIND, CONST_STR_LEN("UNBIND") }, - { HTTP_METHOD_UNCHECKOUT, CONST_STR_LEN("UNCHECKOUT") }, - { HTTP_METHOD_UNLINK, CONST_STR_LEN("UNLINK") }, - { HTTP_METHOD_UNLOCK, CONST_STR_LEN("UNLOCK") }, - { HTTP_METHOD_UPDATE, CONST_STR_LEN("UPDATE") }, - { HTTP_METHOD_UPDATEREDIRECTREF, CONST_STR_LEN("UPDATEREDIRECTREF") }, - { HTTP_METHOD_VERSION_CONTROL, CONST_STR_LEN("VERSION-CONTROL") }, + { HTTP_METHOD_GET, CONST_LEN_STR("GET") }, + { HTTP_METHOD_HEAD, CONST_LEN_STR("HEAD") }, + { HTTP_METHOD_POST, CONST_LEN_STR("POST") }, + { HTTP_METHOD_PUT, CONST_LEN_STR("PUT") }, + { HTTP_METHOD_DELETE, CONST_LEN_STR("DELETE") }, + { HTTP_METHOD_CONNECT, CONST_LEN_STR("CONNECT") }, + { HTTP_METHOD_OPTIONS, CONST_LEN_STR("OPTIONS") }, + { HTTP_METHOD_TRACE, CONST_LEN_STR("TRACE") }, + { HTTP_METHOD_ACL, CONST_LEN_STR("ACL") }, + { HTTP_METHOD_BASELINE_CONTROL, CONST_LEN_STR("BASELINE-CONTROL") }, + { HTTP_METHOD_BIND, CONST_LEN_STR("BIND") }, + { HTTP_METHOD_CHECKIN, CONST_LEN_STR("CHECKIN") }, + { HTTP_METHOD_CHECKOUT, CONST_LEN_STR("CHECKOUT") }, + { HTTP_METHOD_COPY, CONST_LEN_STR("COPY") }, + { HTTP_METHOD_LABEL, CONST_LEN_STR("LABEL") }, + { HTTP_METHOD_LINK, CONST_LEN_STR("LINK") }, + { HTTP_METHOD_LOCK, CONST_LEN_STR("LOCK") }, + { HTTP_METHOD_MERGE, CONST_LEN_STR("MERGE") }, + { HTTP_METHOD_MKACTIVITY, CONST_LEN_STR("MKACTIVITY") }, + { HTTP_METHOD_MKCALENDAR, CONST_LEN_STR("MKCALENDAR") }, + { HTTP_METHOD_MKCOL, CONST_LEN_STR("MKCOL") }, + { HTTP_METHOD_MKREDIRECTREF, CONST_LEN_STR("MKREDIRECTREF") }, + { HTTP_METHOD_MKWORKSPACE, CONST_LEN_STR("MKWORKSPACE") }, + { HTTP_METHOD_MOVE, CONST_LEN_STR("MOVE") }, + { HTTP_METHOD_ORDERPATCH, CONST_LEN_STR("ORDERPATCH") }, + { HTTP_METHOD_PATCH, CONST_LEN_STR("PATCH") }, + { HTTP_METHOD_PROPFIND, CONST_LEN_STR("PROPFIND") }, + { HTTP_METHOD_PROPPATCH, CONST_LEN_STR("PROPPATCH") }, + { HTTP_METHOD_REBIND, CONST_LEN_STR("REBIND") }, + { HTTP_METHOD_REPORT, CONST_LEN_STR("REPORT") }, + { HTTP_METHOD_SEARCH, CONST_LEN_STR("SEARCH") }, + { HTTP_METHOD_UNBIND, CONST_LEN_STR("UNBIND") }, + { HTTP_METHOD_UNCHECKOUT, CONST_LEN_STR("UNCHECKOUT") }, + { HTTP_METHOD_UNLINK, CONST_LEN_STR("UNLINK") }, + { HTTP_METHOD_UNLOCK, CONST_LEN_STR("UNLOCK") }, + { HTTP_METHOD_UPDATE, CONST_LEN_STR("UPDATE") }, + { HTTP_METHOD_UPDATEREDIRECTREF, CONST_LEN_STR("UPDATEREDIRECTREF") }, + { HTTP_METHOD_VERSION_CONTROL, CONST_LEN_STR("VERSION-CONTROL") }, - { HTTP_METHOD_UNSET, NULL, 0 } + { HTTP_METHOD_UNSET, 0, NULL } }; static const keyvalue http_status[] = { - { 100, CONST_STR_LEN("100 Continue") }, - { 101, CONST_STR_LEN("101 Switching Protocols") }, - { 102, CONST_STR_LEN("102 Processing") }, /* WebDAV */ - { 200, CONST_STR_LEN("200 OK") }, - { 201, CONST_STR_LEN("201 Created") }, - { 202, CONST_STR_LEN("202 Accepted") }, - { 203, CONST_STR_LEN("203 Non-Authoritative Information") }, - { 204, CONST_STR_LEN("204 No Content") }, - { 205, CONST_STR_LEN("205 Reset Content") }, - { 206, CONST_STR_LEN("206 Partial Content") }, - { 207, CONST_STR_LEN("207 Multi-status") }, /* WebDAV */ - { 300, CONST_STR_LEN("300 Multiple Choices") }, - { 301, CONST_STR_LEN("301 Moved Permanently") }, - { 302, CONST_STR_LEN("302 Found") }, - { 303, CONST_STR_LEN("303 See Other") }, - { 304, CONST_STR_LEN("304 Not Modified") }, - { 305, CONST_STR_LEN("305 Use Proxy") }, - { 306, CONST_STR_LEN("306 (Unused)") }, - { 307, CONST_STR_LEN("307 Temporary Redirect") }, - { 308, CONST_STR_LEN("308 Permanent Redirect") }, - { 400, CONST_STR_LEN("400 Bad Request") }, - { 401, CONST_STR_LEN("401 Unauthorized") }, - { 402, CONST_STR_LEN("402 Payment Required") }, - { 403, CONST_STR_LEN("403 Forbidden") }, - { 404, CONST_STR_LEN("404 Not Found") }, - { 405, CONST_STR_LEN("405 Method Not Allowed") }, - { 406, CONST_STR_LEN("406 Not Acceptable") }, - { 407, CONST_STR_LEN("407 Proxy Authentication Required") }, - { 408, CONST_STR_LEN("408 Request Timeout") }, - { 409, CONST_STR_LEN("409 Conflict") }, - { 410, CONST_STR_LEN("410 Gone") }, - { 411, CONST_STR_LEN("411 Length Required") }, - { 412, CONST_STR_LEN("412 Precondition Failed") }, - { 413, CONST_STR_LEN("413 Request Entity Too Large") }, - { 414, CONST_STR_LEN("414 Request-URI Too Long") }, - { 415, CONST_STR_LEN("415 Unsupported Media Type") }, - { 416, CONST_STR_LEN("416 Requested Range Not Satisfiable") }, - { 417, CONST_STR_LEN("417 Expectation Failed") }, - { 422, CONST_STR_LEN("422 Unprocessable Entity") }, /* WebDAV */ - { 423, CONST_STR_LEN("423 Locked") }, /* WebDAV */ - { 424, CONST_STR_LEN("424 Failed Dependency") }, /* WebDAV */ - { 426, CONST_STR_LEN("426 Upgrade Required") }, /* TLS */ - { 500, CONST_STR_LEN("500 Internal Server Error") }, - { 501, CONST_STR_LEN("501 Not Implemented") }, - { 502, CONST_STR_LEN("502 Bad Gateway") }, - { 503, CONST_STR_LEN("503 Service Not Available") }, - { 504, CONST_STR_LEN("504 Gateway Timeout") }, - { 505, CONST_STR_LEN("505 HTTP Version Not Supported") }, - { 507, CONST_STR_LEN("507 Insufficient Storage") }, /* WebDAV */ + { 100, CONST_LEN_STR("100 Continue") }, + { 101, CONST_LEN_STR("101 Switching Protocols") }, + { 102, CONST_LEN_STR("102 Processing") }, /* WebDAV */ + { 200, CONST_LEN_STR("200 OK") }, + { 201, CONST_LEN_STR("201 Created") }, + { 202, CONST_LEN_STR("202 Accepted") }, + { 203, CONST_LEN_STR("203 Non-Authoritative Information") }, + { 204, CONST_LEN_STR("204 No Content") }, + { 205, CONST_LEN_STR("205 Reset Content") }, + { 206, CONST_LEN_STR("206 Partial Content") }, + { 207, CONST_LEN_STR("207 Multi-status") }, /* WebDAV */ + { 300, CONST_LEN_STR("300 Multiple Choices") }, + { 301, CONST_LEN_STR("301 Moved Permanently") }, + { 302, CONST_LEN_STR("302 Found") }, + { 303, CONST_LEN_STR("303 See Other") }, + { 304, CONST_LEN_STR("304 Not Modified") }, + { 305, CONST_LEN_STR("305 Use Proxy") }, + { 306, CONST_LEN_STR("306 (Unused)") }, + { 307, CONST_LEN_STR("307 Temporary Redirect") }, + { 308, CONST_LEN_STR("308 Permanent Redirect") }, + { 400, CONST_LEN_STR("400 Bad Request") }, + { 401, CONST_LEN_STR("401 Unauthorized") }, + { 402, CONST_LEN_STR("402 Payment Required") }, + { 403, CONST_LEN_STR("403 Forbidden") }, + { 404, CONST_LEN_STR("404 Not Found") }, + { 405, CONST_LEN_STR("405 Method Not Allowed") }, + { 406, CONST_LEN_STR("406 Not Acceptable") }, + { 407, CONST_LEN_STR("407 Proxy Authentication Required") }, + { 408, CONST_LEN_STR("408 Request Timeout") }, + { 409, CONST_LEN_STR("409 Conflict") }, + { 410, CONST_LEN_STR("410 Gone") }, + { 411, CONST_LEN_STR("411 Length Required") }, + { 412, CONST_LEN_STR("412 Precondition Failed") }, + { 413, CONST_LEN_STR("413 Request Entity Too Large") }, + { 414, CONST_LEN_STR("414 Request-URI Too Long") }, + { 415, CONST_LEN_STR("415 Unsupported Media Type") }, + { 416, CONST_LEN_STR("416 Requested Range Not Satisfiable") }, + { 417, CONST_LEN_STR("417 Expectation Failed") }, + { 422, CONST_LEN_STR("422 Unprocessable Entity") }, /* WebDAV */ + { 423, CONST_LEN_STR("423 Locked") }, /* WebDAV */ + { 424, CONST_LEN_STR("424 Failed Dependency") }, /* WebDAV */ + { 426, CONST_LEN_STR("426 Upgrade Required") }, /* TLS */ + { 500, CONST_LEN_STR("500 Internal Server Error") }, + { 501, CONST_LEN_STR("501 Not Implemented") }, + { 502, CONST_LEN_STR("502 Bad Gateway") }, + { 503, CONST_LEN_STR("503 Service Not Available") }, + { 504, CONST_LEN_STR("504 Gateway Timeout") }, + { 505, CONST_LEN_STR("505 HTTP Version Not Supported") }, + { 507, CONST_LEN_STR("507 Insufficient Storage") }, /* WebDAV */ - { -1, NULL, 0 } + { -1, 0, NULL } }; @@ -123,10 +125,10 @@ static const char *keyvalue_get_value(const keyvalue *kv, int k) { return NULL; } -static int keyvalue_get_key(const keyvalue *kv, const char *s) { - int i; - for (i = 0; kv[i].value; i++) { - if (0 == strcmp(kv[i].value, s)) return kv[i].key; +static int keyvalue_get_key(const keyvalue *kv, const char *s, unsigned int slen) { + for (int i = 0; kv[i].vlen; ++i) { + if (kv[i].vlen == slen && 0 == memcmp(kv[i].value, s, slen)) + return kv[i].key; } return -1; } @@ -144,20 +146,20 @@ const char *get_http_method_name(http_method_t i) { return keyvalue_get_value(http_methods, i); } -int get_http_version_key(const char *s) { - return keyvalue_get_key(http_versions, s); +int get_http_version_key(const char *s, size_t slen) { + return keyvalue_get_key(http_versions, s, (unsigned int)slen); } -http_method_t get_http_method_key(const char *s) { - return (http_method_t)keyvalue_get_key(http_methods, s); +http_method_t get_http_method_key(const char *s, size_t slen) { + return (http_method_t)keyvalue_get_key(http_methods, s, (unsigned int)slen); } void http_status_append(buffer * const b, const int status) { const keyvalue * const kv = http_status; int i; - for (i = 0; kv[i].key != status && kv[i].value; ++i) ; - if (kv[i].value) { + for (i = 0; kv[i].key != status && kv[i].vlen; ++i) ; + if (kv[i].vlen) { buffer_append_string_len(b, kv[i].value, kv[i].vlen); } else { @@ -169,8 +171,8 @@ void http_status_append(buffer * const b, const int status) { void http_method_append(buffer * const b, const http_method_t method) { const keyvalue * const kv = http_methods; int i; - for (i = 0; kv[i].key != method && kv[i].value; ++i) ; - if (kv[i].value) { + for (i = 0; kv[i].key != method && kv[i].vlen; ++i) ; + if (kv[i].vlen) { buffer_append_string_len(b, kv[i].value, kv[i].vlen); } } diff --git a/src/http_kv.h b/src/http_kv.h index 41abb6aa..8b73d7b2 100644 --- a/src/http_kv.h +++ b/src/http_kv.h @@ -61,8 +61,8 @@ typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } htt const char *get_http_status_name(int i); const char *get_http_version_name(int i); const char *get_http_method_name(http_method_t i); -int get_http_version_key(const char *s); -http_method_t get_http_method_key(const char *s); +int get_http_version_key(const char *s, size_t slen); +http_method_t get_http_method_key(const char *s, size_t slen); void http_status_append(buffer *b, int status); void http_method_append(buffer *b, http_method_t method); diff --git a/src/request.c b/src/request.c index 236e1ce1..b38df938 100644 --- a/src/request.c +++ b/src/request.c @@ -619,11 +619,8 @@ static size_t http_request_parse_reqline(server *srv, connection *con, buffer *h return http_request_header_line_invalid(srv, 400, "incomplete request line -> 400"); } - *(uri - 1) = '\0'; - *(proto - 1) = '\0'; - /* we got the first one :) */ - if (HTTP_METHOD_UNSET == (r = get_http_method_key(ptr))) { + if (HTTP_METHOD_UNSET == (r = get_http_method_key(ptr, uri - 1 - ptr))) { return http_request_header_line_invalid(srv, 501, "unknown http-method -> 501"); } @@ -674,6 +671,8 @@ static size_t http_request_parse_reqline(server *srv, connection *con, buffer *h return http_request_header_line_invalid(srv, 400, "unknown protocol -> 400"); } + *(proto - 1) = '\0'; /*(terminate for strchr())*/ + if (*uri == '/') { /* (common case) */ buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);