Repository URL to install this package:
|
Version:
2.0.17 ▾
|
/*
uWSGI SPDY3 router
*/
#include "common.h"
#ifdef UWSGI_SPDY
extern struct uwsgi_http uhttp;
#include "spdy3.h"
static uint8_t spdy_h_read_control(uint8_t *header) {
return header[0] >> 7;
}
static uint16_t spdy_h_read_version(uint8_t *header) {
uint16_t ret = 0;
uint8_t *ptr = (uint8_t *) &ret;
ptr[0] = header[0] & 0x7f;
ptr[1] = header[1];
return ntohs(ret);
}
static uint16_t spdy_h_read_type(uint8_t *header) {
uint16_t ret = 0;
uint8_t *ptr = (uint8_t *) &ret;
ptr[0] = header[2];
ptr[1] = header[3];
return ntohs(ret);
}
static uint8_t spdy_h_read_flags(uint8_t *header) {
return header[4];
}
static uint32_t spdy_h_read_length(uint8_t *header) {
uint32_t ret = 0;
uint8_t *ptr = (uint8_t *) &ret;
ptr[1] = header[5];
ptr[2] = header[6];
ptr[3] = header[7];
return ntohl(ret);
}
static uint32_t spdy_stream_id(uint8_t *body) {
uint32_t ret = 0;
uint8_t *ptr = (uint8_t *) &ret;
ptr[0] = body[0] & 0x7f;
ptr[1] = body[1];
ptr[2] = body[2];
ptr[3] = body[3];
return ntohl(ret);
}
/*
static uint32_t spdy_associated_stream_id(uint8_t *body) {
uint32_t ret = 0;
uint8_t *ptr = (uint8_t *) &ret;
ptr[0] = body[4] & 0x7f;
ptr[1] = body[5];
ptr[2] = body[6];
ptr[3] = body[7];
return ntohl(ret);
}
*/
static char *spdy_translate(char *buf, uint32_t len, uint16_t *d_len) {
uint32_t i;
if (len == 0) return NULL;
if (buf[0] == ':') {
if (!uwsgi_strncmp(buf+1, len-1, "method", 6)) {
*d_len = 14;
return uwsgi_str("REQUEST_METHOD");
}
if (!uwsgi_strncmp(buf+1, len-1, "path", 4)) {
*d_len = 11;
return uwsgi_str("REQUEST_URI");
}
if (!uwsgi_strncmp(buf+1, len-1, "version", 7)) {
*d_len = 15;
return uwsgi_str("SERVER_PROTOCOL");
}
if (!uwsgi_strncmp(buf+1, len-1, "host", 4)) {
*d_len = 9;
return uwsgi_str("HTTP_HOST");
}
if (!uwsgi_strncmp(buf+1, len-1, "scheme", 6)) {
*d_len = 12;
return uwsgi_str("UWSGI_SCHEME");
}
return NULL;
}
if (!uwsgi_strncmp(buf, len, "content-length", 14)) {
*d_len = 14;
return uwsgi_str("CONTENT_LENGTH");
}
if (!uwsgi_strncmp(buf, len, "content-type", 12)) {
*d_len = 12;
return uwsgi_str("CONTENT_TYPE");
}
char *buf2 = uwsgi_malloc(len + 5);
memcpy(buf2, "HTTP_", 5);
char *ptr = buf2+5;
for(i=0;i<len;i++) {
if (buf[i] == '-') {
*ptr++= '_';
}
else {
*ptr++= toupper((int) buf[i]);
}
}
*d_len = len+5;
return buf2;
}
struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
size_t i;
size_t next = 0;
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
// leave space for the number of items
ub->pos+=4;
int found = 0;
// :version
for(i=0;i<len;i++) {
if (buf[i] == ' ') {
if (uwsgi_buffer_append_keyval32(ub, ":version", 8, buf, i)) goto end;
if (i+1 >= len) goto end;
next = i+1;
found = 1;
break;
}
}
if (!found) goto end;
// :status
found = 0;
for(i=next;i<len;i++) {
if (buf[i] == '\r' || buf[i] == '\n') {
if (uwsgi_buffer_append_keyval32(ub, ":status", 7, buf + next, i-next)) goto end;
if (i+1 >= len) goto end;
next = i + 1;
found = 1;
break;
}
}
if (!found) goto end;
*hh = 2;
char *key = NULL;
// find first header position
for(i=next;i<len;i++) {
if (buf[i] != '\r' && buf[i] != '\n') {
key = buf + i;
next = i;
break;
}
}
if (!key) return ub;
uint32_t h_len = 0;
// merge header values and ensure keys are all lowercase
struct uwsgi_string_list *hr=NULL, *usl=NULL;
char *line_value;
size_t line_key_len, line_value_len;
for(i=next;i<len;i++) {
if (key) {
if (buf[i] == '\r' || buf[i] == '\n') {
char *colon = memchr(key, ':', h_len);
if (!colon) goto end;
// security check
if (colon+2 >= buf+len) goto end;
// tolower !!!
size_t j;
for(j=0;j<h_len;j++) {
// don't lowercase values, only keys
if (key[j] == ':') break;
key[j] = tolower((int) key[j]);
}
line_key_len = colon - key;
key[line_key_len] = 0;
line_value_len = h_len - 2 - line_key_len;
line_value = uwsgi_strncopy(colon+2, line_value_len);
if (hr) {
// check if we already store values for this key
usl = uwsgi_string_list_has_item(hr, key, line_key_len);
if (usl) {
// we have this key, append new value
char *oldval = usl->custom_ptr;
usl->custom_ptr = uwsgi_concat3n(usl->custom_ptr, usl->custom, "\0", 1, line_value, line_value_len);
usl->custom = usl->custom + 1 + line_value_len;
free(oldval);
}
else {
// this key is new
usl = uwsgi_string_new_list(&hr, key);
usl->custom_ptr = line_value;
usl->custom = line_value_len;
}
}
else {
// this is first key
usl = uwsgi_string_new_list(&hr, key);
usl->custom_ptr = line_value;
usl->custom = line_value_len;
}
key = NULL;
h_len = 0;
}
else {
h_len++;
}
}
else {
if (buf[i] != '\r' && buf[i] != '\n') {
key = buf+i;
h_len = 1;
}
}
}
// append all merged header lines to buffer and free memory
struct uwsgi_string_list *ohr;
while (hr) {
if (uwsgi_buffer_append_keyval32(ub, hr->value, hr->len, hr->custom_ptr, hr->custom)) goto end;
*hh+=1;
ohr = hr;
hr = hr->next;
free(ohr->custom_ptr);
free(ohr);
}
return ub;
end:
uwsgi_buffer_destroy(ub);
return NULL;
}
char *spdy_deflate_http_headers(struct http_session *, struct uwsgi_buffer *, size_t *);
// be sure to have at least 8 free bytes
static void spdy_data_header(char *buf, uint32_t len, uint32_t stream_id) {
// stream id
buf[3] = (uint8_t) (stream_id & 0xff);
buf[2] = (uint8_t) ((stream_id >> 8) & 0xff);
buf[1] = (uint8_t) ((stream_id >> 16) & 0xff);
buf[0] = (uint8_t) ((stream_id >> 24) & 0xff);
// FIN
if (len == 0) {
buf[4] = 1;
}
// length
buf[7] = (uint8_t) (len & 0xff);
buf[6] = (uint8_t) ((len >> 8) & 0xff);
buf[5] = (uint8_t) ((len >> 16) & 0xff);
}
// be sure to have at least 12 free bytes
static void spdy_reply_header(char *buf, uint32_t len, uint32_t stream_id) {
buf[0] = 0x80;
buf[1] = 0x03;
buf[2] = 0;
buf[3] = 0x02;
// flags
buf[4] = 0;
// length
buf[7] = (uint8_t) (len & 0xff);
buf[6] = (uint8_t) ((len >> 8) & 0xff);
buf[5] = (uint8_t) ((len >> 16) & 0xff);
// stream id
buf[11] = (uint8_t) (stream_id & 0xff);
buf[10] = (uint8_t) ((stream_id >> 8) & 0xff);
buf[9] = (uint8_t) ((stream_id >> 16) & 0xff);
buf[8] = (uint8_t) ((stream_id >> 24) & 0xff);
}
// be sure to have at least 16 free bytes
void spdy_window_update(char *buf, uint32_t stream_id, uint32_t wsize) {
buf[0] = 0x80;
buf[1] = 0x03;
buf[2] = 0;
buf[3] = 0x09;
// flags
buf[4] = 0;
uint32_t len = 8;
// length
buf[7] = (uint8_t) (len & 0xff);
buf[6] = (uint8_t) ((len >> 8) & 0xff);
buf[5] = (uint8_t) ((len >> 16) & 0xff);
// stream id
buf[11] = (uint8_t) (stream_id & 0xff);
buf[10] = (uint8_t) ((stream_id >> 8) & 0xff);
buf[9] = (uint8_t) ((stream_id >> 16) & 0xff);
buf[8] = (uint8_t) ((stream_id >> 24) & 0xff);
buf[15] = (uint8_t) (wsize & 0xff);
buf[14] = (uint8_t) ((wsize >> 8) & 0xff);
buf[13] = (uint8_t) ((wsize >> 16) & 0xff);
buf[12] = (uint8_t) ((wsize >> 24) & 0xff);
}
static ssize_t http_parse_to_spdy(struct corerouter_peer *peer) {
size_t i;
struct uwsgi_buffer *ub = peer->in;
struct uwsgi_buffer *out = peer->out;
// reset the out buf (it will hold the spdy frame)
out->pos = 0;
peer->session->main_peer->out_pos = 0;
// end of the stream
if (peer->r_parser_status == 5) {
return -1;
}
// send DATA frame
if (peer->r_parser_status == 4) {
spdy_data_header(out->buf, ub->pos, peer->sid);
out->pos = 8;
// no need to call append on empty values
if (ub->pos > 0) {
if (uwsgi_buffer_append(out, ub->buf, ub->pos)) return -1;
}
else {
peer->r_parser_status = 5;
}
// reset the input buffer
ub->pos = 0;
return 1;
}
// try to send REPLY frame
for(i=0;i<ub->pos;i++) {
char c = ub->buf[i];
if (c == '\r' && (peer->r_parser_status == 0 || peer->r_parser_status == 2)) {
peer->r_parser_status++;
}
else if (c == '\r') {
peer->r_parser_status = 1;
}
else if (c == '\n' && peer->r_parser_status == 1) {
peer->r_parser_status = 2;
}
// parsing done
else if (c == '\n' && peer->r_parser_status == 3) {
peer->r_parser_status = 4;
uint32_t hh = 0;
struct uwsgi_buffer *h_buf = spdy_http_to_spdy(ub->buf, i, &hh);
if (!h_buf) return -1;
// put the number of headers on front of the buffer
h_buf->buf[3] = (uint8_t) (hh & 0xff);
h_buf->buf[2] = (uint8_t) ((hh >> 8) & 0xff);
h_buf->buf[1] = (uint8_t) ((hh >> 16) & 0xff);
h_buf->buf[0] = (uint8_t) ((hh >> 24) & 0xff);
// ok now we need to deflate the buffer
size_t cb_len = 0;
char *compressed_buf = spdy_deflate_http_headers((struct http_session *) peer->session, h_buf, &cb_len);
uwsgi_buffer_destroy(h_buf);
if (!compressed_buf) {
return -1;
}
// ok now we need an additional buffer
spdy_reply_header(out->buf, 4+cb_len, peer->sid);
out->pos = 12;
if (uwsgi_buffer_append(out, compressed_buf, cb_len)) {
free(compressed_buf);
return -1;
}
free(compressed_buf);
// any push request ???
// after all of the pushed requests are sent, we have to come back here...
// remains ?
if (ub->pos-i > 1) {
uint32_t remains = ub->pos-(i+1);
if (uwsgi_buffer_append(out, "\0\0\0\0\0\0\0\0", 8)) {
return -1;
}
spdy_data_header(out->buf + (out->pos - 8), remains, peer->sid);
if (uwsgi_buffer_append(out, ub->buf+i+1, remains)) {
return -1;
}
}
// reset the input buffer
ub->pos = 0;
return 1;
}
else {
peer->r_parser_status = 0;
}
}
return 0;
}
ssize_t hr_instance_read_to_spdy(struct corerouter_peer *peer) {
ssize_t len = cr_read(peer, "hr_instance_read_to_spdy()");
// do not check for empty packet, as 0 will trigger a data frame
len = http_parse_to_spdy(peer);
if (len > 0) goto parsed;
if (len < 0) {
if (peer->r_parser_status == 5) return 0;
return -1;
}
// need more data
return 1;
parsed:
peer->session->main_peer->out = peer->out;
peer->session->main_peer->out_pos = 0;
cr_write_to_main(peer, hr_ssl_write);
return 1;
}
char *spdy_deflate_http_headers(struct http_session *hr, struct uwsgi_buffer *h_buf, size_t *dlen) {
// calculate the amount of bytes needed for output (+30 should be enough)
Bytef *dbuf = uwsgi_malloc(h_buf->pos+30);
z_stream *z = &hr->spdy_z_out;
z->avail_in = h_buf->pos; z->next_in = (Bytef *) h_buf->buf; z->avail_out = h_buf->pos+30; z->next_out = dbuf;
if (deflate(z, Z_SYNC_FLUSH) != Z_OK) {
free(dbuf);
return NULL;
}
*dlen = z->next_out - dbuf;
return (char *) dbuf;
}
static ssize_t spdy_inflate_http_headers(struct http_session *hr) {
Bytef zbuf[4096];
uint8_t *src = (uint8_t *) hr->session.main_peer->in->buf;
hr->spdy_z_in.avail_in = hr->spdy_control_length - 10;
hr->spdy_z_in.next_in = src + 10;
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
while(hr->spdy_z_in.avail_in > 0) {
hr->spdy_z_in.avail_out = 4096;
hr->spdy_z_in.next_out = zbuf;
int ret = inflate(&hr->spdy_z_in, Z_NO_FLUSH);
if (ret == Z_NEED_DICT) {
inflateSetDictionary(&hr->spdy_z_in, (Bytef *) SPDY_dictionary_txt, sizeof(SPDY_dictionary_txt));
ret = inflate(&hr->spdy_z_in, Z_NO_FLUSH);
}
if (ret != Z_OK) {
uwsgi_buffer_destroy(ub);
return -1;
}
size_t zlen = hr->spdy_z_in.next_out-zbuf;
if (uwsgi_buffer_append(ub, (char *) zbuf, zlen)) {
uwsgi_buffer_destroy(ub);
return -1;
}
}
if (ub->pos < 4) {
uwsgi_buffer_destroy(ub);
return -1;
}
uint32_t headers_num = uwsgi_be32(ub->buf);
uint32_t i, watermark = ub->pos, pos = 4;
struct corerouter_peer *new_peer = uwsgi_cr_peer_add(&hr->session);
new_peer->last_hook_read = hr_instance_read_to_spdy;
new_peer->out = uwsgi_buffer_new(uwsgi.page_size);
// this will avoid the buffer being destroyed on the first instance write
new_peer->out_need_free = 2;
// leave space for uwsgi header
new_peer->out->pos = 4;
new_peer->sid = hr->spdy_data_stream_id;
// leave space for header
for(i=0;i<headers_num;i++) {
// key
if (pos + 4 > watermark) {
uwsgi_buffer_destroy(ub);
return -1;
}
uint32_t k_len = uwsgi_be32( ub->buf + pos);
pos += 4;
if (pos + k_len > watermark) {
uwsgi_buffer_destroy(ub);
return -1;
}
char *k = ub->buf + pos;
pos += k_len;
// value
if (pos + 4 > watermark) {
uwsgi_buffer_destroy(ub);
return -1;
}
uint32_t v_len = uwsgi_be32( ub->buf + pos);
pos += 4;
if (pos + v_len > watermark) {
uwsgi_buffer_destroy(ub);
return -1;
}
char *v = ub->buf + pos;
pos += v_len;
uint16_t nk_len = 0;
char *cgi_name = spdy_translate(k, k_len, &nk_len);
if (!cgi_name) {
uwsgi_buffer_destroy(ub);
return -1;
}
if (uwsgi_buffer_append_keyval(new_peer->out, cgi_name, nk_len, v, v_len)) {
uwsgi_buffer_destroy(ub);
return -1;
}
if (!uwsgi_strncmp(cgi_name, nk_len, "HTTP_HOST", 9)) {
if (v_len <= 0xff) {
memcpy(new_peer->key, new_peer->out->buf + (new_peer->out->pos - v_len), v_len);
new_peer->key_len = v_len;
}
}
else if (!uwsgi_strncmp(cgi_name, nk_len, "REQUEST_URI", 11)) {
char *path_info = new_peer->out->buf + (new_peer->out->pos - v_len);
uint16_t path_info_len = v_len;
char *query_string = memchr(path_info, '?', v_len);
if (query_string) {
query_string++;
path_info_len = (query_string - path_info) -1;
uint16_t query_string_len = v_len - (path_info_len + 1);
if (uwsgi_buffer_append_keyval(new_peer->out, "QUERY_STRING", 12, query_string, query_string_len)) {
free(cgi_name);
uwsgi_buffer_destroy(ub);
return -1;
}
}
if (uwsgi_buffer_append_keyval(new_peer->out, "PATH_INFO", 9, path_info, path_info_len)) {
free(cgi_name);
uwsgi_buffer_destroy(ub);
return -1;
}
}
free(cgi_name);
}
uwsgi_buffer_destroy(ub);
// find the backend node
if (new_peer->key_len == 0) return -1;
if (uwsgi_buffer_append_keyval(new_peer->out, "HTTPS", 5, "on", 2)) return -1;
if (uwsgi_buffer_append_keyval(new_peer->out, "SPDY", 4, "on", 2)) return -1;
if (uwsgi_buffer_append_keynum(new_peer->out, "SPDY.version", 12, 3)) return -1;
if (uwsgi_buffer_append_keynum(new_peer->out, "SPDY.stream", 11, new_peer->sid)) return -1;
struct uwsgi_corerouter *ucr = hr->session.corerouter;
// get instance name
if (ucr->mapper(ucr, new_peer )) return -1;
if (new_peer->instance_address_len == 0) {
return -1;
}
uint16_t pktsize = new_peer->out->pos-4;
// fix modifiers
new_peer->out->buf[0] = new_peer->session->main_peer->modifier1;
new_peer->out->buf[3] = new_peer->session->main_peer->modifier2;
// fix pktsize
new_peer->out->buf[1] = (uint8_t) (pktsize & 0xff);
new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
new_peer->can_retry = 1;
cr_connect(new_peer, hr_instance_connected);
return 1;
}
ssize_t spdy_manage_settings(struct http_session *hs) {
uwsgi_log("settings received !!!\n");
return 1;
}
ssize_t spdy_manage_syn_stream(struct http_session *hr) {
uint8_t *buf = (uint8_t *) hr->session.main_peer->in->buf;
hr->spdy_data_stream_id = spdy_stream_id(buf);
//uwsgi_log("SYN_STREAM received %u !!!\n", hr->spdy_data_stream_id) ;
//uwsgi_log("associated stream %u\n", spdy_associated_stream_id(buf));
return spdy_inflate_http_headers(hr);
}
ssize_t spdy_manage_rst_stream(struct http_session *hr) {
uint8_t *buf = (uint8_t *) hr->session.main_peer->in->buf;
hr->spdy_data_stream_id = spdy_stream_id(buf);
//uwsgi_log("RST_STREAM received %u !!!\n", hr->spdy_data_stream_id) ;
struct corerouter_peer *peer = uwsgi_cr_peer_find_by_sid(&hr->session, hr->spdy_data_stream_id);
if (peer) {
corerouter_close_peer(hr->session.corerouter, peer);
}
return 0;
}
ssize_t spdy_manage_ping(struct http_session *hr) {
if (!hr->spdy_ping) {
hr->spdy_ping = uwsgi_buffer_new(12);
}
hr->spdy_ping->pos = 0;
if (uwsgi_buffer_append(hr->spdy_ping, hr->session.main_peer->in->buf, 12)) return -1;
hr->session.main_peer->out = hr->spdy_ping;
hr->session.main_peer->out_pos = 0;
cr_write_to_main(hr->session.main_peer, hr_ssl_write);
//uwsgi_log("PONG\n");
return 1;
}
/*
read from ssl peer.
This must be able to efficiently manage both http and spdy packets
when the first chunk is received the spdy field of the session is checked.
If it is a spdy packet, the SPDY parser will run...
*/
#define UWSGI_SPDY_PHASE_HEADER 0
#define UWSGI_SPDY_PHASE_CONTROL 1
#define UWSGI_SPDY_PHASE_DATA 2
ssize_t spdy_parse(struct corerouter_peer *main_peer) {
struct corerouter_session *cs = main_peer->session;
struct http_session *hr = (struct http_session *) cs;
ssize_t ret = -1;
if (!hr->spdy_initialized) {
hr->spdy_z_in.zalloc = Z_NULL;
hr->spdy_z_in.zfree = Z_NULL;
hr->spdy_z_in.opaque = Z_NULL;
if (inflateInit(&hr->spdy_z_in) != Z_OK) {
return -1;
}
hr->spdy_z_out.zalloc = Z_NULL;
hr->spdy_z_out.zfree = Z_NULL;
hr->spdy_z_out.opaque = Z_NULL;
if (deflateInit(&hr->spdy_z_out, Z_DEFAULT_COMPRESSION) != Z_OK) {
return -1;
}
if (deflateSetDictionary(&hr->spdy_z_out, (Bytef *) SPDY_dictionary_txt, sizeof(SPDY_dictionary_txt)) != Z_OK) {
return -1;
}
cs->can_keepalive = 1;
hr->spdy_initialized = 1;
hr->spdy_phase = UWSGI_SPDY_PHASE_HEADER;
hr->spdy_need = 8;
main_peer->out = uhttp.spdy3_settings;
main_peer->out->pos = uhttp.spdy3_settings_size;
main_peer->out_pos = 0;
cr_write_to_main(main_peer, hr_ssl_write);
return 1;
}
for(;;) {
size_t len = main_peer->in->pos;
if (len == 0) {
return 1;
}
uint8_t *buf = (uint8_t *) main_peer->in->buf;
//uwsgi_log("%d bytes available\n", len);
switch(hr->spdy_phase) {
case UWSGI_SPDY_PHASE_HEADER:
if (len >= hr->spdy_need) {
hr->spdy_frame_type = spdy_h_read_control(buf);
if (hr->spdy_frame_type) {
hr->spdy_control_version = spdy_h_read_version(buf);
hr->spdy_control_type = spdy_h_read_type(buf);
hr->spdy_control_flags = spdy_h_read_flags(buf);
hr->spdy_control_length = spdy_h_read_length(buf);
hr->spdy_phase = UWSGI_SPDY_PHASE_CONTROL;
hr->spdy_need = hr->spdy_control_length;
//uwsgi_log("now i need %llu bytes for type %u\n", (unsigned long long) hr->spdy_need, hr->spdy_control_type);
}
else {
hr->spdy_phase = UWSGI_SPDY_PHASE_DATA;
hr->spdy_data_stream_id = spdy_stream_id(buf);
hr->spdy_control_length = spdy_h_read_length(buf);
hr->spdy_need = hr->spdy_control_length;
//uwsgi_log("need %llu bytes for stream_id %lu\n", (unsigned long long) hr->spdy_need, hr->spdy_data_stream_id);
}
if (uwsgi_buffer_decapitate(main_peer->in, 8)) return -1;
continue;
}
return 1;
case UWSGI_SPDY_PHASE_CONTROL:
if (len >= hr->spdy_need) {
switch(hr->spdy_control_type) {
// SYN_STREAM
case 1:
ret = spdy_manage_syn_stream(hr);
if (ret == 0) goto goon;
if (ret < 0) return -1;
goto newframe;
// RST_STREAM
case 3:
ret = spdy_manage_rst_stream(hr);
if (ret == 0) goto goon;
if (ret < 0) return -1;
goto newframe;
case 4:
//uwsgi_log("settings request...\n");
break;
case 6:
ret = spdy_manage_ping(hr);
if (ret == 0) goto goon;
if (ret < 0) return -1;
goto newframe;
break;
case 7:
// uwsgi_log("GO AWAY...\n");
break;
case 9:
// uwsgi_log("window update...\n");
break;
default:
uwsgi_log("i do not know how to manage type %u\n", hr->spdy_control_type);
break;
}
goon:
hr->spdy_phase = UWSGI_SPDY_PHASE_HEADER;
hr->spdy_need = 8;
if (uwsgi_buffer_decapitate(main_peer->in, hr->spdy_control_length)) return -1;
continue;
}
return 1;
case UWSGI_SPDY_PHASE_DATA:
if (len >= hr->spdy_need) {
struct corerouter_peer *peer = uwsgi_cr_peer_find_by_sid(&hr->session, hr->spdy_data_stream_id);
if (!peer) {
return -1;
}
peer->out->pos = 0;
if (uwsgi_buffer_append(peer->out, main_peer->in->buf, hr->spdy_need)) return -1;
peer->out_pos = 0;
hr->spdy_update_window = hr->spdy_data_stream_id;
cr_write_to_backend(peer, hr_instance_write);
ret = 1;
goto newframe;
}
return 1;
default:
return -1;
}
}
return -1;
newframe:
hr->spdy_phase = UWSGI_SPDY_PHASE_HEADER;
hr->spdy_need = 8;
if (uwsgi_buffer_decapitate(main_peer->in, hr->spdy_control_length)) return -1;
return ret;
}
int uwsgi_spdy_npn(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg) {
//*data = (const unsigned char *) "\x06spdy/3\x06spdy/2\x08http/1.1\x08http/1.0";
*data = (const unsigned char *) "\x06spdy/3\x08http/1.1\x08http/1.0";
*len = strlen((const char *) *data);
return SSL_TLSEXT_ERR_OK;
}
void uwsgi_spdy_info_cb(SSL const *ssl, int where, int ret) {
if (where & SSL_CB_HANDSHAKE_DONE) {
const unsigned char * proto = NULL;
unsigned len = 0;
SSL_get0_next_proto_negotiated(ssl, &proto, &len);
if (len == 6) {
if (!memcmp(proto, "spdy/3", 6)) {
//uwsgi_log("SPDY 3 !!!\n");
struct http_session *hr = SSL_get_ex_data(ssl, uhttp.spdy_index);
hr->spdy = 3;
//hr->spdy_hook = hr_recv_spdy_control_frame;
}
else if (!memcmp(proto, "spdy/2", 6)) {
//uwsgi_log("SPDY 2 !!!\n");
struct http_session *hr = SSL_get_ex_data(ssl, uhttp.spdy_index);
hr->spdy = 2;
//uwsgi_log("SPDY/2\n");
//hr->spdy_hook = hr_recv_spdy_control_frame;
}
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (ssl->s3) {
ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
}
#endif
}
}
#endif