mirror of
https://github.com/jorisvink/kore
synced 2025-03-09 12:39:01 -04:00
Add the on_body_chunk handler for routes.
If set, will call a given handler with the prototype of `void body_chunk(struct http_request *req, const void *data, size_t len);` for each chunk of the received HTTP body, allowing a developer to handle it in their own way. The incoming body is still being handled and retained in the same way as before (in a kore_buf or temporary file). While here, allow HTTP_STATUS_CONTINUE to work via http_response() and make the handling of incoming HTTP header data a bit better.
This commit is contained in:
parent
f5a58368b7
commit
351eec7eb4
@ -287,6 +287,8 @@ struct kore_runtime {
|
|||||||
int type;
|
int type;
|
||||||
#if !defined(KORE_NO_HTTP)
|
#if !defined(KORE_NO_HTTP)
|
||||||
int (*http_request)(void *, struct http_request *);
|
int (*http_request)(void *, struct http_request *);
|
||||||
|
void (*http_body_chunk)(void *,
|
||||||
|
struct http_request *, const void *, size_t);
|
||||||
int (*validator)(void *, struct http_request *, const void *);
|
int (*validator)(void *, struct http_request *, const void *);
|
||||||
void (*wsconnect)(void *, struct connection *);
|
void (*wsconnect)(void *, struct connection *);
|
||||||
void (*wsdisconnect)(void *, struct connection *);
|
void (*wsdisconnect)(void *, struct connection *);
|
||||||
@ -986,6 +988,8 @@ void kore_runtime_connect(struct kore_runtime_call *, struct connection *);
|
|||||||
#if !defined(KORE_NO_HTTP)
|
#if !defined(KORE_NO_HTTP)
|
||||||
int kore_runtime_http_request(struct kore_runtime_call *,
|
int kore_runtime_http_request(struct kore_runtime_call *,
|
||||||
struct http_request *);
|
struct http_request *);
|
||||||
|
void kore_runtime_http_body_chunk(struct kore_runtime_call *,
|
||||||
|
struct http_request *, const void *, size_t);
|
||||||
int kore_runtime_validator(struct kore_runtime_call *,
|
int kore_runtime_validator(struct kore_runtime_call *,
|
||||||
struct http_request *, const void *);
|
struct http_request *, const void *);
|
||||||
void kore_runtime_wsconnect(struct kore_runtime_call *, struct connection *);
|
void kore_runtime_wsconnect(struct kore_runtime_call *, struct connection *);
|
||||||
|
91
src/http.c
91
src/http.c
@ -132,6 +132,7 @@ static int http_release_buffer(struct netbuf *);
|
|||||||
static void http_error_response(struct connection *, int);
|
static void http_error_response(struct connection *, int);
|
||||||
static int http_data_convert(void *, void **, void *, int);
|
static int http_data_convert(void *, void **, void *, int);
|
||||||
static void http_write_response_cookie(struct http_cookie *);
|
static void http_write_response_cookie(struct http_cookie *);
|
||||||
|
static int http_body_update(struct http_request *, const void *, size_t);
|
||||||
static void http_argument_add(struct http_request *, char *, char *,
|
static void http_argument_add(struct http_request *, char *, char *,
|
||||||
int, int);
|
int, int);
|
||||||
static int http_check_redirect(struct http_request *,
|
static int http_check_redirect(struct http_request *,
|
||||||
@ -806,10 +807,8 @@ http_header_recv(struct netbuf *nb)
|
|||||||
{
|
{
|
||||||
struct connection *c;
|
struct connection *c;
|
||||||
size_t len;
|
size_t len;
|
||||||
ssize_t ret;
|
|
||||||
struct http_header *hdr;
|
struct http_header *hdr;
|
||||||
struct http_request *req;
|
struct http_request *req;
|
||||||
u_int64_t bytes_left;
|
|
||||||
u_int8_t *end_headers;
|
u_int8_t *end_headers;
|
||||||
int h, i, v, skip, l;
|
int h, i, v, skip, l;
|
||||||
char *headers[HTTP_REQ_HEADER_MAX];
|
char *headers[HTTP_REQ_HEADER_MAX];
|
||||||
@ -821,6 +820,11 @@ http_header_recv(struct netbuf *nb)
|
|||||||
if (nb->b_len < 4)
|
if (nb->b_len < 4)
|
||||||
return (KORE_RESULT_OK);
|
return (KORE_RESULT_OK);
|
||||||
|
|
||||||
|
if (!isalpha(nb->buf[0])) {
|
||||||
|
http_error_response(c, HTTP_STATUS_BAD_REQUEST);
|
||||||
|
return (KORE_RESULT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
skip = 4;
|
skip = 4;
|
||||||
end_headers = kore_mem_find(nb->buf, nb->s_off, "\r\n\r\n", 4);
|
end_headers = kore_mem_find(nb->buf, nb->s_off, "\r\n\r\n", 4);
|
||||||
if (end_headers == NULL) {
|
if (end_headers == NULL) {
|
||||||
@ -962,47 +966,19 @@ http_header_recv(struct netbuf *nb)
|
|||||||
HTTP_STATUS_INTERNAL_ERROR);
|
HTTP_STATUS_INTERNAL_ERROR);
|
||||||
return (KORE_RESULT_OK);
|
return (KORE_RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = write(req->http_body_fd,
|
|
||||||
end_headers, (nb->s_off - len));
|
|
||||||
if (ret == -1 || (size_t)ret != (nb->s_off - len)) {
|
|
||||||
req->flags |= HTTP_REQUEST_DELETE;
|
|
||||||
http_error_response(req->owner,
|
|
||||||
HTTP_STATUS_INTERNAL_ERROR);
|
|
||||||
return (KORE_RESULT_OK);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
req->http_body_fd = -1;
|
req->http_body_fd = -1;
|
||||||
req->http_body = kore_buf_alloc(req->content_length);
|
req->http_body = kore_buf_alloc(req->content_length);
|
||||||
kore_buf_append(req->http_body, end_headers,
|
|
||||||
(nb->s_off - len));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SHA256_Init(&req->hashctx);
|
SHA256_Init(&req->hashctx);
|
||||||
SHA256_Update(&req->hashctx, end_headers, (nb->s_off - len));
|
c->http_timeout = http_body_timeout * 1000;
|
||||||
|
|
||||||
bytes_left = req->content_length - (nb->s_off - len);
|
if (!http_body_update(req, end_headers, nb->s_off - len)) {
|
||||||
if (bytes_left > 0) {
|
req->flags |= HTTP_REQUEST_DELETE;
|
||||||
kore_debug("%ld/%ld (%ld - %ld) more bytes for body",
|
http_error_response(req->owner,
|
||||||
bytes_left, req->content_length, nb->s_off, len);
|
HTTP_STATUS_INTERNAL_ERROR);
|
||||||
net_recv_reset(c,
|
return (KORE_RESULT_OK);
|
||||||
MIN(bytes_left, NETBUF_SEND_PAYLOAD_MAX),
|
|
||||||
http_body_recv);
|
|
||||||
c->rnb->extra = req;
|
|
||||||
http_request_sleep(req);
|
|
||||||
req->content_length = bytes_left;
|
|
||||||
c->http_timeout = http_body_timeout * 1000;
|
|
||||||
} else {
|
|
||||||
c->http_timeout = 0;
|
|
||||||
req->flags |= HTTP_REQUEST_COMPLETE;
|
|
||||||
req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
|
|
||||||
SHA256_Final(req->http_body_digest, &req->hashctx);
|
|
||||||
if (!http_body_rewind(req)) {
|
|
||||||
req->flags |= HTTP_REQUEST_DELETE;
|
|
||||||
http_error_response(req->owner,
|
|
||||||
HTTP_STATUS_INTERNAL_ERROR);
|
|
||||||
return (KORE_RESULT_OK);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c->http_timeout = 0;
|
c->http_timeout = 0;
|
||||||
@ -1505,7 +1481,6 @@ http_start_recv(struct connection *c)
|
|||||||
c->http_start = kore_time_ms();
|
c->http_start = kore_time_ms();
|
||||||
c->http_timeout = http_header_timeout * 1000;
|
c->http_timeout = http_header_timeout * 1000;
|
||||||
net_recv_reset(c, http_header_max, http_header_recv);
|
net_recv_reset(c, http_header_max, http_header_recv);
|
||||||
(void)net_recv_flush(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2360,22 +2335,29 @@ http_argument_add(struct http_request *req, char *name, char *value, int qs,
|
|||||||
static int
|
static int
|
||||||
http_body_recv(struct netbuf *nb)
|
http_body_recv(struct netbuf *nb)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
|
||||||
u_int64_t bytes_left;
|
|
||||||
struct http_request *req = (struct http_request *)nb->extra;
|
struct http_request *req = (struct http_request *)nb->extra;
|
||||||
|
|
||||||
SHA256_Update(&req->hashctx, nb->buf, nb->s_off);
|
return (http_body_update(req, nb->buf, nb->s_off));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
http_body_update(struct http_request *req, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
u_int64_t bytes_left;
|
||||||
|
|
||||||
|
SHA256_Update(&req->hashctx, data, len);
|
||||||
|
|
||||||
if (req->http_body_fd != -1) {
|
if (req->http_body_fd != -1) {
|
||||||
ret = write(req->http_body_fd, nb->buf, nb->s_off);
|
ret = write(req->http_body_fd, data, len);
|
||||||
if (ret == -1 || (size_t)ret != nb->s_off) {
|
if (ret == -1 || (size_t)ret != len) {
|
||||||
req->flags |= HTTP_REQUEST_DELETE;
|
req->flags |= HTTP_REQUEST_DELETE;
|
||||||
http_error_response(req->owner,
|
http_error_response(req->owner,
|
||||||
HTTP_STATUS_INTERNAL_ERROR);
|
HTTP_STATUS_INTERNAL_ERROR);
|
||||||
return (KORE_RESULT_ERROR);
|
return (KORE_RESULT_ERROR);
|
||||||
}
|
}
|
||||||
} else if (req->http_body != NULL) {
|
} else if (req->http_body != NULL) {
|
||||||
kore_buf_append(req->http_body, nb->buf, nb->s_off);
|
kore_buf_append(req->http_body, data, len);
|
||||||
} else {
|
} else {
|
||||||
req->flags |= HTTP_REQUEST_DELETE;
|
req->flags |= HTTP_REQUEST_DELETE;
|
||||||
http_error_response(req->owner,
|
http_error_response(req->owner,
|
||||||
@ -2383,10 +2365,10 @@ http_body_recv(struct netbuf *nb)
|
|||||||
return (KORE_RESULT_ERROR);
|
return (KORE_RESULT_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
req->content_length -= nb->s_off;
|
req->content_length -= len;
|
||||||
|
|
||||||
if (req->content_length == 0) {
|
if (req->content_length == 0) {
|
||||||
nb->extra = NULL;
|
req->owner->rnb->extra = NULL;
|
||||||
http_request_wakeup(req);
|
http_request_wakeup(req);
|
||||||
req->flags |= HTTP_REQUEST_COMPLETE;
|
req->flags |= HTTP_REQUEST_COMPLETE;
|
||||||
req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
|
req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
|
||||||
@ -2398,12 +2380,17 @@ http_body_recv(struct netbuf *nb)
|
|||||||
return (KORE_RESULT_ERROR);
|
return (KORE_RESULT_ERROR);
|
||||||
}
|
}
|
||||||
SHA256_Final(req->http_body_digest, &req->hashctx);
|
SHA256_Final(req->http_body_digest, &req->hashctx);
|
||||||
net_recv_reset(nb->owner, http_header_max, http_header_recv);
|
|
||||||
} else {
|
} else {
|
||||||
bytes_left = req->content_length;
|
bytes_left = req->content_length;
|
||||||
net_recv_reset(nb->owner,
|
net_recv_reset(req->owner,
|
||||||
MIN(bytes_left, NETBUF_SEND_PAYLOAD_MAX),
|
MIN(bytes_left, NETBUF_SEND_PAYLOAD_MAX),
|
||||||
http_body_recv);
|
http_body_recv);
|
||||||
|
req->owner->rnb->extra = req;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->rt->on_body_chunk != NULL && len > 0) {
|
||||||
|
kore_runtime_http_body_chunk(req->rt->on_body_chunk,
|
||||||
|
req, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (KORE_RESULT_OK);
|
return (KORE_RESULT_OK);
|
||||||
@ -2442,7 +2429,6 @@ http_response_normal(struct http_request *req, struct connection *c,
|
|||||||
send_body = 1;
|
send_body = 1;
|
||||||
text = http_status_text(status);
|
text = http_status_text(status);
|
||||||
|
|
||||||
kore_buf_init(&buf, 1024);
|
|
||||||
kore_buf_reset(header_buf);
|
kore_buf_reset(header_buf);
|
||||||
|
|
||||||
if (req != NULL) {
|
if (req != NULL) {
|
||||||
@ -2456,6 +2442,13 @@ http_response_normal(struct http_request *req, struct connection *c,
|
|||||||
|
|
||||||
kore_buf_appendf(header_buf, "HTTP/1.%c %d %s\r\n",
|
kore_buf_appendf(header_buf, "HTTP/1.%c %d %s\r\n",
|
||||||
version, status, text);
|
version, status, text);
|
||||||
|
|
||||||
|
if (status == 100) {
|
||||||
|
kore_buf_append(header_buf, "\r\n", 2);
|
||||||
|
net_send_queue(c, header_buf->data, header_buf->offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
kore_buf_append(header_buf, http_version, http_version_len);
|
kore_buf_append(header_buf, http_version, http_version_len);
|
||||||
|
|
||||||
if ((c->flags & CONN_CLOSE_EMPTY) ||
|
if ((c->flags & CONN_CLOSE_EMPTY) ||
|
||||||
@ -2474,6 +2467,8 @@ http_response_normal(struct http_request *req, struct connection *c,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kore_buf_init(&buf, 1024);
|
||||||
|
|
||||||
/* Note that req CAN be NULL. */
|
/* Note that req CAN be NULL. */
|
||||||
if (req == NULL || req->owner->proto != CONN_PROTO_WEBSOCKET) {
|
if (req == NULL || req->owner->proto != CONN_PROTO_WEBSOCKET) {
|
||||||
if (http_keepalive_time && connection_close == 0) {
|
if (http_keepalive_time && connection_close == 0) {
|
||||||
|
@ -292,6 +292,9 @@ net_recv_flush(struct connection *c)
|
|||||||
if (c->rnb->buf == NULL)
|
if (c->rnb->buf == NULL)
|
||||||
return (KORE_RESULT_OK);
|
return (KORE_RESULT_OK);
|
||||||
|
|
||||||
|
if ((c->rnb->b_len - c->rnb->s_off) == 0)
|
||||||
|
return (KORE_RESULT_OK);
|
||||||
|
|
||||||
if (!c->read(c, &r))
|
if (!c->read(c, &r))
|
||||||
return (KORE_RESULT_ERROR);
|
return (KORE_RESULT_ERROR);
|
||||||
if (!(c->evt.flags & KORE_EVENT_READ))
|
if (!(c->evt.flags & KORE_EVENT_READ))
|
||||||
|
@ -33,6 +33,8 @@ static void native_runtime_connect(void *, struct connection *);
|
|||||||
static void native_runtime_configure(void *, int, char **);
|
static void native_runtime_configure(void *, int, char **);
|
||||||
#if !defined(KORE_NO_HTTP)
|
#if !defined(KORE_NO_HTTP)
|
||||||
static int native_runtime_http_request(void *, struct http_request *);
|
static int native_runtime_http_request(void *, struct http_request *);
|
||||||
|
static void native_runtime_http_body_chunk(void *, struct http_request *,
|
||||||
|
const void *, size_t);
|
||||||
static int native_runtime_validator(void *, struct http_request *,
|
static int native_runtime_validator(void *, struct http_request *,
|
||||||
const void *);
|
const void *);
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ struct kore_runtime kore_native_runtime = {
|
|||||||
KORE_RUNTIME_NATIVE,
|
KORE_RUNTIME_NATIVE,
|
||||||
#if !defined(KORE_NO_HTTP)
|
#if !defined(KORE_NO_HTTP)
|
||||||
.http_request = native_runtime_http_request,
|
.http_request = native_runtime_http_request,
|
||||||
|
.http_body_chunk= native_runtime_http_body_chunk,
|
||||||
.validator = native_runtime_validator,
|
.validator = native_runtime_validator,
|
||||||
.wsconnect = native_runtime_connect,
|
.wsconnect = native_runtime_connect,
|
||||||
.wsmessage = native_runtime_wsmessage,
|
.wsmessage = native_runtime_wsmessage,
|
||||||
@ -105,6 +108,13 @@ kore_runtime_http_request(struct kore_runtime_call *rcall,
|
|||||||
return (rcall->runtime->http_request(rcall->addr, req));
|
return (rcall->runtime->http_request(rcall->addr, req));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kore_runtime_http_body_chunk(struct kore_runtime_call *rcall,
|
||||||
|
struct http_request *req, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
rcall->runtime->http_body_chunk(rcall->addr, req, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
kore_runtime_validator(struct kore_runtime_call *rcall,
|
kore_runtime_validator(struct kore_runtime_call *rcall,
|
||||||
struct http_request *req, const void *data)
|
struct http_request *req, const void *data)
|
||||||
@ -178,6 +188,17 @@ native_runtime_http_request(void *addr, struct http_request *req)
|
|||||||
return (cb(req));
|
return (cb(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
native_runtime_http_body_chunk(void *addr, struct http_request *req,
|
||||||
|
const void *data, size_t len)
|
||||||
|
{
|
||||||
|
void (*cb)(struct http_request *, const void *, size_t);
|
||||||
|
|
||||||
|
*(void **)&(cb) = addr;
|
||||||
|
|
||||||
|
cb(req, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
native_runtime_validator(void *addr, struct http_request *req, const void *data)
|
native_runtime_validator(void *addr, struct http_request *req, const void *data)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user