diff options
Diffstat (limited to 'http.c')
-rw-r--r-- | http.c | 139 |
1 files changed, 99 insertions, 40 deletions
@@ -1,69 +1,126 @@ #include "http.h" +#include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -struct http_request http_parse_request(const char *reqstr) +ssize_t http_parse_request_line(const char *reqline, struct http_request *req_out) { char uribuf[CFWS_MAXURI]; size_t urilen = 0, query_len = 0; - const char *counter; - struct http_request req; - req.method = HTTP_METHOD_UNKNOWN; - req.uri = NULL; - req.query_str = NULL; - req.body = NULL; + const char *ch = reqline; - if (strncmp(reqstr, "GET ", 4) == 0) { - req.method = HTTP_METHOD_GET; - counter = reqstr + 4; - } else if (strncmp(reqstr, "POST ", 5) == 0) { - req.method = HTTP_METHOD_POST; - counter = reqstr + 5; + /* Quick 'n' dirty strncmp to determine the request method. */ + if (strncmp(reqline, "GET ", 4) == 0) { + req_out->method = HTTP_METHOD_GET; + ch += 4; + } else if (strncmp(reqline, "POST ", 5) == 0) { + req_out->method = HTTP_METHOD_POST; + ch += 5; } else { - fprintf(stderr, "Unhandled request type: %s\n", reqstr); - return req; + fprintf(stderr, "Unhandled request type: '%s'\n", reqline); + return -1; + } + + /* The first char after the first space should be a slash, otherwise + * there's either an invalid URI or something we don't handle yet. */ + if (*ch != '/') { + fprintf(stderr, "Invalid URI string: '%s'\n", ch); + return -1; } - while (*counter != ' ' && *counter != '?' && *counter != 0 - && urilen < CFWS_MAXURI) { - uribuf[urilen++] = *counter; - ++counter; + /* Copy URI path into a buffer, until we reach a space, query string, or + * one of the buffers reaches the end. */ + while (*ch != ' ' && *ch != '?' && *ch != 0 && urilen < CFWS_MAXURI) { + uribuf[urilen++] = *ch; + ++ch; } - req.uri = malloc(urilen + 1); - memcpy(req.uri, uribuf, urilen); - req.uri[urilen] = '\0'; + req_out->uri = malloc(urilen + 1); + memcpy(req_out->uri, uribuf, urilen); + req_out->uri[urilen] = '\0'; /* Parse the query string if one exists. */ - if (*counter == '?') { - /* Skip the question mark at the beginning. */ - counter++; - - while (*counter != ' ' && *counter != 0 - && query_len < CFWS_MAXURI) { - uribuf[query_len++] = *counter; - ++counter; + if (*ch == '?') { + ch++; /* Skip the question mark at the beginning. */ + + while (*ch != ' ' && *ch != 0 && query_len < CFWS_MAXURI) { + uribuf[query_len++] = *ch; + ++ch; } - req.query_str = malloc(query_len + 1); - memcpy(req.query_str, uribuf, query_len); - req.query_str[query_len] = '\0'; + req_out->query_str = malloc(query_len + 1); + memcpy(req_out->query_str, uribuf, query_len); + req_out->query_str[query_len] = '\0'; + } + + /* Lastly, read the HTTP version and for now make sure it's HTTP/1.1. */ + if (strncmp(ch, " HTTP/1.1\r\n", 9) != 0) { + fprintf(stderr, "Invalid HTTP version: '%s'", ch); + return -1; } - /* TODO: Parse request headers. For now they are just ignored. */ - counter = strstr(reqstr, "\r\n\r\n"); - if (req.method == HTTP_METHOD_POST) { - size_t body_len; - counter += 4; + ch += 9; + return ch - reqline; +} + +struct http_request http_parse_request(const char *reqstr) +{ + const char *current_line = reqstr; + bool has_parsed_header = false; - body_len = strlen(counter); + struct http_request req; + req.method = HTTP_METHOD_UNKNOWN; + req.uri = NULL; + req.query_str = NULL; + req.cookie = NULL; + req.body = NULL; + + while (current_line) { + char *next_line = strstr(current_line, "\r\n"); + size_t line_length = 0; + if (next_line) { + line_length = next_line - current_line; + *next_line = '\0'; + next_line++; + } + + if (!has_parsed_header) { + http_parse_request_line(current_line, &req); + has_parsed_header = true; + } else { + if (line_length == 0) { + /* An empty line means we are at the end of the + * request headers. */ + current_line = next_line ? (next_line + 1) : NULL; + break; + } + + if (strncmp(current_line, "Cookie: ", 8) == 0) { + const char *cookie_str = current_line + 8; + size_t cookie_length = next_line - cookie_str; + + req.cookie = malloc(cookie_length + 1); + memcpy(req.cookie, cookie_str, cookie_length); + req.cookie[cookie_length] = '\0'; + } + } + + if (next_line) + *next_line = '\n'; + current_line = next_line ? (next_line + 1) : NULL; + } + + /* Copy the request body if we have one */ + if (current_line && *current_line != '\0') { + size_t body_len; + body_len = strlen(current_line); req.body = malloc(body_len + 1); - memcpy(req.body, counter, body_len); + memcpy(req.body, current_line, body_len); req.body[body_len] = '\0'; } @@ -75,6 +132,8 @@ void http_free_request(struct http_request *req) free(req->uri); if (req->query_str) free(req->query_str); + if (req->cookie) + free(req->cookie); if (req->body) free(req->body); } |