mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-26 07:49:05 +00:00
parent
7abca1531f
commit
83abd68029
6 changed files with 59 additions and 26 deletions
net/http
test/net/http
tool/net
|
@ -26,7 +26,7 @@
|
|||
*/
|
||||
ssize_t ParseContentLength(const char *s, size_t n) {
|
||||
int i, r = 0;
|
||||
if (!n) return -1;
|
||||
if (!n) return 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!isdigit(s[i])) return -1;
|
||||
if (__builtin_mul_overflow(r, 10, &r)) return -1;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
|
@ -48,14 +49,18 @@ bool ParseHttpRange(const char *p, size_t n, long resourcelength,
|
|||
}
|
||||
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 (!n) {
|
||||
length = MAX(start, resourcelength) - start;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
|||
return ebadmsg();
|
||||
}
|
||||
break;
|
||||
} else if (!('A' <= c && c <= 'Z')) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "net/http/http.h"
|
||||
|
||||
TEST(ParseContentLength, test) {
|
||||
EXPECT_EQ(-1, ParseContentLength("", 0));
|
||||
EXPECT_EQ(0, ParseContentLength("", 0));
|
||||
EXPECT_EQ(-1, ParseContentLength("-1", 2));
|
||||
EXPECT_EQ(-1, ParseContentLength("-2", 2));
|
||||
EXPECT_EQ(0, ParseContentLength("0", 1));
|
||||
|
|
|
@ -52,6 +52,14 @@ TEST(ParseHttpRange, testOffset) {
|
|||
EXPECT_EQ(10, length);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRange, testEmptySecond) {
|
||||
long start, length;
|
||||
const char *s = "bytes=0-";
|
||||
EXPECT_TRUE(ParseHttpRange(s, strlen(s), 100, &start, &length));
|
||||
EXPECT_EQ(0, start);
|
||||
EXPECT_EQ(100, length);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRange, testToEnd) {
|
||||
long start, length;
|
||||
const char *s = "bytes=40";
|
||||
|
|
|
@ -463,7 +463,7 @@ static void ProgramRedirect(int code, const char *src, const char *dst) {
|
|||
} else {
|
||||
i = redirects.n;
|
||||
redirects.p = xrealloc(redirects.p, (i + 1) * sizeof(*redirects.p));
|
||||
for (j = i; j > 0; --j) {
|
||||
for (j = i; j; --j) {
|
||||
if (CompareSlices(r.path, r.pathlen, redirects.p[j - 1].path,
|
||||
redirects.p[j - 1].pathlen) < 0) {
|
||||
redirects.p[j] = redirects.p[j - 1];
|
||||
|
@ -526,6 +526,10 @@ static const char *GetContentType2(const char *path, size_t n) {
|
|||
}
|
||||
|
||||
static const char *GetContentType(struct Asset *a, const char *path, size_t n) {
|
||||
const char *r;
|
||||
if (a->file && (r = GetContentType2(a->file->path, strlen(a->file->path)))) {
|
||||
return r;
|
||||
}
|
||||
return firstnonnull(
|
||||
GetContentType2(path, n),
|
||||
firstnonnull(GetContentType2(ZIP_LFILE_NAME(zmap + a->lf),
|
||||
|
@ -1114,6 +1118,19 @@ static void ParseRequestUri(void) {
|
|||
u.data = inbuf.p + msg.uri.a;
|
||||
u.size = msg.uri.b - msg.uri.a;
|
||||
memset(&request, 0, sizeof(request));
|
||||
if (u.size > 8 && !memcmp(u.data, "http", 4)) {
|
||||
/*
|
||||
* convert http://www.foo.com/index.html -> /www.foo.com/index.html
|
||||
*/
|
||||
if (u.data[4] == ':' && u.data[5] == '/' && u.data[6] == '/') {
|
||||
u.data += 6;
|
||||
u.size -= 6;
|
||||
} else if (u.data[4] == 's' && u.data[5] == ':' && u.data[6] == '/' &&
|
||||
u.data[7] == '/') {
|
||||
u.data += 7;
|
||||
u.size -= 7;
|
||||
}
|
||||
}
|
||||
u.q = u.p = FreeLater(xmalloc(u.size * 2));
|
||||
ParsePath(&u, &request.path);
|
||||
if (u.c == '?') ParseParams(&u, &request.params);
|
||||
|
@ -1201,7 +1218,7 @@ static char *ServeError(int code, const char *reason) {
|
|||
contentlength = reasonlen + 2;
|
||||
stpcpy(stpcpy(content, reason), "\r\n");
|
||||
WARNF("%s %s %`'.*s %d %s", clientaddrstr, kHttpMethod[msg.method],
|
||||
request.path.n, request.path.p, code, reason);
|
||||
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a, code, reason);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -1233,9 +1250,10 @@ static char *AppendContentLength(char *p, size_t n) {
|
|||
static char *AppendContentRange(char *p, long rangestart, long rangelength,
|
||||
long contentlength) {
|
||||
long endrange;
|
||||
CHECK_GE(rangestart + rangelength, rangestart);
|
||||
CHECK_GT(rangelength, 0);
|
||||
CHECK_GT(rangestart + rangelength, rangestart);
|
||||
CHECK_LE(rangestart + rangelength, contentlength);
|
||||
if (__builtin_add_overflow(rangestart, rangelength, &endrange)) abort();
|
||||
endrange = rangestart + rangelength - 1;
|
||||
p = AppendHeaderName(p, "Content-Range");
|
||||
p = stpcpy(p, "bytes ");
|
||||
p += uint64toarray_radix10(rangestart, p);
|
||||
|
@ -1361,6 +1379,7 @@ static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) {
|
|||
if (ParseHttpRange(inbuf.p + msg.headers[kHttpRange].a,
|
||||
msg.headers[kHttpRange].b - msg.headers[kHttpRange].a,
|
||||
contentlength, &rangestart, &rangelength)) {
|
||||
LOGF("rangestart = %ld rangelength = %ld", rangestart, rangelength);
|
||||
p = SetStatus(206, "Partial Content");
|
||||
p = AppendContentRange(p, rangestart, rangelength, contentlength);
|
||||
content = AddRange(content, rangestart, rangelength);
|
||||
|
@ -2139,7 +2158,7 @@ Content-Length: 0\r\n\
|
|||
|
||||
static void LogClose(const char *reason) {
|
||||
if (amtread) {
|
||||
WARNF("%s %s with %,ld bytes unprocessed", clientaddrstr, reason);
|
||||
WARNF("%s %s with %,ld bytes unprocessed", clientaddrstr, reason, amtread);
|
||||
} else {
|
||||
DEBUGF("%s %s", clientaddrstr, reason);
|
||||
}
|
||||
|
@ -2301,25 +2320,22 @@ static char *HandleMessage(void) {
|
|||
if (httpversion > 101) {
|
||||
return ServeError(505, "HTTP Version Not Supported");
|
||||
}
|
||||
if (msg.method > kHttpOptions ||
|
||||
if (HasHeader(kHttpExpect) && !HeaderEquals(kHttpExpect, "100-continue")) {
|
||||
return ServeError(417, "Expectation Failed");
|
||||
}
|
||||
if (msg.method == kHttpConnect ||
|
||||
(HasHeader(kHttpTransferEncoding) &&
|
||||
!HeaderEquals(kHttpTransferEncoding, "identity"))) {
|
||||
return ServeError(501, "Not Implemented");
|
||||
}
|
||||
if (HasHeader(kHttpExpect) && !HeaderEquals(kHttpExpect, "100-continue")) {
|
||||
return ServeError(417, "Expectation Failed");
|
||||
if (!HasHeader(kHttpContentLength) &&
|
||||
(msg.method == kHttpPost || msg.method == kHttpPut)) {
|
||||
return ServeError(411, "Length Required");
|
||||
}
|
||||
if ((cl = ParseContentLength(inbuf.p + msg.headers[kHttpContentLength].a,
|
||||
msg.headers[kHttpContentLength].b -
|
||||
msg.headers[kHttpContentLength].a)) == -1) {
|
||||
if (HasHeader(kHttpContentLength)) {
|
||||
return ServeError(400, "Bad Request");
|
||||
} else if (msg.method != kHttpGet && msg.method != kHttpHead &&
|
||||
msg.method != kHttpDelete && msg.method != kHttpOptions) {
|
||||
return ServeError(411, "Length Required");
|
||||
} else {
|
||||
cl = 0;
|
||||
}
|
||||
return ServeError(400, "Bad Request");
|
||||
}
|
||||
need = hdrsize + cl; /* synchronization is possible */
|
||||
if (need > inbuf.n) {
|
||||
|
@ -2363,7 +2379,7 @@ static char *HandleMessage(void) {
|
|||
return ServeServerOptions();
|
||||
}
|
||||
if (!IsAcceptableHttpRequestPath(request.path.p, request.path.n)) {
|
||||
WARNF("%s could not parse request request %`'.*s", clientaddrstr,
|
||||
WARNF("%s could not parse request %`'.*s", clientaddrstr,
|
||||
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a);
|
||||
connectionclose = true;
|
||||
return ServeError(400, "Bad Request");
|
||||
|
@ -2399,7 +2415,9 @@ static bool HandleRequest(void) {
|
|||
p = HandleMessage();
|
||||
} else {
|
||||
httpversion = 101;
|
||||
connectionclose = true;
|
||||
p = ServeError(400, "Bad Request");
|
||||
DEBUGF("%s received garbage %`'.*s", clientaddrstr, amtread, inbuf.p);
|
||||
}
|
||||
if (!msgsize) {
|
||||
amtread = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue