mirror of
https://github.com/jorisvink/kore
synced 2025-03-09 12:39:01 -04:00
add very basic support for HTTP/1.1.
This commit is contained in:
parent
5f983d575b
commit
f46bba50ef
2
Makefile
2
Makefile
@ -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)
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
74
src/buf.c
Normal 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);
|
||||
}
|
146
src/http.c
146
src/http.c
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user