mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 02:38:31 +00:00
Add chunked transfer decoding to redbean
This commit is contained in:
parent
8d5f60a9cd
commit
58fb2fb3d3
13 changed files with 693 additions and 292 deletions
|
@ -432,6 +432,7 @@ static const char *certpath;
|
|||
static const char *launchbrowser;
|
||||
static struct pollfd *polls;
|
||||
static struct Strings loops;
|
||||
static size_t payloadlength;
|
||||
static size_t contentlength;
|
||||
static int64_t cacheseconds;
|
||||
static const char *serverheader;
|
||||
|
@ -3474,7 +3475,7 @@ static int LuaParseHttpDateTime(lua_State *L) {
|
|||
}
|
||||
|
||||
static int LuaGetPayload(lua_State *L) {
|
||||
lua_pushlstring(L, inbuf.p + hdrsize, msgsize - hdrsize);
|
||||
lua_pushlstring(L, inbuf.p + hdrsize, payloadlength);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -4712,11 +4713,6 @@ static char *HandleVersionNotSupported(void) {
|
|||
return ServeFailure(505, "HTTP Version Not Supported");
|
||||
}
|
||||
|
||||
static char *HandleTransferRefused(void) {
|
||||
LockInc(&shared->c.transfersrefused);
|
||||
return ServeFailure(501, "Not Implemented");
|
||||
}
|
||||
|
||||
static char *HandleConnectRefused(void) {
|
||||
LockInc(&shared->c.connectsrefused);
|
||||
return ServeFailure(501, "Not Implemented");
|
||||
|
@ -4738,6 +4734,11 @@ static char *HandlePayloadSlowloris(void) {
|
|||
return ServeFailure(408, "Request Timeout");
|
||||
}
|
||||
|
||||
static char *HandleTransferRefused(void) {
|
||||
LockInc(&shared->c.transfersrefused);
|
||||
return ServeFailure(501, "Not Implemented");
|
||||
}
|
||||
|
||||
static char *HandleMapFailed(struct Asset *a, int fd) {
|
||||
LockInc(&shared->c.mapfails);
|
||||
WARNF("mmap(%`'s) failed %s", a->file->path, strerror(errno));
|
||||
|
@ -4868,44 +4869,85 @@ static char *ServeServerOptions(void) {
|
|||
return p;
|
||||
}
|
||||
|
||||
char *SynchronizeStream(void) {
|
||||
static void SendContinueIfNeeded(void) {
|
||||
if (msg.version >= 11 && HeaderEqualCase(kHttpExpect, "100-continue")) {
|
||||
LockInc(&shared->c.continues);
|
||||
SendContinue();
|
||||
}
|
||||
}
|
||||
|
||||
static char *ReadMore(void) {
|
||||
size_t got;
|
||||
ssize_t rc;
|
||||
LockInc(&shared->c.frags);
|
||||
if (++frags == 64) return HandlePayloadSlowloris();
|
||||
if ((rc = reader(client, inbuf.p + amtread, inbuf.n - amtread)) != -1) {
|
||||
if (!(got = rc)) return HandlePayloadDisconnect();
|
||||
amtread += got;
|
||||
} else if (errno == EINTR) {
|
||||
LockInc(&shared->c.readinterrupts);
|
||||
if (killed || ((meltdown || terminated) && nowl() - startread > 1)) {
|
||||
return HandlePayloadDrop();
|
||||
}
|
||||
} else {
|
||||
return HandlePayloadReadError();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *SynchronizeLength(void) {
|
||||
char *p;
|
||||
if (hdrsize + payloadlength > amtread) {
|
||||
if (hdrsize + payloadlength > inbuf.n) return HandleHugePayload();
|
||||
SendContinueIfNeeded();
|
||||
while (amtread < hdrsize + payloadlength) {
|
||||
if ((p = ReadMore())) return p;
|
||||
}
|
||||
}
|
||||
msgsize = hdrsize + payloadlength;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *SynchronizeChunked(void) {
|
||||
char *p;
|
||||
ssize_t transferlength;
|
||||
struct HttpUnchunker u = {0};
|
||||
SendContinueIfNeeded();
|
||||
while (!(transferlength = Unchunk(&u, inbuf.p + hdrsize, amtread - hdrsize,
|
||||
&payloadlength))) {
|
||||
if ((p = ReadMore())) return p;
|
||||
}
|
||||
if (transferlength == -1) return HandleHugePayload();
|
||||
msgsize = hdrsize + transferlength;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *SynchronizeStream(void) {
|
||||
int64_t cl;
|
||||
if (HasHeader(kHttpContentLength)) {
|
||||
if (HasHeader(kHttpTransferEncoding) &&
|
||||
!SlicesEqualCase("identity", 8, HeaderData(kHttpTransferEncoding),
|
||||
HeaderLength(kHttpTransferEncoding))) {
|
||||
if (SlicesEqualCase("chunked", 7, HeaderData(kHttpTransferEncoding),
|
||||
HeaderLength(kHttpTransferEncoding))) {
|
||||
return SynchronizeChunked();
|
||||
} else {
|
||||
return HandleTransferRefused();
|
||||
}
|
||||
} else if (HasHeader(kHttpContentLength)) {
|
||||
if ((cl = ParseContentLength(HeaderData(kHttpContentLength),
|
||||
HeaderLength(kHttpContentLength))) == -1) {
|
||||
HeaderLength(kHttpContentLength))) != -1) {
|
||||
payloadlength = cl;
|
||||
return SynchronizeLength();
|
||||
} else {
|
||||
return HandleBadContentLength();
|
||||
}
|
||||
} else if (msg.method == kHttpPost || msg.method == kHttpPut) {
|
||||
return HandleLengthRequired();
|
||||
} else {
|
||||
cl = 0;
|
||||
msgsize = hdrsize;
|
||||
payloadlength = 0;
|
||||
return NULL;
|
||||
}
|
||||
if (hdrsize + cl > amtread) {
|
||||
if (hdrsize + cl > inbuf.n) HandleHugePayload();
|
||||
if (msg.version >= 11 && HeaderEqualCase(kHttpExpect, "100-continue")) {
|
||||
LockInc(&shared->c.continues);
|
||||
SendContinue();
|
||||
}
|
||||
while (amtread < hdrsize + cl) {
|
||||
LockInc(&shared->c.frags);
|
||||
if (++frags == 64) HandlePayloadSlowloris();
|
||||
if ((rc = reader(client, inbuf.p + amtread, inbuf.n - amtread)) != -1) {
|
||||
if (!(got = rc)) return HandlePayloadDisconnect();
|
||||
amtread += got;
|
||||
} else if (errno == EINTR) {
|
||||
LockInc(&shared->c.readinterrupts);
|
||||
if (killed || ((meltdown || terminated) && nowl() - startread > 1)) {
|
||||
return HandlePayloadDrop();
|
||||
}
|
||||
} else {
|
||||
return HandlePayloadReadError();
|
||||
}
|
||||
}
|
||||
}
|
||||
msgsize = hdrsize + cl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ParseRequestParameters(void) {
|
||||
|
@ -4936,12 +4978,6 @@ static void ParseRequestParameters(void) {
|
|||
url.scheme.n = 4;
|
||||
}
|
||||
}
|
||||
if (HasHeader(kHttpContentType) &&
|
||||
IsMimeType(HeaderData(kHttpContentType), HeaderLength(kHttpContentType),
|
||||
"application/x-www-form-urlencoded")) {
|
||||
FreeLater(ParseParams(inbuf.p + hdrsize, msgsize - hdrsize, &url.params));
|
||||
}
|
||||
FreeLater(url.params.p);
|
||||
}
|
||||
|
||||
static bool HasAtMostThisElement(int h, const char *s) {
|
||||
|
@ -4949,8 +4985,7 @@ static bool HasAtMostThisElement(int h, const char *s) {
|
|||
struct HttpHeader *x;
|
||||
if (HasHeader(h)) {
|
||||
n = strlen(s);
|
||||
if (!SlicesEqualCase(s, n, inbuf.p + msg.headers[h].a,
|
||||
msg.headers[h].b - msg.headers[h].a)) {
|
||||
if (!SlicesEqualCase(s, n, HeaderData(h), HeaderLength(h))) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < msg.xheaders.n; ++i) {
|
||||
|
@ -5000,7 +5035,7 @@ static char *HandleRequest(void) {
|
|||
return HandleVersionNotSupported();
|
||||
}
|
||||
if ((p = SynchronizeStream())) return p;
|
||||
if (logbodies) LogBody("received", inbuf.p + hdrsize, msgsize - hdrsize);
|
||||
if (logbodies) LogBody("received", inbuf.p + hdrsize, payloadlength);
|
||||
if (msg.version < 11 || HeaderEqualCase(kHttpConnection, "close")) {
|
||||
connectionclose = true;
|
||||
}
|
||||
|
@ -5014,9 +5049,6 @@ static char *HandleRequest(void) {
|
|||
if (!HasAtMostThisElement(kHttpExpect, "100-continue")) {
|
||||
return HandleExpectFailed();
|
||||
}
|
||||
if (!HasAtMostThisElement(kHttpTransferEncoding, "identity")) {
|
||||
return HandleTransferRefused();
|
||||
}
|
||||
ParseRequestParameters();
|
||||
if (!url.host.n || !url.path.n || url.path.p[0] != '/' ||
|
||||
!IsAcceptablePath(url.path.p, url.path.n) ||
|
||||
|
@ -5034,6 +5066,12 @@ static char *HandleRequest(void) {
|
|||
FreeLater(EncodeUrl(&url, 0)), HeaderLength(kHttpReferer),
|
||||
HeaderData(kHttpReferer), HeaderLength(kHttpUserAgent),
|
||||
HeaderData(kHttpUserAgent));
|
||||
if (HasHeader(kHttpContentType) &&
|
||||
IsMimeType(HeaderData(kHttpContentType), HeaderLength(kHttpContentType),
|
||||
"application/x-www-form-urlencoded")) {
|
||||
FreeLater(ParseParams(inbuf.p + hdrsize, payloadlength, &url.params));
|
||||
}
|
||||
FreeLater(url.params.p);
|
||||
#ifndef STATIC
|
||||
if (hasluaglobalhandler) return LuaOnHttpRequest();
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue