|
@@ -6927,17 +6927,15 @@ mg_store_body(struct mg_connection *conn, const char *path)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-/* Parse HTTP headers from the given buffer, advance buffer to the point
|
|
|
|
- * where parsing stopped. */
|
|
|
|
-static void
|
|
|
|
|
|
+/* Parse HTTP headers from the given buffer, advance buf pointer
|
|
|
|
+ * to the point where parsing stopped.
|
|
|
|
+ * All parameters must be valid pointers (not NULL).
|
|
|
|
+ * Return <0 on error. */
|
|
|
|
+static int
|
|
parse_http_headers(char **buf, struct mg_request_info *ri)
|
|
parse_http_headers(char **buf, struct mg_request_info *ri)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- if (!ri) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
ri->num_headers = 0;
|
|
ri->num_headers = 0;
|
|
|
|
|
|
for (i = 0; i < (int)ARRAY_SIZE(ri->http_headers); i++) {
|
|
for (i = 0; i < (int)ARRAY_SIZE(ri->http_headers); i++) {
|
|
@@ -6945,24 +6943,31 @@ parse_http_headers(char **buf, struct mg_request_info *ri)
|
|
while ((*dp != ':') && (*dp >= 32) && (*dp <= 126)) {
|
|
while ((*dp != ':') && (*dp >= 32) && (*dp <= 126)) {
|
|
dp++;
|
|
dp++;
|
|
}
|
|
}
|
|
- if ((dp == *buf) || (*dp != ':')) {
|
|
|
|
- /* This is not a valid field. */
|
|
|
|
|
|
+ if (dp == *buf) {
|
|
|
|
+ /* End of headers reached. */
|
|
break;
|
|
break;
|
|
- } else {
|
|
|
|
- /* (*dp == ':') */
|
|
|
|
- *dp = 0;
|
|
|
|
- ri->http_headers[i].name = *buf;
|
|
|
|
- do {
|
|
|
|
- dp++;
|
|
|
|
- } while (*dp == ' ');
|
|
|
|
|
|
+ }
|
|
|
|
+ if (*dp != ':') {
|
|
|
|
+ /* This is not a valid field. */
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
|
|
- ri->http_headers[i].value = dp;
|
|
|
|
- *buf = dp + strcspn(dp, "\r\n");
|
|
|
|
- if (((*buf)[0] != '\r') || ((*buf)[1] != '\n')) {
|
|
|
|
- *buf = NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ /* End of header key (*dp == ':') */
|
|
|
|
+ /* Truncate here and set the key name */
|
|
|
|
+ *dp = 0;
|
|
|
|
+ ri->http_headers[i].name = *buf;
|
|
|
|
+ do {
|
|
|
|
+ dp++;
|
|
|
|
+ } while (*dp == ' ');
|
|
|
|
+
|
|
|
|
+ /* The rest of the line is the value */
|
|
|
|
+ ri->http_headers[i].value = dp;
|
|
|
|
+ *buf = dp + strcspn(dp, "\r\n");
|
|
|
|
+ if (((*buf)[0] != '\r') || ((*buf)[1] != '\n')) {
|
|
|
|
+ *buf = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
ri->num_headers = i + 1;
|
|
ri->num_headers = i + 1;
|
|
if (*buf) {
|
|
if (*buf) {
|
|
(*buf)[0] = 0;
|
|
(*buf)[0] = 0;
|
|
@@ -6978,6 +6983,7 @@ parse_http_headers(char **buf, struct mg_request_info *ri)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ return ri->num_headers;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -7012,17 +7018,19 @@ is_valid_http_method(const char *method)
|
|
|
|
|
|
/* Parse HTTP request, fill in mg_request_info structure.
|
|
/* Parse HTTP request, fill in mg_request_info structure.
|
|
* This function modifies the buffer by NUL-terminating
|
|
* This function modifies the buffer by NUL-terminating
|
|
- * HTTP request components, header names and header values. */
|
|
|
|
|
|
+ * 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. */
|
|
static int
|
|
static int
|
|
parse_http_message(char *buf, int len, struct mg_request_info *ri)
|
|
parse_http_message(char *buf, int len, struct mg_request_info *ri)
|
|
{
|
|
{
|
|
int is_request, request_length;
|
|
int is_request, request_length;
|
|
char *start_line;
|
|
char *start_line;
|
|
|
|
|
|
- if (!ri) {
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
request_length = get_request_len(buf, len);
|
|
request_length = get_request_len(buf, len);
|
|
|
|
|
|
if (request_length > 0) {
|
|
if (request_length > 0) {
|
|
@@ -7043,17 +7051,24 @@ parse_http_message(char *buf, int len, struct mg_request_info *ri)
|
|
ri->request_uri = skip(&start_line, " ");
|
|
ri->request_uri = skip(&start_line, " ");
|
|
ri->http_version = start_line;
|
|
ri->http_version = start_line;
|
|
|
|
|
|
- /* HTTP message could be either HTTP request or HTTP response, e.g.
|
|
|
|
- * "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */
|
|
|
|
|
|
+ /* 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);
|
|
is_request = is_valid_http_method(ri->request_method);
|
|
if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0)
|
|
if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0)
|
|
|| (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
|
|
|| (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
|
|
- request_length = -1;
|
|
|
|
- } else {
|
|
|
|
- if (is_request) {
|
|
|
|
- ri->http_version += 5;
|
|
|
|
- }
|
|
|
|
- parse_http_headers(&buf, ri);
|
|
|
|
|
|
+ /* Not a valid request or response: invalid */
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ if (is_request) {
|
|
|
|
+ ri->http_version += 5;
|
|
|
|
+ }
|
|
|
|
+ if (parse_http_headers(&buf, ri) < 0) {
|
|
|
|
+ /* Error while parsing headers */
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return request_length;
|
|
return request_length;
|