diff options
Diffstat (limited to 'event-httpd.c')
-rw-r--r-- | event-httpd.c | 95 |
1 files changed, 55 insertions, 40 deletions
diff --git a/event-httpd.c b/event-httpd.c index c080107..1b5df6a 100644 --- a/event-httpd.c +++ b/event-httpd.c @@ -22,8 +22,10 @@ static GHashTable *resource_hash; void close_client(struct client *c) { - if (c->request) - g_free(c->request); + g_free(c->method); + g_free(c->uri); + g_free(c->query); + g_free(c->version); g_object_unref(c->data); g_object_unref(c->conn); g_free(c); @@ -123,13 +125,51 @@ static void update(GObject *source, GAsyncResult *res, gpointer user_data) g_data_input_stream_read_line_async(c->data, 0, NULL, update, c); } -static bool parse_request(struct client *c, const char *line) +static void parse_request_line(struct client *c, const char *line) { + char **parts, **uri; + // In the interest of robustness, servers SHOULD ignore any empty // line(s) received where a Request-Line is expected. - if (!c->request) { - if (line[0]) - c->request = g_strdup(line); + if (!line[0]) + return; + + // Split the request line: Method SP Request-URI SP HTTP-Version + // We do not support early HTTP. + parts = g_strsplit(line, " ", 3); + if (!parts || !parts[0] || !parts[1] || !parts[2]) { + c->error = 400; + c->errstr = "Bad Request"; + g_strfreev(parts); + return; + } + + c->method = g_strdup(parts[0]); + c->version = g_strdup(parts[2]); + + // Split the URI and query string + uri = g_strsplit(parts[1], "?", 2); + g_strfreev(parts); + if (!uri || !uri[0]) { + c->error = 400; + c->errstr = "Bad Request"; + g_strfreev(uri); + return; + } + + // Unescape the URI + c->uri = g_uri_unescape_string(uri[0], NULL); + if (uri[1]) + c->query = g_strdup(uri[1]); + + g_strfreev(uri); +} + +static bool parse_request(struct client *c, const char *line) +{ + // Parse the request line + if (!c->method && !c->error) { + parse_request_line(c, line); return true; } @@ -157,7 +197,7 @@ static void receive(GObject *source, GAsyncResult *res, gpointer user_data) enum method method; GError *error = NULL; gsize len; - char *line, *uri, *query, *unescaped, *version; + char *line; bool more; line = g_data_input_stream_read_line_finish(c->data, res, &len, &error); @@ -178,50 +218,28 @@ static void receive(GObject *source, GAsyncResult *res, gpointer user_data) return; } - // End of request. Parse it. - // Find the URI - uri = strchr(c->request, ' '); - if (!uri) { - respond_error(c, 400, "Invalid request"); + // Did we encounter an error? + if (c->error) { + respond_error(c, c->error, c->errstr); return; } - *uri++ = '\0'; - - // Find the version - version = strchr(uri, ' '); - if (!version) { - respond_error(c, 400, "Invalid request"); - return; - } - - *version++ = '\0'; - // Check that the version is HTTP/1.x. We probably ought to // parse the major version better, as leading zeros should be // accepted. - if (!g_str_has_prefix(version, "HTTP/1.")) { + if (!g_str_has_prefix(c->version, "HTTP/1.")) { respond_error(c, 505, "HTTP Version Not Supported"); return; } - // Split the query string - query = strchr(uri, '?'); - if (query) - *query++ = '\0'; - - c->uri = uri; - c->query = query; - c->version = version; - // HTTP/1.1 and later can use chunked mode. Note that http 1.1 // allows leading zeros. - c->can_chunk = atoi(version + 7) != '0'; + c->can_chunk = atoi(c->version + 7) != '0'; // Check the method - if (!strcmp(c->request, "GET")) { + if (!strcmp(c->method, "GET")) { method = GET; - } else if (!strcmp(c->request, "UPDATE") && !c->forwarded) { + } else if (!strcmp(c->method, "UPDATE") && !c->forwarded) { // Update is only permitted if not forwarded through a // proxy. NOTE: this is the only way we control access. method = UPDATE; @@ -230,11 +248,8 @@ static void receive(GObject *source, GAsyncResult *res, gpointer user_data) return; } - // Unescape the URI - unescaped = g_uri_unescape_string(uri, NULL); - // Lookup the resource handler - resource = g_hash_table_lookup(resource_hash, unescaped); + resource = g_hash_table_lookup(resource_hash, c->uri); if (!resource) { respond_error(c, 404, "Not Found"); return; |