ws_parse_state_t _ws_read_http_headers(ws_t ws, struct evbuffer *in) { char *line = NULL; char *header_name = NULL; char *header_val = NULL; ws_parse_state_t state = WS_PARSE_STATE_NEED_MORE; size_t len; assert(ws); assert(in); // TODO: Set a max header size to allow. while ((line = evbuffer_readln(in, &len, EVBUFFER_EOL_CRLF)) != NULL) { // Check for end of HTTP response (empty line). if (*line == '\0') { LIBWS_LOG(LIBWS_DEBUG2, "End of HTTP request"); state = WS_PARSE_STATE_SUCCESS; break; } if (_ws_parse_http_header(line, &header_name, &header_val)) { LIBWS_LOG(LIBWS_ERR, "Failed to parse HTTP upgrade " "repsonse line: %s", line); state = WS_PARSE_STATE_ERROR; break; } LIBWS_LOG(LIBWS_DEBUG2, "%s: %s", header_name, header_val); // Let the user get the header. if (ws->header_cb) { LIBWS_LOG(LIBWS_DEBUG2, " Call header callback"); if (ws->header_cb(ws, header_name, header_val, ws->header_arg)) { LIBWS_LOG(LIBWS_DEBUG, "User header callback cancelled " "handshake"); state = WS_PARSE_STATE_USER_ABORT; break; } } if (_ws_validate_http_headers(ws, header_name, header_val)) { LIBWS_LOG(LIBWS_ERR, " invalid"); state = WS_PARSE_STATE_ERROR; break; } LIBWS_LOG(LIBWS_DEBUG2, " valid"); _ws_free(line); line = NULL; if (header_name) { _ws_free(header_name); header_name = NULL; } if (header_val) { _ws_free(header_val); header_val = NULL; } } if (line) _ws_free(line); if (header_name) _ws_free(header_name); if (header_val) _ws_free(header_val); return state; }
int TEST_ws_parse_http_header(int argc, char **argv) { int ret = 0; char *line = "Origin: arne weise "; char *invalid_line = "Blarg"; char *header_name; char *header_val; int i; libws_test_HEADLINE("TEST_ws_parse_http_header"); if (libws_test_init(argc, argv)) return -1; libws_test_STATUS("Parse header \"%s\"", line); if (_ws_parse_http_header(line, &header_name, &header_val)) { libws_test_FAILURE("Failed to parse header \"%s\"", line); ret = -1; } else { if (!header_name || !header_val) { if (!header_name) { libws_test_FAILURE("Header name NULL after parse"); ret = -1; } if (!header_name) { libws_test_FAILURE("Header val NULL after parse"); ret = -1; } } else { libws_test_SUCCESS("Parsed header \"%s\". " "Name = \"%s\", Value = \"%s\"", line, header_name, header_val); } } free(header_name); free(header_val); libws_test_STATUS("Parse invalid line:"); if (_ws_parse_http_header(invalid_line, &header_name, &header_val)) { if (header_name || header_val) { if (header_name) { libws_test_FAILURE("Header name not NULL after parse failure"); ret = -1; } if (header_name) { libws_test_FAILURE("Header value not NULL after parse failure"); ret = -1; } } else { libws_test_SUCCESS("Header name and value NULL after failed parse"); } } libws_test_STATUS("Parse NULL line:"); if (_ws_parse_http_header(NULL, &header_name, &header_val)) { libws_test_SUCCESS("Failed on NULL input"); } else { libws_test_FAILURE("Did not fail o NULL input"); ret |= -1; } { int http_major_version; int http_minor_verson; int http_status; if (_ws_parse_http_status(NULL, &http_major_version, &http_minor_verson, &http_status)) { libws_test_SUCCESS("Failed to parse HTTP status with NULL input"); } else { libws_test_FAILURE("Success parsing HTTP status with NULL input"); ret |= -1; } if (_ws_parse_http_status("HTTP/1.1 abc", &http_major_version, &http_minor_verson, &http_status)) { libws_test_SUCCESS("Failed to parse HTTP status with NULL input"); } else { libws_test_FAILURE("Success parsing HTTP status with NULL input"); ret |= -1; } } ws_set_memory_functions(libws_test_malloc, free, libws_test_realloc); for (i = 1; i <= 2; i++) { libws_test_STATUS("Test failing malloc on allocation: %d", i); libws_test_set_malloc_fail_count(i); if (_ws_parse_http_header(line, &header_name, &header_val)) { libws_test_SUCCESS("Failed as expected on NULL memory allocation " "after %d allocations", i); } else { libws_test_FAILURE("Did not fail on NULL memory allocation " "after %d allocations", i); ret |= -1; } } ws_set_memory_functions(NULL, NULL, NULL); return ret; }