Massive rework of HTTP layer.

This commit is a flag day, your old modules will almost certainly
need to be updated in order to build properly with these changes.

Summary of changes:

- Offload HTTP bodies to disk if they are large (inspired by #100).
  (disabled by default)
- The http_argument_get* macros now takes an explicit http_request parameter.
- Kore will now throw 404 errors almost immediately after an HTTP request
  has come in instead of waiting until all data has arrived.

API changes:

- http_argument_get* macros now require an explicit http_request parameter.
  (no more magic invokations).
- http_generic_404() is gone
- http_populate_arguments() is gone
- http_body_bytes() is gone
- http_body_text() is gone
- http_body_read() has been added
- http_populate_post() has been added
- http_populate_get() has been added
- http_file_read() has been added
- http_file_rewind() has been added
- http_file_lookup() no longer takes name, fname, data and len parameters.
- http_file_lookup() now returns a struct http_file pointer.
- http_populate_multipart_form() no longer takes an secondary parameter.

New configuration options:

- http_body_disk_offload:
	Number of bytes after which Kore will offload the HTTP body to
	disk instead of retaining it in memory. If 0 this feature is
	disabled. (Default: 0)

- http_body_disk_path:
	The path where Kore will store temporary HTTP body files.
	(this directory does not get created if http_body_disk_offload is 0).

New example:

The upload example has been added, demonstrating how to deal with file
uploads from a multipart form.
This commit is contained in:
Joris Vink 2016-01-18 11:30:22 +01:00
parent 96641d3caa
commit fcb86ddb8b
17 changed files with 953 additions and 478 deletions

View File

@ -61,6 +61,16 @@ workers 4
# http_body_max Maximum size of an HTTP body (in bytes).
# If set to 0 disallows requests with a body
# all together.
#
# http_body_disk_offload Number of bytes after which Kore will use
# a temporary file to hold the HTTP body
# instead of holding it in memory. If set to
# 0 no disk offloading will be done. This is
# turned off by default.
#
# http_body_disk_path Path where Kore will store any temporary
# HTTP body files.
#
# http_keepalive_time Maximum seconds an HTTP connection can be
# kept alive by the browser.
# (Set to 0 to disable keepalive completely).
@ -76,6 +86,8 @@ workers 4
#http_keepalive_time 0
#http_hsts_enable 31536000
#http_request_limit 1000
#http_body_disk_offload 0
#http_body_disk_path tmp_files
# Websocket specific settings.
# websocket_maxframe Specifies the maximum frame size we can receive

View File

@ -5,6 +5,9 @@ load ./generic.so example_load
tls_dhparam dh2048.pem
http_body_max 1024000000
http_body_disk_offload 1024000
validator v_example function v_example_func
validator v_regex regex ^/test/[a-z]*$
validator v_number regex ^[0-9]*$

View File

@ -17,6 +17,12 @@
#include <kore/kore.h>
#include <kore/http.h>
#include <openssl/sha.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "assets.h"
int example_load(int);
@ -132,9 +138,9 @@ serve_b64test(struct http_request *req)
int
serve_file_upload(struct http_request *req)
{
int r;
u_int8_t *d;
struct kore_buf *b;
struct http_file *f;
u_int32_t len;
char *name, buf[BUFSIZ];
@ -142,16 +148,20 @@ serve_file_upload(struct http_request *req)
kore_buf_append(b, asset_upload_html, asset_len_upload_html);
if (req->method == HTTP_METHOD_POST) {
http_populate_multipart_form(req, &r);
if (http_argument_get_string("firstname", &name, &len)) {
kore_buf_replace_string(b, "$firstname$", name, len);
if (req->http_body_fd != -1)
kore_log(LOG_NOTICE, "file is on disk");
http_populate_multipart_form(req);
if (http_argument_get_string(req, "firstname", &name)) {
kore_buf_replace_string(b, "$firstname$",
name, strlen(name));
} else {
kore_buf_replace_string(b, "$firstname$", NULL, 0);
}
if (http_file_lookup(req, "file", &name, &d, &len)) {
if ((f = http_file_lookup(req, "file")) != NULL) {
(void)snprintf(buf, sizeof(buf),
"%s is %d bytes", name, len);
"%s is %ld bytes", f->filename, f->length);
kore_buf_replace_string(b,
"$upload$", buf, strlen(buf));
} else {
@ -232,7 +242,10 @@ serve_params_test(struct http_request *req)
int r, i;
char *test, name[10];
http_populate_arguments(req);
if (req->method == HTTP_METHOD_GET)
http_populate_get(req);
else if (req->method == HTTP_METHOD_POST)
http_populate_post(req);
b = kore_buf_create(asset_len_params_html);
kore_buf_append(b, asset_params_html, asset_len_params_html);
@ -240,14 +253,14 @@ serve_params_test(struct http_request *req)
/*
* The GET parameters will be filtered out on POST.
*/
if (http_argument_get_string("arg1", &test, &len)) {
kore_buf_replace_string(b, "$arg1$", test, len);
if (http_argument_get_string(req, "arg1", &test)) {
kore_buf_replace_string(b, "$arg1$", test, strlen(test));
} else {
kore_buf_replace_string(b, "$arg1$", NULL, 0);
}
if (http_argument_get_string("arg2", &test, &len)) {
kore_buf_replace_string(b, "$arg2$", test, len);
if (http_argument_get_string(req, "arg2", &test)) {
kore_buf_replace_string(b, "$arg2$", test, strlen(test));
} else {
kore_buf_replace_string(b, "$arg2$", NULL, 0);
}
@ -257,7 +270,7 @@ serve_params_test(struct http_request *req)
kore_buf_replace_string(b, "$test2$", NULL, 0);
kore_buf_replace_string(b, "$test3$", NULL, 0);
if (http_argument_get_uint16("id", &r))
if (http_argument_get_uint16(req, "id", &r))
kore_log(LOG_NOTICE, "id: %d", r);
else
kore_log(LOG_NOTICE, "No id set");
@ -272,9 +285,9 @@ serve_params_test(struct http_request *req)
for (i = 1; i < 4; i++) {
(void)snprintf(name, sizeof(name), "test%d", i);
if (http_argument_get_string(name, &test, &len)) {
if (http_argument_get_string(req, name, &test)) {
(void)snprintf(name, sizeof(name), "$test%d$", i);
kore_buf_replace_string(b, name, test, len);
kore_buf_replace_string(b, name, test, strlen(test));
} else {
(void)snprintf(name, sizeof(name), "$test%d$", i);
kore_buf_replace_string(b, name, NULL, 0);

View File

@ -15,28 +15,28 @@ page(struct http_request *req)
u_int32_t u32, len;
u_int8_t c, *data;
http_populate_arguments(req);
http_populate_get(req);
buf = kore_buf_create(128);
if (http_argument_get_byte("id", &c))
if (http_argument_get_byte(req, "id", &c))
kore_buf_appendf(buf, "byte\t%c\n", c);
if (http_argument_get_int16("id", &s16))
if (http_argument_get_int16(req, "id", &s16))
kore_buf_appendf(buf, "int16\t%d\n", s16);
if (http_argument_get_uint16("id", &u16))
if (http_argument_get_uint16(req, "id", &u16))
kore_buf_appendf(buf, "uint16\t%d\n", u16);
if (http_argument_get_int32("id", &s32))
if (http_argument_get_int32(req, "id", &s32))
kore_buf_appendf(buf, "int32\t%d\n", s32);
if (http_argument_get_uint32("id", &u32))
if (http_argument_get_uint32(req, "id", &u32))
kore_buf_appendf(buf, "uint32\t%d\n", u32);
if (http_argument_get_int64("id", &s64))
if (http_argument_get_int64(req, "id", &s64))
kore_buf_appendf(buf, "int64\t%ld\n", s64);
if (http_argument_get_uint64("id", &u64))
if (http_argument_get_uint64(req, "id", &u64))
kore_buf_appendf(buf, "uint64\t%lu\n", u64);
data = kore_buf_release(buf, &len);

View File

@ -1,3 +1,19 @@
/*
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <kore/kore.h>
#include <kore/http.h>
@ -8,10 +24,12 @@ int page(struct http_request *);
int
page(struct http_request *req)
{
ssize_t ret;
struct kore_buf *buf;
char *body;
yajl_val node, v;
char eb[1024];
u_int8_t data[BUFSIZ];
const char *path[] = { "foo", "bar", NULL };
/* We only allow POST/PUT methods. */
@ -23,14 +41,27 @@ page(struct http_request *req)
}
/*
* Grab the entire body we received as text (NUL-terminated).
* Note: this can return NULL and the result MUST be freed.
* Read the entire received body into a memory buffer.
*/
if ((body = http_body_text(req)) == NULL) {
http_response(req, 400, NULL, 0);
return (KORE_RESULT_OK);
buf = kore_buf_create(128);
for (;;) {
ret = http_body_read(req, data, sizeof(data));
if (ret == -1) {
kore_buf_free(buf);
kore_log(LOG_NOTICE, "error reading body");
http_response(req, 500, NULL, 0);
return (KORE_RESULT_OK);
}
if (ret == 0)
break;
kore_buf_append(buf, data, ret);
}
/* Grab our body data as a NUL-terminated string. */
body = kore_buf_stringify(buf);
/* Parse the body via yajl now. */
node = yajl_tree_parse(body, eb, sizeof(eb));
if (node == NULL) {
@ -40,12 +71,13 @@ page(struct http_request *req)
kore_log(LOG_NOTICE, "parse error: unknown");
}
kore_mem_free(body);
kore_buf_free(buf);
http_response(req, 400, NULL, 0);
return (KORE_RESULT_OK);
}
buf = kore_buf_create(128);
/* Reuse old buffer, don't need it anymore for body. */
kore_buf_reset(buf);
/* Attempt to grab foo.bar from the JSON tree. */
v = yajl_tree_get(node, path, yajl_t_string);

View File

@ -49,9 +49,9 @@ open_connection(struct http_request *req)
}
/* Parse the query string and grab our arguments. */
http_populate_arguments(req);
if (!http_argument_get_string("host", &host, NULL) ||
!http_argument_get_string("port", &port, NULL)) {
http_populate_get(req);
if (!http_argument_get_string(req, "host", &host) ||
!http_argument_get_string(req, "port", &port)) {
http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
return (KORE_RESULT_OK);
}

View File

@ -22,9 +22,7 @@ int page(struct http_request *);
int
page(struct http_request *req)
{
int p;
u_int16_t id;
u_int32_t len;
char *sid;
struct kore_buf *buf;
@ -40,17 +38,8 @@ page(struct http_request *req)
* See conf/parameters.conf on how that is done, this is an
* important step as without the params block you will never
* get any parameters returned from Kore.
*
* http_populate_arguments() returns the number of arguments
* that were successfully processed and are available.
*/
p = http_populate_arguments(req);
/* If we had no arguments available what so ever, return 400. */
if (p == 0) {
http_response(req, 400, NULL, 0);
return (KORE_RESULT_OK);
}
http_populate_get(req);
/*
* Lets grab the "id" parameter if available. Kore can obtain
@ -73,11 +62,11 @@ page(struct http_request *req)
buf = kore_buf_create(128);
/* Grab it as a string, we shouldn't free the result in sid. */
if (http_argument_get_string("id", &sid, &len))
kore_buf_appendf(buf, "id as a string: '%s' (%d)\n", sid, len);
if (http_argument_get_string(req, "id", &sid))
kore_buf_appendf(buf, "id as a string: '%s'\n", sid);
/* Grab it as an actual u_int16_t. */
if (http_argument_get_uint16("id", &id))
if (http_argument_get_uint16(req, "id", &id))
kore_buf_appendf(buf, "id as an u_int16_t: %d\n", id);
/* Now return the result to the client with a 200 status code. */

View File

@ -58,8 +58,8 @@ page_handler(struct http_request *req)
*/
if (req->hdlr_extra == NULL) {
/* Grab the user argument */
http_populate_arguments(req);
if (!http_argument_get_string("user", &user, &len)) {
http_populate_get(req);
if (!http_argument_get_string(req, "user", &user)) {
http_response(req, 500, "ERROR\n", 6);
return (KORE_RESULT_OK);
}
@ -87,7 +87,7 @@ page_handler(struct http_request *req)
* GET request to its channel.
*/
kore_task_run(&state->task);
kore_task_channel_write(&state->task, user, len);
kore_task_channel_write(&state->task, user, strlen(user));
/*
* Tell Kore to retry us later.
@ -142,7 +142,6 @@ page_handler(struct http_request *req)
int
post_back(struct http_request *req)
{
u_int32_t len;
char *user;
if (req->method != HTTP_METHOD_POST) {
@ -150,14 +149,14 @@ post_back(struct http_request *req)
return (KORE_RESULT_OK);
}
http_populate_arguments(req);
if (!http_argument_get_string("user", &user, &len)) {
http_populate_post(req);
if (!http_argument_get_string(req, "user", &user)) {
http_response(req, 500, NULL, 0);
return (KORE_RESULT_OK);
}
/* Simply echo the supplied user argument back. */
http_response(req, 200, user, len);
http_response(req, 200, user, strlen(user));
return (KORE_RESULT_OK);
}

5
examples/upload/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.o
.objs
upload.so
assets.h
cert

View File

@ -0,0 +1,19 @@
# Placeholder configuration
bind 127.0.0.1 8888
load ./upload.so
http_body_max 1024000000
http_body_disk_offload 4096
validator v_name regex ^[a-zA-Z]*$
validator v_number regex ^[0-9]*$
domain 127.0.0.1 {
static / page
params post / {
validate field1 v_name
validate field2 v_number
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2016 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This example demonstrates how to properly deal with file uploads
* coming from a multipart form.
*
* The basics are quite trivial:
* 1) call http_populate_multipart_form()
* 2) find the file using http_file_lookup().
* 3) read the file data using http_file_read().
*
* In this example the contents is written to a newly created file
* on the server that matches the naming given by the uploader.
*
* Note that the above is probably not what you want to do in real life.
*/
#include <kore/kore.h>
#include <kore/http.h>
#include <fcntl.h>
#include <unistd.h>
int page(struct http_request *);
int
page(struct http_request *req)
{
int fd;
struct http_file *file;
u_int8_t buf[BUFSIZ];
ssize_t ret, written;
/* Only deal with POSTs. */
if (req->method != HTTP_METHOD_POST) {
http_response(req, 405, NULL, 0);
return (KORE_RESULT_OK);
}
/* Parse the multipart data that was present. */
http_populate_multipart_form(req);
/* Find our file. */
if ((file = http_file_lookup(req, "file")) == NULL) {
http_response(req, 400, NULL, 0);
return (KORE_RESULT_OK);
}
/* Open dump file where we will write file contents. */
fd = open(file->filename, O_CREAT | O_TRUNC | O_WRONLY, 0700);
if (fd == -1) {
http_response(req, 500, NULL, 0);
return (KORE_RESULT_OK);
}
/* While we have data from http_file_read(), write it. */
ret = KORE_RESULT_ERROR;
for (;;) {
ret = http_file_read(file, buf, sizeof(buf));
if (ret == -1) {
kore_log(LOG_ERR, "failed to read from file");
http_response(req, 500, NULL, 0);
goto cleanup;
}
if (ret == 0)
break;
written = write(fd, buf, ret);
if (written == -1) {
kore_log(LOG_ERR,"write(%s): %s",
file->filename, errno_s);
http_response(req, 500, NULL, 0);
goto cleanup;
}
if (written != ret) {
kore_log(LOG_ERR, "partial write on %s",
file->filename);
http_response(req, 500, NULL, 0);
goto cleanup;
}
}
ret = KORE_RESULT_OK;
http_response(req, 200, NULL, 0);
kore_log(LOG_INFO, "file '%s' successfully received",
file->filename);
cleanup:
if (close(fd) == -1)
kore_log(LOG_WARNING, "close(%s): %s", file->filename, errno_s);
if (ret == KORE_RESULT_ERROR) {
if (unlink("dump") == -1) {
kore_log(LOG_WARNING, "unlink(%s): %s",
file->filename, errno_s);
}
ret = KORE_RESULT_OK;
}
return (KORE_RESULT_OK);
}

View File

@ -33,6 +33,10 @@ extern "C" {
#define HTTP_MAX_QUERY_ARGS 20
#define HTTP_MAX_COOKIES 10
#define HTTP_REQUEST_LIMIT 1000
#define HTTP_BODY_DISK_PATH "tmp_files"
#define HTTP_BODY_DISK_OFFLOAD 0
#define HTTP_BODY_PATH_MAX 256
#define HTTP_BOUNDARY_MAX 80
#define HTTP_ARG_TYPE_RAW 0
#define HTTP_ARG_TYPE_BYTE 1
@ -58,19 +62,13 @@ struct http_header {
struct http_arg {
char *name;
void *value;
u_int32_t len;
char *s_value;
u_int32_t s_len;
TAILQ_ENTRY(http_arg) list;
};
#define COPY_ARG_TYPE(v, l, t) \
#define COPY_ARG_TYPE(v, t) \
do { \
if (l != NULL) \
*l = sizeof(t); \
*(t *)nout = v; \
} while (0);
@ -81,7 +79,7 @@ struct http_arg {
nval = (type)kore_strtonum64(q->s_value, sign, &err); \
if (err != KORE_RESULT_OK) \
return (KORE_RESULT_ERROR); \
COPY_ARG_TYPE(nval, len, type); \
COPY_ARG_TYPE(nval, type); \
} while (0);
#define COPY_ARG_INT(min, max, type) \
@ -91,23 +89,13 @@ struct http_arg {
nval = kore_strtonum(q->s_value, 10, min, max, &err); \
if (err != KORE_RESULT_OK) \
return (KORE_RESULT_ERROR); \
COPY_ARG_TYPE(nval, len, type); \
} while (0);
#define CACHE_STRING() \
do { \
if (q->s_value == NULL) { \
q->s_len = q->len + 1; \
q->s_value = kore_malloc(q->s_len); \
kore_strlcpy(q->s_value, q->value, q->s_len); \
} \
COPY_ARG_TYPE(nval, type); \
} while (0);
#define COPY_AS_INTTYPE_64(type, sign) \
do { \
if (nout == NULL) \
return (KORE_RESULT_ERROR); \
CACHE_STRING(); \
COPY_ARG_INT64(type, sign); \
} while (0);
@ -115,45 +103,44 @@ struct http_arg {
do { \
if (nout == NULL) \
return (KORE_RESULT_ERROR); \
CACHE_STRING(); \
COPY_ARG_INT(min, max, type); \
} while (0);
#define http_argument_type(r, n, so, no, l, t) \
http_argument_get(r, n, so, no, l, t)
#define http_argument_type(r, n, so, no, t) \
http_argument_get(r, n, so, no, t)
#define http_argument_get_string(n, o, l) \
http_argument_type(req, n, (void **)o, NULL, l, HTTP_ARG_TYPE_STRING)
#define http_argument_get_string(r, n, o) \
http_argument_type(r, n, (void **)o, NULL, HTTP_ARG_TYPE_STRING)
#define http_argument_get_byte(n, o) \
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_BYTE)
#define http_argument_get_byte(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
#define http_argument_get_uint16(n, o) \
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_UINT16)
#define http_argument_get_uint16(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
#define http_argument_get_int16(n, o) \
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_INT16)
#define http_argument_get_int16(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
#define http_argument_get_uint32(n, o) \
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_UINT32)
#define http_argument_get_uint32(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
#define http_argument_get_int32(n, o) \
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_INT32)
#define http_argument_get_int32(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
#define http_argument_get_uint64(n, o) \
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_UINT64)
#define http_argument_get_uint64(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
#define http_argument_get_int64(n, o) \
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_INT64)
#define http_argument_get_int64(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
struct http_file {
char *name;
char *filename;
u_int8_t *data;
u_int32_t len;
size_t position;
size_t offset;
size_t length;
struct http_request *req;
TAILQ_ENTRY(http_file) list;
};
@ -163,20 +150,21 @@ struct http_file {
#define HTTP_METHOD_DELETE 3
#define HTTP_METHOD_HEAD 4
#define HTTP_REQUEST_COMPLETE 0x01
#define HTTP_REQUEST_DELETE 0x02
#define HTTP_REQUEST_SLEEPING 0x04
#define HTTP_REQUEST_PGSQL_QUEUE 0x10
#define HTTP_REQUEST_EXPECT_BODY 0x20
#define HTTP_REQUEST_RETAIN_EXTRA 0x40
#define HTTP_REQUEST_NO_CONTENT_LENGTH 0x80
#define HTTP_REQUEST_COMPLETE 0x0001
#define HTTP_REQUEST_DELETE 0x0002
#define HTTP_REQUEST_SLEEPING 0x0004
#define HTTP_REQUEST_PGSQL_QUEUE 0x0010
#define HTTP_REQUEST_EXPECT_BODY 0x0020
#define HTTP_REQUEST_RETAIN_EXTRA 0x0040
#define HTTP_REQUEST_NO_CONTENT_LENGTH 0x0080
#define HTTP_REQUEST_AUTHED 0x0100
struct kore_task;
struct http_request {
u_int8_t method;
u_int8_t flags;
u_int8_t fsm_state;
u_int16_t flags;
u_int16_t status;
u_int64_t start;
u_int64_t end;
@ -186,10 +174,13 @@ struct http_request {
char *agent;
struct connection *owner;
struct kore_buf *http_body;
u_int64_t content_length;
int http_body_fd;
char *http_body_path;
size_t http_body_length;
size_t http_body_offset;
size_t content_length;
void *hdlr_extra;
char *query_string;
u_int8_t *multipart_body;
struct kore_module_handle *hdlr;
LIST_HEAD(, kore_task) tasks;
@ -214,6 +205,10 @@ extern u_int64_t http_body_max;
extern u_int64_t http_hsts_enable;
extern u_int16_t http_keepalive_time;
extern u_int32_t http_request_limit;
extern u_int64_t http_body_disk_offload;
extern char *http_body_disk_path;
void kore_accesslog(struct http_request *);
void http_init(void);
void http_process(void);
@ -222,9 +217,8 @@ time_t http_date_to_time(char *);
void http_request_free(struct http_request *);
void http_request_sleep(struct http_request *);
void http_request_wakeup(struct http_request *);
char *http_body_text(struct http_request *);
void http_process_request(struct http_request *, int);
u_int8_t *http_body_bytes(struct http_request *, u_int32_t *);
void http_process_request(struct http_request *);
ssize_t http_body_read(struct http_request *, void *, size_t);
void http_response(struct http_request *, int, void *, u_int32_t);
void http_response_stream(struct http_request *, int, void *,
u_int64_t, int (*cb)(struct netbuf *), void *);
@ -240,15 +234,15 @@ int http_state_run(struct http_state *, u_int8_t,
int http_argument_urldecode(char *);
int http_header_recv(struct netbuf *);
int http_generic_404(struct http_request *);
int http_populate_arguments(struct http_request *);
int http_populate_multipart_form(struct http_request *, int *);
void http_populate_get(struct http_request *);
void http_populate_post(struct http_request *);
void http_populate_multipart_form(struct http_request *);
int http_argument_get(struct http_request *,
const char *, void **, void *, u_int32_t *, int);
int http_file_lookup(struct http_request *, const char *, char **,
u_int8_t **, u_int32_t *);
const char *, void **, void *, int);
void kore_accesslog(struct http_request *);
void http_file_rewind(struct http_file *);
ssize_t http_file_read(struct http_file *, void *, size_t);
struct http_file *http_file_lookup(struct http_request *, const char *);
enum http_status_code {
HTTP_STATUS_CONTINUE = 100,

View File

@ -322,8 +322,7 @@ struct kore_validator {
};
#endif
#define KORE_BUF_INITIAL 128
#define KORE_BUF_INCREMENT KORE_BUF_INITIAL
#define KORE_BUF_INCREMENT 4096
struct kore_buf {
u_int8_t *data;
@ -592,8 +591,9 @@ void kore_buf_free(struct kore_buf *);
struct kore_buf *kore_buf_create(u_int32_t);
void kore_buf_append(struct kore_buf *, const void *, u_int32_t);
u_int8_t *kore_buf_release(struct kore_buf *, u_int32_t *);
void kore_buf_reset(struct kore_buf *);
void kore_buf_reset(struct kore_buf *);
char *kore_buf_stringify(struct kore_buf *);
void kore_buf_appendf(struct kore_buf *, const char *, ...);
void kore_buf_appendv(struct kore_buf *, const char *, va_list);
void kore_buf_appendb(struct kore_buf *, struct kore_buf *);

View File

@ -77,6 +77,7 @@ kore_auth_run(struct http_request *req, struct kore_auth *auth)
switch (r) {
case KORE_RESULT_OK:
req->flags |= HTTP_REQUEST_AUTHED;
kore_debug("kore_auth_run() for %s successful", req->path);
/* FALLTHROUGH */
case KORE_RESULT_RETRY:

View File

@ -65,6 +65,8 @@ static int configure_http_body_max(char **);
static int configure_http_hsts_enable(char **);
static int configure_http_keepalive_time(char **);
static int configure_http_request_limit(char **);
static int configure_http_body_disk_offload(char **);
static int configure_http_body_disk_path(char **);
static int configure_validator(char **);
static int configure_params(char **);
static int configure_validate(char **);
@ -122,6 +124,8 @@ static struct {
{ "http_hsts_enable", configure_http_hsts_enable },
{ "http_keepalive_time", configure_http_keepalive_time },
{ "http_request_limit", configure_http_request_limit },
{ "http_body_disk_offload", configure_http_body_disk_offload },
{ "http_body_disk_path", configure_http_body_disk_path },
{ "validator", configure_validator },
{ "params", configure_params },
{ "validate", configure_validate },
@ -545,6 +549,36 @@ configure_http_body_max(char **argv)
return (KORE_RESULT_OK);
}
static int
configure_http_body_disk_offload(char **argv)
{
int err;
if (argv[1] == NULL)
return (KORE_RESULT_ERROR);
http_body_disk_offload = kore_strtonum(argv[1], 10, 0, LONG_MAX, &err);
if (err != KORE_RESULT_OK) {
printf("bad http_body_disk_offload value: %s\n", argv[1]);
return (KORE_RESULT_ERROR);
}
return (KORE_RESULT_OK);
}
static int
configure_http_body_disk_path(char **argv)
{
if (argv[1] == NULL)
return (KORE_RESULT_ERROR);
if (http_body_disk_path != HTTP_BODY_DISK_PATH)
kore_mem_free(http_body_disk_path);
http_body_disk_path = kore_strdup(argv[1]);
return (KORE_RESULT_OK);
}
static int
configure_http_hsts_enable(char **argv)
{

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,8 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/resource.h>
@ -23,6 +25,10 @@
#include "kore.h"
#if !defined(KORE_NO_HTTP)
#include "http.h"
#endif
volatile sig_atomic_t sig_recv;
struct listener_head listeners;
@ -161,6 +167,13 @@ main(int argc, char *argv[])
#if !defined(KORE_NO_HTTP)
kore_accesslog_init();
if (http_body_disk_offload > 0) {
if (mkdir(http_body_disk_path, 0700) == -1 && errno != EEXIST) {
printf("can't create http_body_disk_path '%s': %s\n",
http_body_disk_path, errno_s);
return (KORE_RESULT_ERROR);
}
}
#endif
sig_recv = 0;