commit a603b77e24dd6b8394e25e32941ccc4185080a22
parent 3741e8ca3ffd2d16cc5ae899781174ad645c37f7
Author: Joris Vink <joris@coders.se>
Date: Wed, 8 Oct 2014 11:03:14 +0200
Add PUT/DELETE/HEAD methods (finally).
This commit renames certain POST centric variable and configuration
naming to the correct HTTP body stuff.
API changes include http_postbody_text() and http_postbody_bytes() to
have become http_body_text() and http_body_bytes().
The developer is still responsible for validating the method their
page handler is called with. Hopefully this becomes a configuration
option soon enough.
Diffstat:
8 files changed, 95 insertions(+), 71 deletions(-)
diff --git a/conf/kore.conf.example b/conf/kore.conf.example
@@ -26,7 +26,7 @@ workers 4
# 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_body_max Maximum size of an HTTP body (in bytes).
#
# http_keepalive_time Maximum seconds an HTTP connection can be
# kept alive by the browser.
@@ -36,7 +36,7 @@ workers 4
# all responses. Parameter is the age.
# (Set to 0 to disable sending this header).
#http_header_max 4096
-#http_postbody_max 10240000
+#http_body_max 10240000
#http_keepalive_time 0
#http_hsts_enable 31536000
diff --git a/examples/json_yajl/src/json_yajl.c b/examples/json_yajl/src/json_yajl.c
@@ -14,9 +14,11 @@ page(struct http_request *req)
char eb[1024];
const char *path[] = { "foo", "bar", NULL };
- /* We only allow POST methods. */
- if (req->method != HTTP_METHOD_POST) {
- http_response(req, 400, NULL, 0);
+ /* We only allow POST/PUT methods. */
+ if (req->method != HTTP_METHOD_POST &&
+ req->method != HTTP_METHOD_PUT) {
+ http_response_header(req, "allow", "POST, PUT");
+ http_response(req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0);
return (KORE_RESULT_OK);
}
@@ -24,7 +26,7 @@ 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.
*/
- if ((body = http_post_data_text(req)) == NULL) {
+ if ((body = http_body_text(req)) == NULL) {
http_response(req, 400, NULL, 0);
return (KORE_RESULT_OK);
}
diff --git a/includes/http.h b/includes/http.h
@@ -20,7 +20,7 @@
#define HTTP_KEEPALIVE_TIME 20
#define HTTP_HSTS_ENABLE 31536000
#define HTTP_HEADER_MAX_LEN 4096
-#define HTTP_POSTBODY_MAX_LEN 10240000
+#define HTTP_BODY_MAX_LEN 10240000
#define HTTP_URI_LEN 2000
#define HTTP_USERAGENT_LEN 256
#define HTTP_REQ_HEADER_MAX 25
@@ -152,11 +152,15 @@ struct http_file {
#define HTTP_METHOD_GET 0
#define HTTP_METHOD_POST 1
+#define HTTP_METHOD_PUT 2
+#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
struct kore_task;
@@ -173,7 +177,7 @@ struct http_request {
char *agent;
struct connection *owner;
struct spdy_stream *stream;
- struct kore_buf *post_data;
+ struct kore_buf *http_body;
void *hdlr_extra;
char *query_string;
u_int8_t *multipart_body;
@@ -197,7 +201,7 @@ struct http_state {
extern int http_request_count;
extern u_int16_t http_header_max;
-extern u_int64_t http_postbody_max;
+extern u_int64_t http_body_max;
extern u_int64_t http_hsts_enable;
extern u_int16_t http_keepalive_time;
@@ -208,9 +212,9 @@ 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_post_data_text(struct http_request *);
+char *http_body_text(struct http_request *);
void http_process_request(struct http_request *, int);
-u_int8_t *http_post_data_bytes(struct http_request *, u_int32_t *);
+u_int8_t *http_body_bytes(struct http_request *, u_int32_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 *);
diff --git a/src/accesslog.c b/src/accesslog.c
@@ -101,6 +101,15 @@ kore_accesslog_wait(void)
case HTTP_METHOD_POST:
method = "POST";
break;
+ case HTTP_METHOD_PUT:
+ method = "PUT";
+ break;
+ case HTTP_METHOD_DELETE:
+ method = "DELETE";
+ break;
+ case HTTP_METHOD_HEAD:
+ method = "HEAD";
+ break;
default:
method = "UNKNOWN";
break;
diff --git a/src/config.c b/src/config.c
@@ -49,7 +49,7 @@ static int configure_ssl_dhparam(char **);
static int configure_ssl_no_compression(char **);
static int configure_spdy_idle_time(char **);
static int configure_http_header_max(char **);
-static int configure_http_postbody_max(char **);
+static int configure_http_body_max(char **);
static int configure_http_hsts_enable(char **);
static int configure_http_keepalive_time(char **);
static int configure_validator(char **);
@@ -94,7 +94,7 @@ static struct {
{ "certkey", configure_certkey },
{ "require_client_cert", configure_require_client_cert },
{ "http_header_max", configure_http_header_max },
- { "http_postbody_max", configure_http_postbody_max },
+ { "http_body_max", configure_http_body_max },
{ "http_hsts_enable", configure_http_hsts_enable },
{ "http_keepalive_time", configure_http_keepalive_time },
{ "validator", configure_validator },
@@ -584,21 +584,21 @@ configure_http_header_max(char **argv)
}
static int
-configure_http_postbody_max(char **argv)
+configure_http_body_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");
+ if (http_body_max != HTTP_BODY_MAX_LEN) {
+ kore_debug("http_body_max already set");
return (KORE_RESULT_ERROR);
}
- http_postbody_max = kore_strtonum(argv[1], 10, 1, LONG_MAX, &err);
+ http_body_max = kore_strtonum(argv[1], 10, 1, LONG_MAX, &err);
if (err != KORE_RESULT_OK) {
- printf("bad http_postbody_max value: %s\n", argv[1]);
+ printf("bad http_body_max value: %s\n", argv[1]);
return (KORE_RESULT_ERROR);
}
diff --git a/src/http.c b/src/http.c
@@ -31,7 +31,7 @@
#include "tasks.h"
#endif
-static int http_post_data_recv(struct netbuf *);
+static int http_body_recv(struct netbuf *);
static void http_error_response(struct connection *,
struct spdy_stream *, int);
static void http_argument_add(struct http_request *, const char *,
@@ -54,7 +54,7 @@ int http_request_count;
u_int64_t http_hsts_enable = HTTP_HSTS_ENABLE;
u_int16_t http_header_max = HTTP_HEADER_MAX_LEN;
u_int16_t http_keepalive_time = HTTP_KEEPALIVE_TIME;
-u_int64_t http_postbody_max = HTTP_POSTBODY_MAX_LEN;
+u_int64_t http_body_max = HTTP_BODY_MAX_LEN;
void
http_init(void)
@@ -104,11 +104,20 @@ http_request_new(struct connection *c, struct spdy_stream *s, const char *host,
if (!strcasecmp(method, "get")) {
m = HTTP_METHOD_GET;
flags = HTTP_REQUEST_COMPLETE;
+ } else if (!strcasecmp(method, "delete")) {
+ m = HTTP_METHOD_DELETE;
+ flags = HTTP_REQUEST_COMPLETE;
} else if (!strcasecmp(method, "post")) {
- flags = 0;
m = HTTP_METHOD_POST;
+ flags = HTTP_REQUEST_EXPECT_BODY;
+ } else if (!strcasecmp(method, "put")) {
+ m = HTTP_METHOD_PUT;
+ flags = HTTP_REQUEST_EXPECT_BODY;
+ } else if (!strcasecmp(method, "head")) {
+ m = HTTP_METHOD_HEAD;
+ flags = HTTP_REQUEST_COMPLETE;
} else {
- http_error_response(c, s, 405);
+ http_error_response(c, s, 400);
return (KORE_RESULT_ERROR);
}
@@ -124,7 +133,7 @@ http_request_new(struct connection *c, struct spdy_stream *s, const char *host,
req->agent = NULL;
req->flags = flags;
req->fsm_state = 0;
- req->post_data = NULL;
+ req->http_body = NULL;
req->hdlr_extra = NULL;
req->query_string = NULL;
req->multipart_body = NULL;
@@ -389,9 +398,9 @@ http_request_free(struct http_request *req)
kore_mem_free(f);
}
- if (req->method == HTTP_METHOD_POST && req->post_data != NULL)
- kore_buf_free(req->post_data);
- if (req->method == HTTP_METHOD_POST && req->multipart_body != NULL)
+ if (req->http_body != NULL)
+ kore_buf_free(req->http_body);
+ if (req->multipart_body != NULL)
kore_mem_free(req->multipart_body);
if (req->agent != NULL)
@@ -438,8 +447,10 @@ http_response_stream(struct http_request *req, int status, void *base,
break;
}
- net_send_stream(req->owner, base, len, req->stream, cb, &nb);
- nb->extra = arg;
+ if (req->method != HTTP_METHOD_HEAD) {
+ net_send_stream(req->owner, base, len, req->stream, cb, &nb);
+ nb->extra = arg;
+ }
}
int
@@ -568,9 +579,9 @@ http_header_recv(struct netbuf *nb)
req->agent = kore_strdup(hdr->value);
}
- if (req->method == HTTP_METHOD_POST) {
+ if (req->flags & HTTP_REQUEST_EXPECT_BODY) {
if (!http_request_header(req, "content-length", &p)) {
- kore_debug("POST but no content-length");
+ kore_debug("expected body but no content-length");
req->flags |= HTTP_REQUEST_DELETE;
http_error_response(req->owner, NULL, 411);
return (KORE_RESULT_OK);
@@ -589,30 +600,31 @@ http_header_recv(struct netbuf *nb)
if (clen == 0) {
req->flags |= HTTP_REQUEST_COMPLETE;
+ req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
return (KORE_RESULT_OK);
}
- if (clen > http_postbody_max) {
- kore_log(LOG_NOTICE, "POST data too large (%ld > %ld)",
- clen, http_postbody_max);
+ if (clen > http_body_max) {
+ kore_log(LOG_NOTICE, "body too large (%ld > %ld)",
+ clen, http_body_max);
req->flags |= HTTP_REQUEST_DELETE;
http_error_response(req->owner, NULL, 411);
return (KORE_RESULT_OK);
}
- req->post_data = kore_buf_create(clen);
- kore_buf_append(req->post_data, end_headers,
+ req->http_body = kore_buf_create(clen);
+ kore_buf_append(req->http_body, end_headers,
(nb->s_off - len));
bytes_left = clen - (nb->s_off - len);
if (bytes_left > 0) {
- kore_debug("%ld/%ld (%ld - %ld) more bytes for POST",
+ kore_debug("%ld/%ld (%ld - %ld) more bytes for body",
bytes_left, clen, nb->s_off, len);
- net_recv_queue(c, bytes_left,
- 0, &nnb, http_post_data_recv);
+ net_recv_queue(c, bytes_left, 0, &nnb, http_body_recv);
nnb->extra = req;
} else if (bytes_left == 0) {
req->flags |= HTTP_REQUEST_COMPLETE;
+ req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
} else {
kore_debug("bytes_left would become zero (%ld)", clen);
http_error_response(req->owner, NULL, 500);
@@ -630,9 +642,9 @@ http_populate_arguments(struct http_request *req)
char *query, *args[HTTP_MAX_QUERY_ARGS], *val[3];
if (req->method == HTTP_METHOD_POST) {
- if (req->post_data == NULL)
+ if (req->http_body == NULL)
return (0);
- query = http_post_data_text(req);
+ query = http_body_text(req);
} else {
if (req->query_string == NULL)
return (0);
@@ -825,7 +837,7 @@ http_populate_multipart_form(struct http_request *req, int *v)
slen = l;
kore_mem_free(type);
- req->multipart_body = http_post_data_bytes(req, &blen);
+ req->multipart_body = http_body_bytes(req, &blen);
if (slen < 3 || blen < (slen * 2)) {
kore_mem_free(boundary);
return (KORE_RESULT_ERROR);
@@ -943,17 +955,17 @@ http_generic_404(struct http_request *req)
}
char *
-http_post_data_text(struct http_request *req)
+http_body_text(struct http_request *req)
{
u_int32_t len;
u_int8_t *data;
char *text;
- if (req->post_data == NULL)
+ if (req->http_body == NULL)
return (NULL);
- data = kore_buf_release(req->post_data, &len);
- req->post_data = NULL;
+ data = kore_buf_release(req->http_body, &len);
+ req->http_body = NULL;
len++;
text = kore_malloc(len);
@@ -964,15 +976,15 @@ http_post_data_text(struct http_request *req)
}
u_int8_t *
-http_post_data_bytes(struct http_request *req, u_int32_t *len)
+http_body_bytes(struct http_request *req, u_int32_t *len)
{
u_int8_t *data;
- if (req->post_data == NULL)
+ if (req->http_body == NULL)
return (NULL);
- data = kore_buf_release(req->post_data, len);
- req->post_data = NULL;
+ data = kore_buf_release(req->http_body, len);
+ req->http_body = NULL;
return (data);
}
@@ -1073,14 +1085,16 @@ http_file_add(struct http_request *req, const char *name, const char *filename,
}
static int
-http_post_data_recv(struct netbuf *nb)
+http_body_recv(struct netbuf *nb)
{
struct http_request *req = (struct http_request *)nb->extra;
- kore_buf_append(req->post_data, nb->buf, nb->s_off);
+ kore_buf_append(req->http_body, nb->buf, nb->s_off);
+
req->flags |= HTTP_REQUEST_COMPLETE;
+ req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
- kore_debug("post complete for request %p", req);
+ kore_debug("received all body data for request %p", req);
return (KORE_RESULT_OK);
}
@@ -1128,9 +1142,6 @@ http_response_spdy(struct http_request *req, struct connection *c,
KORE_VERSION_STATE);
spdy_header_block_add(hblock, ":server", sbuf);
- if (status == HTTP_STATUS_METHOD_NOT_ALLOWED)
- spdy_header_block_add(hblock, ":allow", "get, post");
-
if (http_hsts_enable) {
(void)snprintf(sbuf, sizeof(sbuf),
"max-age=%" PRIu64, http_hsts_enable);
@@ -1153,7 +1164,7 @@ http_response_spdy(struct http_request *req, struct connection *c,
net_send_queue(c, htext, hlen, NULL, NETBUF_LAST_CHAIN);
kore_mem_free(htext);
- if (len > 0) {
+ if (len > 0 && req != NULL && req->method != HTTP_METHOD_HEAD) {
s->send_size += len;
s->flags |= SPDY_DATAFRAME_PRELUDE;
@@ -1181,9 +1192,6 @@ http_response_normal(struct http_request *req, struct connection *c,
KORE_NAME_STRING, KORE_VERSION_MAJOR, KORE_VERSION_MINOR,
KORE_VERSION_STATE);
- if (status == HTTP_STATUS_METHOD_NOT_ALLOWED)
- kore_buf_appendf(header_buf, "allow: GET, POST\r\n");
-
if (c->flags & CONN_CLOSE_EMPTY)
connection_close = 1;
else
@@ -1227,7 +1235,7 @@ http_response_normal(struct http_request *req, struct connection *c,
net_send_queue(c, header_buf->data, header_buf->offset,
NULL, NETBUF_LAST_CHAIN);
- if (d != NULL)
+ if (d != NULL && req != NULL && req->method != HTTP_METHOD_HEAD)
net_send_queue(c, d, len, NULL, NETBUF_LAST_CHAIN);
if (!(c->flags & CONN_CLOSE_EMPTY)) {
diff --git a/src/pgsql.c b/src/pgsql.c
@@ -306,7 +306,6 @@ pgsql_schedule(struct kore_pgsql *pgsql, struct http_request *req)
kore_platform_schedule_read(fd, pgsql->conn);
pgsql->state = KORE_PGSQL_STATE_WAIT;
- kore_debug("query '%s' for %p sent on %p", query, req, pgsql->conn);
}
static void
diff --git a/src/spdy.c b/src/spdy.c
@@ -781,16 +781,16 @@ spdy_data_frame_recv(struct netbuf *nb)
}
req = (struct http_request *)s->httpreq;
- if (req == NULL || req->method != HTTP_METHOD_POST) {
+ if (req == NULL || !(req->flags & HTTP_REQUEST_EXPECT_BODY)) {
kore_debug("data frame for non post received");
/* stream error */
return (KORE_RESULT_ERROR);
}
- if (req->post_data == NULL) {
+ if (req->http_body == NULL) {
if (!spdy_stream_get_header(s->hblock,
"content-length", &content)) {
- kore_debug("no content-length found for post");
+ kore_debug("no content-length found for body");
return (KORE_RESULT_ERROR);
}
@@ -805,28 +805,29 @@ spdy_data_frame_recv(struct netbuf *nb)
if (s->post_size == 0) {
req->flags |= HTTP_REQUEST_COMPLETE;
+ req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
return (KORE_RESULT_OK);
}
- if (s->post_size > http_postbody_max) {
- kore_log(LOG_NOTICE, "POST data too large (%ld > %ld)",
- s->post_size, http_postbody_max);
+ if (s->post_size > http_body_max) {
+ kore_log(LOG_NOTICE, "body data too large (%ld > %ld)",
+ s->post_size, http_body_max);
return (KORE_RESULT_ERROR);
}
- req->post_data = kore_buf_create(s->post_size);
+ req->http_body = kore_buf_create(s->post_size);
}
- if ((req->post_data->offset + data.length) > s->post_size) {
+ if ((req->http_body->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),
+ kore_buf_append(req->http_body, (nb->buf + SPDY_FRAME_SIZE),
data.length);
if (data.flags & FLAG_FIN) {
- if (req->post_data->offset != s->post_size) {
+ if (req->http_body->offset != s->post_size) {
kore_debug("FLAG_FIN before all POST data received");
return (KORE_RESULT_ERROR);
}
@@ -834,6 +835,7 @@ spdy_data_frame_recv(struct netbuf *nb)
s->post_size = 0;
s->flags |= FLAG_FIN;
req->flags |= HTTP_REQUEST_COMPLETE;
+ req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
}
/*