aboutsummaryrefslogtreecommitdiff
path: root/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'http.c')
-rw-r--r--http.c152
1 files changed, 110 insertions, 42 deletions
diff --git a/http.c b/http.c
index 67aa62e..c173c3d 100644
--- a/http.c
+++ b/http.c
@@ -103,6 +103,8 @@ struct http_ctx
struct http_header *headers;
bool has_length, expect_continue;
int (*response)(struct http_ctx *);
+ void *buf;
+ size_t buflen;
} ctx;
struct write_ctx
@@ -653,6 +655,7 @@ static void ctx_free(struct ctx *const c)
free(c->headers);
free(c->args);
+ free(c->buf);
*c = (const struct ctx){0};
}
@@ -1220,7 +1223,7 @@ static int process_payload(struct http_ctx *const h)
ctx_free(c);
return ret;
}
- else if (!r->step)
+ else if (!r->step.payload)
{
h->wctx.op = c->op;
ctx_free(c);
@@ -1475,29 +1478,15 @@ static int check_length(struct http_ctx *const h)
return h->cfg.length(c->u2.payload.len, &cookie, &h->wctx.r, h->cfg.user);
}
-static int process_expect(struct http_ctx *const h)
+static int process_payload_expect(struct http_ctx *const h)
{
struct ctx *const c = &h->ctx;
struct write_ctx *const w = &h->wctx;
- const int res = check_length(h);
-
- if (res)
- {
- if (res < 0)
- {
- fprintf(stderr, "%s: check_length failed\n", __func__);
- return res;
- }
-
- w->close = true;
- return start_response(h);
- }
-
+ struct http_response *const r = &h->wctx.r;
struct http_payload p = ctx_to_payload(c);
p.expect_continue = true;
- struct http_response *const r = &h->wctx.r;
const int ret = h->cfg.payload(&p, r, h->cfg.user);
if (ret)
@@ -1505,7 +1494,7 @@ static int process_expect(struct http_ctx *const h)
ctx_free(c);
return ret;
}
- else if (!r->step)
+ else if (!r->step.payload)
{
w->op = c->op;
c->state = BODY_LINE;
@@ -1515,6 +1504,30 @@ static int process_expect(struct http_ctx *const h)
return 0;
}
+static int process_expect(struct http_ctx *const h)
+{
+ struct ctx *const c = &h->ctx;
+ struct write_ctx *const w = &h->wctx;
+ struct http_response *const r = &h->wctx.r;
+ const int res = check_length(h);
+
+ if (res)
+ {
+ if (res < 0)
+ {
+ fprintf(stderr, "%s: check_length failed\n", __func__);
+ return res;
+ }
+
+ w->close = true;
+ return start_response(h);
+ }
+ else if (!r->step.length)
+ c->response = process_payload_expect;
+
+ return 0;
+}
+
static int process_get(struct http_ctx *const h)
{
int ret;
@@ -1530,7 +1543,7 @@ static int process_get(struct http_ctx *const h)
ctx_free(c);
return ret;
}
- else if (!r->step)
+ else if (!r->step.payload)
{
w->op = c->op;
ctx_free(c);
@@ -1544,6 +1557,34 @@ static int process_get(struct http_ctx *const h)
return 0;
}
+static int process_boundary(struct http_ctx *const h)
+{
+ struct ctx *const c = &h->ctx;
+ struct write_ctx *const w = &h->wctx;
+ const int res = check_length(h);
+
+ if (res)
+ {
+ if (res < 0)
+ {
+ fprintf(stderr, "%s: check_length failed\n",
+ __func__);
+ return res;
+ }
+
+ w->close = true;
+ ctx_free(c);
+ return start_response(h);
+ }
+ else if (!w->r.step.length)
+ {
+ c->response = NULL;
+ c->state = BODY_LINE;
+ }
+
+ return 0;
+}
+
static int header_cr_line(struct http_ctx *const h)
{
const char *const line = (const char *)h->line;
@@ -1575,20 +1616,8 @@ static int header_cr_line(struct http_ctx *const h)
}
else if (c->boundary)
{
- const int res = check_length(h);
-
- if (res)
- {
- if (res < 0)
- {
- fprintf(stderr, "%s: check_length failed\n",
- __func__);
- return res;
- }
-
- h->wctx.close = true;
- return start_response(h);
- }
+ c->response = process_boundary;
+ return 0;
}
c->state = BODY_LINE;
@@ -1640,7 +1669,7 @@ static int send_payload(struct http_ctx *const h,
ctx_free(c);
return ret;
}
- else if (!r->step)
+ else if (!r->step.payload)
{
ctx_free(c);
return start_response(h);
@@ -2524,28 +2553,67 @@ static int read_buf(struct http_ctx *const h, const char *const buf,
return -1;
}
+static int storebuf(struct http_ctx *const h, const void *const src,
+ const size_t n)
+{
+ struct ctx *const c = &h->ctx;
+ void *const dst = malloc(n);
+
+ if (!dst)
+ {
+ fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ memcpy((c->buf = dst), src, (c->buflen = n));
+ return 0;
+}
+
+static int loadbuf(struct http_ctx *const h, void *const dst, const size_t n)
+{
+ struct ctx *const c = &h->ctx;
+
+ memcpy(dst, c->buf, c->buflen);
+ free(c->buf);
+ c->buf = NULL;
+ return c->buflen;
+}
+
int http_read(struct http_ctx *const h, bool *const close)
{
+ struct ctx *const c = &h->ctx;
char buf[BUFSIZ];
- const int r = h->cfg.read(buf, sizeof buf, h->cfg.user);
+ int ret, r;
- if (r <= 0)
+ if (c->buf)
+ r = loadbuf(h, buf, sizeof buf);
+ else if ((r = h->cfg.read(buf, sizeof buf, h->cfg.user)) <= 0)
return rw_error(r, close);
size_t rem = r;
while (rem)
{
- const int ret = read_buf(h, &buf[r - rem], &rem);
-
- if (ret)
+ if ((ret = read_buf(h, &buf[r - rem], &rem)))
+ goto failure;
+ else if (c->response && rem)
{
- ctx_free(&h->ctx);
- return ret;
+ if (storebuf(h, &buf[r - rem], rem))
+ {
+ fprintf(stderr, "%s: storebuf failed\n", __func__);
+ ret = -1;
+ goto failure;
+ }
+
+ break;
}
}
return 0;
+
+failure:
+ ctx_free(&h->ctx);
+ return ret;
}
static int append_expire(struct dynstr *const d)
@@ -2615,7 +2683,7 @@ int http_update(struct http_ctx *const h, bool *const write, bool *const close)
else
ret = w->pending ? http_write(h, close) : http_read(h, close);
- *write = c->response || w->pending;
+ *write = c->buf || c->response || w->pending;
return ret;
}