aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--handler.c15
-rw-r--r--http.c149
-rw-r--r--include/libweb/http.h1
3 files changed, 121 insertions, 44 deletions
diff --git a/handler.c b/handler.c
index 9ae9b10..8a777fa 100644
--- a/handler.c
+++ b/handler.c
@@ -28,6 +28,7 @@ struct handler
struct handler *h;
struct server_client *c;
struct http_ctx *http;
+ int (*fn)(const struct http_payload *, struct http_response *, void *);
struct client *next;
} *clients;
@@ -59,7 +60,19 @@ static int on_payload(const struct http_payload *const p,
const struct elem *const e = &h->elem[i];
if (e->op == p->op && !wildcard_cmp(p->resource, e->url, true))
- return e->f(p, r, e->user);
+ {
+ int ret;
+
+ if (c->fn)
+ ret = c->fn(p, r, e->user);
+ else
+ ret = e->f(p, r, e->user);
+
+ if (!ret)
+ c->fn = r->step;
+
+ return ret;
+ }
}
fprintf(stderr, "Not found: %s\n", p->resource);
diff --git a/http.c b/http.c
index 54ed5e3..67aa62e 100644
--- a/http.c
+++ b/http.c
@@ -102,6 +102,7 @@ struct http_ctx
size_t n_args, n_headers;
struct http_header *headers;
bool has_length, expect_continue;
+ int (*response)(struct http_ctx *);
} ctx;
struct write_ctx
@@ -1211,15 +1212,22 @@ static int process_payload(struct http_ctx *const h)
{
struct ctx *const c = &h->ctx;
const struct http_payload p = ctx_to_payload(c);
+ struct http_response *const r = &h->wctx.r;
const int ret = h->cfg.payload(&p, &h->wctx.r, h->cfg.user);
- h->wctx.op = c->op;
- ctx_free(c);
-
if (ret)
+ {
+ ctx_free(c);
return ret;
+ }
+ else if (!r->step)
+ {
+ h->wctx.op = c->op;
+ ctx_free(c);
+ return start_response(h);
+ }
- return start_response(h);
+ return 0;
}
static int get_field_value(const char *const line, size_t *const n,
@@ -1470,6 +1478,7 @@ static int check_length(struct http_ctx *const h)
static int process_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)
@@ -1480,7 +1489,7 @@ static int process_expect(struct http_ctx *const h)
return res;
}
- h->wctx.close = true;
+ w->close = true;
return start_response(h);
}
@@ -1488,36 +1497,51 @@ static int process_expect(struct http_ctx *const h)
p.expect_continue = true;
- const int ret = h->cfg.payload(&p, &h->wctx.r, h->cfg.user);
-
- h->wctx.op = c->op;
+ struct http_response *const r = &h->wctx.r;
+ const int ret = h->cfg.payload(&p, r, h->cfg.user);
if (ret)
+ {
+ ctx_free(c);
return ret;
+ }
+ else if (!r->step)
+ {
+ w->op = c->op;
+ c->state = BODY_LINE;
+ return start_response(h);
+ }
- c->state = BODY_LINE;
- return start_response(h);
+ return 0;
}
static int process_get(struct http_ctx *const h)
{
+ int ret;
struct ctx *const c = &h->ctx;
struct http_payload p = ctx_to_payload(c);
struct write_ctx *const w = &h->wctx;
+ struct http_response *const r = &w->r;
p.u.get.range = w->gr = c->u2.get.range;
- const int ret = h->cfg.payload(&p, &h->wctx.r, h->cfg.user);
+ if ((ret = h->cfg.payload(&p, &h->wctx.r, h->cfg.user)))
+ {
+ ctx_free(c);
+ return ret;
+ }
+ else if (!r->step)
+ {
+ w->op = c->op;
+ ctx_free(c);
- w->op = c->op;
- ctx_free(c);
+ if (w->gr.state)
+ w->r.status = HTTP_STATUS_PARTIAL_CONTENT;
- if (ret)
- return ret;
- else if (w->gr.state)
- w->r.status = HTTP_STATUS_PARTIAL_CONTENT;
+ return start_response(h);
+ }
- return start_response(h);
+ return 0;
}
static int header_cr_line(struct http_ctx *const h)
@@ -1530,17 +1554,25 @@ static int header_cr_line(struct http_ctx *const h)
switch (c->op)
{
case HTTP_OP_GET:
- return process_get(h);
+ c->response = process_get;
+ return 0;
case HTTP_OP_HEAD:
- return process_payload(h);
+ c->response = process_payload;
+ return 0;
case HTTP_OP_POST:
{
if (!c->u2.payload.len)
- return process_payload(h);
+ {
+ c->response = process_payload;
+ return 0;
+ }
else if (c->expect_continue)
- return process_expect(h);
+ {
+ c->response = process_expect;
+ return 0;
+ }
else if (c->boundary)
{
const int res = check_length(h);
@@ -1571,9 +1603,15 @@ static int header_cr_line(struct http_ctx *const h)
return 1;
}
else if (!c->u2.payload.len)
- return process_payload(h);
+ {
+ c->response = process_payload;
+ return 0;
+ }
else if (c->expect_continue)
- return process_expect(h);
+ {
+ c->response = process_expect;
+ return 0;
+ }
c->state = BODY_LINE;
return 0;
@@ -1594,14 +1632,21 @@ static int send_payload(struct http_ctx *const h,
const struct http_payload *const p)
{
struct ctx *const c = &h->ctx;
- const int ret = h->cfg.payload(p, &h->wctx.r, h->cfg.user);
-
- ctx_free(c);
+ struct http_response *const r = &h->wctx.r;
+ const int ret = h->cfg.payload(p, r, h->cfg.user);
if (ret)
+ {
+ ctx_free(c);
return ret;
+ }
+ else if (!r->step)
+ {
+ ctx_free(c);
+ return start_response(h);
+ }
- return start_response(h);
+ return 0;
}
static int update_lstate(struct http_ctx *const h,
@@ -2216,7 +2261,7 @@ static int read_mf_end_boundary(struct http_ctx *const h,
/* Found end boundary. */
if (!*n)
- return end_boundary(h);
+ c->response = end_boundary;
else
m->state = MF_END_BOUNDARY_CR_LINE;
}
@@ -2243,7 +2288,8 @@ static int process_mf_end_crlf(struct http_ctx *const h)
return 1;
}
- return end_boundary(h);
+ h->ctx.response = end_boundary;
+ return 0;
}
static int read_multiform(struct http_ctx *const h, const char *const buf,
@@ -2284,6 +2330,15 @@ static int read_multiform(struct http_ctx *const h, const char *const buf,
return 0;
}
+static int send_line_payload(struct http_ctx *const h)
+{
+ struct ctx *const c = &h->ctx;
+ struct http_payload pl = ctx_to_payload(c);
+
+ pl.u.post.data = h->line;
+ return send_payload(h, &pl);
+}
+
static int read_body_to_mem(struct http_ctx *const h, const char *const buf,
size_t *const sz)
{
@@ -2302,11 +2357,8 @@ static int read_body_to_mem(struct http_ctx *const h, const char *const buf,
if (p->read >= p->len)
{
- struct http_payload pl = ctx_to_payload(c);
-
h->line[p->len] = '\0';
- pl.u.post.data = h->line;
- return send_payload(h, &pl);
+ c->response = send_line_payload;
}
return 0;
@@ -2396,6 +2448,15 @@ static int read_put_body_to_file(struct http_ctx *const h,
return 0;
}
+static int send_put_payload(struct http_ctx *const h)
+{
+ struct ctx *const c = &h->ctx;
+ struct http_payload pl = ctx_to_payload(c);
+
+ pl.u.put.tmpname = c->u.put.tmpname;
+ return send_payload(h, &pl);
+}
+
static int read_to_file(struct http_ctx *const h, const char *const buf,
size_t *const sz)
{
@@ -2405,12 +2466,7 @@ static int read_to_file(struct http_ctx *const h, const char *const buf,
if (read_put_body_to_file(h, buf, sz))
return -1;
else if (p->read >= p->len)
- {
- struct http_payload pl = ctx_to_payload(c);
-
- pl.u.put.tmpname = c->u.put.tmpname;
- return send_payload(h, &pl);
- }
+ c->response = send_put_payload;
return 0;
}
@@ -2547,12 +2603,19 @@ failure:
int http_update(struct http_ctx *const h, bool *const write, bool *const close)
{
+ int ret;
+ struct ctx *const c = &h->ctx;
+ struct write_ctx *const w = &h->wctx;
+ struct http_response *const r = &w->r;
+
*close = false;
- struct write_ctx *const w = &h->wctx;
- const int ret = w->pending ? http_write(h, close) : http_read(h, close);
+ if (c->response)
+ ret = c->response(h);
+ else
+ ret = w->pending ? http_write(h, close) : http_read(h, close);
- *write = w->pending;
+ *write = c->response || w->pending;
return ret;
}
diff --git a/include/libweb/http.h b/include/libweb/http.h
index 736a561..f18b5c4 100644
--- a/include/libweb/http.h
+++ b/include/libweb/http.h
@@ -109,6 +109,7 @@ struct http_response
unsigned long long n;
size_t n_headers;
void (*free)(void *);
+ int (*step)(const struct http_payload *, struct http_response *, void *);
};
struct http_cfg