mirror of
https://github.com/moparisthebest/spdylay
synced 2024-12-22 07:38:52 -05:00
Added header deflate/inflate using zlib. Added send/recv frame.
This commit is contained in:
parent
1330d74b73
commit
9c8270436f
@ -40,8 +40,13 @@ AM_PROG_LIBTOOL
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
PKG_PROG_PKG_CONFIG([0.20])
|
||||
|
||||
# Checks for libraries.
|
||||
PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3])
|
||||
LIBS=$ZLIB_LIBS $LIBS
|
||||
CFLAGS=$CFLAGS $ZLIB_CFLAGS
|
||||
|
||||
AC_CHECK_LIB([cunit], [CU_initialize_registry],
|
||||
[have_cunit=yes], [have_cunit=no])
|
||||
AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ])
|
||||
|
@ -32,10 +32,12 @@ DISTCLEANFILES = $(pkgconfig_DATA)
|
||||
lib_LTLIBRARIES = libspdylay.la
|
||||
|
||||
OBJECTS = spdylay_pq.c spdylay_map.c spdylay_queue.c \
|
||||
spdylay_buffer.c
|
||||
spdylay_buffer.c spdylay_frame.c spdylay_zlib.c \
|
||||
spdylay_session.c spdylay_helper.c spdylay_stream.c
|
||||
|
||||
HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h spdylay_queue.h \
|
||||
spdylay_buffer.h
|
||||
spdylay_buffer.h spdylay_frame.h spdylay_zlib.h \
|
||||
spdylay_session.h spdylay_helper.h spdylay_stream.h spdylay_int.h
|
||||
|
||||
libspdylay_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||
libspdylay_la_LDFLAGS = -no-undefined \
|
||||
|
@ -32,10 +32,49 @@ extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum spdylay_error {
|
||||
typedef enum {
|
||||
SPDYLAY_ERR_NOMEM = -500,
|
||||
SPDYLAY_ERR_INVALID_ARGUMENT = -501
|
||||
};
|
||||
SPDYLAY_ERR_INVALID_ARGUMENT = -501,
|
||||
SPDYLAY_ERR_ZLIB = -502,
|
||||
SPDYLAY_ERR_ZLIB_BUF = -503,
|
||||
SPDYLAY_ERR_WOULDBLOCK = -504,
|
||||
SPDYLAY_ERR_PROTO = -505,
|
||||
SPDYLAY_ERR_CALLBACK_FAILURE = -505,
|
||||
} spdylay_error;
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_MSG_MORE
|
||||
} spdylay_io_flag;
|
||||
|
||||
typedef ssize_t (*spdylay_send_callback)
|
||||
(const uint8_t *data, size_t length, int flags, void *user_data);
|
||||
|
||||
typedef ssize_t (*spdylay_recv_callback)
|
||||
(uint8_t *buf, size_t length, int flags, void *user_data);
|
||||
|
||||
typedef struct {
|
||||
spdylay_send_callback send_callback;
|
||||
spdylay_recv_callback recv_callback;
|
||||
} spdylay_session_callbacks;
|
||||
|
||||
struct spdylay_session;
|
||||
typedef struct spdylay_session spdylay_session;
|
||||
|
||||
int spdylay_session_client_init(spdylay_session **session_ptr,
|
||||
const spdylay_session_callbacks *callbacks,
|
||||
void *user_data);
|
||||
|
||||
void spdylay_session_free(struct spdylay_session *session);
|
||||
|
||||
int spdylay_session_send(spdylay_session *session);
|
||||
|
||||
int spdylay_session_recv(spdylay_session *session);
|
||||
|
||||
int spdylay_session_want_read(spdylay_session *session);
|
||||
|
||||
int spdylay_session_want_write(spdylay_session *session);
|
||||
|
||||
int spdylay_req_submit(spdylay_session *session, const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -122,3 +122,18 @@ void spdylay_buffer_pop(spdylay_buffer *buffer)
|
||||
spdylay_queue_pop(&buffer->q);
|
||||
}
|
||||
}
|
||||
|
||||
size_t spdylay_buffer_capacity(spdylay_buffer *buffer)
|
||||
{
|
||||
return buffer->capacity;
|
||||
}
|
||||
|
||||
void spdylay_buffer_serialize(spdylay_buffer *buffer, uint8_t *buf)
|
||||
{
|
||||
while(spdylay_buffer_length(buffer)) {
|
||||
size_t len = spdylay_buffer_front_length(buffer);
|
||||
memcpy(buf, spdylay_buffer_front_data(buffer), len);
|
||||
buf += len;
|
||||
spdylay_buffer_pop(buffer);
|
||||
}
|
||||
}
|
||||
|
@ -75,4 +75,11 @@ uint8_t* spdylay_buffer_front_data(spdylay_buffer *buffer);
|
||||
size of poped chunk buffer. */
|
||||
void spdylay_buffer_pop(spdylay_buffer *buffer);
|
||||
|
||||
/* Returns capacity of each fixed chunk buffer */
|
||||
size_t spdylay_buffer_capacity(spdylay_buffer *buffer);
|
||||
|
||||
/* Stores the contents of buffer into buf. buf must be at least
|
||||
spdylay_buffer_length(buffer) bytes long. */
|
||||
void spdylay_buffer_serialize(spdylay_buffer *buffer, uint8_t *buf);
|
||||
|
||||
#endif /* SPDYLAY_BUFFER_H */
|
||||
|
395
lib/spdylay_frame.c
Normal file
395
lib/spdylay_frame.c
Normal file
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_frame.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "spdylay_helper.h"
|
||||
|
||||
static uint8_t spdylay_unpack_pri(const uint8_t *data)
|
||||
{
|
||||
return (data[0] >> 6) & 0x3;
|
||||
}
|
||||
|
||||
static uint8_t* spdylay_pack_str(uint8_t *buf, const char *str, size_t len)
|
||||
{
|
||||
spdylay_put_uint16be(buf, len);
|
||||
buf += 2;
|
||||
memcpy(buf, str, len);
|
||||
return buf+len;
|
||||
}
|
||||
|
||||
static void spdylay_frame_pack_ctrl_hd(uint8_t* buf, const spdylay_ctrl_hd *hd)
|
||||
{
|
||||
spdylay_put_uint16be(&buf[0], hd->version);
|
||||
buf[0] |= 1 << 7;
|
||||
spdylay_put_uint16be(&buf[2], hd->type);
|
||||
spdylay_put_uint32be(&buf[4], hd->length);
|
||||
printf("hd->length=%d\n", hd->length);
|
||||
buf[4] = hd->flags;
|
||||
printf("hd->flags=%d\n", hd->flags);
|
||||
}
|
||||
|
||||
static void spdylay_frame_unpack_ctrl_hd(spdylay_ctrl_hd *hd,
|
||||
const uint8_t* buf)
|
||||
{
|
||||
hd->version = spdylay_get_uint16(buf) & 0x7fff;
|
||||
hd->type = spdylay_get_uint16(buf+2);
|
||||
hd->flags = buf[4];
|
||||
hd->length = spdylay_get_uint32(buf+5) & 0xffffff;
|
||||
}
|
||||
|
||||
static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
||||
char **nv, size_t nv_offset,
|
||||
spdylay_zlib *deflater)
|
||||
{
|
||||
size_t nvbuflen = spdylay_frame_count_nv_space(nv);
|
||||
uint8_t *nvbuf = malloc(nvbuflen);
|
||||
size_t maxframelen = nv_offset+
|
||||
spdylay_zlib_deflate_hd_bound(deflater, nvbuflen);
|
||||
uint8_t *framebuf = malloc(maxframelen);
|
||||
ssize_t framelen;
|
||||
spdylay_frame_pack_nv(nvbuf, nv);
|
||||
framelen = spdylay_zlib_deflate_hd(deflater, framebuf+18, maxframelen-18,
|
||||
nvbuf, nvbuflen);
|
||||
free(nvbuf);
|
||||
if(framelen < 0) {
|
||||
free(framebuf);
|
||||
return framelen;
|
||||
}
|
||||
framelen += 18;
|
||||
*buf_ptr = framebuf;
|
||||
return framelen;
|
||||
}
|
||||
|
||||
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
int r = 0;
|
||||
uint16_t n;
|
||||
size_t off;
|
||||
size_t nv_max = 126;
|
||||
int i, j, k;
|
||||
char *name = NULL, *val = NULL;
|
||||
if(inlen < 2) {
|
||||
return SPDYLAY_ERR_PROTO;
|
||||
}
|
||||
memcpy(&n, in, sizeof(uint16_t));
|
||||
n = ntohs(n);
|
||||
if(n > nv_max) {
|
||||
nv_max = n;
|
||||
}
|
||||
*nv_ptr = malloc(nv_max*sizeof(char*)+1);
|
||||
if(*nv_ptr == NULL) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
off = 2;
|
||||
for(i = 0, j = 0; i < n; ++i) {
|
||||
uint16_t nlen, vlen;
|
||||
size_t last, len;
|
||||
if(off+2 > inlen) {
|
||||
r = SPDYLAY_ERR_PROTO;
|
||||
break;
|
||||
}
|
||||
/* For NULL delimited values, they are splitted with each name */
|
||||
memcpy(&nlen, &in[off], sizeof(uint16_t));
|
||||
nlen = ntohs(nlen);
|
||||
off += 2;
|
||||
if(off+nlen > inlen || nlen == 0) {
|
||||
r = SPDYLAY_ERR_PROTO;
|
||||
break;
|
||||
}
|
||||
name = malloc(nlen+1);
|
||||
if(name == NULL) {
|
||||
r = SPDYLAY_ERR_NOMEM;
|
||||
break;
|
||||
}
|
||||
memcpy(name, &in[off], nlen);
|
||||
name[nlen] = '\0';
|
||||
off += nlen;
|
||||
if(off+2 > inlen) {
|
||||
r = SPDYLAY_ERR_PROTO;
|
||||
break;
|
||||
}
|
||||
memcpy(&vlen, &in[off], sizeof(uint16_t));
|
||||
vlen = ntohs(vlen);
|
||||
off += 2;
|
||||
if(off+vlen > inlen) {
|
||||
r = SPDYLAY_ERR_PROTO;
|
||||
break;
|
||||
}
|
||||
for(k = 0, last = off; k < vlen; ++k) {
|
||||
size_t len;
|
||||
if(in[off+k] == '\0') {
|
||||
len = off+k-last;
|
||||
if(len == 0) {
|
||||
r = SPDYLAY_ERR_PROTO;
|
||||
break;
|
||||
}
|
||||
val = malloc(len+1);
|
||||
if(val == NULL) {
|
||||
r = SPDYLAY_ERR_NOMEM;
|
||||
break;
|
||||
}
|
||||
memcpy(val, &in[last], len);
|
||||
val[len] = '\0';
|
||||
if(j >= nv_max) {
|
||||
char **nnv;
|
||||
nv_max *= 2;
|
||||
nnv = realloc(*nv_ptr, nv_max+1);
|
||||
if(nnv == NULL) {
|
||||
r = SPDYLAY_ERR_NOMEM;
|
||||
break;
|
||||
} else {
|
||||
*nv_ptr = nnv;
|
||||
}
|
||||
}
|
||||
(*nv_ptr)[j] = strdup(name);
|
||||
(*nv_ptr)[j+1] = val;
|
||||
val = NULL;
|
||||
last = off+k+1;
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
if(r != 0) {
|
||||
break;
|
||||
}
|
||||
len = vlen-(last-off);
|
||||
if(len == 0) {
|
||||
r = SPDYLAY_ERR_PROTO;
|
||||
break;
|
||||
}
|
||||
val = malloc(len+1);
|
||||
if(val == NULL) {
|
||||
free(name);
|
||||
r = SPDYLAY_ERR_NOMEM;
|
||||
break;
|
||||
}
|
||||
memcpy(val, &in[last], len);
|
||||
val[len] = '\0';
|
||||
if(j >= nv_max) {
|
||||
char **nnv;
|
||||
nv_max *= 2;
|
||||
nnv = realloc(*nv_ptr, nv_max+1);
|
||||
if(nnv == NULL) {
|
||||
r = SPDYLAY_ERR_NOMEM;
|
||||
break;
|
||||
} else {
|
||||
*nv_ptr = nnv;
|
||||
}
|
||||
}
|
||||
(*nv_ptr)[j] = name;
|
||||
(*nv_ptr)[j+1] = val;
|
||||
name = val = NULL;
|
||||
j += 2;
|
||||
off += vlen;
|
||||
}
|
||||
free(name);
|
||||
free(val);
|
||||
if(r == 0) {
|
||||
(*nv_ptr)[j] = NULL;
|
||||
} else {
|
||||
for(i = 0; i < j; ++i) {
|
||||
free((*nv_ptr)[i]);
|
||||
}
|
||||
free(*nv_ptr);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int spdylay_frame_alloc_unpack_nv(char ***nv_ptr,
|
||||
const uint8_t *in, size_t inlen,
|
||||
spdylay_zlib *inflater)
|
||||
{
|
||||
ssize_t r;
|
||||
spdylay_buffer outbuffer;
|
||||
spdylay_buffer_init(&outbuffer, 4096);
|
||||
r = spdylay_zlib_inflate_hd(inflater, &outbuffer, in, inlen);
|
||||
if(r < 0) {
|
||||
spdylay_buffer_free(&outbuffer);
|
||||
return r;
|
||||
} else {
|
||||
uint8_t *buf = malloc(r);
|
||||
if(buf == NULL) {
|
||||
spdylay_buffer_free(&outbuffer);
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
spdylay_buffer_serialize(&outbuffer, buf);
|
||||
spdylay_buffer_free(&outbuffer);
|
||||
r = spdylay_frame_unpack_nv(nv_ptr, buf, r);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
size_t spdylay_frame_count_nv_space(char **nv)
|
||||
{
|
||||
size_t sum = 2;
|
||||
int i;
|
||||
const char *prev = "";
|
||||
size_t prevlen = 0;
|
||||
for(i = 0; nv[i]; i += 2) {
|
||||
const char *key = nv[i];
|
||||
const char *val = nv[i+1];
|
||||
size_t keylen = strlen(key);
|
||||
size_t vallen = strlen(val);
|
||||
if(prevlen == keylen && memcmp(prev, key, keylen) == 0) {
|
||||
/* Join previous value, with NULL character */
|
||||
sum += vallen+1;
|
||||
} else {
|
||||
prev = key;
|
||||
/* SPDY NV header does not include terminating NULL byte */
|
||||
sum += keylen+vallen+4;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv)
|
||||
{
|
||||
int i;
|
||||
uint8_t *bufp = buf+2;
|
||||
uint16_t num_nv = 0;
|
||||
/* TODO Join values with same keys, using '\0' as a delimiter */
|
||||
const char *prev = "";
|
||||
uint8_t *prev_vallen_buf = NULL;
|
||||
uint16_t prev_vallen = 0;
|
||||
for(i = 0; nv[i]; i += 2) {
|
||||
const char *key = nv[i];
|
||||
const char *val = nv[i+1];
|
||||
size_t keylen = strlen(key);
|
||||
size_t vallen = strlen(val);
|
||||
if(strcmp(prev, key) == 0) {
|
||||
prev_vallen += vallen+1;
|
||||
spdylay_put_uint16be(prev_vallen_buf, prev_vallen);
|
||||
*bufp = '\0';
|
||||
++bufp;
|
||||
memcpy(bufp, val, vallen);
|
||||
bufp += vallen;
|
||||
} else {
|
||||
++num_nv;
|
||||
bufp = spdylay_pack_str(bufp, key, keylen);
|
||||
prev = key;
|
||||
prev_vallen_buf = bufp;
|
||||
prev_vallen = vallen;
|
||||
bufp = spdylay_pack_str(bufp, val, vallen);
|
||||
}
|
||||
}
|
||||
spdylay_put_uint16be(buf, num_nv);
|
||||
return bufp-buf;
|
||||
}
|
||||
|
||||
int spdylay_frame_is_ctrl_frame(uint8_t first_byte)
|
||||
{
|
||||
return first_byte & 0x80;
|
||||
}
|
||||
|
||||
void spdylay_frame_nv_free(char **nv)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; nv[i]; i += 2) {
|
||||
free(nv[i]);
|
||||
free(nv[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags,
|
||||
int32_t stream_id, int32_t assoc_stream_id,
|
||||
uint8_t pri, char **nv)
|
||||
{
|
||||
memset(frame, 0, sizeof(spdylay_syn_stream));
|
||||
frame->hd.version = 2;
|
||||
frame->hd.type = SPDYLAY_SYN_STREAM;
|
||||
frame->hd.flags = flags;
|
||||
frame->stream_id = stream_id;
|
||||
frame->assoc_stream_id = assoc_stream_id;
|
||||
frame->pri = pri;
|
||||
frame->nv = nv;
|
||||
}
|
||||
|
||||
void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame)
|
||||
{
|
||||
spdylay_frame_nv_free(frame->nv);
|
||||
free(frame->nv);
|
||||
}
|
||||
|
||||
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame)
|
||||
{
|
||||
spdylay_frame_nv_free(frame->nv);
|
||||
free(frame->nv);
|
||||
}
|
||||
|
||||
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
|
||||
spdylay_syn_stream *frame,
|
||||
spdylay_zlib *deflater)
|
||||
{
|
||||
uint8_t *framebuf = NULL;
|
||||
size_t framelen;
|
||||
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 18, deflater);
|
||||
if(framelen < 0) {
|
||||
return framelen;
|
||||
}
|
||||
frame->hd.length = framelen-8;
|
||||
memset(framebuf, 0, 18);
|
||||
/* pack ctrl header after length is determined */
|
||||
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
|
||||
spdylay_put_uint32be(&framebuf[8], frame->stream_id);
|
||||
spdylay_put_uint32be(&framebuf[12], frame->assoc_stream_id);
|
||||
framebuf[16] = (frame->pri << 6);
|
||||
|
||||
*buf_ptr = framebuf;
|
||||
return framelen;
|
||||
}
|
||||
|
||||
int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
|
||||
const uint8_t *head, size_t headlen,
|
||||
const uint8_t *payload, size_t payloadlen,
|
||||
spdylay_zlib *inflater)
|
||||
{
|
||||
int r;
|
||||
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||
frame->stream_id = spdylay_get_uint32(payload);
|
||||
frame->assoc_stream_id = spdylay_get_uint32(payload+4);
|
||||
frame->pri = spdylay_unpack_pri(payload+8);
|
||||
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+10, payloadlen-10,
|
||||
inflater);
|
||||
return r;
|
||||
}
|
||||
|
||||
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
||||
const uint8_t *head, size_t headlen,
|
||||
const uint8_t *payload, size_t payloadlen,
|
||||
spdylay_zlib *inflater)
|
||||
{
|
||||
int r;
|
||||
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||
frame->stream_id = spdylay_get_uint32(payload);
|
||||
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+6, payloadlen-6,
|
||||
inflater);
|
||||
return r;
|
||||
}
|
||||
|
154
lib/spdylay_frame.h
Normal file
154
lib/spdylay_frame.h
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_FRAME_H
|
||||
#define SPDYLAY_FRAME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "spdylay_zlib.h"
|
||||
#include "spdylay_buffer.h"
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_SYN_STREAM = 1,
|
||||
SPDYLAY_SYN_REPLY = 2,
|
||||
SPDYLAY_RST_STREAM = 3,
|
||||
SPDYLAY_SETTINGS = 4,
|
||||
SPDYLAY_NOOP = 5,
|
||||
SPDYLAY_PING = 6,
|
||||
SPDYLAY_GOAWAY = 7,
|
||||
} spdylay_frame_type;
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_FLAG_FIN = 1
|
||||
} spdylay_flag;
|
||||
|
||||
typedef struct {
|
||||
uint16_t version;
|
||||
uint16_t type;
|
||||
uint8_t flags;
|
||||
int32_t length;
|
||||
} spdylay_ctrl_hd;
|
||||
|
||||
typedef struct {
|
||||
spdylay_ctrl_hd hd;
|
||||
int32_t stream_id;
|
||||
int32_t assoc_stream_id;
|
||||
uint8_t pri;
|
||||
char **nv;
|
||||
} spdylay_syn_stream;
|
||||
|
||||
typedef struct {
|
||||
spdylay_ctrl_hd hd;
|
||||
int32_t stream_id;
|
||||
char **nv;
|
||||
} spdylay_syn_reply;
|
||||
|
||||
typedef union {
|
||||
spdylay_syn_stream syn_stream;
|
||||
} spdylay_frame;
|
||||
|
||||
/*
|
||||
* Packs SYN_STREAM frame |frame| in wire frame format and store it in
|
||||
* |*buf_ptr|. This function allocates enough memory to store given
|
||||
* frame in |*buf_ptr|. This function returns the size of packed
|
||||
* frame if it succeeds, or returns negative error
|
||||
* code. frame->hd.length is assigned after length is determined
|
||||
* during packing process.
|
||||
*/
|
||||
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
|
||||
spdylay_syn_stream *frame,
|
||||
spdylay_zlib *deflater);
|
||||
|
||||
/*
|
||||
* Unpacks SYN_STREAM frame byte sequence into |frame|. Header is
|
||||
* given in head and headlen. In spdy/2 spec, headlen is 8
|
||||
* bytes. |payload| is the data after length field of the header.
|
||||
* This function returns 0 if it succeeds or negative error code.
|
||||
*/
|
||||
int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
|
||||
const uint8_t *head, size_t headlen,
|
||||
const uint8_t *payload, size_t payloadlen,
|
||||
spdylay_zlib *inflater);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Unpacks SYN_REPLY frame byte sequence into |frame|. This function
|
||||
* returns 0 if it succeeds or negative error code.
|
||||
*/
|
||||
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
||||
const uint8_t *head, size_t headlen,
|
||||
const uint8_t *payload, size_t payloadlen,
|
||||
spdylay_zlib *inflater);
|
||||
|
||||
/*
|
||||
* Returns number of bytes to pack name/value pairs |nv|. This
|
||||
* function expects |nv| is sorted in ascending order of key. This
|
||||
* function can handles duplicate keys and concatenation of thier
|
||||
* values with '\0'.
|
||||
*/
|
||||
size_t spdylay_frame_count_nv_space(char **nv);
|
||||
|
||||
/*
|
||||
* Packs name/value pairs in |nv| in |buf|. |buf| must have at least
|
||||
* spdylay_frame_count_nv_space(nv) bytes.
|
||||
*/
|
||||
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv);
|
||||
|
||||
/*
|
||||
* Unpacks name/value pairs in wire format |in| with length |inlen|
|
||||
* and stores them in |*nv_ptr|. Thif function allocates enough
|
||||
* memory to store name/value pairs in |*nv_ptr|. This function
|
||||
* returns 0 if it succeeds, or negative error code.
|
||||
*/
|
||||
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen);
|
||||
|
||||
/*
|
||||
* Initializes SYN_STREAM frame |frame| with given values. |frame|
|
||||
* takes ownership of |nv|, so caller must not free it. If stream_id
|
||||
* is not assigned yet, it must be 0.
|
||||
*/
|
||||
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags,
|
||||
int32_t stream_id, int32_t assoc_stream_id,
|
||||
uint8_t pri, char **nv);
|
||||
|
||||
void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame);
|
||||
|
||||
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame);
|
||||
|
||||
/*
|
||||
* Returns 1 if the first byte of this frame indicates it is a control
|
||||
* frame.
|
||||
*/
|
||||
int spdylay_frame_is_ctrl_frame(uint8_t first_byte);
|
||||
|
||||
/*
|
||||
* Deallocates memory of key/value pairs in |nv|.
|
||||
*/
|
||||
void spdylay_frame_nv_free(char **nv);
|
||||
|
||||
#endif /* SPDYLAY_FRAME_H */
|
54
lib/spdylay_helper.c
Normal file
54
lib/spdylay_helper.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_helper.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
void spdylay_put_uint16be(uint8_t *buf, uint16_t n)
|
||||
{
|
||||
uint16_t x = htons(n);
|
||||
memcpy(buf, &x, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void spdylay_put_uint32be(uint8_t *buf, uint32_t n)
|
||||
{
|
||||
uint32_t x = htonl(n);
|
||||
memcpy(buf, &x, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint16_t spdylay_get_uint16(const uint8_t *data)
|
||||
{
|
||||
uint16_t n;
|
||||
memcpy(&n, data, sizeof(uint16_t));
|
||||
return ntohs(n);
|
||||
}
|
||||
|
||||
uint32_t spdylay_get_uint32(const uint8_t *data)
|
||||
{
|
||||
uint32_t n;
|
||||
memcpy(&n, data, sizeof(uint32_t));
|
||||
return ntohl(n);
|
||||
}
|
58
lib/spdylay_helper.h
Normal file
58
lib/spdylay_helper.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_HELPER_H
|
||||
#define SPDYLAY_HELPER_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <spdylay/spdylay.h>
|
||||
|
||||
/*
|
||||
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
||||
* network byte order.
|
||||
*/
|
||||
void spdylay_put_uint16be(uint8_t *buf, uint16_t n);
|
||||
|
||||
/*
|
||||
* Copies 4 byte unsigned integer |n| in host byte order to |buf| in
|
||||
* network byte order.
|
||||
*/
|
||||
void spdylay_put_uint32be(uint8_t *buf, uint32_t n);
|
||||
|
||||
/*
|
||||
* Retrieves 2 byte unsigned integer stored in |data| in network byte
|
||||
* order and returns it in host byte order.
|
||||
*/
|
||||
uint16_t spdylay_get_uint16(const uint8_t *data);
|
||||
|
||||
/*
|
||||
* Retrieves 4 byte unsigned integer stored in |data| in network byte
|
||||
* order and returns it in host byte order.
|
||||
*/
|
||||
uint32_t spdylay_get_uint32(const uint8_t *data);
|
||||
|
||||
#endif /* SPDYLAY_HELPER_H */
|
@ -115,3 +115,8 @@ void spdylay_pq_pop(spdylay_pq *pq)
|
||||
bubble_down(pq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int spdylay_pq_empty(spdylay_pq *pq)
|
||||
{
|
||||
return pq->length == 0;
|
||||
}
|
||||
|
@ -51,5 +51,6 @@ void* spdylay_pq_top(spdylay_pq *pq);
|
||||
|
||||
void spdylay_pq_pop(spdylay_pq *pq);
|
||||
|
||||
int spdylay_pq_empty(spdylay_pq *pq);
|
||||
|
||||
#endif /* SPDYLAY_PQ_H */
|
||||
|
482
lib/spdylay_session.c
Normal file
482
lib/spdylay_session.c
Normal file
@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_session.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "spdylay_stream.h"
|
||||
#include "spdylay_helper.h"
|
||||
|
||||
int spdylay_outbound_item_compar(const void *lhsx, const void *rhsx)
|
||||
{
|
||||
const spdylay_outbound_item *lhs, *rhs;
|
||||
lhs = (const spdylay_outbound_item*)lhsx;
|
||||
rhs = (const spdylay_outbound_item*)rhsx;
|
||||
return lhs->pri-rhs->pri;
|
||||
}
|
||||
|
||||
int spdylay_session_client_init(spdylay_session **session_ptr,
|
||||
const spdylay_session_callbacks *callbacks,
|
||||
void *user_data)
|
||||
{
|
||||
int r;
|
||||
*session_ptr = malloc(sizeof(spdylay_session));
|
||||
if(*session_ptr == NULL) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
memset(*session_ptr, 0, sizeof(spdylay_session));
|
||||
(*session_ptr)->next_stream_id = 1;
|
||||
(*session_ptr)->last_accepted_stream_id = 0;
|
||||
|
||||
r = spdylay_zlib_deflate_hd_init(&(*session_ptr)->hd_deflater);
|
||||
if(r != 0) {
|
||||
free(*session_ptr);
|
||||
return r;
|
||||
}
|
||||
r = spdylay_zlib_inflate_hd_init(&(*session_ptr)->hd_inflater);
|
||||
if(r != 0) {
|
||||
spdylay_zlib_deflate_free(&(*session_ptr)->hd_deflater);
|
||||
free(*session_ptr);
|
||||
return r;
|
||||
}
|
||||
r = spdylay_map_init(&(*session_ptr)->streams);
|
||||
if(r != 0) {
|
||||
spdylay_zlib_inflate_free(&(*session_ptr)->hd_inflater);
|
||||
spdylay_zlib_deflate_free(&(*session_ptr)->hd_deflater);
|
||||
free(*session_ptr);
|
||||
return r;
|
||||
}
|
||||
r = spdylay_pq_init(&(*session_ptr)->ob_pq, spdylay_outbound_item_compar);
|
||||
if(r != 0) {
|
||||
spdylay_map_free(&(*session_ptr)->streams);
|
||||
spdylay_zlib_inflate_free(&(*session_ptr)->hd_inflater);
|
||||
spdylay_zlib_deflate_free(&(*session_ptr)->hd_deflater);
|
||||
free(*session_ptr);
|
||||
return r;
|
||||
}
|
||||
(*session_ptr)->callbacks = *callbacks;
|
||||
(*session_ptr)->user_data = user_data;
|
||||
|
||||
(*session_ptr)->ibuf.mark = (*session_ptr)->ibuf.buf;
|
||||
(*session_ptr)->ibuf.limit = (*session_ptr)->ibuf.buf;
|
||||
|
||||
(*session_ptr)->iframe.state = SPDYLAY_RECV_HEAD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spdylay_free_streams(key_type key, void *val)
|
||||
{
|
||||
spdylay_stream_free((spdylay_stream*)val);
|
||||
free(val);
|
||||
}
|
||||
|
||||
static void spdylay_outbound_item_free(spdylay_outbound_item *item)
|
||||
{
|
||||
if(item == NULL) {
|
||||
return;
|
||||
}
|
||||
switch(item->frame_type) {
|
||||
case SPDYLAY_SYN_STREAM:
|
||||
spdylay_frame_syn_stream_free(&item->frame->syn_stream);
|
||||
break;
|
||||
}
|
||||
free(item->frame);
|
||||
}
|
||||
|
||||
void spdylay_session_free(spdylay_session *session)
|
||||
{
|
||||
spdylay_map_each(&session->streams, spdylay_free_streams);
|
||||
spdylay_map_free(&session->streams);
|
||||
while(!spdylay_pq_empty(&session->ob_pq)) {
|
||||
spdylay_outbound_item *item = (spdylay_outbound_item*)
|
||||
spdylay_pq_top(&session->ob_pq);
|
||||
spdylay_outbound_item_free(item);
|
||||
free(item);
|
||||
spdylay_pq_pop(&session->ob_pq);
|
||||
}
|
||||
spdylay_pq_free(&session->ob_pq);
|
||||
spdylay_zlib_deflate_free(&session->hd_deflater);
|
||||
spdylay_zlib_inflate_free(&session->hd_inflater);
|
||||
free(session->iframe.buf);
|
||||
free(session);
|
||||
}
|
||||
|
||||
int spdylay_session_add_frame(spdylay_session *session,
|
||||
spdylay_frame_type frame_type,
|
||||
spdylay_frame *frame)
|
||||
{
|
||||
int r;
|
||||
spdylay_outbound_item *item;
|
||||
item = malloc(sizeof(spdylay_outbound_item));
|
||||
if(item == NULL) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
item->frame_type = frame_type;
|
||||
item->frame = frame;
|
||||
/* TODO Add pri field to SYN_REPLY, DATA frame which copies
|
||||
corresponding SYN_STREAM pri. PING frame always pri = 0
|
||||
(highest) */
|
||||
switch(frame_type) {
|
||||
case SPDYLAY_SYN_STREAM:
|
||||
item->pri = 4-frame->syn_stream.pri;
|
||||
break;
|
||||
default:
|
||||
item->pri = 4;
|
||||
};
|
||||
r = spdylay_pq_push(&session->ob_pq, item);
|
||||
if(r != 0) {
|
||||
free(item);
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id)
|
||||
{
|
||||
int r;
|
||||
spdylay_stream *stream = malloc(sizeof(spdylay_stream));
|
||||
if(stream == NULL) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
spdylay_stream_init(stream, stream_id);
|
||||
r = spdylay_map_insert(&session->streams, stream_id, stream);
|
||||
if(r != 0) {
|
||||
free(stream);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||
spdylay_outbound_item *item,
|
||||
uint8_t **framebuf_ptr)
|
||||
{
|
||||
uint8_t *framebuf;
|
||||
ssize_t framebuflen;
|
||||
int r;
|
||||
switch(item->frame_type) {
|
||||
case SPDYLAY_SYN_STREAM: {
|
||||
item->frame->syn_stream.stream_id = session->next_stream_id;
|
||||
session->next_stream_id += 2;
|
||||
framebuflen = spdylay_frame_pack_syn_stream(&framebuf,
|
||||
&item->frame->syn_stream,
|
||||
&session->hd_deflater);
|
||||
if(framebuflen < 0) {
|
||||
return framebuflen;
|
||||
}
|
||||
printf("packed %d bytes\n", framebuflen);
|
||||
r = spdylay_session_open_stream(session, item->frame->syn_stream.stream_id);
|
||||
if(r != 0) {
|
||||
free(framebuf);
|
||||
return r;
|
||||
}
|
||||
*framebuf_ptr = framebuf;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
framebuflen = SPDYLAY_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
return framebuflen;
|
||||
}
|
||||
|
||||
static void spdylay_active_outbound_item_reset
|
||||
(spdylay_active_outbound_item *aob)
|
||||
{
|
||||
spdylay_outbound_item_free(aob->item);
|
||||
free(aob->item);
|
||||
free(aob->framebuf);
|
||||
memset(aob, 0, sizeof(spdylay_active_outbound_item));
|
||||
}
|
||||
|
||||
int spdylay_session_send(spdylay_session *session)
|
||||
{
|
||||
printf("session_send\n");
|
||||
while(session->aob.item || !spdylay_pq_empty(&session->ob_pq)) {
|
||||
const uint8_t *data;
|
||||
size_t datalen;
|
||||
ssize_t sentlen;
|
||||
if(session->aob.item == NULL) {
|
||||
spdylay_outbound_item *item = spdylay_pq_top(&session->ob_pq);
|
||||
uint8_t *framebuf;
|
||||
ssize_t framebuflen;
|
||||
spdylay_pq_pop(&session->ob_pq);
|
||||
/* TODO Get or validate stream id here */
|
||||
framebuflen = spdylay_session_prep_frame(session, item, &framebuf);
|
||||
if(framebuflen < 0) {
|
||||
/* TODO Call error callback? */
|
||||
spdylay_outbound_item_free(item);
|
||||
free(item);
|
||||
continue;;
|
||||
}
|
||||
session->aob.item = item;
|
||||
session->aob.framebuf = framebuf;
|
||||
session->aob.framebuflen = framebuflen;
|
||||
}
|
||||
data = session->aob.framebuf + session->aob.framebufoff;
|
||||
datalen = session->aob.framebuflen - session->aob.framebufoff;
|
||||
sentlen = session->callbacks.send_callback(data, datalen, 0,
|
||||
session->user_data);
|
||||
if(sentlen < 0) {
|
||||
if(sentlen == SPDYLAY_ERR_WOULDBLOCK) {
|
||||
return 0;
|
||||
} else {
|
||||
return sentlen;
|
||||
}
|
||||
} else {
|
||||
printf("sent %d bytes\n", sentlen);
|
||||
session->aob.framebufoff += sentlen;
|
||||
if(session->aob.framebufoff == session->aob.framebuflen) {
|
||||
/* Frame has completely sent */
|
||||
spdylay_active_outbound_item_reset(&session->aob);
|
||||
/* TODO If frame is data frame, we need to sent all chunk of
|
||||
data.*/
|
||||
} else {
|
||||
/* partial write */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spdylay_inbound_buffer_shift(spdylay_inbound_buffer *ibuf)
|
||||
{
|
||||
ptrdiff_t len = ibuf->limit-ibuf->mark;
|
||||
memmove(ibuf->buf, ibuf->mark, len);
|
||||
ibuf->limit = ibuf->buf+len;
|
||||
ibuf->mark = ibuf->buf;
|
||||
}
|
||||
|
||||
static ssize_t spdylay_recv(spdylay_session *session)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t recv_max;
|
||||
if(session->ibuf.mark != session->ibuf.buf) {
|
||||
spdylay_inbound_buffer_shift(&session->ibuf);
|
||||
}
|
||||
recv_max = session->ibuf.buf+sizeof(session->ibuf.buf)-session->ibuf.limit;
|
||||
r = session->callbacks.recv_callback
|
||||
(session->ibuf.limit, recv_max, 0, session->user_data);
|
||||
if(r > 0) {
|
||||
if(r > recv_max) {
|
||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||
} else {
|
||||
session->ibuf.limit += r;
|
||||
}
|
||||
} else if(r < 0) {
|
||||
if(r != SPDYLAY_ERR_WOULDBLOCK) {
|
||||
r = SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t spdylay_inbound_buffer_avail(spdylay_inbound_buffer *ibuf)
|
||||
{
|
||||
return ibuf->limit-ibuf->mark;
|
||||
}
|
||||
|
||||
static void spdylay_inbound_frame_reset(spdylay_inbound_frame *iframe)
|
||||
{
|
||||
iframe->state = SPDYLAY_RECV_HEAD;
|
||||
free(iframe->buf);
|
||||
iframe->buf = NULL;
|
||||
iframe->len = iframe->off = 0;
|
||||
iframe->ign = 0;
|
||||
}
|
||||
|
||||
static void spdylay_debug_print_nv(char **nv)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; nv[i]; i += 2) {
|
||||
printf("%s: %s\n", nv[i], nv[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
int spdylay_session_process_ctrl_frame(spdylay_session *session)
|
||||
{
|
||||
int r;
|
||||
uint16_t type;
|
||||
memcpy(&type, &session->iframe.headbuf[2], sizeof(uint16_t));
|
||||
type = ntohs(type);
|
||||
switch(type) {
|
||||
case SPDYLAY_SYN_STREAM: {
|
||||
spdylay_syn_stream frame;
|
||||
printf("SYN_STREAM\n");
|
||||
r = spdylay_frame_unpack_syn_stream(&frame, session->iframe.headbuf,
|
||||
sizeof(session->iframe.headbuf),
|
||||
session->iframe.buf,
|
||||
session->iframe.len,
|
||||
&session->hd_inflater);
|
||||
if(r == 0) {
|
||||
spdylay_debug_print_nv(frame.nv);
|
||||
spdylay_frame_syn_stream_free(&frame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPDYLAY_SYN_REPLY: {
|
||||
spdylay_syn_reply frame;
|
||||
printf("SYN_REPLY\n");
|
||||
r = spdylay_frame_unpack_syn_reply(&frame, session->iframe.headbuf,
|
||||
sizeof(session->iframe.headbuf),
|
||||
session->iframe.buf,
|
||||
session->iframe.len,
|
||||
&session->hd_inflater);
|
||||
if(r == 0) {
|
||||
spdylay_debug_print_nv(frame.nv);
|
||||
spdylay_frame_syn_reply_free(&frame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* ignore */
|
||||
printf("Received control frame type %x\n", type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spdylay_session_process_data_frame(spdylay_session *session)
|
||||
{
|
||||
printf("Received data frame, stream_id %d, %zu bytes, fin=%d\n",
|
||||
spdylay_get_uint32(session->iframe.headbuf),
|
||||
session->iframe.len,
|
||||
session->iframe.headbuf[4] & SPDYLAY_FLAG_FIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spdylay_session_recv(spdylay_session *session)
|
||||
{
|
||||
printf("session_recv\n");
|
||||
while(1) {
|
||||
ssize_t r;
|
||||
if(session->iframe.state == SPDYLAY_RECV_HEAD) {
|
||||
uint32_t payloadlen;
|
||||
if(spdylay_inbound_buffer_avail(&session->ibuf) < SPDYLAY_HEAD_LEN) {
|
||||
r = spdylay_recv(session);
|
||||
printf("r=%d\n", r);
|
||||
/* TODO handle EOF */
|
||||
if(r < 0) {
|
||||
if(r == SPDYLAY_ERR_WOULDBLOCK) {
|
||||
return 0;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
printf("Recved %d bytes\n", r);
|
||||
if(spdylay_inbound_buffer_avail(&session->ibuf) < SPDYLAY_HEAD_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
session->iframe.state = SPDYLAY_RECV_PAYLOAD;
|
||||
payloadlen = spdylay_get_uint32(&session->ibuf.mark[4]) & 0xffffff;
|
||||
memcpy(session->iframe.headbuf, session->ibuf.mark, SPDYLAY_HEAD_LEN);
|
||||
session->ibuf.mark += SPDYLAY_HEAD_LEN;
|
||||
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||
/* control frame */
|
||||
session->iframe.len = payloadlen;
|
||||
session->iframe.buf = malloc(session->iframe.len);
|
||||
if(session->iframe.buf == NULL) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
session->iframe.off = 0;
|
||||
} else {
|
||||
int32_t stream_id;
|
||||
/* data frame */
|
||||
/* For data frame, We dont' buffer data. Instead, just pass
|
||||
received data to callback function. */
|
||||
stream_id = spdylay_get_uint32(session->iframe.headbuf) & 0x7fffffff;
|
||||
/* TODO validate stream id here */
|
||||
session->iframe.len = payloadlen;
|
||||
session->iframe.off = 0;
|
||||
}
|
||||
}
|
||||
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD) {
|
||||
size_t rempayloadlen = session->iframe.len - session->iframe.off;
|
||||
size_t bufavail, readlen;
|
||||
if(spdylay_inbound_buffer_avail(&session->ibuf) == 0 &&
|
||||
rempayloadlen > 0) {
|
||||
r = spdylay_recv(session);
|
||||
if(r <= 0) {
|
||||
if(r == SPDYLAY_ERR_WOULDBLOCK) {
|
||||
return 0;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
bufavail = spdylay_inbound_buffer_avail(&session->ibuf);
|
||||
readlen = bufavail < rempayloadlen ? bufavail : rempayloadlen;
|
||||
if(session->iframe.buf != NULL) {
|
||||
memcpy(session->iframe.buf, session->ibuf.mark, readlen);
|
||||
}
|
||||
session->iframe.off += readlen;
|
||||
session->ibuf.mark += readlen;
|
||||
if(session->iframe.len == session->iframe.off) {
|
||||
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||
spdylay_session_process_ctrl_frame(session);
|
||||
} else {
|
||||
spdylay_session_process_data_frame(session);
|
||||
}
|
||||
spdylay_inbound_frame_reset(&session->iframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spdylay_session_want_read(spdylay_session *session)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spdylay_session_want_write(spdylay_session *session)
|
||||
{
|
||||
return session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq);
|
||||
}
|
||||
|
||||
int spdylay_req_submit(spdylay_session *session, const char *path)
|
||||
{
|
||||
int r;
|
||||
spdylay_frame *frame;
|
||||
char **nv;
|
||||
frame = malloc(sizeof(spdylay_frame));
|
||||
nv = malloc(9*sizeof(char*));
|
||||
nv[0] = strdup("method");
|
||||
nv[1] = strdup("GET");
|
||||
nv[2] = strdup("scheme");
|
||||
nv[3] = strdup("https");
|
||||
nv[4] = strdup("url");
|
||||
nv[5] = strdup(path);
|
||||
nv[6] = strdup("version");
|
||||
nv[7] = strdup("HTTP/1.1");
|
||||
nv[8] = NULL;
|
||||
spdylay_frame_syn_stream_init(&frame->syn_stream,
|
||||
SPDYLAY_FLAG_FIN, 0, 0, 0, nv);
|
||||
r = spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame);
|
||||
assert(r == 0);
|
||||
}
|
105
lib/spdylay_session.h
Normal file
105
lib/spdylay_session.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_SESSION_H
|
||||
#define SPDYLAY_SESSION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <spdylay/spdylay.h>
|
||||
#include "spdylay_pq.h"
|
||||
#include "spdylay_map.h"
|
||||
#include "spdylay_frame.h"
|
||||
#include "spdylay_zlib.h"
|
||||
|
||||
typedef struct {
|
||||
spdylay_frame_type frame_type;
|
||||
spdylay_frame *frame;
|
||||
int pri;
|
||||
} spdylay_outbound_item;
|
||||
|
||||
typedef struct {
|
||||
spdylay_outbound_item *item;
|
||||
uint8_t *framebuf;
|
||||
size_t framebuflen;
|
||||
size_t framebufoff;
|
||||
} spdylay_active_outbound_item;
|
||||
|
||||
typedef struct {
|
||||
uint8_t buf[4096];
|
||||
uint8_t *mark;
|
||||
uint8_t *limit;
|
||||
} spdylay_inbound_buffer;
|
||||
|
||||
typedef enum {
|
||||
SPDYLAY_RECV_HEAD,
|
||||
SPDYLAY_RECV_PAYLOAD
|
||||
} spdylay_inbound_state;
|
||||
|
||||
#define SPDYLAY_HEAD_LEN 8
|
||||
|
||||
typedef struct {
|
||||
spdylay_inbound_state state;
|
||||
uint8_t headbuf[SPDYLAY_HEAD_LEN];
|
||||
/* NULL if inbound frame is data frame */
|
||||
uint8_t *buf;
|
||||
/* length in Length field */
|
||||
size_t len;
|
||||
size_t off;
|
||||
uint8_t ign;
|
||||
} spdylay_inbound_frame;
|
||||
|
||||
typedef struct spdylay_session {
|
||||
uint8_t server;
|
||||
int32_t next_stream_id;
|
||||
int32_t last_accepted_stream_id;
|
||||
|
||||
spdylay_map /* <spdylay_stream*> */ streams;
|
||||
spdylay_pq /* <spdylay_outbound_item*> */ ob_pq;
|
||||
|
||||
spdylay_active_outbound_item aob;
|
||||
|
||||
spdylay_inbound_buffer ibuf;
|
||||
spdylay_inbound_frame iframe;
|
||||
|
||||
spdylay_zlib hd_deflater;
|
||||
spdylay_zlib hd_inflater;
|
||||
|
||||
spdylay_session_callbacks callbacks;
|
||||
void *user_data;
|
||||
} spdylay_session;
|
||||
|
||||
/* TODO stream timeout etc */
|
||||
|
||||
int spdylay_session_add_frame(spdylay_session *session,
|
||||
spdylay_frame_type frame_type,
|
||||
spdylay_frame *frame);
|
||||
|
||||
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id);
|
||||
|
||||
int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id);
|
||||
|
||||
#endif /* SPDYLAY_SESSION_H */
|
33
lib/spdylay_stream.c
Normal file
33
lib/spdylay_stream.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_stream.h"
|
||||
|
||||
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id)
|
||||
{
|
||||
stream->stream_id = stream_id;
|
||||
}
|
||||
|
||||
void spdylay_stream_free(spdylay_stream *stream)
|
||||
{}
|
42
lib/spdylay_stream.h
Normal file
42
lib/spdylay_stream.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_STREAM_H
|
||||
#define SPDYLAY_STREAM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <spdylay/spdylay.h>
|
||||
|
||||
typedef struct {
|
||||
int32_t stream_id;
|
||||
} spdylay_stream;
|
||||
|
||||
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id);
|
||||
|
||||
void spdylay_stream_free(spdylay_stream *stream);
|
||||
|
||||
#endif /* SPDYLAY_STREAM */
|
141
lib/spdylay_zlib.c
Normal file
141
lib/spdylay_zlib.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_zlib.h"
|
||||
|
||||
#define COMPRESSION_LEVEL 9
|
||||
#define WINDOW_BITS 11
|
||||
#define MEM_LEVEL 1
|
||||
|
||||
static const char hd_dict[] =
|
||||
"optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
|
||||
"languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
|
||||
"f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
|
||||
"-agent10010120020120220320420520630030130230330430530630740040140240340440"
|
||||
"5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
|
||||
"glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
|
||||
"ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
|
||||
"sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
|
||||
"oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
|
||||
"ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
|
||||
"pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
|
||||
"ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
|
||||
".1statusversionurl";
|
||||
|
||||
int spdylay_zlib_deflate_hd_init(spdylay_zlib *deflater)
|
||||
{
|
||||
deflater->zst.next_in = Z_NULL;
|
||||
deflater->zst.zalloc = Z_NULL;
|
||||
deflater->zst.zfree = Z_NULL;
|
||||
deflater->zst.opaque = Z_NULL;
|
||||
if(Z_OK != deflateInit2(&deflater->zst, COMPRESSION_LEVEL, Z_DEFLATED,
|
||||
WINDOW_BITS, MEM_LEVEL, Z_DEFAULT_STRATEGY)) {
|
||||
return SPDYLAY_ERR_ZLIB;
|
||||
}
|
||||
if(Z_OK != deflateSetDictionary(&deflater->zst, (uint8_t*)hd_dict,
|
||||
sizeof(hd_dict))) {
|
||||
return SPDYLAY_ERR_ZLIB;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spdylay_zlib_inflate_hd_init(spdylay_zlib *inflater)
|
||||
{
|
||||
inflater->zst.next_in = Z_NULL;
|
||||
inflater->zst.avail_in = 0;
|
||||
inflater->zst.zalloc = Z_NULL;
|
||||
inflater->zst.zfree = Z_NULL;
|
||||
if(Z_OK != inflateInit(&inflater->zst)) {
|
||||
return SPDYLAY_ERR_ZLIB;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spdylay_zlib_deflate_free(spdylay_zlib *zlib)
|
||||
{
|
||||
deflateEnd(&zlib->zst);
|
||||
}
|
||||
|
||||
void spdylay_zlib_inflate_free(spdylay_zlib *zlib)
|
||||
{
|
||||
inflateEnd(&zlib->zst);
|
||||
}
|
||||
|
||||
ssize_t spdylay_zlib_deflate_hd(spdylay_zlib *deflater,
|
||||
uint8_t *out, size_t outlen,
|
||||
const uint8_t *in, size_t inlen)
|
||||
{
|
||||
int r;
|
||||
deflater->zst.avail_in = inlen;
|
||||
deflater->zst.next_in = (uint8_t*)in;
|
||||
deflater->zst.avail_out = outlen;
|
||||
deflater->zst.next_out = out;
|
||||
r = deflate(&deflater->zst, Z_SYNC_FLUSH);
|
||||
if(r == Z_OK) {
|
||||
return outlen-deflater->zst.avail_out;
|
||||
} else {
|
||||
return SPDYLAY_ERR_ZLIB;
|
||||
}
|
||||
}
|
||||
|
||||
size_t spdylay_zlib_deflate_hd_bound(spdylay_zlib *deflater, size_t len)
|
||||
{
|
||||
return deflateBound(&deflater->zst, len);
|
||||
}
|
||||
|
||||
ssize_t spdylay_zlib_inflate_hd(spdylay_zlib *inflater,
|
||||
spdylay_buffer* buf,
|
||||
const uint8_t *in, size_t inlen)
|
||||
{
|
||||
int r;
|
||||
inflater->zst.avail_in = inlen;
|
||||
inflater->zst.next_in = (uint8_t*)in;
|
||||
while(1) {
|
||||
if(spdylay_buffer_avail(buf) == 0) {
|
||||
if((r = spdylay_buffer_alloc(buf)) != 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
inflater->zst.avail_out = spdylay_buffer_avail(buf);
|
||||
inflater->zst.next_out = spdylay_buffer_get(buf);
|
||||
r = inflate(&inflater->zst, Z_NO_FLUSH);
|
||||
if(r == Z_STREAM_ERROR || r == Z_STREAM_END) {
|
||||
return SPDYLAY_ERR_ZLIB;
|
||||
} else if(r == Z_NEED_DICT) {
|
||||
if(Z_OK != inflateSetDictionary(&inflater->zst, (uint8_t*)hd_dict,
|
||||
sizeof(hd_dict))) {
|
||||
return SPDYLAY_ERR_ZLIB;
|
||||
}
|
||||
} else {
|
||||
if(r == Z_OK) {
|
||||
size_t adv = spdylay_buffer_avail(buf)-inflater->zst.avail_out;
|
||||
spdylay_buffer_advance(buf, adv);
|
||||
}
|
||||
if(inflater->zst.avail_in == 0 && inflater->zst.avail_out > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return spdylay_buffer_length(buf);
|
||||
}
|
57
lib/spdylay_zlib.h
Normal file
57
lib/spdylay_zlib.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_ZLIB_H
|
||||
#define SPDYLAY_ZLIB_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
#include <zlib.h>
|
||||
|
||||
#include "spdylay_buffer.h"
|
||||
|
||||
typedef struct {
|
||||
z_stream zst;
|
||||
} spdylay_zlib;
|
||||
|
||||
int spdylay_zlib_deflate_hd_init(spdylay_zlib *deflater);
|
||||
|
||||
int spdylay_zlib_inflate_hd_init(spdylay_zlib *inflater);
|
||||
|
||||
void spdylay_zlib_deflate_free(spdylay_zlib *zlib);
|
||||
|
||||
void spdylay_zlib_inflate_free(spdylay_zlib *zlib);
|
||||
|
||||
size_t spdylay_zlib_deflate_hd_bound(spdylay_zlib *deflater, size_t len);
|
||||
|
||||
ssize_t spdylay_zlib_deflate_hd(spdylay_zlib *deflater,
|
||||
uint8_t *out, size_t outlen,
|
||||
const uint8_t *in, size_t inlen);
|
||||
|
||||
ssize_t spdylay_zlib_inflate_hd(spdylay_zlib *inflater,
|
||||
spdylay_buffer* buf,
|
||||
const uint8_t *in, size_t inlen);
|
||||
|
||||
#endif /* SPDYLAY_ZLIB_H */
|
@ -26,10 +26,12 @@ if HAVE_CUNIT
|
||||
check_PROGRAMS = main
|
||||
|
||||
OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \
|
||||
spdylay_buffer_test.c
|
||||
spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \
|
||||
spdylay_frame_test.c
|
||||
|
||||
HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \
|
||||
spdylay_buffer_test.h
|
||||
spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h
|
||||
spdylay_frame_test.h
|
||||
|
||||
main_SOURCES = $(HFILES) $(OBJECTS)
|
||||
|
||||
|
11
tests/main.c
11
tests/main.c
@ -30,6 +30,9 @@
|
||||
#include "spdylay_map_test.h"
|
||||
#include "spdylay_queue_test.h"
|
||||
#include "spdylay_buffer_test.h"
|
||||
#include "spdylay_zlib_test.h"
|
||||
#include "spdylay_session_test.h"
|
||||
#include "spdylay_frame_test.h"
|
||||
|
||||
int init_suite1(void)
|
||||
{
|
||||
@ -61,7 +64,13 @@ int main()
|
||||
if(!CU_add_test(pSuite, "pq", test_spdylay_pq) ||
|
||||
!CU_add_test(pSuite, "map", test_spdylay_map) ||
|
||||
!CU_add_test(pSuite, "queue", test_spdylay_queue) ||
|
||||
!CU_add_test(pSuite, "buffer", test_spdylay_buffer)) {
|
||||
!CU_add_test(pSuite, "buffer", test_spdylay_buffer) ||
|
||||
!CU_add_test(pSuite, "zlib", test_spdylay_zlib) ||
|
||||
!CU_add_test(pSuite, "session_recv", test_spdylay_session_recv) ||
|
||||
!CU_add_test(pSuite, "session_add_frame",
|
||||
test_spdylay_session_add_frame) ||
|
||||
!CU_add_test(pSuite, "frame_unpack_nv",
|
||||
test_spdylay_frame_unpack_nv)) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
50
tests/spdylay_frame_test.c
Normal file
50
tests/spdylay_frame_test.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_frame_test.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
#include "spdylay_frame.h"
|
||||
|
||||
void test_spdylay_frame_unpack_nv()
|
||||
{
|
||||
const char *headers[] = {
|
||||
"method", "GET",
|
||||
"scheme", "https",
|
||||
"url", "/",
|
||||
"version", "HTTP/1.1",
|
||||
"x-head", "foo",
|
||||
"x-head", "bar",
|
||||
NULL
|
||||
};
|
||||
const char in[1024];
|
||||
char **nv;
|
||||
int i;
|
||||
size_t inlen = spdylay_frame_pack_nv(in, (char**)headers);
|
||||
CU_ASSERT(0 == spdylay_frame_unpack_nv(&nv, in, inlen));
|
||||
spdylay_frame_nv_free(nv);
|
||||
free(nv);
|
||||
}
|
||||
|
30
tests/spdylay_frame_test.h
Normal file
30
tests/spdylay_frame_test.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_FRAME_TEST_H
|
||||
#define SPDYLAY_FRAME_TEST_H
|
||||
|
||||
void test_spdylay_frame_unpack_nv();
|
||||
|
||||
#endif /* SPDYLAY_FRAME_TEST_H */
|
175
tests/spdylay_session_test.c
Normal file
175
tests/spdylay_session_test.c
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_session_test.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "spdylay_session.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t buf[4096];
|
||||
size_t length;
|
||||
} accumulator;
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[8192];
|
||||
uint8_t* datamark;
|
||||
uint8_t* datalimit;
|
||||
size_t feedseq[8192];
|
||||
size_t seqidx;
|
||||
} scripted_data_feed;
|
||||
|
||||
typedef struct {
|
||||
accumulator *acc;
|
||||
scripted_data_feed *df;
|
||||
} my_user_data;
|
||||
|
||||
static void scripted_data_feed_init(scripted_data_feed *df,
|
||||
uint8_t *data, size_t data_length)
|
||||
{
|
||||
memset(df, 0, sizeof(scripted_data_feed));
|
||||
memcpy(df->data, data, data_length);
|
||||
df->datamark = df->data;
|
||||
df->datalimit = df->data+data_length;
|
||||
df->feedseq[0] = data_length;
|
||||
}
|
||||
|
||||
static ssize_t scripted_recv_callback(uint8_t* data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
scripted_data_feed *df = ((my_user_data*)user_data)->df;
|
||||
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
|
||||
memcpy(data, df->datamark, wlen);
|
||||
df->datamark += wlen;
|
||||
if(wlen <= len) {
|
||||
++df->seqidx;
|
||||
} else {
|
||||
df->feedseq[df->seqidx] -= wlen;
|
||||
}
|
||||
return wlen;
|
||||
}
|
||||
|
||||
static ssize_t accumulator_send_callback(const uint8_t *buf, size_t len,
|
||||
int flags, void* user_data)
|
||||
{
|
||||
accumulator *acc = ((my_user_data*)user_data)->acc;
|
||||
assert(acc->length+len < sizeof(acc->buf));
|
||||
memcpy(acc->buf+acc->length, buf, len);
|
||||
acc->length += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static char** dup_nv(const char **src)
|
||||
{
|
||||
int i;
|
||||
char **dst;
|
||||
for(i = 0; src[i]; ++i);
|
||||
dst = malloc((i+1)*sizeof(char*));
|
||||
for(i = 0; src[i]; ++i) {
|
||||
dst[i] = strdup(src[i]);
|
||||
}
|
||||
dst[i] = NULL;
|
||||
return dst;
|
||||
}
|
||||
|
||||
void test_spdylay_session_recv()
|
||||
{
|
||||
spdylay_session *session;
|
||||
spdylay_session_callbacks callbacks = {
|
||||
NULL,
|
||||
scripted_recv_callback
|
||||
};
|
||||
scripted_data_feed df;
|
||||
my_user_data user_data;
|
||||
const char *nv[] = {
|
||||
"url", "/", NULL
|
||||
};
|
||||
uint8_t *framedata;
|
||||
size_t framelen;
|
||||
spdylay_frame frame;
|
||||
|
||||
user_data.df = &df;
|
||||
spdylay_session_client_init(&session, &callbacks, &user_data);
|
||||
spdylay_frame_syn_stream_init(&frame.syn_stream, 0, 0, 0, 3, dup_nv(nv));
|
||||
framelen = spdylay_frame_pack_syn_stream(&framedata, &frame.syn_stream,
|
||||
&session->hd_deflater);
|
||||
scripted_data_feed_init(&df, framedata, framelen);
|
||||
free(framedata);
|
||||
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||
|
||||
CU_ASSERT(0 == spdylay_session_recv(session));
|
||||
spdylay_session_free(session);
|
||||
}
|
||||
|
||||
void test_spdylay_session_add_frame()
|
||||
{
|
||||
spdylay_session *session;
|
||||
spdylay_session_callbacks callbacks = {
|
||||
accumulator_send_callback,
|
||||
NULL,
|
||||
};
|
||||
accumulator acc;
|
||||
my_user_data user_data;
|
||||
const char *nv[] = {
|
||||
"method", "GET",
|
||||
"scheme", "https",
|
||||
"url", "/",
|
||||
"version", "HTTP/1.1",
|
||||
NULL
|
||||
};
|
||||
spdylay_frame *frame;
|
||||
const uint8_t hd_ans1[] = {
|
||||
0x80, 0x02, 0x00, 0x01
|
||||
};
|
||||
uint32_t temp32;
|
||||
acc.length = 0;
|
||||
user_data.acc = &acc;
|
||||
CU_ASSERT(0 == spdylay_session_client_init(&session, &callbacks, &user_data));
|
||||
|
||||
frame = malloc(sizeof(spdylay_frame));
|
||||
spdylay_frame_syn_stream_init(&frame->syn_stream, 0, 0, 0, 3, dup_nv(nv));
|
||||
|
||||
CU_ASSERT(0 == spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame));
|
||||
CU_ASSERT(0 == spdylay_pq_empty(&session->ob_pq));
|
||||
CU_ASSERT(0 == spdylay_session_send(session));
|
||||
CU_ASSERT(memcmp(hd_ans1, acc.buf, 4) == 0);
|
||||
/* check stream id */
|
||||
memcpy(&temp32, &acc.buf[8], 4);
|
||||
temp32 = ntohl(temp32);
|
||||
CU_ASSERT(1 == temp32);
|
||||
/* check assoc stream id */
|
||||
memcpy(&temp32, &acc.buf[12], 4);
|
||||
temp32 = ntohl(temp32);
|
||||
CU_ASSERT(0 == temp32);
|
||||
/* check pri */
|
||||
temp32 = (acc.buf[16] >> 6) & 0x3;
|
||||
CU_ASSERT(3 == temp32);
|
||||
|
||||
spdylay_session_free(session);
|
||||
}
|
31
tests/spdylay_session_test.h
Normal file
31
tests/spdylay_session_test.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_SESSION_TEST_H
|
||||
#define SPDYLAY_SESSION_TEST_H
|
||||
|
||||
void test_spdylay_session_recv();
|
||||
void test_spdylay_session_add_frame();
|
||||
|
||||
#endif // SPDYLAY_SESSION_TEST_H
|
70
tests/spdylay_zlib_test.c
Normal file
70
tests/spdylay_zlib_test.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "spdylay_zlib_test.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "spdylay_zlib.h"
|
||||
|
||||
void test_spdylay_zlib()
|
||||
{
|
||||
spdylay_zlib deflater, inflater;
|
||||
const char msg[] =
|
||||
"GET /chat HTTP/1.1\r\n"
|
||||
"Host: server.example.com\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"Origin: http://example.com\r\n"
|
||||
"Sec-WebSocket-Protocol: chat, superchat\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"\r\n";
|
||||
uint8_t inflatebuf[sizeof(msg)];
|
||||
spdylay_buffer buf;
|
||||
uint8_t *deflatebuf;
|
||||
size_t deflatebuf_max;
|
||||
ssize_t deflatebuf_len;
|
||||
spdylay_buffer_init(&buf, 4096);
|
||||
|
||||
deflatebuf_max = spdylay_zlib_deflate_hd_bound(&deflater, sizeof(msg));
|
||||
deflatebuf = malloc(deflatebuf_max);
|
||||
|
||||
CU_ASSERT(0 == spdylay_zlib_deflate_hd_init(&deflater));
|
||||
CU_ASSERT(0 == spdylay_zlib_inflate_hd_init(&inflater));
|
||||
|
||||
CU_ASSERT(0 < (deflatebuf_len = spdylay_zlib_deflate_hd
|
||||
(&deflater, deflatebuf, deflatebuf_max,
|
||||
(const uint8_t*)msg, sizeof(msg))));
|
||||
CU_ASSERT(sizeof(msg) == spdylay_zlib_inflate_hd
|
||||
(&inflater, &buf, deflatebuf, deflatebuf_len));
|
||||
free(deflatebuf);
|
||||
spdylay_buffer_serialize(&buf, inflatebuf);
|
||||
|
||||
|
||||
spdylay_zlib_deflate_free(&deflater);
|
||||
spdylay_zlib_inflate_free(&inflater);
|
||||
}
|
30
tests/spdylay_zlib_test.h
Normal file
30
tests/spdylay_zlib_test.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Spdylay - SPDY Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPDYLAY_ZLIB_TEST_H
|
||||
#define SPDYLAY_ZLIB_TEST_H
|
||||
|
||||
void test_spdylay_zlib();
|
||||
|
||||
#endif // SPDYLAY_ZLIB_TEST_H
|
Loading…
Reference in New Issue
Block a user