diff options
Diffstat (limited to 'http.c')
| -rw-r--r-- | http.c | 152 |
1 files changed, 110 insertions, 42 deletions
@@ -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; } |
