mirror of
https://github.com/jorisvink/kore
synced 2025-03-09 04:29:02 -04:00
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:
parent
96641d3caa
commit
fcb86ddb8b
@ -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
|
||||
|
@ -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]*$
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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
5
examples/upload/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.o
|
||||
.objs
|
||||
upload.so
|
||||
assets.h
|
||||
cert
|
19
examples/upload/conf/upload.conf
Normal file
19
examples/upload/conf/upload.conf
Normal 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
|
||||
}
|
||||
}
|
117
examples/upload/src/upload.c
Normal file
117
examples/upload/src/upload.c
Normal 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);
|
||||
}
|
118
includes/http.h
118
includes/http.h
@ -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,
|
||||
|
@ -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 *);
|
||||
|
@ -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:
|
||||
|
34
src/config.c
34
src/config.c
@ -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)
|
||||
{
|
||||
|
962
src/http.c
962
src/http.c
File diff suppressed because it is too large
Load Diff
13
src/kore.c
13
src/kore.c
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user