diff --git a/core/buffer.c b/core/buffer.c index 8437f501..939fe67b 100644 --- a/core/buffer.c +++ b/core/buffer.c @@ -105,6 +105,14 @@ int uwsgi_buffer_u16be(struct uwsgi_buffer *ub, uint16_t num) { return uwsgi_buffer_append(ub, (char *) buf, 2); } +int uwsgi_buffer_u24be(struct uwsgi_buffer *ub, uint32_t num) { + uint8_t buf[3]; + buf[2] = (uint8_t) (num & 0xff); + buf[1] = (uint8_t) ((num >> 8) & 0xff); + buf[0] = (uint8_t) ((num >> 16) & 0xff); + return uwsgi_buffer_append(ub, (char *) buf, 3); +} + int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) { uint8_t buf[4]; buf[3] = (uint8_t) (num & 0xff); diff --git a/plugins/http/common.h b/plugins/http/common.h index 49f5d3ab..4f29726b 100644 --- a/plugins/http/common.h +++ b/plugins/http/common.h @@ -32,6 +32,8 @@ struct uwsgi_http { #ifdef UWSGI_SPDY int spdy_index; + struct uwsgi_buffer *spdy3_settings; + size_t spdy3_settings_size; #endif }; @@ -97,6 +99,8 @@ struct http_session { uint8_t spdy_data_flags; uint32_t spdy_data_length; + struct uwsgi_buffer *spdy_ping; + ssize_t (*spdy_hook)(struct corerouter_peer *); #endif diff --git a/plugins/http/https.c b/plugins/http/https.c index e1bfa27d..3414068a 100644 --- a/plugins/http/https.c +++ b/plugins/http/https.c @@ -104,6 +104,19 @@ void uwsgi_opt_https2(char *opt, char *value, void *cr) { #ifdef UWSGI_SPDY if (s_spdy) { uhttp.spdy_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); + uhttp.spdy3_settings = uwsgi_buffer_new(uwsgi.page_size); + if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x80\x03\x00\x04\x01", 5)) goto spdyerror; + if (uwsgi_buffer_u24be(uhttp.spdy3_settings, (8 * 2) + 4)) goto spdyerror; + if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 2)) goto spdyerror; + + // SETTINGS_ROUND_TRIP_TIME + if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x01\x00\x00\x03", 4)) goto spdyerror; + if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 30 * 1000)) goto spdyerror; + // SETTINGS_INITIAL_WINDOW_SIZE + if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x01\x00\x00\x07", 4)) goto spdyerror; + if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 8192)) goto spdyerror; + + uhttp.spdy3_settings_size = uhttp.spdy3_settings->pos; } #endif @@ -121,6 +134,12 @@ void uwsgi_opt_https2(char *opt, char *value, void *cr) { ugs->mode = UWSGI_HTTP_SSL; ucr->has_sockets++; + + return; + +spdyerror: + uwsgi_log("unable to inizialize SPDY settings buffers\n"); + exit(1); } @@ -219,32 +238,36 @@ int hr_https_add_vars(struct http_session *hr, struct uwsgi_buffer *out) { void hr_session_ssl_close(struct corerouter_session *cs) { hr_session_close(cs); - struct http_session *hs = (struct http_session *) cs; - SSL_shutdown(hs->ssl); - if (hs->ssl_client_dn) { - OPENSSL_free(hs->ssl_client_dn); + struct http_session *hr = (struct http_session *) cs; + SSL_shutdown(hr->ssl); + if (hr->ssl_client_dn) { + OPENSSL_free(hr->ssl_client_dn); } - if (hs->ssl_cc) { - free(hs->ssl_cc); + if (hr->ssl_cc) { + free(hr->ssl_cc); } - if (hs->ssl_bio) { - BIO_free(hs->ssl_bio); + if (hr->ssl_bio) { + BIO_free(hr->ssl_bio); } - if (hs->ssl_client_cert) { - X509_free(hs->ssl_client_cert); + if (hr->ssl_client_cert) { + X509_free(hr->ssl_client_cert); } - SSL_free(hs->ssl); + if (hr->spdy_ping) { + uwsgi_buffer_destroy(hr->spdy_ping); + } + + SSL_free(hr->ssl); } ssize_t hr_ssl_write(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; - struct http_session *hs = (struct http_session *) cs; + struct http_session *hr = (struct http_session *) cs; - int ret = SSL_write(hs->ssl, main_peer->out->buf + main_peer->out_pos, main_peer->out->pos - main_peer->out_pos); + int ret = SSL_write(hr->ssl, main_peer->out->buf + main_peer->out_pos, main_peer->out->pos - main_peer->out_pos); if (ret > 0) { main_peer->out_pos += ret; if (main_peer->out->pos == main_peer->out_pos) { @@ -255,7 +278,7 @@ ssize_t hr_ssl_write(struct corerouter_peer *main_peer) { return ret; } if (ret == 0) return 0; - int err = SSL_get_error(hs->ssl, ret); + int err = SSL_get_error(hr->ssl, ret); if (err == SSL_ERROR_WANT_READ) { cr_reset_hooks_and_read(main_peer, hr_ssl_write); @@ -280,36 +303,36 @@ ssize_t hr_ssl_write(struct corerouter_peer *main_peer) { ssize_t hr_ssl_read(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; - struct http_session *hs = (struct http_session *) cs; + struct http_session *hr = (struct http_session *) cs; // try to always leave 4k available if (uwsgi_buffer_ensure(main_peer->in, uwsgi.page_size)) return -1; - int ret = SSL_read(hs->ssl, main_peer->in->buf + main_peer->in->pos, main_peer->in->len - main_peer->in->pos); + int ret = SSL_read(hr->ssl, main_peer->in->buf + main_peer->in->pos, main_peer->in->len - main_peer->in->pos); if (ret > 0) { // fix the buffer main_peer->in->pos += ret; // check for pending data - int ret2 = SSL_pending(hs->ssl); + int ret2 = SSL_pending(hr->ssl); if (ret2 > 0) { if (uwsgi_buffer_fix(main_peer->in, main_peer->in->len + ret2 )) { uwsgi_log("[uwsgi-https] cannot fix the buffer to %d\n", main_peer->in->len + ret2); return -1; } - if (SSL_read(hs->ssl, main_peer->in->buf + main_peer->in->pos, ret2) != ret2) { + if (SSL_read(hr->ssl, main_peer->in->buf + main_peer->in->pos, ret2) != ret2) { uwsgi_log("[uwsgi-https] SSL_read() on %d bytes of pending data failed\n", ret2); return -1; } // fix the buffer main_peer->in->pos += ret2; } - if (hs->spdy) { + if (hr->spdy) { uwsgi_log("RUNNING THE SPDY PARSER FOR %d bytes\n", main_peer->in->pos); return spdy_parse(main_peer); } return http_parse(main_peer); } if (ret == 0) return 0; - int err = SSL_get_error(hs->ssl, ret); + int err = SSL_get_error(hr->ssl, ret); if (err == SSL_ERROR_WANT_READ) { cr_reset_hooks_and_read(main_peer, hr_ssl_read); diff --git a/plugins/http/spdy3.c b/plugins/http/spdy3.c index ba2a10e7..4a56ec0e 100644 --- a/plugins/http/spdy3.c +++ b/plugins/http/spdy3.c @@ -519,6 +519,19 @@ ssize_t spdy_manage_rst_stream(struct http_session *hr) { 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; +} + /* @@ -566,7 +579,11 @@ ssize_t spdy_parse(struct corerouter_peer *main_peer) { hr->spdy_phase = UWSGI_SPDY_PHASE_HEADER; hr->spdy_need = 8; - uwsgi_log("SPDY %d INITIALIZED\n", hr->spdy); + 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; } @@ -616,7 +633,12 @@ ssize_t spdy_parse(struct corerouter_peer *main_peer) { if (ret == 0) goto goon; goto newframe; case 4: - //uwsgi_log("settings request...\n"); + uwsgi_log("settings request...\n"); + break; + case 6: + ret = spdy_manage_ping(hr); + if (ret == 0) goto goon; + goto newframe; break; default: uwsgi_log("i do not know how to manage type %u\n", hr->spdy_control_type); diff --git a/uwsgi.h b/uwsgi.h index 9914de3c..731e4de8 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -3541,6 +3541,7 @@ int uwsgi_buffer_byte(struct uwsgi_buffer *, char); int uwsgi_buffer_u16le(struct uwsgi_buffer *, uint16_t); int uwsgi_buffer_u16be(struct uwsgi_buffer *, uint16_t); int uwsgi_buffer_u32be(struct uwsgi_buffer *, uint32_t); +int uwsgi_buffer_u24be(struct uwsgi_buffer *, uint32_t); int uwsgi_buffer_u64be(struct uwsgi_buffer *, uint64_t); int uwsgi_buffer_num64(struct uwsgi_buffer *, int64_t); int uwsgi_buffer_append_keyval(struct uwsgi_buffer *, char *, uint16_t, char *, uint16_t);