Add fixes performance and static web server

This commit is contained in:
Justine Tunney 2020-10-05 23:11:49 -07:00
parent b6793d42d5
commit c45e46f871
108 changed files with 2927 additions and 819 deletions

View file

@ -0,0 +1,67 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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; version 2 of the License.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
#include "net/http/http.h"
/**
* Formats HTTP timestamp, e.g.
*
* Sun, 04 Oct 2020 19:50:10 GMT
*
* @param tm must be zulu see gmtime_r() and nowl()
* @see ParseHttpDateTime()
*/
char *FormatHttpDateTime(char p[hasatleast 30], struct tm *tm) {
unsigned i;
p = mempcpy(p, kWeekdayNameShort[tm->tm_wday], 3);
*p++ = ',';
*p++ = ' ';
i = tm->tm_mday;
*p++ = '0' + i / 10;
*p++ = '0' + i % 10;
*p++ = ' ';
p = mempcpy(p, kMonthNameShort[tm->tm_mon], 3);
*p++ = ' ';
i = tm->tm_year + 1900;
*p++ = '0' + i / 1000;
*p++ = '0' + i / 100 % 10;
*p++ = '0' + i / 10 % 10;
*p++ = '0' + i % 10;
*p++ = ' ';
i = tm->tm_hour;
*p++ = '0' + i / 10;
*p++ = '0' + i % 10;
*p++ = ':';
i = tm->tm_min;
*p++ = '0' + i / 10;
*p++ = '0' + i % 10;
*p++ = ':';
i = tm->tm_sec;
*p++ = '0' + i / 10;
*p++ = '0' + i % 10;
*p++ = ' ';
*p++ = 'G';
*p++ = 'M';
*p++ = 'T';
*p = '\0';
return p;
}

View file

@ -58,5 +58,5 @@ Retry-After, kHttpRetryAfter
Server, kHttpServer
Vary, kHttpVary
Warning, kHttpWarning
WWW-Authenticate, kHttpWwwAuthenticate
Www-Authenticate, kHttpWwwAuthenticate
Last-Modified, kHttpLastModified

View file

@ -216,7 +216,7 @@ LookupHttpHeader (register const char *str, register size_t len)
#line 43 "gethttpheader.gperf"
{"Keep-Alive", kHttpKeepAlive},
#line 61 "gethttpheader.gperf"
{"WWW-Authenticate", kHttpWwwAuthenticate},
{"Www-Authenticate", kHttpWwwAuthenticate},
#line 35 "gethttpheader.gperf"
{"Expires", kHttpExpires},
#line 46 "gethttpheader.gperf"

View file

@ -9,7 +9,7 @@
%readonly-tables
%struct-type
%define lookup-function-name LookupHttpMethod
struct HttpMethodSlot { char *name; char code; };
struct HttpMethodSlot { char name[8]; char code; };
%%
DELETE, kHttpDelete
GET, kHttpGet
@ -20,17 +20,11 @@ CONNECT, kHttpConnect
OPTIONS, kHttpOptions
TRACE, kHttpTrace
COPY, kHttpCopy
CHECKOUT, kHttpCheckout
LOCK, kHttpLock
MERGE, kHttpMerge
MKACTIVITY, kHttpMkactivity
MKCOL, kHttpMkcol
MOVE, kHttpMove
NOTIFY, kHttpNotify
PATCH, kHttpPatch
PROPFIND, kHttpPropfind
PROPPATCH, kHttpProppatch
REPORT, kHttpReport
SUBSCRIBE, kHttpSubscribe
UNLOCK, kHttpUnlock
UNSUBSCRIBE, kHttpUnsubscribe

View file

@ -35,14 +35,14 @@
#include "net/http/http.h"
#define GPERF_DOWNCASE
#line 12 "gethttpmethod.gperf"
struct HttpMethodSlot { char *name; char code; };
struct HttpMethodSlot { char name[8]; char code; };
#define TOTAL_KEYWORDS 23
#define TOTAL_KEYWORDS 17
#define MIN_WORD_LENGTH 3
#define MAX_WORD_LENGTH 11
#define MIN_HASH_VALUE 4
#define MAX_HASH_VALUE 34
/* maximum key range = 31, duplicates = 0 */
#define MAX_WORD_LENGTH 7
#define MIN_HASH_VALUE 3
#define MAX_HASH_VALUE 25
/* maximum key range = 23, duplicates = 0 */
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
@ -101,32 +101,32 @@ hash (register const char *str, register size_t len)
{
static const unsigned char asso_values[] =
{
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 0, 35, 5, 10, 10,
35, 5, 10, 35, 35, 0, 30, 15, 0, 0,
0, 35, 5, 15, 0, 5, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 0, 35, 5,
10, 10, 35, 5, 10, 35, 35, 0, 30, 15,
0, 0, 0, 35, 5, 15, 0, 5, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 0, 26, 5, 15, 0,
26, 5, 0, 26, 26, 10, 15, 10, 0, 5,
0, 26, 10, 26, 5, 0, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 0, 26, 5,
15, 0, 26, 5, 0, 26, 26, 10, 15, 10,
0, 5, 0, 26, 10, 26, 5, 0, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26
};
return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
}
@ -136,58 +136,46 @@ LookupHttpMethod (register const char *str, register size_t len)
{
static const struct HttpMethodSlot wordlist[] =
{
{""}, {""}, {""}, {""},
#line 17 "gethttpmethod.gperf"
{"POST", kHttpPost},
#line 30 "gethttpmethod.gperf"
{"PATCH", kHttpPatch},
#line 29 "gethttpmethod.gperf"
{"NOTIFY", kHttpNotify},
#line 20 "gethttpmethod.gperf"
{"OPTIONS", kHttpOptions},
{""}, {""}, {""},
#line 18 "gethttpmethod.gperf"
{"PUT", kHttpPut},
#line 22 "gethttpmethod.gperf"
{"COPY", kHttpCopy},
#line 21 "gethttpmethod.gperf"
{"TRACE", kHttpTrace},
#line 35 "gethttpmethod.gperf"
#line 16 "gethttpmethod.gperf"
{"HEAD", kHttpHead},
#line 28 "gethttpmethod.gperf"
{"PATCH", kHttpPatch},
#line 30 "gethttpmethod.gperf"
{"UNLOCK", kHttpUnlock},
#line 19 "gethttpmethod.gperf"
{"CONNECT", kHttpConnect},
#line 31 "gethttpmethod.gperf"
{"PROPFIND", kHttpPropfind},
#line 32 "gethttpmethod.gperf"
{"PROPPATCH", kHttpProppatch},
{""},
#line 36 "gethttpmethod.gperf"
{"UNSUBSCRIBE", kHttpUnsubscribe},
{""},
#line 15 "gethttpmethod.gperf"
{"GET", kHttpGet},
#line 28 "gethttpmethod.gperf"
{"MOVE", kHttpMove},
#line 27 "gethttpmethod.gperf"
{"MKCOL", kHttpMkcol},
#line 33 "gethttpmethod.gperf"
{"REPORT", kHttpReport},
#line 17 "gethttpmethod.gperf"
{"POST", kHttpPost},
{""},
#line 27 "gethttpmethod.gperf"
{"NOTIFY", kHttpNotify},
#line 20 "gethttpmethod.gperf"
{"OPTIONS", kHttpOptions},
{""},
#line 22 "gethttpmethod.gperf"
{"COPY", kHttpCopy},
#line 24 "gethttpmethod.gperf"
{"MERGE", kHttpMerge},
#line 29 "gethttpmethod.gperf"
{"REPORT", kHttpReport},
#line 19 "gethttpmethod.gperf"
{"CONNECT", kHttpConnect},
{""},
#line 23 "gethttpmethod.gperf"
{"CHECKOUT", kHttpCheckout},
#line 16 "gethttpmethod.gperf"
{"HEAD", kHttpHead},
#line 26 "gethttpmethod.gperf"
{"MKACTIVITY", kHttpMkactivity},
{"MOVE", kHttpMove},
#line 21 "gethttpmethod.gperf"
{"TRACE", kHttpTrace},
#line 14 "gethttpmethod.gperf"
{"DELETE", kHttpDelete},
{""}, {""},
#line 34 "gethttpmethod.gperf"
{"SUBSCRIBE", kHttpSubscribe},
#line 23 "gethttpmethod.gperf"
{"LOCK", kHttpLock},
#line 25 "gethttpmethod.gperf"
{"MERGE", kHttpMerge},
{""}, {""}, {""},
#line 24 "gethttpmethod.gperf"
{"LOCK", kHttpLock}
{"MKCOL", kHttpMkcol}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)

View file

@ -1,30 +1,25 @@
#ifndef COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#define COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#include "libc/alg/alg.h"
#include "libc/time/struct/tm.h"
#define kHttpGet 0
#define kHttpHead 1
#define kHttpPost 2
#define kHttpPut 3
#define kHttpDelete 4
#define kHttpConnect 5
#define kHttpOptions 6
#define kHttpTrace 7
#define kHttpCopy 8
#define kHttpCheckout 9
#define kHttpLock 10
#define kHttpMerge 11
#define kHttpMkactivity 12
#define kHttpMkcol 13
#define kHttpMove 14
#define kHttpNotify 15
#define kHttpPatch 16
#define kHttpPropfind 17
#define kHttpProppatch 18
#define kHttpReport 19
#define kHttpSubscribe 20
#define kHttpUnlock 21
#define kHttpUnsubscribe 22
#define kHttpGet 0
#define kHttpHead 1
#define kHttpPost 2
#define kHttpPut 3
#define kHttpDelete 4
#define kHttpConnect 5
#define kHttpOptions 6
#define kHttpTrace 7
#define kHttpCopy 8
#define kHttpLock 9
#define kHttpMerge 10
#define kHttpMkcol 11
#define kHttpMove 12
#define kHttpNotify 13
#define kHttpPatch 14
#define kHttpReport 15
#define kHttpUnlock 16
#define kHttpAccept 0
#define kHttpAcceptCharset 1
@ -86,17 +81,24 @@ struct HttpRequestSlice {
struct HttpRequest {
int method;
int length;
struct HttpRequestSlice uri;
struct HttpRequestSlice version;
struct HttpRequestSlice scratch;
struct HttpRequestSlice headers[kHttpHeadersMax];
};
extern const char kHttpMethod[17][8];
int GetHttpHeader(const char *, size_t);
int GetHttpMethod(const char *, size_t);
int ParseHttpRequest(struct HttpRequest *, const char *, size_t);
int NegotiateHttpRequest(int, const char *, uint32_t *, char *, uint32_t *,
uint32_t *, bool, long double);
char *FormatHttpDateTime(char[hasatleast 30], struct tm *);
bool ParseHttpRange(const char *, size_t, long, long *, long *);
unsigned ParseHttpVersion(const char *, size_t);
int64_t ParseHttpDateTime(const char *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -12,65 +12,70 @@ NET_HTTP_A_SRCS_S = $(filter %.S,$(NET_HTTP_A_FILES))
NET_HTTP_A_SRCS_C = $(filter %.c,$(NET_HTTP_A_FILES))
NET_HTTP_A_SRCS_R = $(filter %.rl,$(NET_HTTP_A_FILES))
NET_HTTP_A_SRCS = \
$(NET_HTTP_A_SRCS_S) \
$(NET_HTTP_A_SRCS_C) \
NET_HTTP_A_SRCS = \
$(NET_HTTP_A_SRCS_S) \
$(NET_HTTP_A_SRCS_C) \
$(NET_HTTP_A_SRCS_R)
NET_HTTP_A_OBJS = \
$(NET_HTTP_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(NET_HTTP_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(NET_HTTP_A_SRCS_C:%.c=o/$(MODE)/%.o) \
NET_HTTP_A_OBJS = \
$(NET_HTTP_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(NET_HTTP_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(NET_HTTP_A_SRCS_C:%.c=o/$(MODE)/%.o) \
$(NET_HTTP_A_SRCS_R:%.rl=o/$(MODE)/%.o)
NET_HTTP_A_CHECKS = \
$(NET_HTTP_A).pkg \
NET_HTTP_A_CHECKS = \
$(NET_HTTP_A).pkg \
$(NET_HTTP_A_HDRS:%=o/$(MODE)/%.ok)
NET_HTTP_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CONV \
LIBC_FMT \
LIBC_LOG \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_STUBS \
LIBC_SYSV \
LIBC_TIME \
NET_HTTP_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CONV \
LIBC_FMT \
LIBC_LOG \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_STUBS \
LIBC_SYSV \
LIBC_TIME \
LIBC_X
NET_HTTP_A_DEPS := \
NET_HTTP_A_DEPS := \
$(call uniq,$(foreach x,$(NET_HTTP_A_DIRECTDEPS),$($(x))))
$(NET_HTTP_A): net/http/ \
$(NET_HTTP_A).pkg \
$(NET_HTTP_A): net/http/ \
$(NET_HTTP_A).pkg \
$(NET_HTTP_A_OBJS)
$(NET_HTTP_A).pkg: \
$(NET_HTTP_A_OBJS) \
$(NET_HTTP_A).pkg: \
$(NET_HTTP_A_OBJS) \
$(foreach x,$(NET_HTTP_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/net/http/formathttpdatetime.o: \
OVERRIDE_CFLAGS += \
-O3
ifeq (,$(MODE))
$(NET_HTTP_A_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
endif
NET_HTTP_LIBS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)))
NET_HTTP_SRCS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_SRCS))
NET_HTTP_HDRS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_HDRS))
NET_HTTP_CHECKS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_CHECKS))
NET_HTTP_OBJS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_OBJS))
$(NET_HTTP_OBJS): $(BUILD_FILES) net/http/http.mk
.PRECIOUS: \
$(NET_HTTP_A_SRCS_R:%.rl=build/bootstrap/%.c) \
o/$(MODE)/net/http/uricspn.s \
o/$(MODE)/net/http/uriparse.s \
o/$(MODE)/net/http/uricspn.i \
o/$(MODE)/net/http/uriparse.i \
o/$(MODE)/net/http/uriparse.c \
.PRECIOUS: \
$(NET_HTTP_A_SRCS_R:%.rl=o/$(MODE)/%.c) \
o/$(MODE)/net/http/uricspn.s \
o/$(MODE)/net/http/uricspn.i \
o/$(MODE)/net/http/uricspn.c
.PHONY: o/$(MODE)/net/http
o/$(MODE)/net/http: \
$(NET_HTTP_CHECKS) \
o/$(MODE)/net/http: \
$(NET_HTTP_CHECKS) \
$(NET_HTTP_A_SRCS_R:%.rl=%.svgz)

40
net/http/khttpmethod.c Normal file
View file

@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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; version 2 of the License.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "net/http/http.h"
const char kHttpMethod[17][8] = {
"GET", //
"HEAD", //
"POST", //
"PUT", //
"DELETE", //
"CONNECT", //
"OPTIONS", //
"TRACE", //
"COPY", //
"LOCK", //
"MERGE", //
"MKCOL", //
"MOVE", //
"NOTIFY", //
"PATCH", //
"REPORT", //
"UNLOCK", //
};

View file

@ -0,0 +1,57 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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; version 2 of the License.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/time/time.h"
#include "net/http/http.h"
static unsigned ParseMonth(const char *p) {
int i;
for (i = 0; i < 12; ++i) {
if ((READ32LE(p) & 0x00ffffff) == READ32LE(kMonthNameShort[i])) {
return i + 1;
}
}
return 1;
}
/**
* Parses HTTP timestamp, e.g.
*
* Sun, 04 Oct 2020 19:50:10 GMT
*
* @return seconds from unix epoch
* @see FormatHttpDateTime()
*/
int64_t ParseHttpDateTime(const char *p, size_t n) {
unsigned weekday, year, month, day, hour, minute, second, yday, leap;
if (n != 29) return 0;
day = (p[5] - '0') * 10 + (p[6] - '0') - 1;
month = ParseMonth(p + 8);
year = (p[12] - '0') * 1000 + (p[13] - '0') * 100 + (p[14] - '0') * 10 +
(p[15] - '0') - 1900;
hour = (p[17] - '0') * 10 + (p[18] - '0');
minute = (p[20] - '0') * 10 + (p[21] - '0');
second = (p[23] - '0') * 10 + (p[24] - '0');
leap = year % 4 == 0 && (year % 100 || year % 400 == 0);
yday = day + kMonthYearDay[leap][month - 1];
return second + minute * 60 + hour * 3600 + yday * 86400 +
(year - 70) * 31536000ull + ((year - 69) / 4) * 86400ull -
((year - 1) / 100) * 86400ull + ((year + 299) / 400) * 86400ull;
}

72
net/http/parsehttprange.c Normal file
View file

@ -0,0 +1,72 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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; version 2 of the License.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "net/http/http.h"
/**
* Parses HTTP Range request header.
*/
bool ParseHttpRange(const char *p, size_t n, long resourcelength,
long *out_start, long *out_length) {
long start, length, ending;
*out_start = 0;
*out_length = 0;
if (memchr(p, ',', n)) return false;
if (n < 7 || memcmp(p, "bytes=", 6) != 0) return false;
p += 6, n -= 6;
if (n && *p == '-') {
++p, --n;
length = 0;
while (n && '0' <= *p && *p <= '9') {
if (__builtin_mul_overflow(length, 10, &length)) return false;
if (__builtin_add_overflow(length, *p - '0', &length)) return false;
++p, --n;
}
if (__builtin_sub_overflow(resourcelength, length, &start)) return false;
} else {
start = 0;
while (n && '0' <= *p && *p <= '9') {
if (__builtin_mul_overflow(start, 10, &start)) return false;
if (__builtin_add_overflow(start, *p - '0', &start)) return false;
++p, --n;
}
if (n && *p == '-') {
++p, --n;
length = 0;
while (n && '0' <= *p && *p <= '9') {
if (__builtin_mul_overflow(length, 10, &length)) return false;
if (__builtin_add_overflow(length, *p - '0', &length)) return false;
++p, --n;
}
if (__builtin_add_overflow(length, 1, &length)) return false;
if (__builtin_sub_overflow(length, start, &length)) return false;
} else if (__builtin_sub_overflow(resourcelength, start, &length)) {
return false;
}
}
if (n) return false;
if (start < 0) return false;
if (length < 0) return false;
*out_start = start;
*out_length = length;
if (__builtin_add_overflow(start, length, &ending)) return false;
if (ending > resourcelength) return false;
return true;
}

View file

@ -112,7 +112,10 @@ int ParseHttpRequest(struct HttpRequest *req, const char *p, size_t n) {
}
break;
case LF2:
if (c == '\n') return 0;
if (c == '\n') {
req->length = i + 1;
return 0;
}
return ebadmsg();
default:
unreachable;

View file

@ -0,0 +1,33 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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; version 2 of the License.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "net/http/http.h"
unsigned ParseHttpVersion(const char *p, size_t n) {
unsigned x;
if (n >= 8 && READ32LE(p) == ('H' | 'T' << 8 | 'T' << 16 | 'P' << 24)) {
if (READ32LE(p + 4) == ('/' | '1' << 8 | '.' << 16 | '1' << 24)) {
return 101;
} else if (READ32LE(p + 4) == ('/' | '1' << 8 | '.' << 16 | '0' << 24)) {
return 100;
}
}
return -1;
}