http-parser.c

Small C library to parse HTTP requests
Log | Files | Refs | README | LICENSE

commit 80acd513ffaa65c3df2a28c7f5d3e3b3db7df255
parent 08385ef17c8d8e2780a9af932190e0337f8a864a
Author: finwo <finwo@pm.me>
Date:   Sat,  9 Nov 2019 20:44:47 +0100

Trying to keep the names unique

Diffstat:
Asrc/http-parser.c | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/http-parser.h | 44++++++++++++++++++++++++++++++++++++++++++++
Dsrc/http.c | 191-------------------------------------------------------------------------------
Dsrc/http.h | 44--------------------------------------------
4 files changed, 235 insertions(+), 235 deletions(-)

diff --git a/src/http-parser.c b/src/http-parser.c @@ -0,0 +1,191 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> + +#include "http.h" + +#ifndef NULL +#define NULL ((void*)0) +#endif + +void http_parser_header_free(struct http_parser_header *header) { + if (header->next) http_parser_header_free(header->next); + if (header->key) free(header->key); + if (header->value) free(header->value); + free(header); +} + +char *http_parser_header_get(struct http_parser_request *request, char *key) { + struct http_parser_header *header = request->headers; + while(header) { + if (!strcasecmp(key, header->key)) { + return header->value; + } + header = header->next; + } + return NULL; +} + +void http_parser_request_free(struct http_parser_request *request) { + if (request->body) free(request->body); + if (request->method) free(request->method); + if (request->path) free(request->path); + if (request->headers) http_parser_header_free(request->headers); + free(request); +} + +struct http_parser_request * http_parser_request_init() { + struct http_parser_request *request = calloc(1, sizeof(struct http_parser_request)); + return request; +} + +void http_parser_request_data(struct http_parser_request *request, char *data, int size) { + struct http_parser_header *header; + struct http_parser_event *ev; + char *index; + int newsize; + char *colon; + char *buf; + char *aContentLength; + int iContentLength; + + // Add event data to buffer + if (!request->body) request->body = malloc(1); + request->body = realloc(request->body, request->bodysize + size + 1); + memcpy(request->body + request->bodysize, data, size); + request->bodysize += size; + + // Make string functions not segfault + *(request->body + request->bodysize) = '\0'; + + int running = 1; + while(running) { + switch(request->state) { + case HTTP_PARSER_STATE_PANIC: + return; + case HTTP_PARSER_STATE_METHOD: + + // Wait for more data if not line break found + index = strstr(request->body, "\r\n"); + if (!index) return; + *(index) = '\0'; + + // Read method and path + request->method = calloc(1, 7); + request->path = calloc(1, 512); + if (sscanf(request->body, "%6s %511s", request->method, request->path) != 2) { + request->state = HTTP_PARSER_STATE_PANIC; + return; + } + + // Remove the method line + newsize = request->bodysize - 2 - (index - request->body); + buf = calloc(1,newsize+1); + memcpy(buf, index + 2, newsize); + free(request->body); + request->body = buf; + request->bodysize = newsize; + + // Signal we're now reading headers + request->state = HTTP_PARSER_STATE_HEADER; + break; + + case HTTP_PARSER_STATE_HEADER: + + // Wait for more data if not line break found + index = strstr(request->body, "\r\n"); + if (!index) return; + *(index) = '\0'; + + // Detect end of headers + newsize = strlen(request->body); + if (!newsize) { + + // Remove the blank line + newsize = request->bodysize - 2; + buf = calloc(1,newsize+1); + memcpy(buf, index + 2, newsize); + free(request->body); + request->body = buf; + request->bodysize = newsize; + + // GET/DELETE = start responding + if ( + (!strcmp(request->method, "GET")) || + (!strcmp(request->method, "DELETE")) + ) { + request->state = HTTP_PARSER_STATE_RESPONSE; + break; + } + + request->state = HTTP_PARSER_STATE_BODY; + break; + } + + // Prepare new header + header = calloc(1,sizeof(header)); + header->key = calloc(1,strlen(request->body)); + header->value = calloc(1,strlen(request->body)); + + // Copy key & value + colon = strstr(request->body, ":"); + if (colon) { + *(colon) = '\0'; + strcpy(header->key, request->body); + strcpy(header->value, colon + 1); + } + + // Assign to the header list + header->next = request->headers; + request->headers = header; + + // Remove the header line + newsize = request->bodysize - 2 - (index - request->body); + buf = calloc(1,newsize+1); + memcpy(buf, index + 2, newsize); + free(request->body); + request->body = buf; + request->bodysize = newsize; + + break; + + case HTTP_PARSER_STATE_BODY: + + // Fetch the content length + aContentLength = http_parser_header_get(request, "content-length"); + iContentLength = atoi(aContentLength); + + // Not enough data = skip + if (request->bodysize < iContentLength) { + running = 0; + break; + } + + // Change size to indicated size + request->bodysize = iContentLength; + request->state = HTTP_PARSER_STATE_RESPONSE; + break; + + case HTTP_PARSER_STATE_RESPONSE: + + if (request->onRequest) { + ev = calloc(1,sizeof(struct http_parser_event)); + ev->request = request; + request->onRequest(ev); + request->onRequest = NULL; + } + + running = 0; + break; + } + } +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/http-parser.h b/src/http-parser.h @@ -0,0 +1,44 @@ +#ifndef _HTTP_PARSER_H_ +#define _HTTP_PARSER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define HTTP_PARSER_STATE_METHOD 0 +#define HTTP_PARSER_STATE_HEADER 1 +#define HTTP_PARSER_STATE_BODY 2 +#define HTTP_PARSER_STATE_RESPONSE 3 +#define HTTP_PARSER_STATE_PANIC 666 + +struct http_parser_header { + void *next; + char *key; + char *value; +}; + +struct http_praser_event { + struct http_parser_request *request; +}; + +struct http_parser_request { + int bodysize; + int state; + char *method; + char *path; + struct http_parser_header *headers; + char *body; + void (*onRequest)(struct http_parser_event*); + void *udata; +}; + +char *http_parser_header_get(struct http_parser_request *request, char *key); +void http_parser_request_free(struct http_parser_request *request); +struct http_parser_request * http_parser_request_init(); +void http_parser_request_data(struct http_parser_request *request, char *data, int size); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _HTTP_PARSER_H_ diff --git a/src/http.c b/src/http.c @@ -1,191 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <strings.h> - -#include "http.h" - -#ifndef NULL -#define NULL ((void*)0) -#endif - -void http_header_free(struct http_header *header) { - if (header->next) http_header_free(header->next); - if (header->key) free(header->key); - if (header->value) free(header->value); - free(header); -} - -char *http_header_get(struct http_request *request, char *key) { - struct http_header *header = request->headers; - while(header) { - if (!strcasecmp(key, header->key)) { - return header->value; - } - header = header->next; - } - return NULL; -} - -void http_request_free(struct http_request *request) { - if (request->body) free(request->body); - if (request->method) free(request->method); - if (request->path) free(request->path); - if (request->headers) http_header_free(request->headers); - free(request); -} - -struct http_request * http_request_init() { - struct http_request *request = calloc(1, sizeof(struct http_request)); - return request; -} - -void http_request_data(struct http_request *request, char *data, int size) { - struct http_header *header; - struct http_event *ev; - char *index; - int newsize; - char *colon; - char *buf; - char *aContentLength; - int iContentLength; - - // Add event data to buffer - if (!request->body) request->body = malloc(1); - request->body = realloc(request->body, request->bodysize + size + 1); - memcpy(request->body + request->bodysize, data, size); - request->bodysize += size; - - // Make string functions not segfault - *(request->body + request->bodysize) = '\0'; - - int running = 1; - while(running) { - switch(request->state) { - case HTTP_STATE_PANIC: - return; - case HTTP_STATE_METHOD: - - // Wait for more data if not line break found - index = strstr(request->body, "\r\n"); - if (!index) return; - *(index) = '\0'; - - // Read method and path - request->method = calloc(1, 7); - request->path = calloc(1, 512); - if (sscanf(request->body, "%6s %511s", request->method, request->path) != 2) { - request->state = HTTP_STATE_PANIC; - return; - } - - // Remove the method line - newsize = request->bodysize - 2 - (index - request->body); - buf = calloc(1,newsize+1); - memcpy(buf, index + 2, newsize); - free(request->body); - request->body = buf; - request->bodysize = newsize; - - // Signal we're now reading headers - request->state = HTTP_STATE_HEADER; - break; - - case HTTP_STATE_HEADER: - - // Wait for more data if not line break found - index = strstr(request->body, "\r\n"); - if (!index) return; - *(index) = '\0'; - - // Detect end of headers - newsize = strlen(request->body); - if (!newsize) { - - // Remove the blank line - newsize = request->bodysize - 2; - buf = calloc(1,newsize+1); - memcpy(buf, index + 2, newsize); - free(request->body); - request->body = buf; - request->bodysize = newsize; - - // GET/DELETE = start responding - if ( - (!strcmp(request->method, "GET")) || - (!strcmp(request->method, "DELETE")) - ) { - request->state = HTTP_STATE_RESPONSE; - break; - } - - request->state = HTTP_STATE_BODY; - break; - } - - // Prepare new header - header = calloc(1,sizeof(header)); - header->key = calloc(1,strlen(request->body)); - header->value = calloc(1,strlen(request->body)); - - // Copy key & value - colon = strstr(request->body, ":"); - if (colon) { - *(colon) = '\0'; - strcpy(header->key, request->body); - strcpy(header->value, colon + 1); - } - - // Assign to the header list - header->next = request->headers; - request->headers = header; - - // Remove the header line - newsize = request->bodysize - 2 - (index - request->body); - buf = calloc(1,newsize+1); - memcpy(buf, index + 2, newsize); - free(request->body); - request->body = buf; - request->bodysize = newsize; - - break; - - case HTTP_STATE_BODY: - - // Fetch the content length - aContentLength = http_header_get(request, "content-length"); - iContentLength = atoi(aContentLength); - - // Not enough data = skip - if (request->bodysize < iContentLength) { - running = 0; - break; - } - - // Change size to indicated size - request->bodysize = iContentLength; - request->state = HTTP_STATE_RESPONSE; - break; - - case HTTP_STATE_RESPONSE: - - if (request->onRequest) { - ev = calloc(1,sizeof(struct http_event)); - ev->request = request; - request->onRequest(ev); - request->onRequest = NULL; - } - - running = 0; - break; - } - } -} - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/src/http.h b/src/http.h @@ -1,44 +0,0 @@ -#ifndef CROSYNC_HTTP_H -#define CROSYNC_HTTP_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define HTTP_STATE_METHOD 0 -#define HTTP_STATE_HEADER 1 -#define HTTP_STATE_BODY 2 -#define HTTP_STATE_RESPONSE 3 -#define HTTP_STATE_PANIC 666 - -struct http_header { - void *next; - char *key; - char *value; -}; - -struct http_event { - struct http_request *request; -}; - -struct http_request { - int bodysize; - int state; - char *method; - char *path; - struct http_header *headers; - char *body; - void (*onRequest)(struct http_event*); - void *udata; -}; - -char *http_header_get(struct http_request *request, char *key); -void http_request_free(struct http_request *request); -struct http_request * http_request_init(); -void http_request_data(struct http_request *request, char *data, int size); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // CROSYNC_HTTP_H