commit 88c3a3eb986ca5df86ae7c149de274d2b4c81345
parent ef463b49eba049fe6180f3a6979b4cd289a02ee0
Author: Joris Vink <joris@coders.se>
Date: Sun, 22 Sep 2013 20:05:24 +0200
Add http_header_max and http_postbody_max configuration variables.
- http_header_max:
Maximum size of HTTP headers (in non SPDY connections).
- http_postbody_max:
Maximum size of an HTTP POST body (both in SPDY and HTTP mode).
Right now Kore will simply DC the client, ideally we want to send
a 413 (entity too large) to the client however.
See modules/examples/module.conf for more.
Diffstat:
9 files changed, 120 insertions(+), 14 deletions(-)
diff --git a/includes/http.h b/includes/http.h
@@ -18,6 +18,7 @@
#define __H_HTTP_H
#define HTTP_HEADER_MAX_LEN 4096
+#define HTTP_POSTBODY_MAX_LEN 10240000
#define HTTP_URI_LEN 2000
#define HTTP_USERAGENT_LEN 256
#define HTTP_REQ_HEADER_MAX 25
@@ -76,7 +77,9 @@ struct http_request {
TAILQ_ENTRY(http_request) olist;
};
-extern int http_request_count;
+extern int http_request_count;
+extern u_int16_t http_header_max;
+extern u_int64_t http_postbody_max;
void http_init(void);
void http_process(void);
diff --git a/includes/kore.h b/includes/kore.h
@@ -194,8 +194,8 @@ TAILQ_HEAD(kore_domain_h, kore_domain);
struct kore_buf {
u_int8_t *data;
- u_int32_t length;
- u_int32_t offset;
+ u_int64_t length;
+ u_int64_t offset;
};
struct buf_vec {
@@ -316,7 +316,7 @@ void kore_strlcpy(char *, const char *, size_t);
void kore_server_disconnect(struct connection *);
int kore_split_string(char *, char *, char **, size_t);
void kore_strip_chars(char *, char, char **);
-long long kore_strtonum(const char *, int, long long, long long, int *);
+u_int64_t kore_strtonum(const char *, int, u_int64_t, u_int64_t, int *);
int kore_base64_encode(u_int8_t *, u_int32_t, char **);
int kore_base64_decode(char *, u_int8_t **, u_int32_t *);
void *kore_mem_find(void *, size_t, void *, u_int32_t);
diff --git a/includes/spdy.h b/includes/spdy.h
@@ -52,6 +52,7 @@ struct spdy_stream {
u_int32_t stream_id;
u_int8_t flags;
u_int8_t prio;
+ u_int64_t post_size;
int32_t recv_wsize;
int32_t send_wsize;
diff --git a/modules/example/module.conf b/modules/example/module.conf
@@ -33,6 +33,12 @@ workers 4
#kore_cb_interval 1000
#kore_cb_worker 3
+# HTTP specific settings.
+# http_header_max Maximum size of HTTP headers (in bytes).
+# http_postbody_max Maximum size of an HTTP POST body (in bytes).
+#http_header_max 4096
+#http_postbody_max 10240000
+
# Specifies what module to be loaded.
load modules/example/example.module
diff --git a/src/config.c b/src/config.c
@@ -20,6 +20,7 @@
#include <pwd.h>
#include "kore.h"
+#include "http.h"
static int configure_bind(char **);
static int configure_load(char **);
@@ -41,6 +42,8 @@ static int configure_spdy_idle_time(char **);
static int configure_kore_cb(char **);
static int configure_kore_cb_interval(char **);
static int configure_kore_cb_worker(char **);
+static int configure_http_header_max(char **);
+static int configure_http_postbody_max(char **);
static void domain_sslstart(void);
static struct {
@@ -68,6 +71,8 @@ static struct {
{ "kore_cb", configure_kore_cb },
{ "kore_cb_worker", configure_kore_cb_worker },
{ "kore_cb_interval", configure_kore_cb_interval },
+ { "http_header_max", configure_http_header_max },
+ { "http_postbody_max", configure_http_postbody_max },
{ NULL, NULL },
};
@@ -500,6 +505,50 @@ configure_kore_cb_worker(char **argv)
return (KORE_RESULT_OK);
}
+static int
+configure_http_header_max(char **argv)
+{
+ int err;
+
+ if (argv[1] == NULL)
+ return (KORE_RESULT_ERROR);
+
+ if (http_header_max != HTTP_HEADER_MAX_LEN) {
+ kore_debug("http_header_max already set");
+ return (KORE_RESULT_ERROR);
+ }
+
+ http_header_max = kore_strtonum(argv[1], 10, 1, 65535, &err);
+ if (err != KORE_RESULT_OK) {
+ printf("bad http_header_max value: %s\n", argv[1]);
+ return (KORE_RESULT_ERROR);
+ }
+
+ return (KORE_RESULT_OK);
+}
+
+static int
+configure_http_postbody_max(char **argv)
+{
+ int err;
+
+ if (argv[1] == NULL)
+ return (KORE_RESULT_ERROR);
+
+ if (http_postbody_max != HTTP_POSTBODY_MAX_LEN) {
+ kore_debug("http_postbody_max already set");
+ return (KORE_RESULT_ERROR);
+ }
+
+ http_postbody_max = kore_strtonum(argv[1], 10, 1, ULONG_MAX, &err);
+ if (err != KORE_RESULT_OK) {
+ printf("bad http_postbody_max value: %s\n", argv[1]);
+ return (KORE_RESULT_ERROR);
+ }
+
+ return (KORE_RESULT_OK);
+}
+
static void
domain_sslstart(void)
{
diff --git a/src/connection.c b/src/connection.c
@@ -152,7 +152,7 @@ kore_connection_handle(struct connection *c)
NULL, spdy_frame_recv);
} else if (!memcmp(data, "http/1.1", MIN(8, len))) {
c->proto = CONN_PROTO_HTTP;
- net_recv_queue(c, HTTP_HEADER_MAX_LEN,
+ net_recv_queue(c, http_header_max,
NETBUF_CALL_CB_ALWAYS, NULL,
http_header_recv);
} else {
@@ -160,7 +160,7 @@ kore_connection_handle(struct connection *c)
}
} else {
c->proto = CONN_PROTO_HTTP;
- net_recv_queue(c, HTTP_HEADER_MAX_LEN,
+ net_recv_queue(c, http_header_max,
NETBUF_CALL_CB_ALWAYS, NULL,
http_header_recv);
}
diff --git a/src/http.c b/src/http.c
@@ -31,6 +31,8 @@ static struct kore_pool http_request_pool;
static struct kore_pool http_header_pool;
int http_request_count;
+u_int16_t http_header_max = HTTP_HEADER_MAX_LEN;
+u_int64_t http_postbody_max = HTTP_POSTBODY_MAX_LEN;
void
http_init(void)
@@ -334,10 +336,11 @@ http_request_header_get(struct http_request *req, char *header, char **out)
int
http_header_recv(struct netbuf *nb)
{
+ size_t len;
+ u_int64_t clen;
struct http_header *hdr;
struct http_request *req;
struct netbuf *nnb;
- size_t clen, len;
u_int8_t *end_headers;
int h, i, v, skip, bytes_left;
char *request[4], *host[3], *hbuf;
@@ -426,7 +429,7 @@ http_header_recv(struct netbuf *nb)
return (KORE_RESULT_ERROR);
}
- clen = kore_strtonum(p, 10, 0, UINT_MAX, &v);
+ clen = kore_strtonum(p, 10, 0, ULONG_MAX, &v);
if (v == KORE_RESULT_ERROR) {
kore_mem_free(p);
kore_debug("content-length invalid: %s", p);
@@ -435,6 +438,14 @@ http_header_recv(struct netbuf *nb)
}
kore_mem_free(p);
+
+ if (clen > http_postbody_max) {
+ kore_log(LOG_NOTICE, "POST data too large (%ld > %ld)",
+ clen, http_postbody_max);
+ req->flags |= HTTP_REQUEST_DELETE;
+ return (KORE_RESULT_ERROR);
+ }
+
req->post_data = kore_buf_create(clen);
kore_buf_append(req->post_data, end_headers,
(nb->offset - len));
@@ -840,7 +851,7 @@ http_send_done(struct netbuf *nb)
{
struct connection *c = (struct connection *)nb->owner;
- net_recv_queue(c, HTTP_HEADER_MAX_LEN,
+ net_recv_queue(c, http_header_max,
NETBUF_CALL_CB_ALWAYS, NULL, http_header_recv);
return (KORE_RESULT_OK);
diff --git a/src/spdy.c b/src/spdy.c
@@ -595,8 +595,10 @@ static int
spdy_data_frame_recv(struct netbuf *nb)
{
struct spdy_stream *s;
+ int err;
struct http_request *req;
struct spdy_data_frame data;
+ char *content;
struct connection *c = (struct connection *)nb->owner;
data.stream_id = net_read32(nb->buf) & ~(1 << 31);
@@ -618,12 +620,46 @@ spdy_data_frame_recv(struct netbuf *nb)
return (KORE_RESULT_ERROR);
}
- if (req->post_data == NULL)
- req->post_data = kore_buf_create(data.length);
+ if (req->post_data == NULL) {
+ if (!spdy_stream_get_header(s->hblock,
+ "content-length", &content)) {
+ kore_debug("no content-length found for post");
+ return (KORE_RESULT_ERROR);
+ }
+
+ s->post_size = kore_strtonum(content, 10, 0, ULONG_MAX, &err);
+ if (err == KORE_RESULT_ERROR) {
+ kore_debug("bad content-length: %s", content);
+ kore_mem_free(content);
+ return (KORE_RESULT_ERROR);
+ }
+
+ kore_mem_free(content);
+
+ if (s->post_size > http_postbody_max) {
+ kore_log(LOG_NOTICE, "POST data too large (%ld > %ld)",
+ s->post_size, http_postbody_max);
+ return (KORE_RESULT_ERROR);
+ }
+
+ req->post_data = kore_buf_create(s->post_size);
+ }
+
+ if ((req->post_data->offset + data.length) > s->post_size) {
+ kore_debug("POST would grow too large");
+ return (KORE_RESULT_ERROR);
+ }
+
kore_buf_append(req->post_data, (nb->buf + SPDY_FRAME_SIZE),
data.length);
if (data.flags & FLAG_FIN) {
+ if (req->post_data->offset != s->post_size) {
+ kore_debug("FLAG_FIN before all POST data received");
+ return (KORE_RESULT_ERROR);
+ }
+
+ s->post_size = 0;
s->flags |= FLAG_FIN;
req->flags |= HTTP_REQUEST_COMPLETE;
}
diff --git a/src/utils.c b/src/utils.c
@@ -86,10 +86,10 @@ kore_strlcpy(char *dst, const char *src, size_t len)
}
}
-long long
-kore_strtonum(const char *str, int base, long long min, long long max, int *err)
+u_int64_t
+kore_strtonum(const char *str, int base, u_int64_t min, u_int64_t max, int *err)
{
- long long l;
+ u_int64_t l;
char *ep;
if (min > max) {