The HTTP/2 implementation (RFC 7240, 7241).

The SPDY support is removed, as it's incompatible with the new module.
This commit is contained in:
Valentin Bartenev 2015-09-11 20:13:06 +03:00
parent 1119b74df7
commit 02f6fb29a2
26 changed files with 9250 additions and 5701 deletions

View file

@ -7,7 +7,7 @@ echo "creating $NGX_MAKEFILE"
mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \
$NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \
$NGX_OBJS/src/http $NGX_OBJS/src/http/modules \
$NGX_OBJS/src/http $NGX_OBJS/src/http/v2 $NGX_OBJS/src/http/modules \
$NGX_OBJS/src/http/modules/perl \
$NGX_OBJS/src/mail \
$NGX_OBJS/src/stream \

View file

@ -94,7 +94,7 @@ fi
# ngx_http_write_filter
# ngx_http_header_filter
# ngx_http_chunked_filter
# ngx_http_spdy_filter
# ngx_http_v2_filter
# ngx_http_range_header_filter
# ngx_http_gzip_filter
# ngx_http_postpone_filter
@ -115,8 +115,8 @@ HTTP_FILTER_MODULES="$HTTP_WRITE_FILTER_MODULE \
$HTTP_HEADER_FILTER_MODULE \
$HTTP_CHUNKED_FILTER_MODULE"
if [ $HTTP_SPDY = YES ]; then
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SPDY_FILTER_MODULE"
if [ $HTTP_V2 = YES ]; then
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_V2_FILTER_MODULE"
fi
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_RANGE_HEADER_FILTER_MODULE"
@ -180,12 +180,12 @@ if [ $HTTP_USERID = YES ]; then
fi
if [ $HTTP_SPDY = YES ]; then
have=NGX_HTTP_SPDY . auto/have
USE_ZLIB=YES
HTTP_MODULES="$HTTP_MODULES $HTTP_SPDY_MODULE"
HTTP_DEPS="$HTTP_DEPS $HTTP_SPDY_DEPS"
HTTP_SRCS="$HTTP_SRCS $HTTP_SPDY_SRCS"
if [ $HTTP_V2 = YES ]; then
have=NGX_HTTP_V2 . auto/have
HTTP_MODULES="$HTTP_MODULES $HTTP_V2_MODULE"
HTTP_INCS="$HTTP_INCS $HTTP_V2_INCS"
HTTP_DEPS="$HTTP_DEPS $HTTP_V2_DEPS"
HTTP_SRCS="$HTTP_SRCS $HTTP_V2_SRCS"
fi
HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE"

View file

@ -58,7 +58,7 @@ HTTP_CACHE=YES
HTTP_CHARSET=YES
HTTP_GZIP=YES
HTTP_SSL=NO
HTTP_SPDY=NO
HTTP_V2=NO
HTTP_SSI=YES
HTTP_POSTPONE=NO
HTTP_REALIP=NO
@ -210,7 +210,7 @@ do
--http-scgi-temp-path=*) NGX_HTTP_SCGI_TEMP_PATH="$value" ;;
--with-http_ssl_module) HTTP_SSL=YES ;;
--with-http_spdy_module) HTTP_SPDY=YES ;;
--with-http_v2_module) HTTP_V2=YES ;;
--with-http_realip_module) HTTP_REALIP=YES ;;
--with-http_addition_module) HTTP_ADDITION=YES ;;
--with-http_xslt_module) HTTP_XSLT=YES ;;
@ -378,7 +378,7 @@ cat << END
--with-ipv6 enable IPv6 support
--with-http_ssl_module enable ngx_http_ssl_module
--with-http_spdy_module enable ngx_http_spdy_module
--with-http_v2_module enable ngx_http_v2_module
--with-http_realip_module enable ngx_http_realip_module
--with-http_addition_module enable ngx_http_addition_module
--with-http_xslt_module enable ngx_http_xslt_module

View file

@ -317,13 +317,17 @@ HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c
HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c
HTTP_SPDY_MODULE=ngx_http_spdy_module
HTTP_SPDY_FILTER_MODULE=ngx_http_spdy_filter_module
HTTP_SPDY_DEPS="src/http/ngx_http_spdy.h \
src/http/ngx_http_spdy_module.h"
HTTP_SPDY_SRCS="src/http/ngx_http_spdy.c \
src/http/ngx_http_spdy_module.c \
src/http/ngx_http_spdy_filter_module.c"
HTTP_V2_MODULE=ngx_http_v2_module
HTTP_V2_FILTER_MODULE=ngx_http_v2_filter_module
HTTP_V2_INCS="src/http/v2"
HTTP_V2_DEPS="src/http/v2/ngx_http_v2.h \
src/http/v2/ngx_http_v2_module.h"
HTTP_V2_SRCS="src/http/v2/ngx_http_v2.c \
src/http/v2/ngx_http_v2_table.c \
src/http/v2/ngx_http_v2_huff_decode.c \
src/http/v2/ngx_http_v2_huff_encode.c \
src/http/v2/ngx_http_v2_module.c \
src/http/v2/ngx_http_v2_filter_module.c"
HTTP_CHARSET_FILTER_MODULE=ngx_http_charset_filter_module

View file

@ -118,7 +118,7 @@ typedef enum {
#define NGX_LOWLEVEL_BUFFERED 0x0f
#define NGX_SSL_BUFFERED 0x01
#define NGX_SPDY_BUFFERED 0x02
#define NGX_HTTP_V2_BUFFERED 0x02
struct ngx_connection_s {

View file

@ -326,10 +326,10 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
#if (NGX_DEBUG)
unsigned int i;
#endif
#if (NGX_HTTP_SPDY)
#if (NGX_HTTP_V2)
ngx_http_connection_t *hc;
#endif
#if (NGX_HTTP_SPDY || NGX_DEBUG)
#if (NGX_HTTP_V2 || NGX_DEBUG)
ngx_connection_t *c;
c = ngx_ssl_get_connection(ssl_conn);
@ -342,12 +342,13 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
}
#endif
#if (NGX_HTTP_SPDY)
#if (NGX_HTTP_V2)
hc = c->data;
if (hc->addr_conf->spdy) {
srv = (unsigned char *) NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE;
srvlen = sizeof(NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1;
if (hc->addr_conf->http2) {
srv =
(unsigned char *) NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE;
srvlen = sizeof(NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1;
} else
#endif
@ -378,22 +379,23 @@ static int
ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn,
const unsigned char **out, unsigned int *outlen, void *arg)
{
#if (NGX_HTTP_SPDY || NGX_DEBUG)
#if (NGX_HTTP_V2 || NGX_DEBUG)
ngx_connection_t *c;
c = ngx_ssl_get_connection(ssl_conn);
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL NPN advertised");
#endif
#if (NGX_HTTP_SPDY)
#if (NGX_HTTP_V2)
{
ngx_http_connection_t *hc;
hc = c->data;
if (hc->addr_conf->spdy) {
*out = (unsigned char *) NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE;
*outlen = sizeof(NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1;
if (hc->addr_conf->http2) {
*out =
(unsigned char *) NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE;
*outlen = sizeof(NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1;
return SSL_TLSEXT_ERR_OK;
}

View file

@ -1233,8 +1233,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
#if (NGX_HTTP_SSL)
ngx_uint_t ssl;
#endif
#if (NGX_HTTP_SPDY)
ngx_uint_t spdy;
#if (NGX_HTTP_V2)
ngx_uint_t http2;
#endif
/*
@ -1290,8 +1290,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
#if (NGX_HTTP_SSL)
ssl = lsopt->ssl || addr[i].opt.ssl;
#endif
#if (NGX_HTTP_SPDY)
spdy = lsopt->spdy || addr[i].opt.spdy;
#if (NGX_HTTP_V2)
http2 = lsopt->http2 || addr[i].opt.http2;
#endif
if (lsopt->set) {
@ -1324,8 +1324,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
#if (NGX_HTTP_SSL)
addr[i].opt.ssl = ssl;
#endif
#if (NGX_HTTP_SPDY)
addr[i].opt.spdy = spdy;
#if (NGX_HTTP_V2)
addr[i].opt.http2 = http2;
#endif
return NGX_OK;
@ -1357,14 +1357,17 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
}
}
#if (NGX_HTTP_SPDY && NGX_HTTP_SSL \
#if (NGX_HTTP_V2 && NGX_HTTP_SSL \
&& !defined TLSEXT_TYPE_application_layer_protocol_negotiation \
&& !defined TLSEXT_TYPE_next_proto_neg)
if (lsopt->spdy && lsopt->ssl) {
if (lsopt->http2 && lsopt->ssl) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"nginx was built without OpenSSL ALPN or NPN "
"support, SPDY is not enabled for %s", lsopt->addr);
"nginx was built with OpenSSL that lacks ALPN "
"and NPN support, HTTP/2 is not enabled for %s",
lsopt->addr);
}
#endif
addr = ngx_array_push(&port->addrs);
@ -1856,8 +1859,8 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
#if (NGX_HTTP_SSL)
addrs[i].conf.ssl = addr[i].opt.ssl;
#endif
#if (NGX_HTTP_SPDY)
addrs[i].conf.spdy = addr[i].opt.spdy;
#if (NGX_HTTP_V2)
addrs[i].conf.http2 = addr[i].opt.http2;
#endif
addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
@ -1921,8 +1924,8 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
#if (NGX_HTTP_SSL)
addrs6[i].conf.ssl = addr[i].opt.ssl;
#endif
#if (NGX_HTTP_SPDY)
addrs6[i].conf.spdy = addr[i].opt.spdy;
#if (NGX_HTTP_V2)
addrs6[i].conf.http2 = addr[i].opt.http2;
#endif
if (addr[i].hash.buckets == NULL

View file

@ -20,8 +20,8 @@ typedef struct ngx_http_file_cache_s ngx_http_file_cache_t;
typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t;
typedef struct ngx_http_chunked_s ngx_http_chunked_t;
#if (NGX_HTTP_SPDY)
typedef struct ngx_http_spdy_stream_s ngx_http_spdy_stream_t;
#if (NGX_HTTP_V2)
typedef struct ngx_http_v2_stream_s ngx_http_v2_stream_t;
#endif
typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r,
@ -38,8 +38,8 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r,
#include <ngx_http_upstream_round_robin.h>
#include <ngx_http_core_module.h>
#if (NGX_HTTP_SPDY)
#include <ngx_http_spdy.h>
#if (NGX_HTTP_V2)
#include <ngx_http_v2.h>
#endif
#if (NGX_HTTP_CACHE)
#include <ngx_http_cache.h>

View file

@ -2132,13 +2132,6 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
return NGX_DECLINED;
}
#if (NGX_HTTP_SPDY)
if (r->spdy_stream) {
r->gzip_ok = 1;
return NGX_OK;
}
#endif
ae = r->headers_in.accept_encoding;
if (ae == NULL) {
return NGX_DECLINED;
@ -2480,8 +2473,8 @@ ngx_http_subrequest(ngx_http_request_t *r,
sr->request_body = r->request_body;
#if (NGX_HTTP_SPDY)
sr->spdy_stream = r->spdy_stream;
#if (NGX_HTTP_V2)
sr->stream = r->stream;
#endif
sr->method = NGX_HTTP_GET;
@ -4203,18 +4196,26 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#endif
}
if (ngx_strcmp(value[n].data, "spdy") == 0) {
#if (NGX_HTTP_SPDY)
lsopt.spdy = 1;
if (ngx_strcmp(value[n].data, "http2") == 0) {
#if (NGX_HTTP_V2)
lsopt.http2 = 1;
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"spdy\" parameter requires "
"ngx_http_spdy_module");
"the \"http2\" parameter requires "
"ngx_http_v2_module");
return NGX_CONF_ERROR;
#endif
}
if (ngx_strcmp(value[n].data, "spdy") == 0) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"invalid parameter \"spdy\": "
"ngx_http_spdy_module was superseded "
"by ngx_http_v2_module");
continue;
}
if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) {
if (ngx_strcmp(&value[n].data[13], "on") == 0) {

View file

@ -79,8 +79,8 @@ typedef struct {
#if (NGX_HTTP_SSL)
unsigned ssl:1;
#endif
#if (NGX_HTTP_SPDY)
unsigned spdy:1;
#if (NGX_HTTP_V2)
unsigned http2:1;
#endif
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:1;
@ -248,8 +248,8 @@ struct ngx_http_addr_conf_s {
#if (NGX_HTTP_SSL)
unsigned ssl:1;
#endif
#if (NGX_HTTP_SPDY)
unsigned spdy:1;
#if (NGX_HTTP_V2)
unsigned http2:1;
#endif
unsigned proxy_protocol:1;
};

View file

@ -312,9 +312,9 @@ ngx_http_init_connection(ngx_connection_t *c)
rev->handler = ngx_http_wait_request_handler;
c->write->handler = ngx_http_empty_handler;
#if (NGX_HTTP_SPDY)
if (hc->addr_conf->spdy) {
rev->handler = ngx_http_spdy_init;
#if (NGX_HTTP_V2)
if (hc->addr_conf->http2) {
rev->handler = ngx_http_v2_init;
}
#endif
@ -764,13 +764,12 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
c->ssl->no_wait_shutdown = 1;
#if (NGX_HTTP_SPDY \
#if (NGX_HTTP_V2 \
&& (defined TLSEXT_TYPE_application_layer_protocol_negotiation \
|| defined TLSEXT_TYPE_next_proto_neg))
{
unsigned int len;
const unsigned char *data;
static const ngx_str_t spdy = ngx_string(NGX_SPDY_NPN_NEGOTIATED);
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
SSL_get0_alpn_selected(c->ssl->connection, &data, &len);
@ -785,8 +784,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
#endif
if (len == spdy.len && ngx_strncmp(data, spdy.data, spdy.len) == 0) {
ngx_http_spdy_init(c->read);
if (len == 2 && data[0] == 'h' && data[1] == '2') {
ngx_http_v2_init(c->read);
return;
}
}
@ -2499,8 +2498,8 @@ ngx_http_finalize_connection(ngx_http_request_t *r)
{
ngx_http_core_loc_conf_t *clcf;
#if (NGX_HTTP_SPDY)
if (r->spdy_stream) {
#if (NGX_HTTP_V2)
if (r->stream) {
ngx_http_close_request(r, 0);
return;
}
@ -2565,8 +2564,8 @@ ngx_http_set_write_handler(ngx_http_request_t *r)
ngx_http_test_reading;
r->write_event_handler = ngx_http_writer;
#if (NGX_HTTP_SPDY)
if (r->spdy_stream) {
#if (NGX_HTTP_V2)
if (r->stream) {
return NGX_OK;
}
#endif
@ -2656,8 +2655,8 @@ ngx_http_writer(ngx_http_request_t *r)
if (r->buffered || r->postponed || (r == r->main && c->buffered)) {
#if (NGX_HTTP_SPDY)
if (r->spdy_stream) {
#if (NGX_HTTP_V2)
if (r->stream) {
return;
}
#endif
@ -2724,9 +2723,9 @@ ngx_http_test_reading(ngx_http_request_t *r)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http test reading");
#if (NGX_HTTP_SPDY)
#if (NGX_HTTP_V2)
if (r->spdy_stream) {
if (r->stream) {
if (c->error) {
err = 0;
goto closed;
@ -3399,9 +3398,9 @@ ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
return;
}
#if (NGX_HTTP_SPDY)
if (r->spdy_stream) {
ngx_http_spdy_close_stream(r->spdy_stream, rc);
#if (NGX_HTTP_V2)
if (r->stream) {
ngx_http_v2_close_stream(r->stream, rc);
return;
}
#endif

View file

@ -23,6 +23,7 @@
#define NGX_HTTP_VERSION_9 9
#define NGX_HTTP_VERSION_10 1000
#define NGX_HTTP_VERSION_11 1001
#define NGX_HTTP_VERSION_20 2000
#define NGX_HTTP_UNKNOWN 0x0001
#define NGX_HTTP_GET 0x0002
@ -431,8 +432,8 @@ struct ngx_http_request_s {
ngx_uint_t err_status;
ngx_http_connection_t *http_connection;
#if (NGX_HTTP_SPDY)
ngx_http_spdy_stream_t *spdy_stream;
#if (NGX_HTTP_V2)
ngx_http_v2_stream_t *stream;
#endif
ngx_http_log_handler_pt log_handler;

View file

@ -40,10 +40,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
r->main->count++;
#if (NGX_HTTP_SPDY)
if (r->spdy_stream && r == r->main) {
#if (NGX_HTTP_V2)
if (r->stream && r == r->main) {
r->request_body_no_buffering = 0;
rc = ngx_http_spdy_read_request_body(r, post_handler);
rc = ngx_http_v2_read_request_body(r, post_handler);
goto done;
}
#endif
@ -570,9 +570,9 @@ ngx_http_discard_request_body(ngx_http_request_t *r)
ngx_int_t rc;
ngx_event_t *rev;
#if (NGX_HTTP_SPDY)
if (r->spdy_stream && r == r->main) {
r->spdy_stream->skip_data = NGX_SPDY_DATA_DISCARD;
#if (NGX_HTTP_V2)
if (r->stream && r == r->main) {
r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD;
return NGX_OK;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,261 +0,0 @@
/*
* Copyright (C) Nginx, Inc.
* Copyright (C) Valentin V. Bartenev
*/
#ifndef _NGX_HTTP_SPDY_H_INCLUDED_
#define _NGX_HTTP_SPDY_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <zlib.h>
#define NGX_SPDY_VERSION 3
#define NGX_SPDY_NPN_ADVERTISE "\x08spdy/3.1"
#define NGX_SPDY_NPN_NEGOTIATED "spdy/3.1"
#define NGX_SPDY_STATE_BUFFER_SIZE 16
#define NGX_SPDY_CTL_BIT 1
#define NGX_SPDY_SYN_STREAM 1
#define NGX_SPDY_SYN_REPLY 2
#define NGX_SPDY_RST_STREAM 3
#define NGX_SPDY_SETTINGS 4
#define NGX_SPDY_PING 6
#define NGX_SPDY_GOAWAY 7
#define NGX_SPDY_HEADERS 8
#define NGX_SPDY_WINDOW_UPDATE 9
#define NGX_SPDY_FRAME_HEADER_SIZE 8
#define NGX_SPDY_SID_SIZE 4
#define NGX_SPDY_DELTA_SIZE 4
#define NGX_SPDY_SYN_STREAM_SIZE 10
#define NGX_SPDY_SYN_REPLY_SIZE 4
#define NGX_SPDY_RST_STREAM_SIZE 8
#define NGX_SPDY_PING_SIZE 4
#define NGX_SPDY_GOAWAY_SIZE 8
#define NGX_SPDY_WINDOW_UPDATE_SIZE 8
#define NGX_SPDY_NV_NUM_SIZE 4
#define NGX_SPDY_NV_NLEN_SIZE 4
#define NGX_SPDY_NV_VLEN_SIZE 4
#define NGX_SPDY_SETTINGS_NUM_SIZE 4
#define NGX_SPDY_SETTINGS_FID_SIZE 4
#define NGX_SPDY_SETTINGS_VAL_SIZE 4
#define NGX_SPDY_SETTINGS_PAIR_SIZE \
(NGX_SPDY_SETTINGS_FID_SIZE + NGX_SPDY_SETTINGS_VAL_SIZE)
#define NGX_SPDY_HIGHEST_PRIORITY 0
#define NGX_SPDY_LOWEST_PRIORITY 7
#define NGX_SPDY_FLAG_FIN 0x01
#define NGX_SPDY_FLAG_UNIDIRECTIONAL 0x02
#define NGX_SPDY_FLAG_CLEAR_SETTINGS 0x01
#define NGX_SPDY_MAX_FRAME_SIZE ((1 << 24) - 1)
#define NGX_SPDY_DATA_DISCARD 1
#define NGX_SPDY_DATA_ERROR 2
#define NGX_SPDY_DATA_INTERNAL_ERROR 3
typedef struct ngx_http_spdy_connection_s ngx_http_spdy_connection_t;
typedef struct ngx_http_spdy_out_frame_s ngx_http_spdy_out_frame_t;
typedef u_char *(*ngx_http_spdy_handler_pt) (ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
struct ngx_http_spdy_connection_s {
ngx_connection_t *connection;
ngx_http_connection_t *http_connection;
ngx_uint_t processing;
size_t send_window;
size_t recv_window;
size_t init_window;
ngx_queue_t waiting;
u_char buffer[NGX_SPDY_STATE_BUFFER_SIZE];
size_t buffer_used;
ngx_http_spdy_handler_pt handler;
z_stream zstream_in;
z_stream zstream_out;
ngx_pool_t *pool;
ngx_http_spdy_out_frame_t *free_ctl_frames;
ngx_connection_t *free_fake_connections;
ngx_http_spdy_stream_t **streams_index;
ngx_http_spdy_out_frame_t *last_out;
ngx_queue_t posted;
ngx_http_spdy_stream_t *stream;
ngx_uint_t entries;
size_t length;
u_char flags;
ngx_uint_t last_sid;
unsigned blocked:1;
unsigned incomplete:1;
};
struct ngx_http_spdy_stream_s {
ngx_uint_t id;
ngx_http_request_t *request;
ngx_http_spdy_connection_t *connection;
ngx_http_spdy_stream_t *index;
ngx_uint_t header_buffers;
ngx_uint_t queued;
/*
* A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the
* send_window to become negative, hence it's signed.
*/
ssize_t send_window;
size_t recv_window;
ngx_http_spdy_out_frame_t *free_frames;
ngx_chain_t *free_data_headers;
ngx_chain_t *free_bufs;
ngx_queue_t queue;
unsigned priority:3;
unsigned handled:1;
unsigned blocked:1;
unsigned exhausted:1;
unsigned in_closed:1;
unsigned out_closed:1;
unsigned skip_data:2;
};
struct ngx_http_spdy_out_frame_s {
ngx_http_spdy_out_frame_t *next;
ngx_chain_t *first;
ngx_chain_t *last;
ngx_int_t (*handler)(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame);
ngx_http_spdy_stream_t *stream;
size_t length;
ngx_uint_t priority;
unsigned blocked:1;
unsigned fin:1;
};
static ngx_inline void
ngx_http_spdy_queue_frame(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame)
{
ngx_http_spdy_out_frame_t **out;
for (out = &sc->last_out; *out; out = &(*out)->next)
{
/*
* NB: higher values represent lower priorities.
*/
if (frame->priority >= (*out)->priority) {
break;
}
}
frame->next = *out;
*out = frame;
}
static ngx_inline void
ngx_http_spdy_queue_blocked_frame(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame)
{
ngx_http_spdy_out_frame_t **out;
for (out = &sc->last_out; *out; out = &(*out)->next)
{
if ((*out)->blocked) {
break;
}
}
frame->next = *out;
*out = frame;
}
void ngx_http_spdy_init(ngx_event_t *rev);
void ngx_http_spdy_request_headers_init(void);
ngx_int_t ngx_http_spdy_read_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler);
void ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc);
ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc);
#define ngx_spdy_frame_aligned_write_uint16(p, s) \
(*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))
#define ngx_spdy_frame_aligned_write_uint32(p, s) \
(*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t))
#if (NGX_HAVE_NONALIGNED)
#define ngx_spdy_frame_write_uint16 ngx_spdy_frame_aligned_write_uint16
#define ngx_spdy_frame_write_uint32 ngx_spdy_frame_aligned_write_uint32
#else
#define ngx_spdy_frame_write_uint16(p, s) \
((p)[0] = (u_char) ((s) >> 8), \
(p)[1] = (u_char) (s), \
(p) + sizeof(uint16_t))
#define ngx_spdy_frame_write_uint32(p, s) \
((p)[0] = (u_char) ((s) >> 24), \
(p)[1] = (u_char) ((s) >> 16), \
(p)[2] = (u_char) ((s) >> 8), \
(p)[3] = (u_char) (s), \
(p) + sizeof(uint32_t))
#endif
#define ngx_spdy_ctl_frame_head(t) \
((uint32_t) NGX_SPDY_CTL_BIT << 31 | NGX_SPDY_VERSION << 16 | (t))
#define ngx_spdy_frame_write_head(p, t) \
ngx_spdy_frame_aligned_write_uint32(p, ngx_spdy_ctl_frame_head(t))
#define ngx_spdy_frame_write_flags_and_len(p, f, l) \
ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (l))
#define ngx_spdy_frame_write_flags_and_id(p, f, i) \
ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (i))
#define ngx_spdy_frame_write_sid ngx_spdy_frame_aligned_write_uint32
#define ngx_spdy_frame_write_window ngx_spdy_frame_aligned_write_uint32
#endif /* _NGX_HTTP_SPDY_H_INCLUDED_ */

File diff suppressed because it is too large Load diff

View file

@ -1,408 +0,0 @@
/*
* Copyright (C) Nginx, Inc.
* Copyright (C) Valentin V. Bartenev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_http_spdy_module.h>
static ngx_int_t ngx_http_spdy_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_spdy_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_spdy_request_priority_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_spdy_module_init(ngx_cycle_t *cycle);
static void *ngx_http_spdy_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf);
static void *ngx_http_spdy_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
static void *ngx_http_spdy_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
static char *ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post,
void *data);
static char *ngx_http_spdy_pool_size(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post,
void *data);
static char *ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data);
static ngx_conf_num_bounds_t ngx_http_spdy_headers_comp_bounds = {
ngx_conf_check_num_bounds, 0, 9
};
static ngx_conf_post_t ngx_http_spdy_recv_buffer_size_post =
{ ngx_http_spdy_recv_buffer_size };
static ngx_conf_post_t ngx_http_spdy_pool_size_post =
{ ngx_http_spdy_pool_size };
static ngx_conf_post_t ngx_http_spdy_streams_index_mask_post =
{ ngx_http_spdy_streams_index_mask };
static ngx_conf_post_t ngx_http_spdy_chunk_size_post =
{ ngx_http_spdy_chunk_size };
static ngx_command_t ngx_http_spdy_commands[] = {
{ ngx_string("spdy_recv_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof(ngx_http_spdy_main_conf_t, recv_buffer_size),
&ngx_http_spdy_recv_buffer_size_post },
{ ngx_string("spdy_pool_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_spdy_srv_conf_t, pool_size),
&ngx_http_spdy_pool_size_post },
{ ngx_string("spdy_max_concurrent_streams"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_spdy_srv_conf_t, concurrent_streams),
NULL },
{ ngx_string("spdy_streams_index_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_spdy_srv_conf_t, streams_index_mask),
&ngx_http_spdy_streams_index_mask_post },
{ ngx_string("spdy_recv_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_spdy_srv_conf_t, recv_timeout),
NULL },
{ ngx_string("spdy_keepalive_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_spdy_srv_conf_t, keepalive_timeout),
NULL },
{ ngx_string("spdy_headers_comp"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_spdy_srv_conf_t, headers_comp),
&ngx_http_spdy_headers_comp_bounds },
{ ngx_string("spdy_chunk_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_spdy_loc_conf_t, chunk_size),
&ngx_http_spdy_chunk_size_post },
ngx_null_command
};
static ngx_http_module_t ngx_http_spdy_module_ctx = {
ngx_http_spdy_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
ngx_http_spdy_create_main_conf, /* create main configuration */
ngx_http_spdy_init_main_conf, /* init main configuration */
ngx_http_spdy_create_srv_conf, /* create server configuration */
ngx_http_spdy_merge_srv_conf, /* merge server configuration */
ngx_http_spdy_create_loc_conf, /* create location configuration */
ngx_http_spdy_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_spdy_module = {
NGX_MODULE_V1,
&ngx_http_spdy_module_ctx, /* module context */
ngx_http_spdy_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
ngx_http_spdy_module_init, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_variable_t ngx_http_spdy_vars[] = {
{ ngx_string("spdy"), NULL,
ngx_http_spdy_variable, 0, 0, 0 },
{ ngx_string("spdy_request_priority"), NULL,
ngx_http_spdy_request_priority_variable, 0, 0, 0 },
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
static ngx_int_t
ngx_http_spdy_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var, *v;
for (v = ngx_http_spdy_vars; v->name.len; v++) {
var = ngx_http_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_spdy_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->spdy_stream) {
v->len = sizeof("3.1") - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "3.1";
return NGX_OK;
}
*v = ngx_http_variable_null_value;
return NGX_OK;
}
static ngx_int_t
ngx_http_spdy_request_priority_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->spdy_stream) {
v->len = 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = ngx_pnalloc(r->pool, 1);
if (v->data == NULL) {
return NGX_ERROR;
}
v->data[0] = '0' + (u_char) r->spdy_stream->priority;
return NGX_OK;
}
*v = ngx_http_variable_null_value;
return NGX_OK;
}
static ngx_int_t
ngx_http_spdy_module_init(ngx_cycle_t *cycle)
{
ngx_http_spdy_request_headers_init();
return NGX_OK;
}
static void *
ngx_http_spdy_create_main_conf(ngx_conf_t *cf)
{
ngx_http_spdy_main_conf_t *smcf;
smcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_main_conf_t));
if (smcf == NULL) {
return NULL;
}
smcf->recv_buffer_size = NGX_CONF_UNSET_SIZE;
return smcf;
}
static char *
ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_spdy_main_conf_t *smcf = conf;
ngx_conf_init_size_value(smcf->recv_buffer_size, 256 * 1024);
return NGX_CONF_OK;
}
static void *
ngx_http_spdy_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_spdy_srv_conf_t *sscf;
sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_srv_conf_t));
if (sscf == NULL) {
return NULL;
}
sscf->pool_size = NGX_CONF_UNSET_SIZE;
sscf->concurrent_streams = NGX_CONF_UNSET_UINT;
sscf->streams_index_mask = NGX_CONF_UNSET_UINT;
sscf->recv_timeout = NGX_CONF_UNSET_MSEC;
sscf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
sscf->headers_comp = NGX_CONF_UNSET;
return sscf;
}
static char *
ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_spdy_srv_conf_t *prev = parent;
ngx_http_spdy_srv_conf_t *conf = child;
ngx_conf_merge_size_value(conf->pool_size, prev->pool_size, 4096);
ngx_conf_merge_uint_value(conf->concurrent_streams,
prev->concurrent_streams, 100);
ngx_conf_merge_uint_value(conf->streams_index_mask,
prev->streams_index_mask, 32 - 1);
ngx_conf_merge_msec_value(conf->recv_timeout,
prev->recv_timeout, 30000);
ngx_conf_merge_msec_value(conf->keepalive_timeout,
prev->keepalive_timeout, 180000);
ngx_conf_merge_value(conf->headers_comp, prev->headers_comp, 0);
return NGX_CONF_OK;
}
static void *
ngx_http_spdy_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_spdy_loc_conf_t *slcf;
slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_loc_conf_t));
if (slcf == NULL) {
return NULL;
}
slcf->chunk_size = NGX_CONF_UNSET_SIZE;
return slcf;
}
static char *
ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_spdy_loc_conf_t *prev = parent;
ngx_http_spdy_loc_conf_t *conf = child;
ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024);
return NGX_CONF_OK;
}
static char *
ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
if (*sp <= 2 * NGX_SPDY_STATE_BUFFER_SIZE) {
return "value is too small";
}
return NGX_CONF_OK;
}
static char *
ngx_http_spdy_pool_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
if (*sp < NGX_MIN_POOL_SIZE) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the pool size must be no less than %uz",
NGX_MIN_POOL_SIZE);
return NGX_CONF_ERROR;
}
if (*sp % NGX_POOL_ALIGNMENT) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the pool size must be a multiple of %uz",
NGX_POOL_ALIGNMENT);
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post, void *data)
{
ngx_uint_t *np = data;
ngx_uint_t mask;
mask = *np - 1;
if (*np == 0 || (*np & mask)) {
return "must be a power of two";
}
*np = mask;
return NGX_CONF_OK;
}
static char *
ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
if (*sp == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the spdy chunk size cannot be zero");
return NGX_CONF_ERROR;
}
if (*sp > NGX_SPDY_MAX_FRAME_SIZE) {
*sp = NGX_SPDY_MAX_FRAME_SIZE;
}
return NGX_CONF_OK;
}

View file

@ -475,8 +475,8 @@ ngx_http_upstream_init(ngx_http_request_t *r)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http init upstream, client timer: %d", c->read->timer_set);
#if (NGX_HTTP_SPDY)
if (r->spdy_stream) {
#if (NGX_HTTP_V2)
if (r->stream) {
ngx_http_upstream_init_request(r);
return;
}
@ -1151,8 +1151,8 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
return;
}
#if (NGX_HTTP_SPDY)
if (r->spdy_stream) {
#if (NGX_HTTP_V2)
if (r->stream) {
return;
}
#endif

3964
src/http/v2/ngx_http_v2.c Normal file

File diff suppressed because it is too large Load diff

334
src/http/v2/ngx_http_v2.h Normal file
View file

@ -0,0 +1,334 @@
/*
* Copyright (C) Nginx, Inc.
* Copyright (C) Valentin V. Bartenev
*/
#ifndef _NGX_HTTP_V2_H_INCLUDED_
#define _NGX_HTTP_V2_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2"
#define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE
#define NGX_HTTP_V2_STATE_BUFFER_SIZE 16
#define NGX_HTTP_V2_MAX_FRAME_SIZE ((1 << 24) - 1)
#define NGX_HTTP_V2_INT_OCTETS 4
#define NGX_HTTP_V2_MAX_FIELD ((1 << NGX_HTTP_V2_INT_OCTETS * 7) - 1)
#define NGX_HTTP_V2_DATA_DISCARD 1
#define NGX_HTTP_V2_DATA_ERROR 2
#define NGX_HTTP_V2_DATA_INTERNAL_ERROR 3
#define NGX_HTTP_V2_FRAME_HEADER_SIZE 9
/* frame types */
#define NGX_HTTP_V2_DATA_FRAME 0x0
#define NGX_HTTP_V2_HEADERS_FRAME 0x1
#define NGX_HTTP_V2_PRIORITY_FRAME 0x2
#define NGX_HTTP_V2_RST_STREAM_FRAME 0x3
#define NGX_HTTP_V2_SETTINGS_FRAME 0x4
#define NGX_HTTP_V2_PUSH_PROMISE_FRAME 0x5
#define NGX_HTTP_V2_PING_FRAME 0x6
#define NGX_HTTP_V2_GOAWAY_FRAME 0x7
#define NGX_HTTP_V2_WINDOW_UPDATE_FRAME 0x8
#define NGX_HTTP_V2_CONTINUATION_FRAME 0x9
/* frame flags */
#define NGX_HTTP_V2_NO_FLAG 0x00
#define NGX_HTTP_V2_ACK_FLAG 0x01
#define NGX_HTTP_V2_END_STREAM_FLAG 0x01
#define NGX_HTTP_V2_END_HEADERS_FLAG 0x04
#define NGX_HTTP_V2_PADDED_FLAG 0x08
#define NGX_HTTP_V2_PRIORITY_FLAG 0x20
typedef struct ngx_http_v2_connection_s ngx_http_v2_connection_t;
typedef struct ngx_http_v2_node_s ngx_http_v2_node_t;
typedef struct ngx_http_v2_out_frame_s ngx_http_v2_out_frame_t;
typedef u_char *(*ngx_http_v2_handler_pt) (ngx_http_v2_connection_t *h2c,
u_char *pos, u_char *end);
typedef struct {
ngx_str_t name;
ngx_str_t value;
} ngx_http_v2_header_t;
typedef struct {
ngx_uint_t sid;
size_t length;
size_t padding;
unsigned flags:8;
unsigned incomplete:1;
/* HPACK */
unsigned parse_name:1;
unsigned parse_value:1;
unsigned index:1;
ngx_http_v2_header_t header;
size_t header_limit;
size_t field_limit;
u_char field_state;
u_char *field_start;
u_char *field_end;
size_t field_rest;
ngx_pool_t *pool;
ngx_http_v2_stream_t *stream;
u_char buffer[NGX_HTTP_V2_STATE_BUFFER_SIZE];
size_t buffer_used;
ngx_http_v2_handler_pt handler;
} ngx_http_v2_state_t;
typedef struct {
ngx_http_v2_header_t **entries;
ngx_uint_t added;
ngx_uint_t deleted;
ngx_uint_t reused;
ngx_uint_t allocated;
size_t size;
size_t free;
u_char *storage;
u_char *pos;
} ngx_http_v2_hpack_t;
struct ngx_http_v2_connection_s {
ngx_connection_t *connection;
ngx_http_connection_t *http_connection;
ngx_uint_t processing;
size_t send_window;
size_t recv_window;
size_t init_window;
size_t frame_size;
ngx_queue_t waiting;
ngx_http_v2_state_t state;
ngx_http_v2_hpack_t hpack;
ngx_pool_t *pool;
ngx_http_v2_out_frame_t *free_frames;
ngx_connection_t *free_fake_connections;
ngx_http_v2_node_t **streams_index;
ngx_http_v2_out_frame_t *last_out;
ngx_queue_t posted;
ngx_queue_t dependencies;
ngx_queue_t closed;
ngx_uint_t last_sid;
unsigned closed_nodes:8;
unsigned blocked:1;
};
struct ngx_http_v2_node_s {
ngx_uint_t id;
ngx_http_v2_node_t *index;
ngx_http_v2_node_t *parent;
ngx_queue_t queue;
ngx_queue_t children;
ngx_queue_t reuse;
ngx_uint_t rank;
ngx_uint_t weight;
double rel_weight;
ngx_http_v2_stream_t *stream;
};
struct ngx_http_v2_stream_s {
ngx_http_request_t *request;
ngx_http_v2_connection_t *connection;
ngx_http_v2_node_t *node;
ngx_uint_t header_buffers;
ngx_uint_t queued;
/*
* A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the
* send_window to become negative, hence it's signed.
*/
ssize_t send_window;
size_t recv_window;
ngx_http_v2_out_frame_t *free_frames;
ngx_chain_t *free_data_headers;
ngx_chain_t *free_bufs;
ngx_queue_t queue;
ngx_array_t *cookies;
size_t header_limit;
unsigned handled:1;
unsigned blocked:1;
unsigned exhausted:1;
unsigned end_headers:1;
unsigned in_closed:1;
unsigned out_closed:1;
unsigned skip_data:2;
};
struct ngx_http_v2_out_frame_s {
ngx_http_v2_out_frame_t *next;
ngx_chain_t *first;
ngx_chain_t *last;
ngx_int_t (*handler)(ngx_http_v2_connection_t *h2c,
ngx_http_v2_out_frame_t *frame);
ngx_http_v2_stream_t *stream;
size_t length;
unsigned blocked:1;
unsigned fin:1;
};
static ngx_inline void
ngx_http_v2_queue_frame(ngx_http_v2_connection_t *h2c,
ngx_http_v2_out_frame_t *frame)
{
ngx_http_v2_out_frame_t **out;
for (out = &h2c->last_out; *out; out = &(*out)->next) {
if ((*out)->blocked || (*out)->stream == NULL) {
break;
}
if ((*out)->stream->node->rank < frame->stream->node->rank
|| ((*out)->stream->node->rank == frame->stream->node->rank
&& (*out)->stream->node->rel_weight
>= frame->stream->node->rel_weight))
{
break;
}
}
frame->next = *out;
*out = frame;
}
static ngx_inline void
ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t *h2c,
ngx_http_v2_out_frame_t *frame)
{
ngx_http_v2_out_frame_t **out;
for (out = &h2c->last_out; *out; out = &(*out)->next)
{
if ((*out)->blocked || (*out)->stream == NULL) {
break;
}
}
frame->next = *out;
*out = frame;
}
void ngx_http_v2_init(ngx_event_t *rev);
void ngx_http_v2_request_headers_init(void);
ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler);
void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc);
ngx_int_t ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c);
ngx_int_t ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c,
ngx_uint_t index, ngx_uint_t name_only);
ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c,
ngx_http_v2_header_t *header);
ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size);
ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len,
u_char **dst, ngx_uint_t last, ngx_log_t *log);
#define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1)
#if (NGX_HAVE_NONALIGNED)
#define ngx_http_v2_parse_uint16(p) ntohs(*(uint16_t *) (p))
#define ngx_http_v2_parse_uint32(p) ntohl(*(uint32_t *) (p))
#else
#define ngx_http_v2_parse_uint16(p) ((p)[0] << 8 | (p)[1])
#define ngx_http_v2_parse_uint32(p) \
((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])
#endif
#define ngx_http_v2_parse_length(p) ((p) >> 8)
#define ngx_http_v2_parse_type(p) ((p) & 0xff)
#define ngx_http_v2_parse_sid(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff)
#define ngx_http_v2_parse_window(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff)
#define ngx_http_v2_write_uint16_aligned(p, s) \
(*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))
#define ngx_http_v2_write_uint32_aligned(p, s) \
(*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t))
#if (NGX_HAVE_NONALIGNED)
#define ngx_http_v2_write_uint16 ngx_http_v2_write_uint16_aligned
#define ngx_http_v2_write_uint32 ngx_http_v2_write_uint32_aligned
#else
#define ngx_http_v2_write_uint16(p, s) \
((p)[0] = (u_char) ((s) >> 8), \
(p)[1] = (u_char) (s), \
(p) + sizeof(uint16_t))
#define ngx_http_v2_write_uint32(p, s) \
((p)[0] = (u_char) ((s) >> 24), \
(p)[1] = (u_char) ((s) >> 16), \
(p)[2] = (u_char) ((s) >> 8), \
(p)[3] = (u_char) (s), \
(p) + sizeof(uint32_t))
#endif
#define ngx_http_v2_write_len_and_type(p, l, t) \
ngx_http_v2_write_uint32_aligned(p, (l) << 8 | (t))
#define ngx_http_v2_write_sid ngx_http_v2_write_uint32
#endif /* _NGX_HTTP_V2_H_INCLUDED_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
/*
* Copyright (C) Nginx, Inc.
* Copyright (C) Valentin V. Bartenev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

View file

@ -0,0 +1,469 @@
/*
* Copyright (C) Nginx, Inc.
* Copyright (C) Valentin V. Bartenev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_http_v2_module.h>
static ngx_int_t ngx_http_v2_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_v2_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_v2_module_init(ngx_cycle_t *cycle);
static void *ngx_http_v2_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_v2_init_main_conf(ngx_conf_t *cf, void *conf);
static void *ngx_http_v2_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
static void *ngx_http_v2_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post,
void *data);
static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post,
void *data);
static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post =
{ ngx_http_v2_recv_buffer_size };
static ngx_conf_post_t ngx_http_v2_pool_size_post =
{ ngx_http_v2_pool_size };
static ngx_conf_post_t ngx_http_v2_streams_index_mask_post =
{ ngx_http_v2_streams_index_mask };
static ngx_conf_post_t ngx_http_v2_chunk_size_post =
{ ngx_http_v2_chunk_size };
static ngx_command_t ngx_http_v2_commands[] = {
{ ngx_string("http2_recv_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof(ngx_http_v2_main_conf_t, recv_buffer_size),
&ngx_http_v2_recv_buffer_size_post },
{ ngx_string("http2_pool_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_v2_srv_conf_t, pool_size),
&ngx_http_v2_pool_size_post },
{ ngx_string("http2_max_concurrent_streams"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_v2_srv_conf_t, concurrent_streams),
NULL },
{ ngx_string("http2_max_field_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_v2_srv_conf_t, max_field_size),
NULL },
{ ngx_string("http2_max_header_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_v2_srv_conf_t, max_header_size),
NULL },
{ ngx_string("http2_streams_index_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_v2_srv_conf_t, streams_index_mask),
&ngx_http_v2_streams_index_mask_post },
{ ngx_string("http2_recv_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_v2_srv_conf_t, recv_timeout),
NULL },
{ ngx_string("http2_idle_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_v2_srv_conf_t, idle_timeout),
NULL },
{ ngx_string("http2_chunk_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_v2_loc_conf_t, chunk_size),
&ngx_http_v2_chunk_size_post },
{ ngx_string("spdy_recv_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_MAIN_CONF_OFFSET,
0,
NULL },
{ ngx_string("spdy_pool_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("spdy_max_concurrent_streams"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("spdy_streams_index_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("spdy_recv_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("spdy_keepalive_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("spdy_headers_comp"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("spdy_chunk_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_v2_module_ctx = {
ngx_http_v2_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
ngx_http_v2_create_main_conf, /* create main configuration */
ngx_http_v2_init_main_conf, /* init main configuration */
ngx_http_v2_create_srv_conf, /* create server configuration */
ngx_http_v2_merge_srv_conf, /* merge server configuration */
ngx_http_v2_create_loc_conf, /* create location configuration */
ngx_http_v2_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_v2_module = {
NGX_MODULE_V1,
&ngx_http_v2_module_ctx, /* module context */
ngx_http_v2_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
ngx_http_v2_module_init, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_variable_t ngx_http_v2_vars[] = {
{ ngx_string("http2"), NULL,
ngx_http_v2_variable, 0, 0, 0 },
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
static ngx_int_t
ngx_http_v2_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var, *v;
for (v = ngx_http_v2_vars; v->name.len; v++) {
var = ngx_http_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_v2_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->stream) {
#if (NGX_HTTP_SSL)
if (r->connection->ssl) {
v->len = sizeof("h2") - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "h2";
return NGX_OK;
}
#endif
v->len = sizeof("h2c") - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "h2c";
return NGX_OK;
}
*v = ngx_http_variable_null_value;
return NGX_OK;
}
static ngx_int_t
ngx_http_v2_module_init(ngx_cycle_t *cycle)
{
return NGX_OK;
}
static void *
ngx_http_v2_create_main_conf(ngx_conf_t *cf)
{
ngx_http_v2_main_conf_t *h2mcf;
h2mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_main_conf_t));
if (h2mcf == NULL) {
return NULL;
}
h2mcf->recv_buffer_size = NGX_CONF_UNSET_SIZE;
return h2mcf;
}
static char *
ngx_http_v2_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_v2_main_conf_t *h2mcf = conf;
ngx_conf_init_size_value(h2mcf->recv_buffer_size, 256 * 1024);
return NGX_CONF_OK;
}
static void *
ngx_http_v2_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_v2_srv_conf_t *h2scf;
h2scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_srv_conf_t));
if (h2scf == NULL) {
return NULL;
}
h2scf->pool_size = NGX_CONF_UNSET_SIZE;
h2scf->concurrent_streams = NGX_CONF_UNSET_UINT;
h2scf->max_field_size = NGX_CONF_UNSET_SIZE;
h2scf->max_header_size = NGX_CONF_UNSET_SIZE;
h2scf->streams_index_mask = NGX_CONF_UNSET_UINT;
h2scf->recv_timeout = NGX_CONF_UNSET_MSEC;
h2scf->idle_timeout = NGX_CONF_UNSET_MSEC;
return h2scf;
}
static char *
ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_v2_srv_conf_t *prev = parent;
ngx_http_v2_srv_conf_t *conf = child;
ngx_conf_merge_size_value(conf->pool_size, prev->pool_size, 4096);
ngx_conf_merge_uint_value(conf->concurrent_streams,
prev->concurrent_streams, 128);
ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size,
4096);
ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size,
16384);
ngx_conf_merge_uint_value(conf->streams_index_mask,
prev->streams_index_mask, 32 - 1);
ngx_conf_merge_msec_value(conf->recv_timeout,
prev->recv_timeout, 30000);
ngx_conf_merge_msec_value(conf->idle_timeout,
prev->idle_timeout, 180000);
return NGX_CONF_OK;
}
static void *
ngx_http_v2_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_v2_loc_conf_t *h2lcf;
h2lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_loc_conf_t));
if (h2lcf == NULL) {
return NULL;
}
h2lcf->chunk_size = NGX_CONF_UNSET_SIZE;
return h2lcf;
}
static char *
ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_v2_loc_conf_t *prev = parent;
ngx_http_v2_loc_conf_t *conf = child;
ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024);
return NGX_CONF_OK;
}
static char *
ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
if (*sp <= 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE) {
return "value is too small";
}
return NGX_CONF_OK;
}
static char *
ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
if (*sp < NGX_MIN_POOL_SIZE) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the pool size must be no less than %uz",
NGX_MIN_POOL_SIZE);
return NGX_CONF_ERROR;
}
if (*sp % NGX_POOL_ALIGNMENT) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the pool size must be a multiple of %uz",
NGX_POOL_ALIGNMENT);
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data)
{
ngx_uint_t *np = data;
ngx_uint_t mask;
mask = *np - 1;
if (*np == 0 || (*np & mask)) {
return "must be a power of two";
}
*np = mask;
return NGX_CONF_OK;
}
static char *
ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
if (*sp == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the http2 chunk size cannot be zero");
return NGX_CONF_ERROR;
}
if (*sp > NGX_HTTP_V2_MAX_FRAME_SIZE) {
*sp = NGX_HTTP_V2_MAX_FRAME_SIZE;
}
return NGX_CONF_OK;
}
static char *
ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"invalid directive \"%V\": ngx_http_spdy_module "
"was superseded by ngx_http_v2_module", &cmd->name);
return NGX_CONF_OK;
}

View file

@ -5,8 +5,8 @@
*/
#ifndef _NGX_HTTP_SPDY_MODULE_H_INCLUDED_
#define _NGX_HTTP_SPDY_MODULE_H_INCLUDED_
#ifndef _NGX_HTTP_V2_MODULE_H_INCLUDED_
#define _NGX_HTTP_V2_MODULE_H_INCLUDED_
#include <ngx_config.h>
@ -17,25 +17,26 @@
typedef struct {
size_t recv_buffer_size;
u_char *recv_buffer;
} ngx_http_spdy_main_conf_t;
} ngx_http_v2_main_conf_t;
typedef struct {
size_t pool_size;
ngx_uint_t concurrent_streams;
size_t max_field_size;
size_t max_header_size;
ngx_uint_t streams_index_mask;
ngx_msec_t recv_timeout;
ngx_msec_t keepalive_timeout;
ngx_int_t headers_comp;
} ngx_http_spdy_srv_conf_t;
ngx_msec_t idle_timeout;
} ngx_http_v2_srv_conf_t;
typedef struct {
size_t chunk_size;
} ngx_http_spdy_loc_conf_t;
} ngx_http_v2_loc_conf_t;
extern ngx_module_t ngx_http_spdy_module;
extern ngx_module_t ngx_http_v2_module;
#endif /* _NGX_HTTP_SPDY_MODULE_H_INCLUDED_ */
#endif /* _NGX_HTTP_V2_MODULE_H_INCLUDED_ */

View file

@ -0,0 +1,349 @@
/*
* Copyright (C) Nginx, Inc.
* Copyright (C) Valentin V. Bartenev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#define NGX_HTTP_V2_TABLE_SIZE 4096
static ngx_int_t ngx_http_v2_table_account(ngx_http_v2_connection_t *h2c,
size_t size);
static ngx_http_v2_header_t ngx_http_v2_static_table[] = {
{ ngx_string(":authority"), ngx_string("") },
{ ngx_string(":method"), ngx_string("GET") },
{ ngx_string(":method"), ngx_string("POST") },
{ ngx_string(":path"), ngx_string("/") },
{ ngx_string(":path"), ngx_string("/index.html") },
{ ngx_string(":scheme"), ngx_string("http") },
{ ngx_string(":scheme"), ngx_string("https") },
{ ngx_string(":status"), ngx_string("200") },
{ ngx_string(":status"), ngx_string("204") },
{ ngx_string(":status"), ngx_string("206") },
{ ngx_string(":status"), ngx_string("304") },
{ ngx_string(":status"), ngx_string("400") },
{ ngx_string(":status"), ngx_string("404") },
{ ngx_string(":status"), ngx_string("500") },
{ ngx_string("accept-charset"), ngx_string("") },
{ ngx_string("accept-encoding"), ngx_string("gzip, deflate") },
{ ngx_string("accept-language"), ngx_string("") },
{ ngx_string("accept-ranges"), ngx_string("") },
{ ngx_string("accept"), ngx_string("") },
{ ngx_string("access-control-allow-origin"), ngx_string("") },
{ ngx_string("age"), ngx_string("") },
{ ngx_string("allow"), ngx_string("") },
{ ngx_string("authorization"), ngx_string("") },
{ ngx_string("cache-control"), ngx_string("") },
{ ngx_string("content-disposition"), ngx_string("") },
{ ngx_string("content-encoding"), ngx_string("") },
{ ngx_string("content-language"), ngx_string("") },
{ ngx_string("content-length"), ngx_string("") },
{ ngx_string("content-location"), ngx_string("") },
{ ngx_string("content-range"), ngx_string("") },
{ ngx_string("content-type"), ngx_string("") },
{ ngx_string("cookie"), ngx_string("") },
{ ngx_string("date"), ngx_string("") },
{ ngx_string("etag"), ngx_string("") },
{ ngx_string("expect"), ngx_string("") },
{ ngx_string("expires"), ngx_string("") },
{ ngx_string("from"), ngx_string("") },
{ ngx_string("host"), ngx_string("") },
{ ngx_string("if-match"), ngx_string("") },
{ ngx_string("if-modified-since"), ngx_string("") },
{ ngx_string("if-none-match"), ngx_string("") },
{ ngx_string("if-range"), ngx_string("") },
{ ngx_string("if-unmodified-since"), ngx_string("") },
{ ngx_string("last-modified"), ngx_string("") },
{ ngx_string("link"), ngx_string("") },
{ ngx_string("location"), ngx_string("") },
{ ngx_string("max-forwards"), ngx_string("") },
{ ngx_string("proxy-authenticate"), ngx_string("") },
{ ngx_string("proxy-authorization"), ngx_string("") },
{ ngx_string("range"), ngx_string("") },
{ ngx_string("referer"), ngx_string("") },
{ ngx_string("refresh"), ngx_string("") },
{ ngx_string("retry-after"), ngx_string("") },
{ ngx_string("server"), ngx_string("") },
{ ngx_string("set-cookie"), ngx_string("") },
{ ngx_string("strict-transport-security"), ngx_string("") },
{ ngx_string("transfer-encoding"), ngx_string("") },
{ ngx_string("user-agent"), ngx_string("") },
{ ngx_string("vary"), ngx_string("") },
{ ngx_string("via"), ngx_string("") },
{ ngx_string("www-authenticate"), ngx_string("") },
};
#define NGX_HTTP_V2_STATIC_TABLE_ENTRIES \
(sizeof(ngx_http_v2_static_table) \
/ sizeof(ngx_http_v2_header_t))
ngx_int_t
ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c, ngx_uint_t index,
ngx_uint_t name_only)
{
u_char *p;
size_t rest;
ngx_http_v2_header_t *entry;
if (index == 0) {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent invalid hpack table index 0");
return NGX_ERROR;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 get indexed %s: %ui",
name_only ? "header" : "header name", index);
index--;
if (index < NGX_HTTP_V2_STATIC_TABLE_ENTRIES) {
h2c->state.header = ngx_http_v2_static_table[index];
return NGX_OK;
}
index -= NGX_HTTP_V2_STATIC_TABLE_ENTRIES;
if (index < h2c->hpack.added - h2c->hpack.deleted) {
index = (h2c->hpack.added - index - 1) % h2c->hpack.allocated;
entry = h2c->hpack.entries[index];
p = ngx_pnalloc(h2c->state.pool, entry->name.len + 1);
if (p == NULL) {
return NGX_ERROR;
}
h2c->state.header.name.len = entry->name.len;
h2c->state.header.name.data = p;
rest = h2c->hpack.storage + NGX_HTTP_V2_TABLE_SIZE - entry->name.data;
if (entry->name.len > rest) {
p = ngx_cpymem(p, entry->name.data, rest);
p = ngx_cpymem(p, h2c->hpack.storage, entry->name.len - rest);
} else {
p = ngx_cpymem(p, entry->name.data, entry->name.len);
}
*p = '\0';
if (name_only) {
return NGX_OK;
}
p = ngx_pnalloc(h2c->state.pool, entry->value.len + 1);
if (p == NULL) {
return NGX_ERROR;
}
h2c->state.header.value.len = entry->value.len;
h2c->state.header.value.data = p;
rest = h2c->hpack.storage + NGX_HTTP_V2_TABLE_SIZE - entry->value.data;
if (entry->value.len > rest) {
p = ngx_cpymem(p, entry->value.data, rest);
p = ngx_cpymem(p, h2c->hpack.storage, entry->value.len - rest);
} else {
p = ngx_cpymem(p, entry->value.data, entry->value.len);
}
*p = '\0';
return NGX_OK;
}
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent out of bound hpack table index: %ui", index);
return NGX_ERROR;
}
ngx_int_t
ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c,
ngx_http_v2_header_t *header)
{
size_t avail;
ngx_uint_t index;
ngx_http_v2_header_t *entry, **entries;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 add header to hpack table: \"%V: %V\"",
&header->name, &header->value);
if (h2c->hpack.entries == NULL) {
h2c->hpack.allocated = 64;
h2c->hpack.size = NGX_HTTP_V2_TABLE_SIZE;
h2c->hpack.free = NGX_HTTP_V2_TABLE_SIZE;
h2c->hpack.entries = ngx_palloc(h2c->connection->pool,
sizeof(ngx_http_v2_header_t *)
* h2c->hpack.allocated);
if (h2c->hpack.entries == NULL) {
return NGX_ERROR;
}
h2c->hpack.storage = ngx_palloc(h2c->connection->pool,
h2c->hpack.free);
if (h2c->hpack.storage == NULL) {
return NGX_ERROR;
}
h2c->hpack.pos = h2c->hpack.storage;
}
if (ngx_http_v2_table_account(h2c, header->name.len + header->value.len)
!= NGX_OK)
{
return NGX_OK;
}
if (h2c->hpack.reused == h2c->hpack.deleted) {
entry = ngx_palloc(h2c->connection->pool, sizeof(ngx_http_v2_header_t));
if (entry == NULL) {
return NGX_ERROR;
}
} else {
entry = h2c->hpack.entries[h2c->hpack.reused++ % h2c->hpack.allocated];
}
avail = h2c->hpack.storage + NGX_HTTP_V2_TABLE_SIZE - h2c->hpack.pos;
entry->name.len = header->name.len;
entry->name.data = h2c->hpack.pos;
if (avail >= header->name.len) {
h2c->hpack.pos = ngx_cpymem(h2c->hpack.pos, header->name.data,
header->name.len);
} else {
ngx_memcpy(h2c->hpack.pos, header->name.data, avail);
h2c->hpack.pos = ngx_cpymem(h2c->hpack.storage,
header->name.data + avail,
header->name.len - avail);
avail = NGX_HTTP_V2_TABLE_SIZE;
}
avail -= header->name.len;
entry->value.len = header->value.len;
entry->value.data = h2c->hpack.pos;
if (avail >= header->value.len) {
h2c->hpack.pos = ngx_cpymem(h2c->hpack.pos, header->value.data,
header->value.len);
} else {
ngx_memcpy(h2c->hpack.pos, header->value.data, avail);
h2c->hpack.pos = ngx_cpymem(h2c->hpack.storage,
header->value.data + avail,
header->value.len - avail);
}
if (h2c->hpack.allocated == h2c->hpack.added - h2c->hpack.deleted) {
entries = ngx_palloc(h2c->connection->pool,
sizeof(ngx_http_v2_header_t *)
* (h2c->hpack.allocated + 64));
if (entries == NULL) {
return NGX_ERROR;
}
index = h2c->hpack.deleted % h2c->hpack.allocated;
ngx_memcpy(entries, &h2c->hpack.entries[index],
(h2c->hpack.allocated - index)
* sizeof(ngx_http_v2_header_t *));
ngx_memcpy(&entries[h2c->hpack.allocated - index], h2c->hpack.entries,
index * sizeof(ngx_http_v2_header_t *));
(void) ngx_pfree(h2c->connection->pool, h2c->hpack.entries);
h2c->hpack.entries = entries;
h2c->hpack.added = h2c->hpack.allocated;
h2c->hpack.deleted = 0;
h2c->hpack.reused = 0;
h2c->hpack.allocated += 64;
}
h2c->hpack.entries[h2c->hpack.added++ % h2c->hpack.allocated] = entry;
return NGX_OK;
}
static ngx_int_t
ngx_http_v2_table_account(ngx_http_v2_connection_t *h2c, size_t size)
{
ngx_http_v2_header_t *entry;
size += 32;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 hpack table account: %uz free:%uz",
size, h2c->hpack.free);
if (size <= h2c->hpack.free) {
h2c->hpack.free -= size;
return NGX_OK;
}
if (size > h2c->hpack.size) {
h2c->hpack.deleted = h2c->hpack.added;
h2c->hpack.free = h2c->hpack.size;
return NGX_DECLINED;
}
do {
entry = h2c->hpack.entries[h2c->hpack.deleted++ % h2c->hpack.allocated];
h2c->hpack.free += 32 + entry->name.len + entry->value.len;
} while (size > h2c->hpack.free);
h2c->hpack.free -= size;
return NGX_OK;
}
ngx_int_t
ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size)
{
ssize_t needed;
ngx_http_v2_header_t *entry;
if (size > NGX_HTTP_V2_TABLE_SIZE) {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent invalid table size update: %uz", size);
return NGX_ERROR;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 new hpack table size: %uz was:%uz",
size, h2c->hpack.size);
needed = h2c->hpack.size - size;
while (needed > (ssize_t) h2c->hpack.free) {
entry = h2c->hpack.entries[h2c->hpack.deleted++ % h2c->hpack.allocated];
h2c->hpack.free += 32 + entry->name.len + entry->value.len;
}
h2c->hpack.size = size;
h2c->hpack.free -= needed;
return NGX_OK;
}