From 73e6b5efc9531bded19e2c63f912aaf509e56b57 Mon Sep 17 00:00:00 2001 From: Hardening Date: Mon, 6 May 2013 22:57:39 +0200 Subject: [PATCH] Misc fixes in HTTP parsing * HTTP headers are case insensitive (see RFC2616 4.2 for details) * Check errors when parsing status line * treat LWS around the colon in headers --- libfreerdp/core/gateway/http.c | 79 ++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c index 9c2ee81fb..335df36e4 100644 --- a/libfreerdp/core/gateway/http.c +++ b/libfreerdp/core/gateway/http.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "http.h" @@ -280,31 +281,36 @@ void http_request_free(HttpRequest* http_request) } } -void http_response_parse_header_status_line(HttpResponse* http_response, char* status_line) +BOOL http_response_parse_header_status_line(HttpResponse* http_response, char* status_line) { char* separator; char* status_code; char* reason_phrase; separator = strchr(status_line, ' '); + if (!separator) + return FALSE; status_code = separator + 1; separator = strchr(status_code, ' '); + if (!separator) + return FALSE; reason_phrase = separator + 1; *separator = '\0'; http_response->StatusCode = atoi(status_code); http_response->ReasonPhrase = _strdup(reason_phrase); *separator = ' '; + return TRUE; } void http_response_parse_header_field(HttpResponse* http_response, char* name, char* value) { - if (strcmp(name, "Content-Length") == 0) + if (_stricmp(name, "Content-Length") == 0) { http_response->ContentLength = atoi(value); } - else if (strcmp(name, "Authorization") == 0) + else if (_stricmp(name, "Authorization") == 0) { char* separator; @@ -320,7 +326,7 @@ void http_response_parse_header_field(HttpResponse* http_response, char* name, c *separator = ' '; } } - else if (strcmp(name, "WWW-Authenticate") == 0) + else if (_stricmp(name, "WWW-Authenticate") == 0) { char* separator; @@ -348,36 +354,63 @@ void http_response_parse_header_field(HttpResponse* http_response, char* name, c } } -void http_response_parse_header(HttpResponse* http_response) +BOOL http_response_parse_header(HttpResponse* http_response) { int count; char* line; char* name; char* value; - char* separator; + char* colon_pos; + char* end_of_header; + char end_of_header_char; + char c; - http_response_parse_header_status_line(http_response, http_response->lines[0]); + if (!http_response_parse_header_status_line(http_response, http_response->lines[0])) + return FALSE; for (count = 1; count < http_response->count; count++) { line = http_response->lines[count]; - separator = strstr(line, ": "); + /** + * name end_of_header + * | | + * v v + *
:
+ * ^ ^ + * | | + * colon_pos value + */ + colon_pos = strchr(line, ':'); + if ((colon_pos == NULL) || (colon_pos == line)) + return FALSE; - if (separator == NULL) - continue; - - separator[0] = '\0'; - separator[1] = '\0'; + /* retrieve the position just after header name */ + for(end_of_header = colon_pos; end_of_header != line; end_of_header--) + { + c = end_of_header[-1]; + if (c != ' ' && c != '\t' && c != ':') + break; + } + if (end_of_header == line) + return FALSE; + end_of_header_char = *end_of_header; + *end_of_header = '\0'; name = line; - value = separator + 2; + + /* eat space and tabs before header value */ + for (value = colon_pos + 1; *value; value++) + { + if ((*value != ' ') && (*value != '\t')) + break; + } http_response_parse_header_field(http_response, name, value); - separator[0] = ':'; - separator[1] = ' '; + *end_of_header = end_of_header_char; } + return TRUE; } void http_response_print(HttpResponse* http_response) @@ -435,11 +468,7 @@ HttpResponse* http_response_recv(rdpTls* tls) header_end = strstr((char*) buffer, "\r\n\r\n"); - if (header_end) - { - header_end += 2; - } - else + if (!header_end) { fprintf(stderr, "http_response_recv: invalid response:\n"); winpr_HexDump(buffer, status); @@ -447,6 +476,8 @@ HttpResponse* http_response_recv(rdpTls* tls) return NULL; } + header_end += 2; + if (header_end != NULL) { int count; @@ -478,7 +509,11 @@ HttpResponse* http_response_recv(rdpTls* tls) count++; } - http_response_parse_header(http_response); + if (!http_response_parse_header(http_response)) + { + http_response_free(http_response); + return NULL; + } if (http_response->ContentLength > 0) {