Merge branch 'master' into oneswig

This commit is contained in:
Stig Telfer 2016-01-24 13:46:38 +00:00
commit 2ac6e7d41d
42 changed files with 1460 additions and 647 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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

View File

@ -59,6 +59,17 @@ workers 4
# http_header_max Maximum size of HTTP headers (in bytes).
#
# 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.
@ -71,10 +82,12 @@ workers 4
# http_request_limit Limit the number of requests Kore processes
# in a single event loop.
#http_header_max 4096
#http_body_max 10240000
#http_body_max 1024000
#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
@ -109,8 +122,7 @@ validator v_session function v_session_validate
# Specify the TLS ciphers that will be used.
#tls_cipher ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!kRSA:!kDSA
# If you wish to use EDH / ECDH specify a file containing
# a generated DH key (See OpenSSL dhparam).
# Required DH parameters for TLS.
#tls_dhparam dh2048.pem
# Authentication configuration

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. */

5
examples/pgsql-sync/.gitignore vendored Normal file
View File

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

View File

@ -0,0 +1,11 @@
# Placeholder configuration
bind 127.0.0.1 8888
load ./pgsql-sync.so init
tls_dhparam dh2048.pem
domain 127.0.0.1 {
certfile cert/server.crt
certkey cert/server.key
static / page
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2015 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 use synchronous PGSQL queries
* with Kore. For an asynchronous example see pgsql/ under examples/.
*
* This example does the same as the asynchronous one, select all entries
* from a table called "coders".
*/
#include <kore/kore.h>
#include <kore/http.h>
#include <kore/pgsql.h>
int init(int);
int page(struct http_request *);
/* Called when our module is loaded (see config) */
int
init(int state)
{
/* Register our database. */
kore_pgsql_register("db", "host=/tmp dbname=test");
return (KORE_RESULT_OK);
}
/* Page handler entry point (see config) */
int
page(struct http_request *req)
{
struct kore_pgsql sql;
char *name;
int rows, i;
req->status = HTTP_STATUS_INTERNAL_ERROR;
/*
* Initialise our kore_pgsql data structure with the database name
* we want to connect to (note that we registered this earlier with
* kore_pgsql_register()). We also say we will perform a synchronous
* query (KORE_PGSQL_SYNC) and we do not need to pass our http_request
* so we pass NULL instead.
*/
if (!kore_pgsql_query_init(&sql, NULL, "db", KORE_PGSQL_SYNC)) {
kore_pgsql_logerror(&sql);
goto out;
}
/*
* Now we can fire off the query, once it returns we either have
* a result on which we can operate or an error occured.
*/
if (!kore_pgsql_query(&sql, "SELECT * FROM coders")) {
kore_pgsql_logerror(&sql);
goto out;
}
/*
* Iterate over the result and dump it to somewhere.
*/
rows = kore_pgsql_ntuples(&sql);
for (i = 0; i < rows; i++) {
name = kore_pgsql_getvalue(&sql, i, 0);
kore_log(LOG_NOTICE, "name: '%s'", name);
}
/* All good. */
req->status = HTTP_STATUS_OK;
out:
http_response(req, req->status, NULL, 0);
/* Don't forget to cleanup the kore_pgsql data structure. */
kore_pgsql_cleanup(&sql);
return (KORE_RESULT_OK);
}

View File

@ -16,7 +16,8 @@
/*
* This example demonstrates on how to use state machines and
* asynchronous pgsql queries.
* asynchronous pgsql queries. For a synchronous query example
* see the pgsql-sync/ example under the examples/ directory.
*
* While this example might seem overly complex for a simple pgsql
* query, there is a reason behind its complexity:
@ -36,15 +37,17 @@
#include <kore/http.h>
#include <kore/pgsql.h>
#define REQ_STATE_QUERY 0
#define REQ_STATE_DB_WAIT 1
#define REQ_STATE_DB_READ 2
#define REQ_STATE_ERROR 3
#define REQ_STATE_DONE 4
#define REQ_STATE_INIT 0
#define REQ_STATE_QUERY 1
#define REQ_STATE_DB_WAIT 2
#define REQ_STATE_DB_READ 3
#define REQ_STATE_ERROR 4
#define REQ_STATE_DONE 5
int init(int);
int page(struct http_request *);
static int request_perform_init(struct http_request *);
static int request_perform_query(struct http_request *);
static int request_db_wait(struct http_request *);
static int request_db_read(struct http_request *);
@ -52,6 +55,7 @@ static int request_error(struct http_request *);
static int request_done(struct http_request *);
struct http_state mystates[] = {
{ "REQ_STATE_INIT", request_perform_init },
{ "REQ_STATE_QUERY", request_perform_query },
{ "REQ_STATE_DB_WAIT", request_db_wait },
{ "REQ_STATE_DB_READ", request_db_read },
@ -62,6 +66,7 @@ struct http_state mystates[] = {
#define mystates_size (sizeof(mystates) / sizeof(mystates[0]))
struct rstate {
int cnt;
struct kore_pgsql sql;
};
@ -69,8 +74,8 @@ struct rstate {
int
init(int state)
{
/* Set our connection string. */
pgsql_conn_string = "host=/var/run/postgresql/ dbname=test";
/* Register our database. */
kore_pgsql_register("db", "host=/tmp dbname=test");
return (KORE_RESULT_OK);
}
@ -84,29 +89,48 @@ page(struct http_request *req)
return (http_state_run(mystates, mystates_size, req));
}
/* The initial state, we setup our context and fire off the pgsql query. */
/* Initialize our PGSQL data structure and prepare for an async query. */
int
request_perform_query(struct http_request *req)
request_perform_init(struct http_request *req)
{
struct rstate *state;
/* Setup our state context. */
state = kore_malloc(sizeof(*state));
/* Setup our state context (if not yet set). */
if (req->hdlr_extra == NULL) {
state = kore_malloc(sizeof(*state));
req->hdlr_extra = state;
} else {
state = req->hdlr_extra;
}
/* Attach the state to our request. */
req->hdlr_extra = state;
/* Initialize our kore_pgsql data structure. */
if (!kore_pgsql_query_init(&state->sql, req, "db", KORE_PGSQL_ASYNC)) {
/* If the state was still INIT, we'll try again later. */
if (state->sql.state == KORE_PGSQL_STATE_INIT) {
req->fsm_state = REQ_STATE_INIT;
return (HTTP_STATE_RETRY);
}
kore_pgsql_logerror(&state->sql);
req->fsm_state = REQ_STATE_ERROR;
} else {
req->fsm_state = REQ_STATE_QUERY;
}
return (HTTP_STATE_CONTINUE);
}
/* After setting everything up we will execute our async query. */
int
request_perform_query(struct http_request *req)
{
struct rstate *state = req->hdlr_extra;
/* We want to move to read result after this. */
req->fsm_state = REQ_STATE_DB_WAIT;
/* Fire off the query. */
if (!kore_pgsql_query(&state->sql, req, "SELECT * FROM coders")) {
/* If the state was still INIT, we'll try again later. */
if (state->sql.state == KORE_PGSQL_STATE_INIT) {
req->fsm_state = REQ_STATE_QUERY;
return (HTTP_STATE_RETRY);
}
if (!kore_pgsql_query(&state->sql, "SELECT * FROM coders")) {
/*
* Let the state machine continue immediately since we
* have an error anyway.

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);
}

View File

@ -166,7 +166,8 @@ client_setup(struct connection *c)
int
backend_handle_connect(struct connection *c)
{
int ret;
int ret;
struct connection *src;
/* We will get a write notification when we can progress. */
if (!(c->flags & CONN_WRITE_POSSIBLE))
@ -208,7 +209,12 @@ backend_handle_connect(struct connection *c)
kore_connection_start_idletimer(c);
kore_platform_event_all(c->fd, c);
return (KORE_RESULT_OK);
/* Allow events from source now. */
src = c->hdlr_extra;
kore_platform_event_all(src->fd, src);
/* Now lets start. */
return (c->handle(c));
}
/*

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,16 @@
# Placeholder configuration
bind 127.0.0.1 8888
load ./upload.so
tls_dhparam dh2048.pem
http_body_max 1024000000
http_body_disk_offload 4096
domain 127.0.0.1 {
certfile cert/server.crt
certkey cert/server.key
static / page
}

View File

@ -0,0 +1,118 @@
/*
* 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. */
/* Alternatively you could look at file->offset and file->length. */
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(file->filename) == -1) {
kore_log(LOG_WARNING, "unlink(%s): %s",
file->filename, errno_s);
}
ret = KORE_RESULT_OK;
}
return (KORE_RESULT_OK);
}

View File

@ -26,13 +26,17 @@ extern "C" {
#define HTTP_KEEPALIVE_TIME 20
#define HTTP_HSTS_ENABLE 31536000
#define HTTP_HEADER_MAX_LEN 4096
#define HTTP_BODY_MAX_LEN 10240000
#define HTTP_BODY_MAX_LEN 1024000
#define HTTP_URI_LEN 2000
#define HTTP_USERAGENT_LEN 256
#define HTTP_REQ_HEADER_MAX 25
#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,9 +174,13 @@ struct http_request {
char *agent;
struct connection *owner;
struct kore_buf *http_body;
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;
@ -213,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_cleanup(void);
@ -222,9 +218,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 +235,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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -22,17 +22,24 @@
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#if !defined(KORE_NO_TLS)
#include <openssl/err.h>
#include <openssl/dh.h>
#include <openssl/ssl.h>
#endif
#include <errno.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <stdarg.h>
@ -67,11 +74,11 @@ extern int daemon(int, int);
#define KORE_DEFAULT_CIPHER_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!kRSA:!kDSA"
#if defined(KORE_DEBUG)
#define kore_debug(fmt, ...) \
#define kore_debug(...) \
if (kore_debug) \
kore_debug_internal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
kore_debug_internal(__FILE__, __LINE__, ##__VA_ARGS__)
#else
#define kore_debug(fmt, ...)
#define kore_debug(...)
#endif
#define NETBUF_RECV 0
@ -160,11 +167,13 @@ struct connection {
u_int8_t state;
u_int8_t proto;
void *owner;
#if !defined(KORE_NO_TLS)
X509 *cert;
SSL *ssl;
int tls_reneg;
#endif
u_int8_t flags;
void *hdlr_extra;
X509 *cert;
int tls_reneg;
int (*handle)(struct connection *);
void (*disconnect)(struct connection *);
@ -284,12 +293,14 @@ struct kore_worker {
struct kore_domain {
char *domain;
char *certfile;
char *certkey;
int accesslog;
#if !defined(KORE_NO_TLS)
char *cafile;
char *crlfile;
int accesslog;
char *certfile;
char *certkey;
SSL_CTX *ssl_ctx;
#endif
TAILQ_HEAD(, kore_module_handle) handlers;
TAILQ_ENTRY(kore_domain) list;
};
@ -312,8 +323,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;
@ -386,7 +396,10 @@ extern char *kore_pidfile;
extern char *config_file;
extern char *kore_tls_cipher_list;
extern int tls_version;
#if !defined(KORE_NO_TLS)
extern DH *tls_dhparam;
#endif
extern u_int8_t nlisteners;
extern u_int16_t cpu_count;
@ -450,9 +463,11 @@ void kore_timer_remove(struct kore_timer *);
struct kore_timer *kore_timer_add(void (*cb)(void *, u_int64_t),
u_int64_t, void *, int);
int kore_tls_sni_cb(SSL *, int *, void *);
int kore_server_bind(const char *, const char *, const char *);
#if !defined(KORE_NO_TLS)
int kore_tls_sni_cb(SSL *, int *, void *);
void kore_tls_info_callback(const SSL *, int, int);
#endif
void kore_connection_init(void);
void kore_connection_cleanup(void);
@ -581,8 +596,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

@ -22,6 +22,9 @@
#define KORE_PGSQL_FORMAT_TEXT 0
#define KORE_PGSQL_FORMAT_BINARY 1
#define KORE_PGSQL_SYNC 0x0001
#define KORE_PGSQL_ASYNC 0x0002
#if defined(__cplusplus)
extern "C" {
#endif
@ -29,14 +32,23 @@ extern "C" {
struct pgsql_conn {
u_int8_t type;
u_int8_t flags;
char *name;
PGconn *db;
struct pgsql_job *job;
TAILQ_ENTRY(pgsql_conn) list;
};
struct pgsql_db {
char *name;
char *conn_string;
LIST_ENTRY(pgsql_db) rlist;
};
struct kore_pgsql {
u_int8_t state;
int flags;
char *error;
PGresult *result;
struct pgsql_conn *conn;
@ -45,17 +57,17 @@ struct kore_pgsql {
};
extern u_int16_t pgsql_conn_max;
extern char *pgsql_conn_string;
void kore_pgsql_init(void);
int kore_pgsql_query_init(struct kore_pgsql *, struct http_request *,
const char *, int);
void kore_pgsql_handle(void *, int);
void kore_pgsql_cleanup(struct kore_pgsql *);
void kore_pgsql_continue(struct http_request *, struct kore_pgsql *);
int kore_pgsql_query(struct kore_pgsql *, struct http_request *,
const char *);
int kore_pgsql_query_params(struct kore_pgsql *, struct http_request *,
int kore_pgsql_query(struct kore_pgsql *, const char *);
int kore_pgsql_query_params(struct kore_pgsql *,
const char *, int, u_int8_t, ...);
int kore_pgsql_register(const char *, const char *);
int kore_pgsql_ntuples(struct kore_pgsql *);
void kore_pgsql_logerror(struct kore_pgsql *);
void kore_pgsql_queue_remove(struct http_request *);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -17,6 +17,7 @@
#include <sys/socket.h>
#include <poll.h>
#include <time.h>
#include "kore.h"
#include "http.h"
@ -32,7 +33,9 @@ struct kore_log_packet {
char host[KORE_DOMAINNAME_LEN];
char path[HTTP_URI_LEN];
char agent[HTTP_USERAGENT_LEN];
#if !defined(KORE_NO_TLS)
char cn[X509_CN_LENGTH];
#endif
};
void
@ -90,10 +93,11 @@ kore_accesslog_write(const void *data, u_int32_t len)
break;
}
cn = "none";
#if !defined(KORE_NO_TLS)
if (logpacket.cn[0] != '\0')
cn = logpacket.cn;
else
cn = "none";
#endif
if (inet_ntop(logpacket.addrtype, &(logpacket.addr),
addr, sizeof(addr)) == NULL)
@ -157,8 +161,8 @@ kore_accesslog(struct http_request *req)
sizeof(logpacket.agent));
}
memset(logpacket.cn, '\0', sizeof(logpacket.cn));
#if !defined(KORE_NO_TLS)
memset(logpacket.cn, '\0', sizeof(logpacket.cn));
if (req->owner->cert != NULL) {
if (X509_GET_CN(req->owner->cert,
logpacket.cn, sizeof(logpacket.cn)) == -1) {

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -37,7 +37,10 @@ kore_buf_create(u_int32_t initial)
void
kore_buf_append(struct kore_buf *buf, const void *d, u_int32_t len)
{
if ((buf->offset + len) >= buf->length) {
if ((buf->offset + len) < len)
fatal("overflow in kore_buf_append");
if ((buf->offset + len) > buf->length) {
buf->length += len + KORE_BUF_INCREMENT;
buf->data = kore_realloc(buf->data, buf->length);
}
@ -90,6 +93,16 @@ kore_buf_appendf(struct kore_buf *buf, const char *fmt, ...)
va_end(args);
}
char *
kore_buf_stringify(struct kore_buf *buf)
{
char c;
c = '\0';
kore_buf_append(buf, &c, sizeof(c));
return ((char *)buf->data);
}
u_int8_t *
kore_buf_release(struct kore_buf *buf, u_int32_t *len)
{
@ -147,7 +160,7 @@ kore_buf_replace_string(struct kore_buf *b, char *src, void *dst, size_t len)
}
void
kore_buf_reset(struct kore_buf *buf)
kore_buf_reset(struct kore_buf *buf)
{
buf->offset = 0;
}

View File

@ -921,7 +921,9 @@ cli_compile_cfile(void *arg)
#if defined(KORE_NO_HTTP)
args[idx++] = "-DKORE_NO_HTTP";
#endif
#if defined(KORE_NO_TLS)
args[idx++] = "-DKORE_NO_TLS";
#endif
args[idx++] = "-Wall";
args[idx++] = "-Wmissing-declarations";
args[idx++] = "-Wshadow";

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -67,6 +67,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 **);
@ -124,6 +126,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 },
@ -162,9 +166,6 @@ kore_parse_config(void)
if (!kore_module_loaded())
fatal("no site module was loaded");
if (LIST_EMPTY(&listeners))
fatal("no listeners defined");
if (skip_chroot != 1 && chroot_path == NULL) {
fatal("missing a chroot path");
}
@ -541,7 +542,7 @@ configure_http_body_max(char **argv)
return (KORE_RESULT_ERROR);
}
http_body_max = kore_strtonum(argv[1], 10, 1, LONG_MAX, &err);
http_body_max = kore_strtonum(argv[1], 10, 0, LONG_MAX, &err);
if (err != KORE_RESULT_OK) {
printf("bad http_body_max value: %s\n", argv[1]);
return (KORE_RESULT_ERROR);
@ -550,6 +551,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 (strcmp(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)
{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -55,13 +55,15 @@ kore_connection_new(void *owner)
c = kore_pool_get(&connection_pool);
#if !defined(KORE_NO_TLS)
c->ssl = NULL;
c->cert = NULL;
c->tls_reneg = 0;
#endif
c->flags = 0;
c->rnb = NULL;
c->snb = NULL;
c->cert = NULL;
c->owner = owner;
c->tls_reneg = 0;
c->handle = NULL;
c->disconnect = NULL;
c->hdlr_extra = NULL;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -24,8 +24,11 @@
struct kore_domain_h domains;
struct kore_domain *primary_dom = NULL;
#if !defined(KORE_NO_TLS)
DH *tls_dhparam = NULL;
int tls_version = KORE_TLS_VERSION_1_2;
#endif
static void domain_load_crl(struct kore_domain *);
@ -51,11 +54,13 @@ kore_domain_new(char *domain)
dom = kore_malloc(sizeof(*dom));
dom->accesslog = -1;
#if !defined(KORE_NO_TLS)
dom->cafile = NULL;
dom->certkey = NULL;
dom->ssl_ctx = NULL;
dom->certfile = NULL;
dom->crlfile = NULL;
#endif
dom->domain = kore_strdup(domain);
TAILQ_INIT(&(dom->handlers));
TAILQ_INSERT_TAIL(&domains, dom, list);

1002
src/http.c

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -15,6 +15,8 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/resource.h>
@ -24,6 +26,10 @@
#include "kore.h"
#if !defined(KORE_NO_HTTP)
#include "http.h"
#endif
volatile sig_atomic_t sig_recv;
struct listener_head listeners;
@ -162,6 +168,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;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Joris Vink <joris@coders.se>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -293,6 +293,19 @@ net_write_ssl(struct connection *c, int len, int *written)
c->snb->flags |= NETBUF_MUST_RESEND;
c->flags &= ~CONN_WRITE_POSSIBLE;
return (KORE_RESULT_OK);
case SSL_ERROR_SYSCALL:
switch (errno) {
case EINTR:
*written = 0;
return (KORE_RESULT_OK);
case EAGAIN:
c->snb->flags |= NETBUF_MUST_RESEND;
c->flags &= ~CONN_WRITE_POSSIBLE;
return (KORE_RESULT_OK);
default:
break;
}
/* FALLTHROUGH */
default:
kore_debug("SSL_write(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
@ -321,6 +334,19 @@ net_read_ssl(struct connection *c, int *bytes)
case SSL_ERROR_WANT_WRITE:
c->flags &= ~CONN_READ_POSSIBLE;
return (KORE_RESULT_OK);
case SSL_ERROR_SYSCALL:
switch (errno) {
case EINTR:
*bytes = 0;
return (KORE_RESULT_OK);
case EAGAIN:
c->snb->flags |= NETBUF_MUST_RESEND;
c->flags &= ~CONN_WRITE_POSSIBLE;
return (KORE_RESULT_OK);
default:
break;
}
/* FALLTHROUGH */
default:
kore_debug("SSL_read(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
@ -341,6 +367,8 @@ net_write(struct connection *c, int len, int *written)
if (r <= -1) {
switch (errno) {
case EINTR:
*written = 0;
return (KORE_RESULT_OK);
case EAGAIN:
c->flags &= ~CONN_WRITE_POSSIBLE;
return (KORE_RESULT_OK);
@ -364,6 +392,8 @@ net_read(struct connection *c, int *bytes)
if (r <= 0) {
switch (errno) {
case EINTR:
*bytes = 0;
return (KORE_RESULT_OK);
case EAGAIN:
c->flags &= ~CONN_READ_POSSIBLE;
return (KORE_RESULT_OK);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014 Joris Vink <joris@coders.se>
* Copyright (c) 2014-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
@ -25,7 +25,6 @@
#include "pgsql.h"
struct pgsql_job {
char *query;
struct http_request *req;
struct kore_pgsql *pgsql;
@ -37,28 +36,30 @@ struct pgsql_wait {
TAILQ_ENTRY(pgsql_wait) list;
};
#define PGSQL_IS_BLOCKING 0
#define PGSQL_IS_ASYNC 1
#define PGSQL_CONN_MAX 2
#define PGSQL_CONN_FREE 0x01
#define PGSQL_LIST_INSERTED 0x0100
static void pgsql_queue_wakeup(void);
static int pgsql_conn_create(struct kore_pgsql *);
static void pgsql_set_error(struct kore_pgsql *, const char *);
static void pgsql_queue_add(struct http_request *);
static void pgsql_conn_release(struct kore_pgsql *);
static void pgsql_conn_cleanup(struct pgsql_conn *);
static void pgsql_read_result(struct kore_pgsql *, int);
static void pgsql_schedule(struct kore_pgsql *, struct http_request *);
static int pgsql_prepare(struct kore_pgsql *, struct http_request *,
const char *);
static void pgsql_read_result(struct kore_pgsql *);
static void pgsql_schedule(struct kore_pgsql *);
static struct pgsql_conn *pgsql_conn_create(struct kore_pgsql *,
struct pgsql_db *);
static struct pgsql_conn *pgsql_conn_next(struct kore_pgsql *,
struct pgsql_db *,
struct http_request *);
static struct kore_pool pgsql_job_pool;
static struct kore_pool pgsql_wait_pool;
static TAILQ_HEAD(, pgsql_conn) pgsql_conn_free;
static TAILQ_HEAD(, pgsql_wait) pgsql_wait_queue;
static LIST_HEAD(, pgsql_db) pgsql_db_conn_strings;
static u_int16_t pgsql_conn_count;
char *pgsql_conn_string = NULL;
u_int16_t pgsql_conn_max = PGSQL_CONN_MAX;
void
@ -67,6 +68,7 @@ kore_pgsql_init(void)
pgsql_conn_count = 0;
TAILQ_INIT(&pgsql_conn_free);
TAILQ_INIT(&pgsql_wait_queue);
LIST_INIT(&pgsql_db_conn_strings);
kore_pool_init(&pgsql_job_pool, "pgsql_job_pool",
sizeof(struct pgsql_job), 100);
@ -75,32 +77,91 @@ kore_pgsql_init(void)
}
int
kore_pgsql_query(struct kore_pgsql *pgsql, struct http_request *req,
const char *query)
kore_pgsql_query_init(struct kore_pgsql *pgsql, struct http_request *req,
const char *dbname, int flags)
{
if (!pgsql_prepare(pgsql, req, query))
return (KORE_RESULT_ERROR);
struct pgsql_db *db;
if (!PQsendQuery(pgsql->conn->db, query)) {
pgsql_conn_cleanup(pgsql->conn);
memset(pgsql, 0, sizeof(*pgsql));
pgsql->flags = flags;
pgsql->state = KORE_PGSQL_STATE_INIT;
if ((req == NULL && (flags & KORE_PGSQL_ASYNC)) ||
((flags & KORE_PGSQL_ASYNC) && (flags & KORE_PGSQL_SYNC))) {
pgsql_set_error(pgsql, "invalid query init parameters");
return (KORE_RESULT_ERROR);
}
pgsql_schedule(pgsql, req);
db = NULL;
LIST_FOREACH(db, &pgsql_db_conn_strings, rlist) {
if (!strcmp(db->name, dbname))
break;
}
if (db == NULL) {
pgsql_set_error(pgsql, "no database found");
return (KORE_RESULT_ERROR);
}
if ((pgsql->conn = pgsql_conn_next(pgsql, db, req)) == NULL)
return (KORE_RESULT_ERROR);
if (pgsql->flags & KORE_PGSQL_ASYNC) {
pgsql->conn->job = kore_pool_get(&pgsql_job_pool);
pgsql->conn->job->req = req;
pgsql->conn->job->pgsql = pgsql;
http_request_sleep(req);
pgsql->flags |= PGSQL_LIST_INSERTED;
LIST_INSERT_HEAD(&(req->pgsqls), pgsql, rlist);
}
return (KORE_RESULT_OK);
}
int
kore_pgsql_query_params(struct kore_pgsql *pgsql, struct http_request *req,
kore_pgsql_query(struct kore_pgsql *pgsql, const char *query)
{
if (pgsql->conn == NULL) {
pgsql_set_error(pgsql, "no connection was set before query");
return (KORE_RESULT_ERROR);
}
if (pgsql->flags & KORE_PGSQL_SYNC) {
pgsql->result = PQexec(pgsql->conn->db, query);
if ((PQresultStatus(pgsql->result) != PGRES_TUPLES_OK) &&
(PQresultStatus(pgsql->result) != PGRES_COMMAND_OK)) {
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
return (KORE_RESULT_ERROR);
}
pgsql->state = KORE_PGSQL_STATE_DONE;
} else {
if (!PQsendQuery(pgsql->conn->db, query)) {
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
return (KORE_RESULT_ERROR);
}
pgsql_schedule(pgsql);
}
return (KORE_RESULT_OK);
}
int
kore_pgsql_query_params(struct kore_pgsql *pgsql,
const char *query, int result, u_int8_t count, ...)
{
u_int8_t i;
va_list args;
char **values;
int *lengths, *formats;
int *lengths, *formats, ret;
if (!pgsql_prepare(pgsql, req, query))
if (pgsql->conn == NULL) {
pgsql_set_error(pgsql, "no connection was set before query");
return (KORE_RESULT_ERROR);
}
if (count > 0) {
va_start(args, count);
@ -120,20 +181,55 @@ kore_pgsql_query_params(struct kore_pgsql *pgsql, struct http_request *req,
values = NULL;
}
if (!PQsendQueryParams(pgsql->conn->db, query, count, NULL,
(const char * const *)values, lengths, formats, result)) {
kore_mem_free(values);
kore_mem_free(lengths);
kore_mem_free(formats);
pgsql_conn_cleanup(pgsql->conn);
return (KORE_RESULT_ERROR);
ret = KORE_RESULT_ERROR;
if (pgsql->flags & KORE_PGSQL_SYNC) {
pgsql->result = PQexecParams(pgsql->conn->db, query, count,
NULL, (const char * const *)values, lengths, formats,
result);
if ((PQresultStatus(pgsql->result) != PGRES_TUPLES_OK) &&
(PQresultStatus(pgsql->result) != PGRES_COMMAND_OK)) {
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
goto cleanup;
}
pgsql->state = KORE_PGSQL_STATE_DONE;
} else {
if (!PQsendQueryParams(pgsql->conn->db, query, count, NULL,
(const char * const *)values, lengths, formats, result)) {
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
goto cleanup;
}
pgsql_schedule(pgsql);
}
ret = KORE_RESULT_OK;
cleanup:
kore_mem_free(values);
kore_mem_free(lengths);
kore_mem_free(formats);
pgsql_schedule(pgsql, req);
return (ret);
}
int
kore_pgsql_register(const char *dbname, const char *connstring)
{
struct pgsql_db *pgsqldb;
LIST_FOREACH(pgsqldb, &pgsql_db_conn_strings, rlist) {
if (!strcmp(pgsqldb->name, dbname))
return (KORE_RESULT_ERROR);
}
pgsqldb = kore_malloc(sizeof(*pgsqldb));
pgsqldb->name = kore_strdup(dbname);
pgsqldb->conn_string = kore_strdup(connstring);
LIST_INSERT_HEAD(&pgsql_db_conn_strings, pgsqldb, rlist);
return (KORE_RESULT_OK);
}
@ -157,7 +253,7 @@ kore_pgsql_handle(void *c, int err)
pgsql->state = KORE_PGSQL_STATE_ERROR;
pgsql->error = kore_strdup(PQerrorMessage(conn->db));
} else {
pgsql_read_result(pgsql, PGSQL_IS_ASYNC);
pgsql_read_result(pgsql);
}
if (pgsql->state == KORE_PGSQL_STATE_WAIT) {
@ -218,7 +314,10 @@ kore_pgsql_cleanup(struct kore_pgsql *pgsql)
pgsql->error = NULL;
pgsql->conn = NULL;
LIST_REMOVE(pgsql, rlist);
if (pgsql->flags & PGSQL_LIST_INSERTED) {
LIST_REMOVE(pgsql, rlist);
pgsql->flags &= ~PGSQL_LIST_INSERTED;
}
}
void
@ -262,47 +361,55 @@ kore_pgsql_queue_remove(struct http_request *req)
}
}
static int
pgsql_prepare(struct kore_pgsql *pgsql, struct http_request *req,
const char *query)
static struct pgsql_conn *
pgsql_conn_next(struct kore_pgsql *pgsql, struct pgsql_db *db,
struct http_request *req)
{
struct pgsql_conn *conn;
pgsql->state = KORE_PGSQL_STATE_INIT;
pgsql->result = NULL;
pgsql->error = NULL;
pgsql->conn = NULL;
conn = NULL;
if (TAILQ_EMPTY(&pgsql_conn_free)) {
if (pgsql_conn_count >= pgsql_conn_max) {
pgsql_queue_add(req);
return (KORE_RESULT_ERROR);
}
if (!pgsql_conn_create(pgsql))
return (KORE_RESULT_ERROR);
TAILQ_FOREACH(conn, &pgsql_conn_free, list) {
if (!(conn->flags & PGSQL_CONN_FREE))
fatal("got a pgsql connection that was not free?");
if (!strcmp(conn->name, db->name))
break;
}
http_request_sleep(req);
conn = TAILQ_FIRST(&pgsql_conn_free);
if (!(conn->flags & PGSQL_CONN_FREE))
fatal("received a pgsql conn that was not free?");
if (conn == NULL) {
if (pgsql_conn_count >= pgsql_conn_max) {
if (pgsql->flags & KORE_PGSQL_ASYNC) {
pgsql_queue_add(req);
} else {
pgsql_set_error(pgsql,
"no available connection");
}
return (NULL);
}
if ((conn = pgsql_conn_create(pgsql, db)) == NULL)
return (NULL);
}
conn->flags &= ~PGSQL_CONN_FREE;
TAILQ_REMOVE(&pgsql_conn_free, conn, list);
pgsql->conn = conn;
conn->job = kore_pool_get(&pgsql_job_pool);
conn->job->query = kore_strdup(query);
conn->job->pgsql = pgsql;
conn->job->req = req;
LIST_INSERT_HEAD(&(req->pgsqls), pgsql, rlist);
return (KORE_RESULT_OK);
return (conn);
}
static void
pgsql_schedule(struct kore_pgsql *pgsql, struct http_request *req)
pgsql_set_error(struct kore_pgsql *pgsql, const char *msg)
{
if (pgsql->error != NULL)
kore_mem_free(pgsql->error);
pgsql->error = kore_strdup(msg);
pgsql->state = KORE_PGSQL_STATE_ERROR;
}
static void
pgsql_schedule(struct kore_pgsql *pgsql)
{
int fd;
@ -347,33 +454,32 @@ pgsql_queue_wakeup(void)
}
}
static int
pgsql_conn_create(struct kore_pgsql *pgsql)
static struct pgsql_conn *
pgsql_conn_create(struct kore_pgsql *pgsql, struct pgsql_db *db)
{
struct pgsql_conn *conn;
if (pgsql_conn_string == NULL)
if (db == NULL || db->conn_string == NULL)
fatal("pgsql_conn_create: no connection string");
pgsql_conn_count++;
conn = kore_malloc(sizeof(*conn));
kore_debug("pgsql_conn_create(): %p", conn);
memset(conn, 0, sizeof(*conn));
conn->db = PQconnectdb(pgsql_conn_string);
conn->db = PQconnectdb(db->conn_string);
if (conn->db == NULL || (PQstatus(conn->db) != CONNECTION_OK)) {
pgsql->state = KORE_PGSQL_STATE_ERROR;
pgsql->error = kore_strdup(PQerrorMessage(conn->db));
pgsql_set_error(pgsql, PQerrorMessage(conn->db));
pgsql_conn_cleanup(conn);
return (KORE_RESULT_ERROR);
return (NULL);
}
conn->job = NULL;
conn->flags = PGSQL_CONN_FREE;
conn->type = KORE_TYPE_PGSQL_CONN;
conn->name = kore_strdup(db->name);
TAILQ_INSERT_TAIL(&pgsql_conn_free, conn, list);
return (KORE_RESULT_OK);
return (conn);
}
static void
@ -384,8 +490,14 @@ pgsql_conn_release(struct kore_pgsql *pgsql)
if (pgsql->conn == NULL)
return;
kore_mem_free(pgsql->conn->job->query);
kore_pool_put(&pgsql_job_pool, pgsql->conn->job);
/* Async query cleanup */
if (pgsql->flags & KORE_PGSQL_ASYNC) {
if (pgsql->conn != NULL) {
fd = PQsocket(pgsql->conn->db);
kore_platform_disable_read(fd);
kore_pool_put(&pgsql_job_pool, pgsql->conn->job);
}
}
/* Drain just in case. */
while (PQgetResult(pgsql->conn->db) != NULL)
@ -395,9 +507,6 @@ pgsql_conn_release(struct kore_pgsql *pgsql)
pgsql->conn->flags |= PGSQL_CONN_FREE;
TAILQ_INSERT_TAIL(&pgsql_conn_free, pgsql->conn, list);
fd = PQsocket(pgsql->conn->db);
kore_platform_disable_read(fd);
pgsql->conn = NULL;
pgsql->state = KORE_PGSQL_STATE_COMPLETE;
@ -421,10 +530,8 @@ pgsql_conn_cleanup(struct pgsql_conn *conn)
http_request_wakeup(req);
pgsql->conn = NULL;
pgsql->state = KORE_PGSQL_STATE_ERROR;
pgsql->error = kore_strdup(PQerrorMessage(conn->db));
pgsql_set_error(pgsql, PQerrorMessage(conn->db));
kore_mem_free(conn->job->query);
kore_pool_put(&pgsql_job_pool, conn->job);
conn->job = NULL;
}
@ -433,17 +540,16 @@ pgsql_conn_cleanup(struct pgsql_conn *conn)
PQfinish(conn->db);
pgsql_conn_count--;
kore_mem_free(conn->name);
kore_mem_free(conn);
}
static void
pgsql_read_result(struct kore_pgsql *pgsql, int async)
pgsql_read_result(struct kore_pgsql *pgsql)
{
if (async) {
if (PQisBusy(pgsql->conn->db)) {
pgsql->state = KORE_PGSQL_STATE_WAIT;
return;
}
if (PQisBusy(pgsql->conn->db)) {
pgsql->state = KORE_PGSQL_STATE_WAIT;
return;
}
pgsql->result = PQgetResult(pgsql->conn->db);
@ -470,8 +576,7 @@ pgsql_read_result(struct kore_pgsql *pgsql, int async)
case PGRES_EMPTY_QUERY:
case PGRES_BAD_RESPONSE:
case PGRES_FATAL_ERROR:
pgsql->state = KORE_PGSQL_STATE_ERROR;
pgsql->error = kore_strdup(PQresultErrorMessage(pgsql->result));
pgsql_set_error(pgsql, PQresultErrorMessage(pgsql->result));
break;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Joris Vink <joris@coders.se>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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
@ -20,6 +20,7 @@
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#include "kore.h"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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

View File

@ -16,6 +16,8 @@
#include <sys/param.h>
#include <openssl/sha.h>
#include <limits.h>
#include <string.h>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
* 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