Inflate response body if content-encoding: gzip is used.
Erase Request from stream2req when stream is closed.
This commit is contained in:
parent
c91a4ec091
commit
fa0ab174e1
|
@ -51,6 +51,7 @@
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <spdylay/spdylay.h>
|
#include <spdylay/spdylay.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "spdylay_ssl.h"
|
#include "spdylay_ssl.h"
|
||||||
#include "uri.h"
|
#include "uri.h"
|
||||||
|
@ -71,7 +72,61 @@ struct Config {
|
||||||
|
|
||||||
struct Request {
|
struct Request {
|
||||||
uri::UriStruct us;
|
uri::UriStruct us;
|
||||||
Request(const uri::UriStruct& us):us(us) {}
|
z_stream *inflater;
|
||||||
|
Request(const uri::UriStruct& us):us(us), inflater(0) {}
|
||||||
|
~Request()
|
||||||
|
{
|
||||||
|
if(inflater) {
|
||||||
|
inflateEnd(inflater);
|
||||||
|
delete inflater;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_inflater()
|
||||||
|
{
|
||||||
|
inflater = new z_stream();
|
||||||
|
inflater->next_in = Z_NULL;
|
||||||
|
inflater->zalloc = Z_NULL;
|
||||||
|
inflater->zfree = Z_NULL;
|
||||||
|
inflater->opaque = Z_NULL;
|
||||||
|
int rv = inflateInit2(inflater, 47);
|
||||||
|
assert(rv == Z_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inflates data in |in| with the length |*inlen_ptr| and stores the
|
||||||
|
// inflated data to |out| which has allocated size at least
|
||||||
|
// |*outlen_ptr|. On return, |*outlen_ptr| is updated to represent
|
||||||
|
// the number of data written in |out|. Similarly, |*inlen_ptr| is
|
||||||
|
// updated to represent the number of input bytes processed.
|
||||||
|
//
|
||||||
|
// This function returns 0 if it succeeds, or -1.
|
||||||
|
int inflate_data(uint8_t *out, size_t *outlen_ptr,
|
||||||
|
const uint8_t *in, size_t *inlen_ptr)
|
||||||
|
{
|
||||||
|
assert(inflater);
|
||||||
|
inflater->avail_in = *inlen_ptr;
|
||||||
|
inflater->next_in = const_cast<unsigned char*>(in);
|
||||||
|
inflater->avail_out = *outlen_ptr;
|
||||||
|
inflater->next_out = out;
|
||||||
|
|
||||||
|
int rv = inflate(inflater, Z_NO_FLUSH);
|
||||||
|
|
||||||
|
*inlen_ptr -= inflater->avail_in;
|
||||||
|
*outlen_ptr -= inflater->avail_out;
|
||||||
|
switch(rv) {
|
||||||
|
case Z_OK:
|
||||||
|
case Z_STREAM_END:
|
||||||
|
case Z_BUF_ERROR:
|
||||||
|
return 0;
|
||||||
|
case Z_DATA_ERROR:
|
||||||
|
case Z_STREAM_ERROR:
|
||||||
|
case Z_NEED_DICT:
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<int32_t, Request*> stream2req;
|
std::map<int32_t, Request*> stream2req;
|
||||||
|
@ -86,9 +141,27 @@ void on_data_chunk_recv_callback
|
||||||
{
|
{
|
||||||
std::map<int32_t, Request*>::iterator itr = stream2req.find(stream_id);
|
std::map<int32_t, Request*>::iterator itr = stream2req.find(stream_id);
|
||||||
if(itr != stream2req.end()) {
|
if(itr != stream2req.end()) {
|
||||||
|
Request *req = (*itr).second;
|
||||||
|
if(req->inflater) {
|
||||||
|
while(len > 0) {
|
||||||
|
const size_t MAX_OUTLEN = 4096;
|
||||||
|
uint8_t out[MAX_OUTLEN];
|
||||||
|
size_t outlen = MAX_OUTLEN;
|
||||||
|
size_t tlen = len;
|
||||||
|
int rv = req->inflate_data(out, &outlen, data, &tlen);
|
||||||
|
if(rv == -1) {
|
||||||
|
spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::cout.write(reinterpret_cast<const char*>(out), outlen);
|
||||||
|
data += tlen;
|
||||||
|
len -= tlen;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
std::cout.write(reinterpret_cast<const char*>(data), len);
|
std::cout.write(reinterpret_cast<const char*>(data), len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void check_stream_id(spdylay_session *session,
|
void check_stream_id(spdylay_session *session,
|
||||||
spdylay_frame_type type, spdylay_frame *frame)
|
spdylay_frame_type type, spdylay_frame *frame)
|
||||||
|
@ -118,6 +191,54 @@ void on_ctrl_send_callback3
|
||||||
on_ctrl_send_callback(session, type, frame, user_data);
|
on_ctrl_send_callback(session, type, frame, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_gzip
|
||||||
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
char **nv;
|
||||||
|
int32_t stream_id;
|
||||||
|
if(type == SPDYLAY_SYN_REPLY) {
|
||||||
|
nv = frame->syn_reply.nv;
|
||||||
|
stream_id = frame->syn_reply.stream_id;
|
||||||
|
} else if(type == SPDYLAY_HEADERS) {
|
||||||
|
nv = frame->headers.nv;
|
||||||
|
stream_id = frame->headers.stream_id;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool gzip = false;
|
||||||
|
for(size_t i = 0; nv[i]; i += 2) {
|
||||||
|
if(strcmp("content-encoding", nv[i]) == 0) {
|
||||||
|
gzip = strcmp("gzip", nv[i+1]) == 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(gzip) {
|
||||||
|
Request *req = (Request*)spdylay_session_get_stream_user_data(session,
|
||||||
|
stream_id);
|
||||||
|
assert(req);
|
||||||
|
if(req->inflater) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req->init_inflater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_ctrl_recv_callback2
|
||||||
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
check_gzip(session, type, frame, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_ctrl_recv_callback3
|
||||||
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
check_gzip(session, type, frame, user_data);
|
||||||
|
on_ctrl_recv_callback(session, type, frame, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
void on_stream_close_callback
|
void on_stream_close_callback
|
||||||
(spdylay_session *session, int32_t stream_id, spdylay_status_code status_code,
|
(spdylay_session *session, int32_t stream_id, spdylay_status_code status_code,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
|
@ -128,6 +249,7 @@ void on_stream_close_callback
|
||||||
if(complete == numreq) {
|
if(complete == numreq) {
|
||||||
spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK);
|
spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK);
|
||||||
}
|
}
|
||||||
|
stream2req.erase(itr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,10 +380,11 @@ int run(char **uris, int n)
|
||||||
callbacks.recv_callback = recv_callback;
|
callbacks.recv_callback = recv_callback;
|
||||||
callbacks.on_stream_close_callback = on_stream_close_callback;
|
callbacks.on_stream_close_callback = on_stream_close_callback;
|
||||||
if(config.verbose) {
|
if(config.verbose) {
|
||||||
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
|
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback3;
|
||||||
callbacks.on_data_recv_callback = on_data_recv_callback;
|
callbacks.on_data_recv_callback = on_data_recv_callback;
|
||||||
callbacks.on_ctrl_send_callback = on_ctrl_send_callback3;
|
callbacks.on_ctrl_send_callback = on_ctrl_send_callback3;
|
||||||
} else {
|
} else {
|
||||||
|
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback2;
|
||||||
callbacks.on_ctrl_send_callback = on_ctrl_send_callback2;
|
callbacks.on_ctrl_send_callback = on_ctrl_send_callback2;
|
||||||
}
|
}
|
||||||
if(!config.null_out) {
|
if(!config.null_out) {
|
||||||
|
|
Loading…
Reference in New Issue