Added header deflate/inflate using zlib. Added send/recv frame.

This commit is contained in:
Tatsuhiro Tsujikawa 2012-01-24 22:02:24 +09:00
parent 1330d74b73
commit 9c8270436f
25 changed files with 2000 additions and 8 deletions

View File

@ -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" ])

View File

@ -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 \

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -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
View 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
View 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
View 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
View 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 */

View File

@ -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;
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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 */

View File

@ -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)

View File

@ -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();
}

View 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);
}

View 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 */

View 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);
}

View 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
View 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
View 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