diff options
| author | Mikhail Burakov <mburakov@mailbox.org> | 2022-12-26 12:15:30 +0100 |
|---|---|---|
| committer | Mikhail Burakov <mburakov@mailbox.org> | 2022-12-26 12:15:30 +0100 |
| commit | b2ccb9ff8fa7e7ad14143cfbf7e26ec79bfbfdc8 (patch) | |
| tree | 1c372c1ef20f3dfa9931f908837ac8f94e7a826c /uhttp.c | |
| parent | 2fcd2038a47b1990532dde4078d71308dfcc58ca (diff) | |
Initial commit for version 2
Diffstat (limited to 'uhttp.c')
| -rw-r--r-- | uhttp.c | 263 |
1 files changed, 0 insertions, 263 deletions
diff --git a/uhttp.c b/uhttp.c deleted file mode 100644 index 1d7e190..0000000 --- a/uhttp.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2021 Mikhail Burakov. This file is part of MQhTTp. - * - * MQhTTp is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MQhTTp is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with MQhTTp. If not, see <https://www.gnu.org/licenses/>. - */ - -#include "uhttp.h" - -#include <ctype.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> - -struct Uhttp { - struct { - char* data; - size_t alloc; - size_t size; - } buffer; - struct { - const char* method; - const char* target; - const char* body; - size_t body_size; - } public; - struct { - _Bool (*state)(struct Uhttp*, char*); - const char* field_name; - const char* field_value; - char* maybe_ows; - _Bool maybe_eol; - } parser; -}; - -static _Bool StrEq(const char* a, const char* b) { - for (; *a && *b; a++, b++) { - if (tolower(*a) != tolower(*b)) return 0; - } - return *a == *b; -} - -static _Bool UhttpOnMethod(struct Uhttp* uhttp, char* glyph); -static _Bool UhttpOnTarget(struct Uhttp* uhttp, char* glyph); -static _Bool UhttpOnVersion(struct Uhttp* uhttp, char* glyph); -static _Bool UhttpOnFieldName(struct Uhttp* uhttp, char* glyph); -static _Bool UhttpOnFieldValue(struct Uhttp* uhttp, char* glyph); -static _Bool UhttpOnBody(struct Uhttp* uhttp, char* glyph); -static _Bool UhttpOnStopped(struct Uhttp* uhttp, char* glyph); - -static _Bool UhttpOnMethod(struct Uhttp* uhttp, char* glyph) { - switch (*glyph) { - case ' ': - if (!uhttp->public.method) return 0; - uhttp->parser.state = UhttpOnTarget; - *glyph = 0; - return 1; - default: - if (!isgraph(*glyph)) return 0; - if (!uhttp->public.method) uhttp->public.method = glyph; - return 1; - } -} - -static _Bool UhttpOnTarget(struct Uhttp* uhttp, char* glyph) { - switch (*glyph) { - case ' ': - if (!uhttp->public.target) return 0; - uhttp->parser.state = UhttpOnVersion; - *glyph = 0; - return 1; - default: - if (!isgraph(*glyph)) return 0; - if (!uhttp->public.target) uhttp->public.target = glyph; - return 1; - } -} - -static _Bool UhttpOnVersion(struct Uhttp* uhttp, char* glyph) { - switch (*glyph) { - case '\r': - if (uhttp->parser.maybe_eol) return 0; - uhttp->parser.maybe_eol = 1; - return 1; - case '\n': - if (!uhttp->parser.maybe_eol) return 0; - uhttp->parser.state = UhttpOnFieldName; - uhttp->parser.maybe_eol = 0; - return 1; - default: - if (uhttp->parser.maybe_eol) return 0; - if (!isprint(*glyph)) return 0; - return 1; - } -} - -static _Bool UhttpOnFieldName(struct Uhttp* uhttp, char* glyph) { - switch (*glyph) { - case '\r': - if (uhttp->parser.maybe_eol) return 0; - uhttp->parser.maybe_eol = 1; - return 1; - case '\n': - if (!uhttp->parser.maybe_eol) return 0; - uhttp->parser.state = - uhttp->public.body_size ? UhttpOnBody : UhttpOnStopped; - return 1; - case ' ': - return 0; - case ':': - if (uhttp->parser.maybe_eol) return 0; - if (!uhttp->parser.field_name) return 0; - uhttp->parser.state = UhttpOnFieldValue; - uhttp->parser.field_value = NULL; - *glyph = 0; - return 1; - default: - if (uhttp->parser.maybe_eol) return 0; - if (!isgraph(*glyph)) return 0; - if (!uhttp->parser.field_name) uhttp->parser.field_name = glyph; - return 1; - } -} - -static _Bool UhttpOnFieldValue(struct Uhttp* uhttp, char* glyph) { - switch (*glyph) { - case '\r': - if (uhttp->parser.maybe_eol) return 0; - uhttp->parser.maybe_ows = glyph; - uhttp->parser.maybe_eol = 1; - return 1; - case '\n': - if (!uhttp->parser.maybe_eol) return 0; - if (!uhttp->parser.field_value) return 0; - *uhttp->parser.maybe_ows = 0; - if (!uhttp->public.body_size && - StrEq(uhttp->parser.field_name, "Content-Length")) - uhttp->public.body_size = (size_t)atoi(uhttp->parser.field_value); - uhttp->parser.state = UhttpOnFieldName; - uhttp->parser.field_name = NULL; - uhttp->parser.maybe_eol = 0; - return 1; - case '\t': - case ' ': - if (uhttp->parser.maybe_eol) return 0; - if (!uhttp->parser.field_value) return 1; - if (!uhttp->parser.maybe_ows) uhttp->parser.maybe_ows = glyph; - return 1; - default: - if (uhttp->parser.maybe_eol) return 0; - if (!isgraph(*glyph)) return 0; - if (!uhttp->parser.field_value) uhttp->parser.field_value = glyph; - uhttp->parser.maybe_ows = NULL; - return 1; - } -} - -static _Bool UhttpOnBody(struct Uhttp* uhttp, char* glyph) { - if (!uhttp->public.body) uhttp->public.body = glyph; - ptrdiff_t body_size = glyph - uhttp->public.body + 1; - if ((size_t)body_size == uhttp->public.body_size) - uhttp->parser.state = UhttpOnStopped; - return 1; -} - -static _Bool UhttpOnStopped(struct Uhttp* uhttp, char* glyph) { - (void)uhttp; - (void)glyph; - return 0; -} - -static void UhttpRelocateBuffer(struct Uhttp* uhttp, char* data) { - if (uhttp->public.method) - uhttp->public.method = data + (uhttp->public.method - uhttp->buffer.data); - if (uhttp->public.target) - uhttp->public.target = data + (uhttp->public.target - uhttp->buffer.data); - if (uhttp->public.body) - uhttp->public.body = data + (uhttp->public.body - uhttp->buffer.data); - if (uhttp->parser.field_name) { - uhttp->parser.field_name = - data + (uhttp->parser.field_name - uhttp->buffer.data); - } - if (uhttp->parser.field_value) { - uhttp->parser.field_value = - data + (uhttp->parser.field_value - uhttp->buffer.data); - } - if (uhttp->parser.maybe_ows) { - uhttp->parser.maybe_ows = - data + (uhttp->parser.maybe_ows - uhttp->buffer.data); - } - uhttp->buffer.data = data; -} - -struct Uhttp* UhttpCreate() { - struct Uhttp* result = calloc(1, sizeof(struct Uhttp)); - UhttpReset(result); - return result; -} - -void UhttpDestroy(struct Uhttp* uhttp) { - free(uhttp->buffer.data); - free(uhttp); -} - -void UhttpReset(struct Uhttp* uhttp) { - const struct Uhttp reset = {.buffer.data = uhttp->buffer.data, - .buffer.alloc = uhttp->buffer.alloc, - .parser.state = UhttpOnMethod}; - *uhttp = reset; -} - -void* UhttpAllocate(struct Uhttp* uhttp, size_t size) { - size_t alloc = uhttp->buffer.size + size; - if (alloc > uhttp->buffer.alloc) { - char* data = realloc(uhttp->buffer.data, alloc); - if (!data) return NULL; - if (data != uhttp->buffer.data) UhttpRelocateBuffer(uhttp, data); - uhttp->buffer.alloc = alloc; - } - return uhttp->buffer.data + uhttp->buffer.size; -} - -enum UhttpResult UhttpConsume(struct Uhttp* uhttp, size_t size) { - if (uhttp->buffer.size + size > uhttp->buffer.alloc) - return kUhttpResultTerminate; - size_t end = uhttp->buffer.size + size; - for (; uhttp->buffer.size < end; uhttp->buffer.size++) { - if (!uhttp->parser.state(uhttp, &uhttp->buffer.data[uhttp->buffer.size])) { - uhttp->parser.state = UhttpOnStopped; - return kUhttpResultFailure; - } - if (uhttp->parser.state == UhttpOnStopped) { - return kUhttpResultFinished; - } - } - return kUhttpResultWantMore; -} - -const char* UhttpGetMethod(const struct Uhttp* uhttp) { - return uhttp->public.method; -} - -const char* UhttpGetTarget(const struct Uhttp* uhttp) { - return uhttp->public.target; -} - -const char* UhttpGetBody(const struct Uhttp* uhttp) { - return uhttp->public.body; -} - -size_t UhttpGetBodySize(const struct Uhttp* uhttp) { - return uhttp->public.body_size; -} |
