mirror of
https://github.com/jorisvink/kore
synced 2025-03-09 04:29:02 -04:00
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.
This commit is contained in:
parent
3741e8ca3f
commit
a603b77e24
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
14
src/config.c
14
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);
|
||||
}
|
||||
|
||||
|
94
src/http.c
94
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);
|
||||
req->flags |= HTTP_REQUEST_COMPLETE;
|
||||
kore_buf_append(req->http_body, nb->buf, nb->s_off);
|
||||
|
||||
kore_debug("post complete for request %p", req);
|
||||
req->flags |= HTTP_REQUEST_COMPLETE;
|
||||
req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
|
||||
|
||||
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)) {
|
||||
|
@ -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
|
||||
|
22
src/spdy.c
22
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user