allow modules to add headers to the response before calling http_response()

by calling http_response_header_add().

fix wrong overflow check in spdy_stream_get_header().

html_inject now exports last modified timestamp for the files that are
compiled into the module in the format static_mtime_<type>_<name>.

modules can now look into the request headers using http_request_header_get().
This commit is contained in:
Joris Vink 2013-05-01 21:16:09 +02:00
parent a228cdba0e
commit a9ebf37cae
7 changed files with 172 additions and 66 deletions

View File

@ -47,9 +47,27 @@ int
betrippin_serve_style_css(struct http_request *req)
{
int ret;
char *date;
time_t tstamp;
ret = http_response(req, 200, static_css_style,
static_len_css_style, "text/css");
if (http_request_header_get(req, "if-modified-since", &date)) {
tstamp = kore_date_to_time(date);
free(date);
kore_log("header was present with %ld", tstamp);
}
if (tstamp != 0 && tstamp <= static_mtime_css_style) {
ret = http_response(req, 304, NULL, 0);
} else {
date = kore_time_to_date(static_mtime_css_style);
if (date != NULL)
http_response_header_add(req, "last-modified", date);
http_response_header_add(req, "content-type", "text/css");
ret = http_response(req, 200, static_css_style,
static_len_css_style);
}
return (ret);
}
@ -59,8 +77,9 @@ betrippin_serve_index(struct http_request *req)
{
int ret;
http_response_header_add(req, "content-type", "text/html");
ret = http_response(req, 200, static_html_index,
static_len_html_index, "text/html");
static_len_html_index);
return (ret);
}

View File

@ -15,6 +15,7 @@
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
@ -27,6 +28,7 @@
int
main(int argc, char *argv[])
{
struct stat st;
size_t len;
FILE *fp, *hdr;
char *ext, *p, *c, buf[1024];
@ -40,6 +42,11 @@ main(int argc, char *argv[])
if ((ext = strchr(argv[2], '.')) != NULL)
*(ext)++ = '\0';
if (stat(argv[1], &st) == -1) {
printf("stat(%s) failed: %d\n", argv[1], errno);
exit(99);
}
printf("/**** AUTO GENERATED BY MAKEFILE - DO NOT TOUCH ****/\n");
printf("#include <sys/param.h>\n\n");
printf("u_int8_t *static_%s_%s = (u_int8_t *)", ext, argv[2]);
@ -64,10 +71,12 @@ main(int argc, char *argv[])
fclose(fp);
printf(";\n\n");
printf("u_int32_t static_len_%s_%s = %ld;", ext, argv[2], len);
printf("u_int32_t static_len_%s_%s = %ld;\n", ext, argv[2], len);
printf("time_t static_mtime_%s_%s = %ld;\n", ext, argv[2], st.st_mtime);
fprintf(hdr, "extern u_int8_t *static_%s_%s;\n", ext, argv[2]);
fprintf(hdr, "extern u_int32_t static_len_%s_%s;\n", ext, argv[2]);
fprintf(hdr, "extern u_int32_t static_mtime_%s_%s;\n", ext, argv[2]);
fclose(hdr);
return (0);

View File

@ -17,6 +17,13 @@
#ifndef __H_HTTP_H
#define __H_HTTP_H
struct http_header {
char *header;
char *value;
TAILQ_ENTRY(http_header) list;
};
struct http_request {
char *host;
char *method;
@ -25,6 +32,7 @@ struct http_request {
struct connection *owner;
struct spdy_stream *stream;
TAILQ_HEAD(, http_header) headers;
TAILQ_ENTRY(http_request) list;
};
@ -33,8 +41,10 @@ void http_process(void);
time_t http_date_to_time(char *);
void http_request_free(struct http_request *);
int http_response(struct http_request *, int,
u_int8_t *, u_int32_t, char *);
int http_new_request(struct connection *, struct spdy_stream *,
u_int8_t *, u_int32_t);
int http_request_header_get(struct http_request *, char *, char **);
void http_response_header_add(struct http_request *, char *, char *);
int http_request_new(struct connection *, struct spdy_stream *,
char *, char *, char *);
#endif /* !__H_HTTP_H */

View File

@ -96,6 +96,7 @@ void *kore_malloc(size_t);
void *kore_calloc(size_t, size_t);
void *kore_realloc(void *, size_t);
time_t kore_date_to_time(char *);
char *kore_time_to_date(time_t);
char *kore_strdup(const char *);
void kore_parse_config(const char *);
void kore_strlcpy(char *, const char *, size_t);
@ -126,8 +127,10 @@ int net_recv_expand(struct connection *c, struct netbuf *, size_t,
int net_send_queue(struct connection *, u_int8_t *, size_t,
struct netbuf **, int (*cb)(struct netbuf *));
struct spdy_stream *spdy_stream_lookup(struct connection *, u_int32_t);
struct spdy_header_block *spdy_header_block_create(int);
struct spdy_stream *spdy_stream_lookup(struct connection *, u_int32_t);
int spdy_stream_get_header(struct spdy_header_block *,
char *, char **);
int spdy_frame_recv(struct netbuf *);
int spdy_frame_send(struct connection *, u_int16_t,

View File

@ -49,12 +49,12 @@ http_init(void)
}
int
http_new_request(struct connection *c, struct spdy_stream *s, char *host,
http_request_new(struct connection *c, struct spdy_stream *s, char *host,
char *method, char *path)
{
struct http_request *req;
kore_log("http_new_request(%p, %p, %s, %s, %s)", c, s,
kore_log("http_request_new(%p, %p, %s, %s, %s)", c, s,
host, method, path);
req = (struct http_request *)kore_malloc(sizeof(*req));
@ -63,14 +63,39 @@ http_new_request(struct connection *c, struct spdy_stream *s, char *host,
req->host = kore_strdup(host);
req->path = kore_strdup(path);
req->method = kore_strdup(method);
TAILQ_INIT(&(req->headers));
TAILQ_INSERT_TAIL(&http_requests, req, list);
return (KORE_RESULT_OK);
}
void
http_response_header_add(struct http_request *req, char *header, char *value)
{
struct http_header *hdr;
kore_log("http_response_header_add(%p, %s, %s)", req, header, value);
hdr = (struct http_header *)kore_malloc(sizeof(*hdr));
hdr->header = kore_strdup(header);
hdr->value = kore_strdup(value);
TAILQ_INSERT_TAIL(&(req->headers), hdr, list);
}
void
http_request_free(struct http_request *req)
{
struct http_header *hdr, *next;
for (hdr = TAILQ_FIRST(&(req->headers)); hdr != NULL; hdr = next) {
next = TAILQ_NEXT(hdr, list);
TAILQ_REMOVE(&(req->headers), hdr, list);
free(hdr->header);
free(hdr->value);
free(hdr);
}
free(req->method);
free(req->path);
free(req->host);
@ -78,25 +103,25 @@ http_request_free(struct http_request *req)
}
int
http_response(struct http_request *req, int status, u_int8_t *d,
u_int32_t len, char *content_type)
http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
{
u_int32_t hlen;
struct http_header *hdr;
u_int8_t *htext;
char sbuf[4];
struct spdy_header_block *hblock;
char sbuf[4];
kore_log("http_response(%p, %d, %p, %d)", req, status, d, len);
if (req->owner->proto == CONN_PROTO_SPDY) {
snprintf(sbuf, sizeof(sbuf), "%d", status);
hblock = spdy_header_block_create(SPDY_HBLOCK_NORMAL);
spdy_header_block_add(hblock, ":status", sbuf);
spdy_header_block_add(hblock, ":version", "HTTP/1.1");
if (content_type != NULL) {
spdy_header_block_add(hblock,
"content-type", content_type);
}
TAILQ_FOREACH(hdr, &(req->headers), list)
spdy_header_block_add(hblock, hdr->header, hdr->value);
htext = spdy_header_block_release(req->owner, hblock, &hlen);
if (htext == NULL)
return (KORE_RESULT_ERROR);
@ -126,6 +151,21 @@ http_response(struct http_request *req, int status, u_int8_t *d,
return (KORE_RESULT_OK);
}
int
http_request_header_get(struct http_request *req, char *header, char **out)
{
int r;
if (req->owner->proto == CONN_PROTO_SPDY) {
r = spdy_stream_get_header(req->stream->hblock, header, out);
} else {
kore_log("http not supported yet");
r = KORE_RESULT_ERROR;
}
return (r);
}
void
http_process(void)
{
@ -160,5 +200,5 @@ http_generic_404(struct http_request *req)
kore_log("http_generic_404(%s, %s, %s)",
req->host, req->method, req->path);
return (http_response(req, 404, NULL, 0, NULL));
return (http_response(req, 404, NULL, 0));
}

View File

@ -40,8 +40,6 @@
static int spdy_ctrl_frame_syn_stream(struct netbuf *);
static int spdy_ctrl_frame_settings(struct netbuf *);
static int spdy_ctrl_frame_ping(struct netbuf *);
static int spdy_stream_get_header(struct spdy_header_block *,
char *, char **);
static int spdy_zlib_inflate(struct connection *, u_int8_t *,
size_t, u_int8_t **, u_int32_t *);
@ -237,6 +235,59 @@ spdy_header_block_release(struct connection *c,
return (deflated);
}
int
spdy_stream_get_header(struct spdy_header_block *s, char *header, char **out)
{
char *cmp, t[128];
u_int8_t *p, *end;
u_int32_t i, nlen, vlen;
kore_log("spdy_stream_get_header(%p, %s) <%d>", s, header,
s->header_pairs);
p = s->header_block + 4;
end = s->header_block + s->header_block_len;
if (p >= end) {
kore_log("p >= end when looking for headers");
return (KORE_RESULT_ERROR);
}
for (i = 0; i < s->header_pairs; i++) {
nlen = net_read32(p);
if ((p + nlen + 4) > end) {
kore_log("nlen out of bounds on %d (%d)", i, nlen);
return (KORE_RESULT_ERROR);
}
vlen = net_read32(p + nlen + 4);
if ((p + nlen + vlen + 8) > end) {
kore_log("vlen out of bounds on %d (%d)", i, vlen);
return (KORE_RESULT_ERROR);
}
cmp = (char *)(p + 4);
memcpy(t, cmp, nlen);
t[nlen] = '\0';
kore_log("header %s", t);
if (!strncasecmp(cmp, header, nlen)) {
kore_log("found %s header", header);
cmp = (char *)(p + nlen + 8);
*out = (char *)kore_malloc(vlen + 1);
kore_strlcpy(*out, cmp, vlen + 1);
return (KORE_RESULT_OK);
}
kore_log("pair name %d bytes, value %d bytes", nlen, vlen);
p += nlen + vlen + 8;
}
return (KORE_RESULT_ERROR);
}
static int
spdy_ctrl_frame_syn_stream(struct netbuf *nb)
{
@ -321,7 +372,7 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb)
GET_HEADER(":path", &path);
GET_HEADER(":method", &method);
GET_HEADER(":host", &host);
if (!http_new_request(c, s, host, method, path)) {
if (!http_request_new(c, s, host, method, path)) {
free(s->hblock->header_block);
free(s->hblock);
free(s);
@ -365,52 +416,6 @@ spdy_ctrl_frame_ping(struct netbuf *nb)
return (spdy_frame_send(c, SPDY_CTRL_FRAME_PING, 0, 4, id));
}
static int
spdy_stream_get_header(struct spdy_header_block *s, char *header, char **out)
{
char *cmp;
u_int8_t *p, *end;
u_int32_t i, nlen, vlen;
p = s->header_block + 4;
end = s->header_block + s->header_block_len;
if (p >= end) {
kore_log("p >= end when looking for headers");
return (KORE_RESULT_ERROR);
}
for (i = 0; i < s->header_pairs; i++) {
nlen = net_read32(p);
if ((p + nlen + 4) >= end) {
kore_log("nlen out of bounds (%d)", nlen);
return (KORE_RESULT_ERROR);
}
vlen = net_read32(p + nlen + 4);
if ((p + nlen + vlen + 8) >= end) {
kore_log("vlen out of bounds (%d)", vlen);
return (KORE_RESULT_ERROR);
}
cmp = (char *)(p + 4);
if (!strncasecmp(cmp, header, nlen)) {
kore_log("found %s header", header);
cmp = (char *)(p + nlen + 8);
*out = (char *)kore_malloc(vlen + 1);
kore_strlcpy(*out, cmp, vlen + 1);
return (KORE_RESULT_OK);
}
kore_log("pair name %d bytes, value %d bytes", nlen, vlen);
p += nlen + vlen + 8;
}
return (KORE_RESULT_ERROR);
}
static int
spdy_zlib_inflate(struct connection *c, u_int8_t *src, size_t len,
u_int8_t **dst, u_int32_t *olen)

View File

@ -255,6 +255,26 @@ out:
return (t);
}
char *
kore_time_to_date(time_t now)
{
struct tm *tm;
static time_t last = 0;
static char tbuf[32];
if (now != last) {
last = now;
tm = gmtime(&now);
if (!strftime(tbuf, sizeof(tbuf), "%a, %d %b %Y %T GMT", tm)) {
kore_log("strftime() gave us NULL (%ld)", now);
return (NULL);
}
}
return (tbuf);
}
void
fatal(const char *fmt, ...)
{