From 1aa0a9977bc7b7265c15275237b5fe343145f526 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 31 Oct 2018 12:26:50 +0000 Subject: [PATCH] Feature: Added all known HTTP methods and improved API --- httpp/httpp.c | 315 +++++++++++++++++++++++++++--------------- include/igloo/httpp.h | 36 +++++ 2 files changed, 239 insertions(+), 112 deletions(-) diff --git a/httpp/httpp.c b/httpp/httpp.c index 1290e11..1f5a075 100644 --- a/httpp/httpp.c +++ b/httpp/httpp.c @@ -59,61 +59,188 @@ static void _httpp_set_param_nocopy(igloo_avl_tree *tree, char *name, char *valu static void _httpp_set_param(igloo_avl_tree *tree, const char *name, const char *value); static igloo_http_var_t *igloo__httpp_get_param_var(igloo_avl_tree *tree, const char *name); +static const struct http_method { + const char *name; + const igloo_httpp_request_type_e req; + const igloo_httpp_request_info_t info; +} igloo_httpp__methods[] = { + /* RFC 7231 */ + {"GET", igloo_httpp_req_get, + igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_IS_CACHEABLE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY + }, + {"HEAD", igloo_httpp_req_head, + igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_IS_CACHEABLE + }, + {"POST", igloo_httpp_req_post, + igloo_HTTPP_REQUEST_IS_CACHEABLE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY + }, + {"PUT", igloo_httpp_req_put, + igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY + }, + {"DELETE", igloo_httpp_req_delete, + igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY + }, + {"CONNECT", igloo_httpp_req_connect, + igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY + }, + {"OPTIONS", igloo_httpp_req_options, + igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY + }, + {"TRACE", igloo_httpp_req_trace, + igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY + }, + /* RFC 5789 */ + {"PATCH", igloo_httpp_req_patch, + igloo_HTTPP_REQUEST_HAS_REQUEST_BODY|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY + }, + /* Icecast specific */ + {"SOURCE", igloo_httpp_req_source, + igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY + }, + {"PLAY", igloo_httpp_req_play, + igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY + }, + {"STATS", igloo_httpp_req_stats, + igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY + }, + + /* Other RFCs */ + /* + * tr -d \\r < www.iana.org/assignments/http-methods/methods.csv | while IFS=, read m s i r; do printf " {\"%-21s igloo_httpp_req_%s,\n /%c Safe: %s, Idempotent: %s, Reference: %s %c/\n igloo_HTTPP_REQUEST_INVALID\n },\n" "$m"\", $(tr A-Z- a-z_ <<<"$m") '*' "$s" "$i" "$r" '*'; done + */ + {"ACL", igloo_httpp_req_acl, + /* Safe: no, Idempotent: yes, Reference: "[RFC3744, Section 8.1]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"BASELINE-CONTROL", igloo_httpp_req_baseline_control, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 12.6]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"BIND", igloo_httpp_req_bind, + /* Safe: no, Idempotent: yes, Reference: "[RFC5842, Section 4]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"CHECKIN", igloo_httpp_req_checkin, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 4.4, Section 9.4]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"CHECKOUT", igloo_httpp_req_checkout, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 4.3, Section 8.8]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"COPY", igloo_httpp_req_copy, + /* Safe: no, Idempotent: yes, Reference: "[RFC4918, Section 9.8]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"LABEL", igloo_httpp_req_label, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 8.2]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"LINK", igloo_httpp_req_link, + /* Safe: no, Idempotent: yes, Reference: "[RFC2068, Section 19.6.1.2]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"LOCK", igloo_httpp_req_lock, + /* Safe: no, Idempotent: no, Reference: "[RFC4918, Section 9.10]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"MERGE", igloo_httpp_req_merge, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 11.2]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"MKACTIVITY", igloo_httpp_req_mkactivity, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 13.5]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"MKCALENDAR", igloo_httpp_req_mkcalendar, + /* Safe: no, Idempotent: yes, Reference: "[RFC4791, Section 5.3.1][RFC8144, Section 2.3]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"MKCOL", igloo_httpp_req_mkcol, + /* Safe: no, Idempotent: yes, Reference: "[RFC4918, Section 9.3][RFC5689, Section 3][RFC8144, Section 2.3]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"MKREDIRECTREF", igloo_httpp_req_mkredirectref, + /* Safe: no, Idempotent: yes, Reference: "[RFC4437, Section 6]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"MKWORKSPACE", igloo_httpp_req_mkworkspace, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 6.3]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"MOVE", igloo_httpp_req_move, + /* Safe: no, Idempotent: yes, Reference: "[RFC4918, Section 9.9]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"ORDERPATCH", igloo_httpp_req_orderpatch, + /* Safe: no, Idempotent: yes, Reference: "[RFC3648, Section 7]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"PRI", igloo_httpp_req_pri, + /* Safe: yes, Idempotent: yes, Reference: "[RFC7540, Section 3.5]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"PROPFIND", igloo_httpp_req_propfind, + /* Safe: yes, Idempotent: yes, Reference: "[RFC4918, Section 9.1][RFC8144, Section 2.1]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"PROPPATCH", igloo_httpp_req_proppatch, + /* Safe: no, Idempotent: yes, Reference: "[RFC4918, Section 9.2][RFC8144, Section 2.2]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"REBIND", igloo_httpp_req_rebind, + /* Safe: no, Idempotent: yes, Reference: "[RFC5842, Section 6]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"REPORT", igloo_httpp_req_report, + /* Safe: yes, Idempotent: yes, Reference: "[RFC3253, Section 3.6][RFC8144, Section 2.1]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"SEARCH", igloo_httpp_req_search, + /* Safe: yes, Idempotent: yes, Reference: "[RFC5323, Section 2]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"UNBIND", igloo_httpp_req_unbind, + /* Safe: no, Idempotent: yes, Reference: "[RFC5842, Section 5]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"UNCHECKOUT", igloo_httpp_req_uncheckout, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 4.5]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"UNLINK", igloo_httpp_req_unlink, + /* Safe: no, Idempotent: yes, Reference: "[RFC2068, Section 19.6.1.3]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"UNLOCK", igloo_httpp_req_unlock, + /* Safe: no, Idempotent: yes, Reference: "[RFC4918, Section 9.11]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"UPDATE", igloo_httpp_req_update, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 7.1]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"UPDATEREDIRECTREF", igloo_httpp_req_updateredirectref, + /* Safe: no, Idempotent: yes, Reference: "[RFC4437, Section 7]" */ + igloo_HTTPP_REQUEST_INVALID + }, + {"VERSION-CONTROL", igloo_httpp_req_version_control, + /* Safe: no, Idempotent: yes, Reference: "[RFC3253, Section 3.5]" */ + igloo_HTTPP_REQUEST_INVALID + }, +}; + igloo_httpp_request_info_t igloo_httpp_request_info(igloo_httpp_request_type_e req) { -#if 0 -#define igloo_HTTPP_REQUEST_IS_SAFE ((igloo_httpp_request_info_t)0x0001U) -#define igloo_HTTPP_REQUEST_IS_IDEMPOTENT ((igloo_httpp_request_info_t)0x0002U) -#define igloo_HTTPP_REQUEST_IS_CACHEABLE ((igloo_httpp_request_info_t)0x0004U) -#define igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY ((igloo_httpp_request_info_t)0x0010U) -#define igloo_HTTPP_REQUEST_HAS_REQUEST_BODY ((igloo_httpp_request_info_t)0x0100U) -#define igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY ((igloo_httpp_request_info_t)0x0200U) -#endif - switch (req) { - /* offical methods */ - case igloo_httpp_req_get: - return igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_IS_CACHEABLE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY; - break; - case igloo_httpp_req_post: - return igloo_HTTPP_REQUEST_IS_CACHEABLE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY; - break; - case igloo_httpp_req_put: - return igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY; - break; - case igloo_httpp_req_head: - return igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_IS_CACHEABLE; - break; - case igloo_httpp_req_options: - return igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY; - break; - case igloo_httpp_req_delete: - return igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY; - break; - case igloo_httpp_req_trace: - return igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_IS_IDEMPOTENT|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY; - break; - case igloo_httpp_req_connect: - return igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY; - break; + size_t i; - /* Icecast specific methods */ - case igloo_httpp_req_source: - return igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_REQUEST_BODY; - break; - case igloo_httpp_req_play: - return igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY; - break; - case igloo_httpp_req_stats: - return igloo_HTTPP_REQUEST_IS_SAFE|igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY; - break; - - /* Virtual and other methods */ - case igloo_httpp_req_none: - case igloo_httpp_req_unknown: - default: - return igloo_HTTPP_REQUEST_HAS_RESPONSE_BODY|igloo_HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY; - break; + for (i = 0; i < (sizeof(igloo_httpp__methods)/sizeof(*igloo_httpp__methods)); i++) { + if (igloo_httpp__methods[i].req == req) { + return igloo_httpp__methods[i].info; + } } + + return igloo_HTTPP_REQUEST_INVALID; } igloo_http_parser_t *igloo_httpp_create_parser(void) @@ -495,42 +622,9 @@ int igloo_httpp_parse(igloo_http_parser_t *parser, const char *http_data, unsign } if (parser->req_type != igloo_httpp_req_none && parser->req_type != igloo_httpp_req_unknown) { - switch (parser->req_type) { - case igloo_httpp_req_get: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "GET"); - break; - case igloo_httpp_req_post: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "POST"); - break; - case igloo_httpp_req_put: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "PUT"); - break; - case igloo_httpp_req_head: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "HEAD"); - break; - case igloo_httpp_req_options: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "OPTIONS"); - break; - case igloo_httpp_req_delete: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "DELETE"); - break; - case igloo_httpp_req_trace: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "TRACE"); - break; - case igloo_httpp_req_connect: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "CONNECT"); - break; - case igloo_httpp_req_source: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "SOURCE"); - break; - case igloo_httpp_req_play: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "PLAY"); - break; - case igloo_httpp_req_stats: - igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, "STATS"); - break; - default: - break; + const char *method = igloo_httpp_method_to_str(parser->req_type); + if (method) { + igloo_httpp_setvar(parser, igloo_HTTPP_VAR_REQ_TYPE, method); } } else { free(data); @@ -921,31 +1015,28 @@ static int igloo__free_vars(void *key) return 1; } -igloo_httpp_request_type_e igloo_httpp_str_to_method(const char * method) { - if (strcasecmp("GET", method) == 0) { - return igloo_httpp_req_get; - } else if (strcasecmp("POST", method) == 0) { - return igloo_httpp_req_post; - } else if (strcasecmp("PUT", method) == 0) { - return igloo_httpp_req_put; - } else if (strcasecmp("HEAD", method) == 0) { - return igloo_httpp_req_head; - } else if (strcasecmp("OPTIONS", method) == 0) { - return igloo_httpp_req_options; - } else if (strcasecmp("DELETE", method) == 0) { - return igloo_httpp_req_delete; - } else if (strcasecmp("TRACE", method) == 0) { - return igloo_httpp_req_trace; - } else if (strcasecmp("CONNECT", method) == 0) { - return igloo_httpp_req_connect; - } else if (strcasecmp("SOURCE", method) == 0) { - return igloo_httpp_req_source; - } else if (strcasecmp("PLAY", method) == 0) { - return igloo_httpp_req_play; - } else if (strcasecmp("STATS", method) == 0) { - return igloo_httpp_req_stats; - } else { - return igloo_httpp_req_unknown; +igloo_httpp_request_type_e igloo_httpp_str_to_method(const char * method) +{ + size_t i; + + for (i = 0; i < (sizeof(igloo_httpp__methods)/sizeof(*igloo_httpp__methods)); i++) { + if (strcasecmp(igloo_httpp__methods[i].name, method) == 0) { + return igloo_httpp__methods[i].req; + } } + + return igloo_httpp_req_unknown; } +const char * igloo_httpp_method_to_str(igloo_httpp_request_type_e method) +{ + size_t i; + + for (i = 0; i < (sizeof(igloo_httpp__methods)/sizeof(*igloo_httpp__methods)); i++) { + if (igloo_httpp__methods[i].req == method) { + return igloo_httpp__methods[i].name; + } + } + + return NULL; +} diff --git a/include/igloo/httpp.h b/include/igloo/httpp.h index 39f8796..efb466d 100644 --- a/include/igloo/httpp.h +++ b/include/igloo/httpp.h @@ -62,17 +62,52 @@ typedef enum httpp_request_type_tag { igloo_httpp_req_delete, igloo_httpp_req_trace, igloo_httpp_req_connect, + igloo_httpp_req_patch, /* Icecast SOURCE, to be replaced with PUT some day */ igloo_httpp_req_source, /* XXX: ??? */ igloo_httpp_req_play, /* Icecast 2.x STATS, to request a live stream of stats events */ igloo_httpp_req_stats, + /* Other: + * Source: https://www.iana.org/assignments/http-methods/methods.csv, 2018-10-31 + */ + igloo_httpp_req_acl, + igloo_httpp_req_baseline_control, + igloo_httpp_req_bind, + igloo_httpp_req_checkin, + igloo_httpp_req_checkout, + igloo_httpp_req_copy, + igloo_httpp_req_label, + igloo_httpp_req_link, + igloo_httpp_req_lock, + igloo_httpp_req_merge, + igloo_httpp_req_mkactivity, + igloo_httpp_req_mkcalendar, + igloo_httpp_req_mkcol, + igloo_httpp_req_mkredirectref, + igloo_httpp_req_mkworkspace, + igloo_httpp_req_move, + igloo_httpp_req_orderpatch, + igloo_httpp_req_pri, + igloo_httpp_req_propfind, + igloo_httpp_req_proppatch, + igloo_httpp_req_rebind, + igloo_httpp_req_report, + igloo_httpp_req_search, + igloo_httpp_req_unbind, + igloo_httpp_req_uncheckout, + igloo_httpp_req_unlink, + igloo_httpp_req_unlock, + igloo_httpp_req_update, + igloo_httpp_req_updateredirectref, + igloo_httpp_req_version_control, /* Used if request method is unknown. MUST BE LAST ONE IN LIST. */ igloo_httpp_req_unknown } igloo_httpp_request_type_e; typedef unsigned int igloo_httpp_request_info_t; +#define igloo_HTTPP_REQUEST_INVALID ((igloo_httpp_request_info_t)0x1000U) #define igloo_HTTPP_REQUEST_IS_SAFE ((igloo_httpp_request_info_t)0x0001U) #define igloo_HTTPP_REQUEST_IS_IDEMPOTENT ((igloo_httpp_request_info_t)0x0002U) #define igloo_HTTPP_REQUEST_IS_CACHEABLE ((igloo_httpp_request_info_t)0x0004U) @@ -127,6 +162,7 @@ int igloo_httpp_release(igloo_http_parser_t *parser); /* util functions */ igloo_httpp_request_type_e igloo_httpp_str_to_method(const char * method); +const char * igloo_httpp_method_to_str(igloo_httpp_request_type_e method); #ifdef __cplusplus }