commit 05156c9a3a41d67b6f32b1a7855c0cec0c9bed7b
parent bb3b8042225205c1b7fec7581dfbfbf6db1021a1
Author: Joris Vink <joris@coders.se>
Date: Wed, 1 May 2013 00:35:33 +0200
properly deflate/inflate of name/value blocks. and add ability
to get headers from them.
Diffstat:
9 files changed, 563 insertions(+), 111 deletions(-)
diff --git a/Makefile b/Makefile
@@ -3,14 +3,14 @@
CC=gcc
BIN=kore
-S_SRC= src/kore.c src/net.c src/spdy.c src/utils.c
+S_SRC= src/kore.c src/net.c src/spdy.c src/http.c src/utils.c src/zlib_dict.c
S_OBJS= $(S_SRC:.c=.o)
CFLAGS+=-I/usr/local/ssl/include
CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+=-Wsign-compare -Iincludes -g
-LDFLAGS=-static -Llibs -lssl -lcrypto -lz
+LDFLAGS=-static -Llibs -lssl -lcrypto -ldl -lz
light: $(S_OBJS)
$(CC) $(CFLAGS) $(S_OBJS) $(LDFLAGS) -o $(BIN)
diff --git a/includes/http.h b/includes/http.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef __H_HTTP_H
+#define __H_HTTP_H
+
+struct http_request {
+ char *host;
+ char *method;
+ char *path;
+
+ struct connection *owner;
+ struct spdy_stream *stream;
+
+ TAILQ_ENTRY(http_request) list;
+};
+
+#endif /* !__H_HTTP_H */
diff --git a/includes/kore.h b/includes/kore.h
@@ -72,10 +72,13 @@ void *kore_malloc(size_t);
void *kore_calloc(size_t, size_t);
void *kore_realloc(void *, size_t);
char *kore_strdup(const char *);
+void kore_strlcpy(char *, const char *, size_t);
void fatal(const char *, ...);
void kore_log_internal(char *, int, const char *, ...);
+u_int16_t net_read16(u_int8_t *);
+u_int32_t net_read32(u_int8_t *);
int net_recv(struct connection *);
int net_send(struct connection *);
int net_recv_queue(struct connection *, size_t,
@@ -85,6 +88,9 @@ int net_recv_expand(struct connection *c, struct netbuf *, size_t,
int net_send_queue(struct connection *, u_int8_t *, size_t,
int (*cb)(struct netbuf *));
+int http_new_request(struct connection *, struct spdy_stream *,
+ char *, char *, char *);
+
int spdy_frame_recv(struct netbuf *);
struct spdy_stream *spdy_stream_lookup(struct connection *, u_int32_t);
diff --git a/includes/spdy.h b/includes/spdy.h
@@ -17,34 +17,25 @@
#ifndef __H_SPDY_H
#define __H_SPDY_H
-#define KORE_SSL_PROTO_STRING "\x06spdy/3\x08http/1.1"
-
-struct spdy_frame {
- u_int32_t frame_1;
- u_int32_t frame_2;
-};
-
struct spdy_ctrl_frame {
- int type:16;
- int version:15;
- int control_bit:1;
- int length:24;
- int flags:8;
+ u_int16_t version;
+ u_int16_t type;
+ u_int8_t flags;
+ u_int32_t length;
};
struct spdy_data_frame {
- int stream_id:31;
- int control_bit:1;
- int length:24;
- int flags:8;
+ u_int32_t stream_id;
+ u_int8_t flags;
+ u_int32_t length;
};
struct spdy_syn_stream {
u_int32_t stream_id;
u_int32_t assoc_stream_id;
u_int8_t slot;
- int reserved:5;
- int prio:3;
+ u_int8_t reserved;
+ u_int8_t prio;
};
struct spdy_stream {
@@ -54,19 +45,26 @@ struct spdy_stream {
u_int8_t *header_block;
u_int32_t header_block_len;
+ u_int32_t header_pairs;
TAILQ_ENTRY(spdy_stream) list;
};
-#define SPDY_CONTROL_FRAME(x) ((x->frame_1 & (1 << 31)))
+extern const unsigned char SPDY_dictionary_txt[];
+
+#define KORE_SSL_PROTO_STRING "\x06spdy/3\x08http/1.1"
+#define SPDY_CONTROL_FRAME(x) ((x & (1 << 31)))
+
#define SPDY_FRAME_SIZE 8
+#define SPDY_SYNFRAME_SIZE 10
+#define SPDY_ZLIB_DICT_SIZE 1423
#define SPDY_ZLIB_CHUNK 16348
-/* control frames. */
+/* control frames */
#define SPDY_CTRL_FRAME_SYN_STREAM 1
#define SPDY_CTRL_FRAME_SETTINGS 4
-/* flags. */
+/* flags */
#define FLAG_FIN 0x01
#define FLAG_UNIDIRECTIONAL 0x02
diff --git a/src/http.c b/src/http.c
@@ -0,0 +1,47 @@
+/*
+ * 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 "spdy.h"
+#include "kore.h"
+#include "http.h"
+
+int
+http_new_request(struct connection *c, struct spdy_stream *s, char *host,
+ char *method, char *path)
+{
+ kore_log("http_new_request(%p, %p, %s, %s, %s)", c, s,
+ host, method, path);
+
+ return (KORE_RESULT_OK);
+}
diff --git a/src/net.c b/src/net.c
@@ -196,3 +196,21 @@ net_recv(struct connection *c)
return (r);
}
+
+u_int16_t
+net_read16(u_int8_t *b)
+{
+ u_int16_t r;
+
+ r = *(u_int16_t *)b;
+ return (ntohs(r));
+}
+
+u_int32_t
+net_read32(u_int8_t *b)
+{
+ u_int32_t r;
+
+ r = *(u_int32_t *)b;
+ return (ntohl(r));
+}
diff --git a/src/spdy.c b/src/spdy.c
@@ -35,30 +35,39 @@
#include "spdy.h"
#include "kore.h"
+#include "http.h"
static int spdy_ctrl_frame_syn_stream(struct netbuf *);
static int spdy_ctrl_frame_settings(struct netbuf *);
+static int spdy_stream_get_header(struct spdy_stream *,
+ char *, char **);
+
+static int spdy_zlib_inflate(u_int8_t *, size_t,
+ u_int8_t **, u_int32_t *);
+static int spdy_zlib_deflate(u_int8_t *, size_t,
+ u_int8_t **, u_int32_t *);
int
spdy_frame_recv(struct netbuf *nb)
{
- struct spdy_ctrl_frame *ctrl;
+ struct spdy_ctrl_frame ctrl;
int (*cb)(struct netbuf *), r;
struct connection *c = (struct connection *)nb->owner;
- struct spdy_frame *frame = (struct spdy_frame *)nb->buf;
-
- frame->frame_1 = ntohl(frame->frame_1);
- frame->frame_2 = ntohl(frame->frame_2);
- if (SPDY_CONTROL_FRAME(frame)) {
+ if (SPDY_CONTROL_FRAME(net_read32(nb->buf))) {
kore_log("received control frame");
- ctrl = (struct spdy_ctrl_frame *)frame;
- kore_log("type is %d", ctrl->type);
- kore_log("version is %d", ctrl->version);
- kore_log("length is %d", ctrl->length);
+ ctrl.version = net_read16(nb->buf) & 0x7fff;
+ ctrl.type = net_read16(nb->buf + 2);
+ ctrl.flags = *(u_int8_t *)(nb->buf + 4);
+ ctrl.length = net_read32(nb->buf + 4) & 0xffffff;
+
+ kore_log("type is %d", ctrl.type);
+ kore_log("version is %d", ctrl.version);
+ kore_log("length is %d", ctrl.length);
+ kore_log("flags are %d", ctrl.flags);
- switch (ctrl->type) {
+ switch (ctrl.type) {
case SPDY_CTRL_FRAME_SYN_STREAM:
cb = spdy_ctrl_frame_syn_stream;
break;
@@ -71,9 +80,9 @@ spdy_frame_recv(struct netbuf *nb)
}
if (cb != NULL) {
- r = net_recv_expand(c, nb, ctrl->length, cb);
+ r = net_recv_expand(c, nb, ctrl.length, cb);
} else {
- kore_log("no callback for type %d", ctrl->type);
+ kore_log("no callback for type %d", ctrl.type);
r = KORE_RESULT_ERROR;
}
} else {
@@ -100,102 +109,78 @@ spdy_stream_lookup(struct connection *c, u_int32_t id)
static int
spdy_ctrl_frame_syn_stream(struct netbuf *nb)
{
- u_int16_t *b;
struct spdy_stream *s;
- z_stream zlib;
- struct spdy_syn_stream *syn;
- size_t have;
- struct spdy_ctrl_frame *ctrl;
- int r, len;
- u_char inflate_buffer[SPDY_ZLIB_CHUNK];
+ struct spdy_syn_stream syn;
+ struct spdy_ctrl_frame ctrl;
+ u_int8_t *src;
+ char *host, *method, *path;
struct connection *c = (struct connection *)nb->owner;
- ctrl = (struct spdy_ctrl_frame *)nb->buf;
- syn = (struct spdy_syn_stream *)(nb->buf + SPDY_FRAME_SIZE);
+ ctrl.version = net_read16(nb->buf) & 0x7fff;
+ ctrl.type = net_read16(nb->buf + 2);
+ ctrl.flags = *(u_int8_t *)(nb->buf + 4);
+ ctrl.length = net_read32(nb->buf + 4) & 0xffffff;
- syn->stream_id = ntohl(syn->stream_id);
- syn->assoc_stream_id = ntohl(syn->assoc_stream_id);
- b = (u_int16_t *)&(syn->slot);
- *b = ntohl(*b);
+ syn.stream_id = net_read32(nb->buf + 8);
+ syn.assoc_stream_id = net_read32(nb->buf + 12);
+ syn.prio = net_read16(nb->buf + 16) & 0xe000;
+ syn.slot = net_read16(nb->buf + 16) & 0x7;
- if ((syn->stream_id % 2) == 0 || syn->stream_id == 0) {
+ /* XXX need to send protocol errors here? */
+ if ((syn.stream_id % 2) == 0 || syn.stream_id == 0) {
kore_log("client sent incorrect id for SPDY_SYN_STREAM (%d)",
- syn->stream_id);
+ syn.stream_id);
return (KORE_RESULT_ERROR);
}
- if ((s = spdy_stream_lookup(c, syn->stream_id)) != NULL) {
- kore_log("duplicate SPDY_SYN_STREAM (%d)", syn->stream_id);
+ if ((s = spdy_stream_lookup(c, syn.stream_id)) != NULL) {
+ kore_log("duplicate SPDY_SYN_STREAM (%d)", syn.stream_id);
return (KORE_RESULT_ERROR);
}
- kore_log("compressed headers are %d bytes long", ctrl->length - 10);
- zlib.avail_in = 0;
- zlib.next_in = Z_NULL;
- zlib.zalloc = Z_NULL;
- zlib.zfree = Z_NULL;
- if ((r = inflateInit(&zlib)) != Z_OK) {
- kore_log("inflateInit() failed: %d", r);
+ s = (struct spdy_stream *)kore_malloc(sizeof(*s));
+ s->prio = syn.prio;
+ s->flags = ctrl.flags;
+ s->stream_id = syn.stream_id;
+ s->header_block_len = 0;
+ s->header_block = NULL;
+
+ src = (nb->buf + SPDY_FRAME_SIZE + SPDY_SYNFRAME_SIZE);
+ kore_log("compressed headers are %d bytes long", ctrl.length - 10);
+ if (!spdy_zlib_inflate(src, (ctrl.length - SPDY_SYNFRAME_SIZE),
+ &(s->header_block), &(s->header_block_len))) {
+ free(s->header_block);
+ free(s);
return (KORE_RESULT_ERROR);
}
- s = (struct spdy_stream *)kore_malloc(sizeof(*s));
- s->prio = syn->prio;
- s->flags = ctrl->flags;
- s->stream_id = syn->stream_id;
- s->header_block_len = ctrl->length;
- s->header_block = (u_int8_t *)kore_malloc(ctrl->length);
-
- have = 0;
- len = ctrl->length - 10;
- do {
- if (len > SPDY_ZLIB_CHUNK) {
- zlib.avail_in = SPDY_ZLIB_CHUNK;
- len -= SPDY_ZLIB_CHUNK;
- } else {
- zlib.avail_in = len;
- len = 0;
- }
-
- if (zlib.avail_in == 0)
- break;
-
- zlib.next_in = (u_char *)(syn + sizeof(struct spdy_syn_stream));
- do {
- zlib.avail_out = SPDY_ZLIB_CHUNK;
- zlib.next_out = inflate_buffer;
+ s->header_pairs = net_read32(s->header_block);
+ kore_log("got %d headers", s->header_pairs);
- r = inflate(&zlib, Z_SYNC_FLUSH);
- switch (r) {
- case Z_NEED_DICT:
- kore_log("I need a dict");
- break;
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- inflateEnd(&zlib);
- free(s->header_block);
- free(s);
- kore_log("inflate(): %d", r);
- return (KORE_RESULT_ERROR);
- }
+#define GET_HEADER(n, r) \
+ if (!spdy_stream_get_header(s, n, r)) { \
+ free(s->header_block); \
+ free(s); \
+ kore_log("no such header: %s", n); \
+ return (KORE_RESULT_ERROR); \
+ }
- have += SPDY_ZLIB_CHUNK - zlib.avail_out;
- if (have > s->header_block_len) {
- s->header_block_len += ctrl->length;
- s->header_block =
- (u_int8_t *)kore_realloc(s->header_block,
- s->header_block_len);
- }
+ GET_HEADER(":path", &path);
+ GET_HEADER(":method", &method);
+ GET_HEADER(":host", &host);
+ if (!http_new_request(c, s, host, method, path)) {
+ free(s->header_block);
+ free(s);
+ return (KORE_RESULT_ERROR);
+ }
- memcpy((s->header_block + have), inflate_buffer,
- SPDY_ZLIB_CHUNK - zlib.avail_out);
- } while (zlib.avail_out == 0);
- } while (r != Z_STREAM_END);
+ free(path);
+ free(method);
+ free(host);
- inflateEnd(&zlib);
TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list);
-
kore_log("SPDY_SYN_STREAM: %d:%d:%d", s->stream_id, s->flags, s->prio);
+
return (KORE_RESULT_OK);
}
@@ -210,3 +195,160 @@ spdy_ctrl_frame_settings(struct netbuf *nb)
return (r);
}
+
+static int
+spdy_stream_get_header(struct spdy_stream *s, char *header, char **out)
+{
+ u_int8_t *p;
+ char *cmp;
+ u_int32_t i, nlen, vlen;
+
+ p = s->header_block + 4;
+ for (i = 0; i < s->header_pairs; i++) {
+ nlen = net_read32(p);
+ vlen = net_read32(p + nlen + 4);
+
+ 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(u_int8_t *src, size_t len, u_int8_t **dst, u_int32_t *olen)
+{
+ z_stream zlib;
+ size_t have;
+ int r, ret;
+ u_char inflate_buffer[SPDY_ZLIB_CHUNK];
+
+ kore_log("spdy_zlib_inflate(%p, %d)", src, len);
+
+ zlib.avail_in = 0;
+ zlib.next_in = Z_NULL;
+ zlib.zalloc = Z_NULL;
+ zlib.zfree = Z_NULL;
+ if ((r = inflateInit(&zlib)) != Z_OK) {
+ kore_log("inflateInit() failed: %d", r);
+ return (KORE_RESULT_ERROR);
+ }
+
+ *olen = 0;
+ *dst = NULL;
+
+ ret = -1;
+ zlib.avail_in = len;
+ zlib.next_in = src;
+ while (ret == -1) {
+ zlib.avail_out = SPDY_ZLIB_CHUNK;
+ zlib.next_out = inflate_buffer;
+
+ r = inflate(&zlib, Z_SYNC_FLUSH);
+ switch (r) {
+ case Z_NEED_DICT:
+ r = inflateSetDictionary(&zlib, SPDY_dictionary_txt,
+ SPDY_ZLIB_DICT_SIZE);
+ if (r != Z_OK) {
+ inflateEnd(&zlib);
+ kore_log("inflateSetDictionary(): %d", r);
+ return (KORE_RESULT_ERROR);
+ }
+
+ continue;
+ case Z_BUF_ERROR:
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ ret = KORE_RESULT_ERROR;
+ kore_log("inflate(): %d", r);
+ break;
+ case Z_OK:
+ have = SPDY_ZLIB_CHUNK - zlib.avail_out;
+ *olen += have;
+ *dst = (u_int8_t *)kore_realloc(*dst, *olen);
+ memcpy((*dst) + (*olen - have), inflate_buffer, have);
+
+ if (zlib.avail_in != 0 || zlib.avail_out == 0)
+ break;
+ /* FALLTHROUGH */
+ case Z_STREAM_END:
+ ret = KORE_RESULT_OK;
+ break;
+ }
+ }
+
+ inflateEnd(&zlib);
+ return (ret);
+}
+
+static int
+spdy_zlib_deflate(u_int8_t *src, size_t len, u_int8_t **dst, u_int32_t *olen)
+{
+ z_stream zlib;
+ size_t have;
+ int r, ret;
+ u_char deflate_buffer[SPDY_ZLIB_CHUNK];
+
+ kore_log("spdy_zlib_deflate(%p, %d)", src, len);
+
+ zlib.avail_in = 0;
+ zlib.next_in = Z_NULL;
+ zlib.zalloc = Z_NULL;
+ zlib.zfree = Z_NULL;
+ if ((r = deflateInit(&zlib, -1)) != Z_OK) {
+ kore_log("deflateInit() failed: %d", r);
+ return (KORE_RESULT_ERROR);
+ }
+
+ r = deflateSetDictionary(&zlib, SPDY_dictionary_txt,
+ SPDY_ZLIB_DICT_SIZE);
+ if (r != Z_OK) {
+ deflateEnd(&zlib);
+ kore_log("delfateSetDictionary(): %d", r);
+ return (KORE_RESULT_ERROR);
+ }
+
+ *olen = 0;
+ *dst = NULL;
+
+ ret = -1;
+ zlib.avail_in = len;
+ zlib.next_in = src;
+ while (ret == -1) {
+ zlib.avail_out = SPDY_ZLIB_CHUNK;
+ zlib.next_out = deflate_buffer;
+
+ r = deflate(&zlib, Z_SYNC_FLUSH);
+ switch (r) {
+ case Z_BUF_ERROR:
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ ret = KORE_RESULT_ERROR;
+ kore_log("deflate(): %d", r);
+ break;
+ case Z_OK:
+ have = SPDY_ZLIB_CHUNK - zlib.avail_out;
+ *olen += have;
+ *dst = (u_int8_t *)kore_realloc(*dst, *olen);
+ memcpy((*dst) + (*olen - have), deflate_buffer, have);
+
+ if (zlib.avail_in == 0 && zlib.avail_out != 0)
+ ret = KORE_RESULT_OK;
+ break;
+ }
+ }
+
+ deflateEnd(&zlib);
+ return (ret);
+}
diff --git a/src/utils.c b/src/utils.c
@@ -93,6 +93,20 @@ kore_log_internal(char *file, int line, const char *fmt, ...)
}
void
+kore_strlcpy(char *dst, const char *src, size_t len)
+{
+ char *d = dst;
+ const char *s = src;
+
+ while ((*d++ = *s++) != '\0') {
+ if (d == (dst + len - 1)) {
+ *d = '\0';
+ break;
+ }
+ }
+}
+
+void
fatal(const char *fmt, ...)
{
va_list args;
diff --git a/src/zlib_dict.c b/src/zlib_dict.c
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+const unsigned char SPDY_dictionary_txt[] = {
+ 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // - - - - o p t i
+ 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // o n s - - - - h
+ 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // e a d - - - - p
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // o s t - - - - p
+ 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // u t - - - - d e
+ 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // l e t e - - - -
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // t r a c e - - -
+ 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // - a c c e p t -
+ 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
+ 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t - c h a r s e
+ 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t - - - - a c c
+ 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e p t - e n c o
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // d i n g - - - -
+ 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // a c c e p t - l
+ 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // a n g u a g e -
+ 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
+ 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t - r a n g e s
+ 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // - - - - a g e -
+ 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // - - - a l l o w
+ 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // - - - - a u t h
+ 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // o r i z a t i o
+ 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n - - - - c a c
+ 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // h e - c o n t r
+ 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // o l - - - - c o
+ 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // n n e c t i o n
+ 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // e n t - b a s e
+ 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e n t - e n c o
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // d i n g - - - -
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // c o n t e n t -
+ 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // l a n g u a g e
+ 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // e n t - l e n g
+ 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // t h - - - - c o
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // n t e n t - l o
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // c a t i o n - -
+ 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
+ 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t - m d 5 - - -
+ 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // - c o n t e n t
+ 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // - r a n g e - -
+ 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
+ 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t - t y p e - -
+ 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // - - d a t e - -
+ 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // - - e t a g - -
+ 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // - - e x p e c t
+ 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // - - - - e x p i
+ 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // r e s - - - - f
+ 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // r o m - - - - h
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // o s t - - - - i
+ 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f - m a t c h -
+ 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // - - - i f - m o
+ 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // d i f i e d - s
+ 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // i n c e - - - -
+ 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // i f - n o n e -
+ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // m a t c h - - -
+ 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // - i f - r a n g
+ 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e - - - - i f -
+ 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // u n m o d i f i
+ 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // e d - s i n c e
+ 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // - - - - l a s t
+ 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // - m o d i f i e
+ 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d - - - - l o c
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // a t i o n - - -
+ 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // - m a x - f o r
+ 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // w a r d s - - -
+ 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // - p r a g m a -
+ 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // - - - p r o x y
+ 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // - a u t h e n t
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // i c a t e - - -
+ 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // - p r o x y - a
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // u t h o r i z a
+ 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // t i o n - - - -
+ 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // r a n g e - - -
+ 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // - r e f e r e r
+ 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // - - - - r e t r
+ 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y - a f t e r -
+ 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // - - - s e r v e
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r - - - - t e -
+ 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // - - - t r a i l
+ 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // e r - - - - t r
+ 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // a n s f e r - e
+ 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // n c o d i n g -
+ 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // - - - u p g r a
+ 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // d e - - - - u s
+ 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // e r - a g e n t
+ 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // - - - - v a r y
+ 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // - - - - v i a -
+ 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // - - - w a r n i
+ 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // n g - - - - w w
+ 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w - a u t h e n
+ 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // t i c a t e - -
+ 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // - - m e t h o d
+ 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // - - - - g e t -
+ 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // - - - s t a t u
+ 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s - - - - 2 0 0
+ 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // - O K - - - - v
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // e r s i o n - -
+ 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // - - H T T P - 1
+ 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // - 1 - - - - u r
+ 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l - - - - p u b
+ 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // l i c - - - - s
+ 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // e t - c o o k i
+ 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e - - - - k e e
+ 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p - a l i v e -
+ 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // - - - o r i g i
+ 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n 1 0 0 1 0 1 2
+ 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 0 1 2 0 2 2 0 5
+ 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 2 0 6 3 0 0 3 0
+ 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 2 3 0 3 3 0 4 3
+ 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 0 5 3 0 6 3 0 7
+ 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 4 0 2 4 0 5 4 0
+ 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 6 4 0 7 4 0 8 4
+ 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 0 9 4 1 0 4 1 1
+ 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 4 1 2 4 1 3 4 1
+ 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 4 4 1 5 4 1 6 4
+ 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 1 7 5 0 2 5 0 4
+ 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 5 0 5 2 0 3 - N
+ 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // o n - A u t h o
+ 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // r i t a t i v e
+ 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // - I n f o r m a
+ 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // t i o n 2 0 4 -
+ 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // N o - C o n t e
+ 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // n t 3 0 1 - M o
+ 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // v e d - P e r m
+ 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // a n e n t l y 4
+ 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 0 0 - B a d - R
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // e q u e s t 4 0
+ 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1 - U n a u t h
+ 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // o r i z e d 4 0
+ 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3 - F o r b i d
+ 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // d e n 4 0 4 - N
+ 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // o t - F o u n d
+ 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 5 0 0 - I n t e
+ 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // r n a l - S e r
+ 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // v e r - E r r o
+ 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r 5 0 1 - N o t
+ 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // - I m p l e m e
+ 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // n t e d 5 0 3 -
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // S e r v i c e -
+ 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // U n a v a i l a
+ 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // b l e J a n - F
+ 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // e b - M a r - A
+ 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // p r - M a y - J
+ 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // u n - J u l - A
+ 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // u g - S e p t -
+ 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // O c t - N o v -
+ 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // D e c - 0 0 - 0
+ 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0 - 0 0 - M o n
+ 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // - - T u e - - W
+ 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // e d - - T h u -
+ 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // - F r i - - S a
+ 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t - - S u n - -
+ 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // G M T c h u n k
+ 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // e d - t e x t -
+ 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // h t m l - i m a
+ 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // g e - p n g - i
+ 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // m a g e - j p g
+ 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // - i m a g e - g
+ 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // i f - a p p l i
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
+ 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // m l - a p p l i
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
+ 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // h t m l - x m l
+ 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // - t e x t - p l
+ 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // a i n - t e x t
+ 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // - j a v a s c r
+ 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // i p t - p u b l
+ 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // i c p r i v a t
+ 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // e m a x - a g e
+ 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // - g z i p - d e
+ 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // f l a t e - s d
+ 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // c h c h a r s e
+ 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t - u t f - 8 c
+ 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // h a r s e t - i
+ 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // s o - 8 8 5 9 -
+ 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1 - u t f - - -
+ 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // - e n q - 0 -
+};