/** * Parse an HTTP parameter * * \param input Pointer to current input byte. Updated on exit. * \param parameter Pointer to location to receive on-heap parameter. * \return NSERROR_OK on success, * NSERROR_NOMEM on memory exhaustion * * The returned parameter is owned by the caller. */ static nserror http_parse_parameter(const char **input, http_parameter **parameter) { const char *pos = *input; char *name; char *value; http_parameter *param; nserror error; /* token "=" ( token | quoted-string ) */ error = http_parse_token(&pos, &name); if (error != NSERROR_OK) return error; while (*pos == ' ' || *pos == '\t') pos++; if (*pos != '=') { value = strdup(""); if (value == NULL) { free(name); return NSERROR_NOMEM; } } else { pos++; while (*pos == ' ' || *pos == '\t') pos++; if (*pos == '"') error = http_parse_quoted_string(&pos, &value); else error = http_parse_token(&pos, &value); if (error != NSERROR_OK) { free(name); return error; } } param = malloc(sizeof(*param)); if (param == NULL) { free(value); free(name); return NSERROR_NOMEM; } param->next = NULL; param->name = name; param->value = value; *parameter = param; *input = pos; return NSERROR_OK; }
int http_parse_token_list_next(struct http_parser *parser, const char **token_r) { /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21; Appendix B: For compatibility with legacy list rules, recipients SHOULD accept empty list elements. In other words, consumers would follow the list productions: #element => [ ( "," / element ) *( OWS "," [ OWS element ] ) ] 1#element => *( "," OWS ) element *( OWS "," [ OWS element ] ) */ for (;;) { if (http_parse_token(parser, token_r) > 0) break; http_parse_ows(parser); if (parser->cur >= parser->end || parser->cur[0] != ',') return 0; parser->cur++; http_parse_ows(parser); } return 1; }
int http_parse_token_or_qstring(struct http_parser *parser, const char **word_r) { if (parser->cur >= parser->end) return 0; if (parser->cur[0] == '"') return http_parse_quoted_string(parser, word_r); return http_parse_token(parser, word_r); }
static int http_request_parse_expect_header(struct http_request_parser *parser, struct http_request *request, const struct http_header_field *hdr) { struct http_message_parser *_parser = &parser->parser; struct http_parser hparser; bool parse_error = FALSE; unsigned int num_expectations = 0; /* Expect = 1#expectation expectation = expect-name [ BWS "=" BWS expect-value ] *( OWS ";" [ OWS expect-param ] ) expect-param = expect-name [ BWS "=" BWS expect-value ] expect-name = token expect-value = token / quoted-string */ http_parser_init(&hparser, (const unsigned char *)hdr->value, hdr->size); while (!parse_error) { const char *expect_name, *expect_value; /* expect-name */ if (http_parse_token(&hparser, &expect_name) > 0) { num_expectations++; if (strcasecmp(expect_name, "100-continue") == 0) { request->expect_100_continue = TRUE; } else { /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23 Section 5.1.1: If all received Expect header field(s) are syntactically valid but contain an expectation that the recipient does not understand or cannot comply with, the recipient MUST respond with a 417 (Expectation Failed) status code. A recipient of a syntactically invalid Expectation header field MUST respond with a 4xx status code other than 417. --> Must check rest of expect header syntax before returning error. */ if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; _parser->error = t_strdup_printf ("Unknown Expectation `%s'", expect_name); } } /* BWS "=" BWS */ http_parse_ows(&hparser); if (hparser.cur >= hparser.end) break; if (*hparser.cur == '=') { hparser.cur++; http_parse_ows(&hparser); /* value */ if (http_parse_word(&hparser, &expect_value) <= 0) { parse_error = TRUE; break; } if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; _parser->error = t_strdup_printf ("Expectation `%s' has unexpected value", expect_name); } } /* *( OWS ";" [ OWS expect-param ] ) */ while (!parse_error) { const char *attribute, *value; /* OWS ";" */ http_parse_ows(&hparser); if (hparser.cur >= hparser.end || *hparser.cur != ';') break; hparser.cur++; http_parse_ows(&hparser); /* expect-param */ if (http_parse_token(&hparser, &attribute) <= 0) { parse_error = TRUE; break; } /* BWS "=" BWS */ http_parse_ows(&hparser); if (hparser.cur >= hparser.end || *hparser.cur != '=') { parse_error = TRUE; break; } hparser.cur++; http_parse_ows(&hparser); /* value */ if (http_parse_word(&hparser, &value) <= 0) { parse_error = TRUE; break; } if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; _parser->error = t_strdup_printf ("Expectation `%s' has unknown parameter `'%s'", expect_name, attribute); } } if (parse_error) break; } http_parse_ows(&hparser); if (hparser.cur >= hparser.end || *hparser.cur != ',') break; hparser.cur++; http_parse_ows(&hparser); } if (parse_error || hparser.cur < hparser.end) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; _parser->error = "Invalid Expect header"; return -1; } if (parser->error_code != HTTP_REQUEST_PARSE_ERROR_NONE) return -1; if (num_expectations == 0) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; _parser->error = "Empty Expect header"; return -1; } return 0; }
/* See http.h for documentation */ nserror http_parse_content_type(const char *header_value, char **media_type, http_parameter **parameters) { const char *pos = header_value; char *type; char *subtype = NULL; http_parameter *params = NULL; char *mime; size_t mime_len; nserror error; /* type "/" subtype *( ";" parameter ) */ while (*pos == ' ' || *pos == '\t') pos++; error = http_parse_token(&pos, &type); if (error != NSERROR_OK) return error; while (*pos == ' ' || *pos == '\t') pos++; if (*pos == '/') { pos++; while (*pos == ' ' || *pos == '\t') pos++; error = http_parse_token(&pos, &subtype); if (error != NSERROR_OK) { free(type); return error; } while (*pos == ' ' || *pos == '\t') pos++; if (*pos == ';') { pos++; while (*pos == ' ' || *pos == '\t') pos++; error = http_parse_parameter_list(&pos, ¶ms); if (error != NSERROR_OK) { free(subtype); free(type); return error; } } } /* <type> + <subtype> + '/' */ mime_len = strlen(type) + (subtype != NULL ? strlen(subtype) : 0) + 1; mime = malloc(mime_len + 1); if (mime == NULL) { http_parameter_list_destroy(params); free(subtype); free(type); return NSERROR_OK; } sprintf(mime, "%s/%s", type, subtype != NULL ? subtype : ""); free(subtype); free(type); *media_type = mime; *parameters = params; return NSERROR_OK; }
static int http_request_parse_expect_header(struct http_request_parser *parser, struct http_request *request, const struct http_header_field *hdr) { struct http_message_parser *_parser = &parser->parser; struct http_parser hparser; bool parse_error = FALSE; unsigned int num_expectations = 0; /* RFC 7231, Section 5.1.1: Expect = "100-continue" */ // FIXME: simplify; RFC 7231 discarded Expect extension mechanism http_parser_init(&hparser, (const unsigned char *)hdr->value, hdr->size); while (!parse_error) { const char *expect_name, *expect_value; /* expect-name */ if (http_parse_token(&hparser, &expect_name) > 0) { num_expectations++; if (strcasecmp(expect_name, "100-continue") == 0) { request->expect_100_continue = TRUE; } else { if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; _parser->error = t_strdup_printf ("Unknown Expectation `%s'", expect_name); } } /* BWS "=" BWS */ http_parse_ows(&hparser); if (hparser.cur >= hparser.end) break; if (*hparser.cur == '=') { hparser.cur++; http_parse_ows(&hparser); /* value */ if (http_parse_token_or_qstring(&hparser, &expect_value) <= 0) { parse_error = TRUE; break; } if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; _parser->error = t_strdup_printf ("Expectation `%s' has unexpected value", expect_name); } } /* *( OWS ";" [ OWS expect-param ] ) */ while (!parse_error) { const char *attribute, *value; /* OWS ";" */ http_parse_ows(&hparser); if (hparser.cur >= hparser.end || *hparser.cur != ';') break; hparser.cur++; http_parse_ows(&hparser); /* expect-param */ if (http_parse_token(&hparser, &attribute) <= 0) { parse_error = TRUE; break; } /* BWS "=" BWS */ http_parse_ows(&hparser); if (hparser.cur >= hparser.end || *hparser.cur != '=') { parse_error = TRUE; break; } hparser.cur++; http_parse_ows(&hparser); /* value */ if (http_parse_token_or_qstring(&hparser, &value) <= 0) { parse_error = TRUE; break; } if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; _parser->error = t_strdup_printf ("Expectation `%s' has unknown parameter `'%s'", expect_name, attribute); } } if (parse_error) break; } http_parse_ows(&hparser); if (hparser.cur >= hparser.end || *hparser.cur != ',') break; hparser.cur++; http_parse_ows(&hparser); } if (parse_error || hparser.cur < hparser.end) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; _parser->error = "Invalid Expect header"; return -1; } if (parser->error_code != HTTP_REQUEST_PARSE_ERROR_NONE) return -1; if (num_expectations == 0) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST; _parser->error = "Empty Expect header"; return -1; } return 0; }