aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2024-08-22 01:56:20 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2024-08-22 02:27:34 +0200
commit34b62bd0c47c915a12ff1b81f52b123fc3eb4a69 (patch)
tree13e4c2d4fd988a2e815d2d6340998f06fbe4e0dd
parent3a25e79f269aa171f4e5646d52eb2f90d275cb3c (diff)
http.c: Fix ending boundaries not followed by CRLF
According to RFC 2046, section 5.1.1, end boundaries might not be followed by CRLF. However, so far libweb naively relied on this behaviour as major implementations, such as cURL, Chromium or Gecko always add the optional CRLF, whereas Dillo does not.
-rw-r--r--http.c125
1 files changed, 84 insertions, 41 deletions
diff --git a/http.c b/http.c
index bc269a7..e9b50ac 100644
--- a/http.c
+++ b/http.c
@@ -63,6 +63,7 @@ struct http_ctx
MF_START_BOUNDARY,
MF_HEADER_CR_LINE,
MF_BODY_BOUNDARY_LINE,
+ MF_END_BOUNDARY,
MF_END_BOUNDARY_CR_LINE
} state;
@@ -1590,46 +1591,32 @@ static int mf_header_cr_line(struct http_ctx *const h)
return 0;
}
-static int end_boundary_line(struct http_ctx *const h)
+static int end_boundary(struct http_ctx *const h)
{
- const char *const line = h->line;
+ /* Found end boundary. */
+ struct ctx *const c = &h->ctx;
+ struct multiform *const m = &c->u.mf;
- if (!*line)
+ const struct http_payload p =
{
- h->ctx.u.mf.state = MF_HEADER_CR_LINE;
- return 0;
- }
- else if (!strcmp(line, "--"))
- {
- /* Found end boundary. */
- struct ctx *const c = &h->ctx;
- struct multiform *const m = &c->u.mf;
-
- const struct http_payload p =
+ .cookie =
{
- .cookie =
- {
- .field = c->field,
- .value = c->value
- },
-
- .op = c->op,
- .resource = c->resource,
- .u.post =
- {
- .files = m->files,
- .pairs = m->pairs,
- .nfiles = m->nfiles,
- .npairs = m->npairs
- }
- };
+ .field = c->field,
+ .value = c->value
+ },
- return send_payload(h, &p);
- }
+ .op = c->op,
+ .resource = c->resource,
+ .u.post =
+ {
+ .files = m->files,
+ .pairs = m->pairs,
+ .nfiles = m->nfiles,
+ .npairs = m->npairs
+ }
+ };
- fprintf(stderr, "%s: unexpected line after boundary: %s\n",
- __func__, line);
- return 1;
+ return send_payload(h, &p);
}
static int process_mf_line(struct http_ctx *const h)
@@ -1637,8 +1624,7 @@ static int process_mf_line(struct http_ctx *const h)
static int (*const state[])(struct http_ctx *) =
{
[MF_START_BOUNDARY] = start_boundary_line,
- [MF_HEADER_CR_LINE] = mf_header_cr_line,
- [MF_END_BOUNDARY_CR_LINE] = end_boundary_line
+ [MF_HEADER_CR_LINE] = mf_header_cr_line
};
h->ctx.payload.read += strlen(h->line) + strlen("\r\n");
@@ -1827,7 +1813,7 @@ static bool name_exists(const struct multiform *const m,
if (!strcmp(f->name, p->name))
{
fprintf(stderr, "%s: \"%s\" defined more than once\n",
- f->name, __func__);
+ __func__, f->name);
return true;
}
}
@@ -1893,7 +1879,7 @@ static int read_mf_body_boundary_byte(struct http_ctx *const h, const char b,
memset(m->boundary, '\0', clen);
m->blen = 0;
- m->state = MF_END_BOUNDARY_CR_LINE;
+ m->state = MF_END_BOUNDARY;
m->written = 0;
return ret;
}
@@ -1991,6 +1977,53 @@ static int read_mf_body_boundary(struct http_ctx *const h,
return 0;
}
+static int read_mf_end_boundary(struct http_ctx *const h,
+ const char *const buf, size_t *const n)
+{
+ struct ctx *const c = &h->ctx;
+ struct multiform *const m = &c->u.mf;
+ static const char end[] = "--", crlf[] = "\r\n";
+ const bool check = c->len >= strlen(end) || c->len >= strlen(crlf);
+
+ h->line[c->len++] = *buf;
+ (*n)--;
+
+ if (c->len >= strlen(end) && !strncmp(h->line, end, strlen(end)))
+ {
+ c->len = 0;
+
+ /* Found end boundary. */
+ if (!*n)
+ return end_boundary(h);
+ else
+ m->state = MF_END_BOUNDARY_CR_LINE;
+ }
+ else if (c->len >= strlen(crlf) && !strncmp(h->line, crlf, strlen(crlf)))
+ {
+ c->len = 0;
+ m->state = MF_HEADER_CR_LINE;
+ }
+ else if (check)
+ {
+ fprintf(stderr, "%s: unexpected boundary delimiter: %.*s\n",
+ __func__, (int)c->len, h->line);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int process_mf_end_crlf(struct http_ctx *const h)
+{
+ if (*h->line)
+ {
+ fprintf(stderr, "%s: expected empty line\n", __func__);
+ return 1;
+ }
+
+ return end_boundary(h);
+}
+
static int read_multiform(struct http_ctx *const h, const char *const buf,
size_t *const sz)
{
@@ -2002,9 +2035,7 @@ static int read_multiform(struct http_ctx *const h, const char *const buf,
case MF_START_BOUNDARY:
/* Fall through. */
case MF_HEADER_CR_LINE:
- /* Fall through. */
- case MF_END_BOUNDARY_CR_LINE:
- if ((res = update_lstate(h, close, process_mf_line, buf, sz)))
+ if ((res = update_lstate(h, process_mf_line, buf, sz)))
return res;
break;
@@ -2014,6 +2045,18 @@ static int read_multiform(struct http_ctx *const h, const char *const buf,
return res;
break;
+
+ case MF_END_BOUNDARY:
+ if ((res = read_mf_end_boundary(h, buf, sz)))
+ return res;
+
+ break;
+
+ case MF_END_BOUNDARY_CR_LINE:
+ if ((res = update_lstate(h, process_mf_end_crlf, buf, sz)))
+ return res;
+
+ break;
}
return 0;