add very basic support for HTTP/1.1.

This commit is contained in:
Joris Vink 2013-05-02 03:51:04 +02:00
parent 5f983d575b
commit f46bba50ef
8 changed files with 238 additions and 17 deletions

View File

@ -3,7 +3,7 @@
CC=gcc
BIN=kore
S_SRC= src/kore.c src/config.c src/net.c src/spdy.c src/http.c \
S_SRC= src/kore.c src/buf.c src/config.c src/net.c src/spdy.c src/http.c \
src/module.c src/utils.c src/zlib_dict.c
S_OBJS= $(S_SRC:.c=.o)

View File

@ -17,6 +17,9 @@
#ifndef __H_HTTP_H
#define __H_HTTP_H
#define HTTP_HEADER_MAX_LEN 8192
#define HTTP_REQ_HEADER_MAX 25
struct http_header {
char *header;
char *value;
@ -28,11 +31,11 @@ struct http_request {
char *host;
char *method;
char *path;
struct connection *owner;
struct spdy_stream *stream;
TAILQ_HEAD(, http_header) headers;
TAILQ_HEAD(, http_header) req_headers;
TAILQ_HEAD(, http_header) resp_headers;
TAILQ_ENTRY(http_request) list;
};
@ -45,6 +48,8 @@ int http_response(struct http_request *, int,
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 *);
char *, char *, char *, struct http_request **);
int http_header_recv(struct netbuf *);
#endif /* !__H_HTTP_H */

View File

@ -92,6 +92,15 @@ struct kore_module_handle {
TAILQ_ENTRY(kore_module_handle) list;
};
#define KORE_BUF_INITIAL 128
#define KORE_BUF_INCREMENT KORE_BUF_INITIAL
struct kore_buf {
u_int8_t *data;
u_int32_t length;
u_int32_t offset;
};
extern int server_port;
extern char *server_ip;
@ -130,6 +139,10 @@ int net_recv_expand(struct connection *c, struct netbuf *, size_t,
int net_send_queue(struct connection *, u_int8_t *, size_t, int,
struct netbuf **, int (*cb)(struct netbuf *));
struct kore_buf *kore_buf_create(u_int32_t);
void kore_buf_append(struct kore_buf *, u_int8_t *, u_int32_t);
u_int8_t *kore_buf_release(struct kore_buf *, 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 *,

74
src/buf.c Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2013 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 <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include "spdy.h"
#include "kore.h"
struct kore_buf *
kore_buf_create(u_int32_t initial)
{
struct kore_buf *buf;
buf = (struct kore_buf *)kore_malloc(sizeof(*buf));
buf->data = (u_int8_t *)kore_malloc(initial);
buf->length = initial;
buf->offset = 0;
return (buf);
}
void
kore_buf_append(struct kore_buf *buf, u_int8_t *d, u_int32_t len)
{
if ((buf->offset + len) >= buf->length) {
buf->length += len + KORE_BUF_INCREMENT;
buf->data = (u_int8_t *)kore_realloc(buf->data, buf->length);
}
memcpy((buf->data + buf->offset), d, len);
buf->offset += len;
}
u_int8_t *
kore_buf_release(struct kore_buf *buf, u_int32_t *len)
{
u_int8_t *p;
p = buf->data;
*len = buf->offset;
free(buf);
return (p);
}

View File

@ -50,7 +50,7 @@ http_init(void)
int
http_request_new(struct connection *c, struct spdy_stream *s, char *host,
char *method, char *path)
char *method, char *path, struct http_request **out)
{
struct http_request *req;
@ -63,9 +63,13 @@ http_request_new(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_INIT(&(req->resp_headers));
TAILQ_INIT(&(req->req_headers));
TAILQ_INSERT_TAIL(&http_requests, req, list);
if (out != NULL)
*out = req;
return (KORE_RESULT_OK);
}
@ -79,7 +83,7 @@ http_response_header_add(struct http_request *req, char *header, char *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);
TAILQ_INSERT_TAIL(&(req->resp_headers), hdr, list);
}
void
@ -87,10 +91,19 @@ http_request_free(struct http_request *req)
{
struct http_header *hdr, *next;
for (hdr = TAILQ_FIRST(&(req->headers)); hdr != NULL; hdr = next) {
for (hdr = TAILQ_FIRST(&(req->resp_headers)); hdr != NULL; hdr = next) {
next = TAILQ_NEXT(hdr, list);
TAILQ_REMOVE(&(req->headers), hdr, list);
TAILQ_REMOVE(&(req->resp_headers), hdr, list);
free(hdr->header);
free(hdr->value);
free(hdr);
}
for (hdr = TAILQ_FIRST(&(req->req_headers)); hdr != NULL; hdr = next) {
next = TAILQ_NEXT(hdr, list);
TAILQ_REMOVE(&(req->req_headers), hdr, list);
free(hdr->header);
free(hdr->value);
free(hdr);
@ -107,9 +120,10 @@ http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
{
u_int32_t hlen;
struct http_header *hdr;
struct kore_buf *buf;
u_int8_t *htext;
struct spdy_header_block *hblock;
char sbuf[4];
char sbuf[64];
kore_log("http_response(%p, %d, %p, %d)", req, status, d, len);
@ -119,7 +133,7 @@ http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
hblock = spdy_header_block_create(SPDY_HBLOCK_NORMAL);
spdy_header_block_add(hblock, ":status", sbuf);
spdy_header_block_add(hblock, ":version", "HTTP/1.1");
TAILQ_FOREACH(hdr, &(req->headers), list)
TAILQ_FOREACH(hdr, &(req->resp_headers), list)
spdy_header_block_add(hblock, hdr->header, hdr->value);
htext = spdy_header_block_release(req->owner, hblock, &hlen);
@ -130,9 +144,12 @@ http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
0, hlen, req->stream->stream_id))
return (KORE_RESULT_ERROR);
if (!net_send_queue(req->owner, htext, hlen, 0, NULL, NULL))
if (!net_send_queue(req->owner, htext, hlen, 0, NULL, NULL)) {
free(htext);
return (KORE_RESULT_ERROR);
}
free(htext);
if (len > 0) {
if (!spdy_frame_send(req->owner, SPDY_DATA_FRAME,
0, len, req->stream->stream_id))
@ -145,7 +162,33 @@ http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
FLAG_FIN, 0, req->stream->stream_id))
return (KORE_RESULT_ERROR);
} else {
kore_log("normal http not functional yet");
buf = kore_buf_create(KORE_BUF_INITIAL);
snprintf(sbuf, sizeof(sbuf), "HTTP/1.1 %d\r\n", status);
kore_buf_append(buf, (u_int8_t *)sbuf, strlen(sbuf));
snprintf(sbuf, sizeof(sbuf), "Content-length: %d\r\n", len);
kore_buf_append(buf, (u_int8_t *)sbuf, strlen(sbuf));
snprintf(sbuf, sizeof(sbuf), "Connection: close\r\n");
kore_buf_append(buf, (u_int8_t *)sbuf, strlen(sbuf));
TAILQ_FOREACH(hdr, &(req->resp_headers), list) {
snprintf(sbuf, sizeof(sbuf), "%s: %s\r\n",
hdr->header, hdr->value);
kore_buf_append(buf, (u_int8_t *)sbuf, strlen(sbuf));
}
kore_buf_append(buf, (u_int8_t *)"\r\n\r\n", 4);
htext = kore_buf_release(buf, &hlen);
if (!net_send_queue(req->owner, htext, hlen, 0, NULL, NULL)) {
free(htext);
return (KORE_RESULT_ERROR);
}
free(htext);
if (!net_send_queue(req->owner, d, len, 0, NULL, NULL))
return (KORE_RESULT_ERROR);
}
return (KORE_RESULT_OK);
@ -154,12 +197,21 @@ http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
int
http_request_header_get(struct http_request *req, char *header, char **out)
{
int r;
int r;
struct http_header *hdr;
if (req->owner->proto == CONN_PROTO_SPDY) {
r = spdy_stream_get_header(req->stream->hblock, header, out);
} else {
kore_log("http not supported yet");
TAILQ_FOREACH(hdr, &(req->req_headers), list) {
if (!strcasecmp(hdr->header, header)) {
r = strlen(hdr->value) + 1;
*out = (char *)kore_malloc(r);
kore_strlcpy(*out, hdr->value, r);
return (KORE_RESULT_OK);
}
}
r = KORE_RESULT_ERROR;
}
@ -194,6 +246,78 @@ http_process(void)
}
}
int
http_header_recv(struct netbuf *nb)
{
char *p;
struct http_header *hdr;
struct http_request *req;
int h, i, v;
char *request[4], *host[3], *hbuf;
char *headers[HTTP_REQ_HEADER_MAX];
struct connection *c = (struct connection *)nb->owner;
kore_log("http_header_recv(%p)", nb);
nb->buf[nb->len] = '\0';
if ((p = strrchr((char *)nb->buf, '\r')) == NULL)
return (KORE_RESULT_OK);
if (nb->len > 2 && strncmp((p - 2), "\r\n\r\n", 4))
return (KORE_RESULT_OK);
hbuf = kore_strdup((const char *)nb->buf);
h = kore_split_string(hbuf, "\r\n", headers, HTTP_REQ_HEADER_MAX);
if (h < 2) {
free(hbuf);
return (KORE_RESULT_ERROR);
}
if (strlen(headers[0]) > 3 && strncasecmp(headers[0], "get", 3)) {
free(hbuf);
return (KORE_RESULT_ERROR);
}
v = kore_split_string(headers[0], " ", request, 4);
if (v != 3) {
free(hbuf);
return (KORE_RESULT_ERROR);
}
v = kore_split_string(headers[1], ":", host, 3);
if (v != 2) {
free(hbuf);
return (KORE_RESULT_ERROR);
}
if (strlen(host[0]) != 4 || strncasecmp(host[0], "host", 5)) {
free(hbuf);
return (KORE_RESULT_ERROR);
}
if (!http_request_new(c, NULL, host[1], request[0], request[1], &req)) {
free(hbuf);
return (KORE_RESULT_ERROR);
}
for (i = 2; i < h; i++) {
p = strchr(headers[i], ':');
if (p == NULL) {
kore_log("malformed header: '%s'", headers[i]);
continue;
}
*(p++) = '\0';
hdr = (struct http_header *)kore_malloc(sizeof(*hdr));
hdr->header = kore_strdup(headers[i]);
hdr->value = kore_strdup(p);
TAILQ_INSERT_TAIL(&(req->req_headers), hdr, list);
}
free(hbuf);
return (KORE_RESULT_OK);
}
static int
http_generic_404(struct http_request *req)
{

View File

@ -329,6 +329,10 @@ kore_connection_handle(struct connection *c, int flags)
} else {
kore_log("using HTTP/1.1");
c->proto = CONN_PROTO_HTTP;
if (!net_recv_queue(c, HTTP_HEADER_MAX_LEN,
NETBUF_CALL_CB_ALWAYS, NULL,
http_header_recv))
return (KORE_RESULT_ERROR);
}
c->state = CONN_STATE_ESTABLISHED;

View File

@ -136,7 +136,6 @@ spdy_frame_send(struct connection *c, u_int16_t type, u_int8_t flags,
net_write32(&nb[8], stream_id);
length = 12;
break;
break;
case SPDY_DATA_FRAME:
net_write32(&nb[0], stream_id);
nb[0] &= ~(1 << 7);
@ -370,7 +369,7 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb)
GET_HEADER(":path", &path);
GET_HEADER(":method", &method);
GET_HEADER(":host", &host);
if (!http_request_new(c, s, host, method, path)) {
if (!http_request_new(c, s, host, method, path, NULL)) {
free(s->hblock->header_block);
free(s->hblock);
free(s);

View File

@ -63,6 +63,7 @@ kore_malloc(size_t len)
if ((ptr = malloc(len)) == NULL)
fatal("kore_malloc(%d): %d", len, errno);
memset(ptr, 0, len);
return (ptr);
}
@ -85,6 +86,7 @@ kore_calloc(size_t memb, size_t len)
if ((ptr = calloc(memb, len)) == NULL)
fatal("kore_calloc(%d, %d): %d", memb, len, errno);
memset(ptr, 0, memb * len);
return (ptr);
}