16 #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
18 #define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
19 *(uint32_t *) m == (c3 << 24 | c2 << 16 | c1 << 8 | c0) \
24 #define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
25 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
30 #if (NGX_HAVE_NONALIGNED)
32 #define ngx_spdy_frame_parse_uint16(p) ntohs(*(uint16_t *) (p))
33 #define ngx_spdy_frame_parse_uint32(p) ntohl(*(uint32_t *) (p))
37 #define ngx_spdy_frame_parse_uint16(p) ((p)[0] << 8 | (p)[1])
38 #define ngx_spdy_frame_parse_uint32(p) \
39 ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])
43 #define ngx_spdy_frame_parse_sid(p) \
44 (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)
47 #define ngx_spdy_ctl_frame_check(h) \
48 (((h) & 0xffffff00) == ngx_spdy_ctl_frame_head(0))
49 #define ngx_spdy_data_frame_check(h) \
50 (!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31))
52 #define ngx_spdy_ctl_frame_type(h) ((h) & 0x000000ff)
53 #define ngx_spdy_frame_flags(p) ((p) >> 24)
54 #define ngx_spdy_frame_length(p) ((p) & 0x00ffffff)
57 #define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE 4096
58 #define NGX_SPDY_CTL_FRAME_BUFFER_SIZE 16
60 #define NGX_SPDY_PROTOCOL_ERROR 1
61 #define NGX_SPDY_INVALID_STREAM 2
62 #define NGX_SPDY_REFUSED_STREAM 3
63 #define NGX_SPDY_UNSUPPORTED_VERSION 4
64 #define NGX_SPDY_CANCEL 5
65 #define NGX_SPDY_INTERNAL_ERROR 6
66 #define NGX_SPDY_FLOW_CONTROL_ERROR 7
68 #define NGX_SPDY_SETTINGS_MAX_STREAMS 4
70 #define NGX_SPDY_SETTINGS_FLAG_PERSIST 0x01
80 static void ngx_http_spdy_read_handler(
ngx_event_t *rev);
81 static void ngx_http_spdy_write_handler(
ngx_event_t *wev);
84 static u_char *ngx_http_spdy_state_detect_settings(
87 u_char *pos, u_char *end);
89 u_char *pos, u_char *end);
91 u_char *pos, u_char *end);
93 u_char *pos, u_char *end);
95 u_char *pos, u_char *end);
97 u_char *pos, u_char *end);
99 u_char *pos, u_char *end);
101 u_char *pos, u_char *end);
103 u_char *pos, u_char *end);
105 u_char *pos, u_char *end);
107 u_char *pos, u_char *end);
109 u_char *pos, u_char *end);
112 static u_char *ngx_http_spdy_state_protocol_error(
114 static u_char *ngx_http_spdy_state_internal_error(
120 static ngx_int_t ngx_http_spdy_settings_frame_handler(
124 static ngx_int_t ngx_http_spdy_ctl_frame_handler(
127 static ngx_http_spdy_stream_t *ngx_http_spdy_create_stream(
129 static ngx_http_spdy_stream_t *ngx_http_spdy_get_stream_by_id(
131 #define ngx_http_spdy_streams_index_size(sscf) (sscf->streams_index_mask + 1)
132 #define ngx_http_spdy_stream_index(sscf, sid) \
133 ((sid >> 1) & sscf->streams_index_mask)
148 static void ngx_http_spdy_handle_connection_handler(
ngx_event_t *rev);
149 static void ngx_http_spdy_keepalive_handler(
ngx_event_t *rev);
153 static void ngx_http_spdy_pool_cleanup(
void *data);
155 static void *ngx_http_spdy_zalloc(
void *opaque, u_int items, u_int size);
156 static void ngx_http_spdy_zfree(
void *opaque,
void *address);
159 static const u_char ngx_http_spdy_dict[] =
160 "options" "get" "head" "post" "put" "delete" "trace"
161 "accept" "accept-charset" "accept-encoding" "accept-language"
162 "authorization" "expect" "from" "host"
163 "if-modified-since" "if-match" "if-none-match" "if-range"
164 "if-unmodifiedsince" "max-forwards" "proxy-authorization"
165 "range" "referer" "te" "user-agent"
166 "100" "101" "200" "201" "202" "203" "204" "205" "206"
167 "300" "301" "302" "303" "304" "305" "306" "307"
168 "400" "401" "402" "403" "404" "405" "406" "407" "408" "409" "410"
169 "411" "412" "413" "414" "415" "416" "417"
170 "500" "501" "502" "503" "504" "505"
171 "accept-ranges" "age" "etag" "location" "proxy-authenticate" "public"
172 "retry-after" "server" "vary" "warning" "www-authenticate" "allow"
173 "content-base" "content-encoding" "cache-control" "connection" "date"
174 "trailer" "transfer-encoding" "upgrade" "via" "warning"
175 "content-language" "content-length" "content-location"
176 "content-md5" "content-range" "content-type" "etag" "expires"
177 "last-modified" "set-cookie"
178 "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"
179 "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
180 "chunked" "text/html" "image/png" "image/jpg" "image/gif"
181 "application/xml" "application/xhtml" "text/plain" "public" "max-age"
182 "charset=iso-8859-1" "utf-8" "gzip" "deflate" "HTTP/1.1" "status"
187 { 0, 6,
"method", ngx_http_spdy_parse_method },
188 { 0, 6,
"scheme", ngx_http_spdy_parse_scheme },
189 { 0, 3,
"url", ngx_http_spdy_parse_url },
190 { 0, 7,
"version", ngx_http_spdy_parse_version },
193 #define NGX_SPDY_REQUEST_HEADERS \
194 (sizeof(ngx_http_spdy_request_headers) \
195 / sizeof(ngx_http_spdy_request_header_t))
213 "init spdy request");
236 sc->
handler = ngx_http_spdy_state_detect_settings;
245 "inflateInit() failed: %d", rc);
257 Z_DEFLATED, 11, 4, Z_DEFAULT_STRATEGY);
261 "deflateInit2() failed: %d", rc);
266 rc = deflateSetDictionary(&sc->
zstream_out, ngx_http_spdy_dict,
267 sizeof(ngx_http_spdy_dict));
270 "deflateSetDictionary() failed: %d", rc);
276 if (sc->
pool == NULL) {
287 cln->
handler = ngx_http_spdy_pool_cleanup;
292 *
sizeof(ngx_http_spdy_stream_t *));
300 rev->
handler = ngx_http_spdy_read_handler;
303 ngx_http_spdy_read_handler(rev);
341 n = c->
recv(c, end, available);
349 "client closed prematurely connection");
353 ngx_http_spdy_finalize_connection(sc,
372 }
while (rev->
ready);
388 ngx_http_spdy_handle_connection(sc);
397 ngx_http_spdy_stream_t *stream, *s, *sn;
405 "spdy write event timed out");
433 for ( ; stream; stream = sn) {
438 "spdy run stream %ui", stream->id);
440 wev = stream->request->connection->
write;
450 ngx_http_spdy_handle_connection(sc);
478 for (frame = sc->
last_out; frame; frame = fn) {
487 "spdy frame out: %p sid:%ui prio:%ui bl:%ui size:%uz",
520 for ( ; out; out = out->
next) {
528 "spdy frame sent: %p sid:%ui bl:%ui size:%uz",
535 for ( ; out; out = fn) {
597 c->
read->
handler = ngx_http_spdy_keepalive_handler;
609 u_char *pos, u_char *end)
612 return ngx_http_spdy_state_save(sc, pos, end,
613 ngx_http_spdy_state_detect_settings);
626 "spdy SETTINGS frame received, size: %uz", sc->
length);
630 return ngx_http_spdy_state_settings(sc, pos, end);
633 ngx_http_spdy_send_settings(sc);
635 return ngx_http_spdy_state_head(sc, pos, end);
646 return ngx_http_spdy_state_save(sc, pos, end,
647 ngx_http_spdy_state_head);
652 pos +=
sizeof(uint32_t);
659 pos +=
sizeof(uint32_t);
662 "spdy process frame head:%08Xd f:%ui l:%ui",
669 return ngx_http_spdy_state_syn_stream(sc, pos, end);
672 return ngx_http_spdy_state_protocol_error(sc);
675 return ngx_http_spdy_state_rst_stream(sc, pos, end);
678 return ngx_http_spdy_state_skip(sc, pos, end);
681 return ngx_http_spdy_state_noop(sc, pos, end);
684 return ngx_http_spdy_state_ping(sc, pos, end);
687 return ngx_http_spdy_state_skip(sc, pos, end);
690 return ngx_http_spdy_state_protocol_error(sc);
693 return ngx_http_spdy_state_skip(sc, pos, end);
698 sc->
stream = ngx_http_spdy_get_stream_by_id(sc, head);
699 return ngx_http_spdy_state_data(sc, pos, end);
705 "spdy unknown frame");
707 return ngx_http_spdy_state_protocol_error(sc);
716 ngx_http_spdy_stream_t *stream;
720 return ngx_http_spdy_state_save(sc, pos, end,
721 ngx_http_spdy_state_syn_stream);
726 return ngx_http_spdy_state_protocol_error(sc);
737 "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio);
745 "spdy concurrent streams excessed %ui", sc->
processing);
751 return ngx_http_spdy_state_internal_error(sc);
754 return ngx_http_spdy_state_headers_skip(sc, pos, end);
757 stream = ngx_http_spdy_create_stream(sc, sid, prio);
758 if (stream == NULL) {
759 return ngx_http_spdy_state_internal_error(sc);
772 return ngx_http_spdy_state_headers(sc, pos, end);
790 return ngx_http_spdy_state_save(sc, pos, end,
791 ngx_http_spdy_state_headers);
805 "spdy process HEADERS %uz of %uz", size, sc->
length);
816 if (z == Z_NEED_DICT) {
817 z = inflateSetDictionary(&sc->
zstream_in, ngx_http_spdy_dict,
818 sizeof(ngx_http_spdy_dict));
821 "spdy inflateSetDictionary() failed: %d", z);
823 return ngx_http_spdy_state_protocol_error(sc);
827 "spdy inflateSetDictionary(): %d", z);
835 "spdy inflate() failed: %d", z);
837 return ngx_http_spdy_state_protocol_error(sc);
841 "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
854 return ngx_http_spdy_state_save(sc, pos, end,
855 ngx_http_spdy_state_headers);
863 "spdy headers count: %ui", sc->
headers);
871 return ngx_http_spdy_state_headers_error(sc, pos, end);
880 return ngx_http_spdy_state_headers_error(sc, pos, end);
886 rc = ngx_http_spdy_parse_header(r);
900 rc = ngx_http_spdy_alloc_large_header_buffer(r);
906 return ngx_http_spdy_state_headers_error(sc, pos, end);
912 return ngx_http_spdy_state_headers_error(sc, pos, end);
924 "spdy inflate() failed: %d", z);
926 return ngx_http_spdy_state_protocol_error(sc);
940 "spdy again while last chunk");
942 return ngx_http_spdy_state_protocol_error(sc);
945 return ngx_http_spdy_state_save(sc, pos, end,
946 ngx_http_spdy_state_headers);
952 "client sent invalid header line");
956 return ngx_http_spdy_state_headers_error(sc, pos, end);
961 "client sent invalid HEADERS spdy frame");
963 return ngx_http_spdy_state_protocol_error(sc);
968 rc = ngx_http_spdy_handle_request_header(r);
973 "client sent invalid HEADERS spdy frame");
975 return ngx_http_spdy_state_protocol_error(sc);
982 return ngx_http_spdy_state_headers_error(sc, pos, end);
989 "end %ui %p %p", complete, buf->
pos, buf->
last);
991 return ngx_http_spdy_state_protocol_error(sc);
995 return ngx_http_spdy_state_save(sc, pos, end,
996 ngx_http_spdy_state_headers);
999 ngx_http_spdy_run_request(r);
1001 return ngx_http_spdy_state_complete(sc, pos, end);
1010 return ngx_http_spdy_state_internal_error(sc);
1013 return ngx_http_spdy_state_headers_skip(sc, pos, end);
1026 return ngx_http_spdy_state_complete(sc, pos, end);
1032 return ngx_http_spdy_state_save(sc, pos, end,
1033 ngx_http_spdy_state_headers_skip);
1046 "spdy inflate(): %d", n);
1050 return ngx_http_spdy_state_protocol_error(sc);
1056 if (size < sc->length) {
1058 return ngx_http_spdy_state_save(sc, pos, end,
1059 ngx_http_spdy_state_headers_skip);
1062 return ngx_http_spdy_state_complete(sc, pos, end);
1077 ngx_http_spdy_stream_t *stream;
1086 if (stream == NULL) {
1087 return ngx_http_spdy_state_skip(sc, pos, end);
1090 if (stream->in_closed) {
1092 return ngx_http_spdy_state_protocol_error(sc);
1095 if (stream->skip_data) {
1098 stream->in_closed = 1;
1102 return ngx_http_spdy_state_skip(sc, pos, end);
1107 if (size >= sc->
length) {
1116 r = stream->request;
1119 && ngx_http_spdy_init_request_body(r) !=
NGX_OK)
1122 return ngx_http_spdy_state_skip(sc, pos, end);
1146 "client intended to send too large chunked "
1184 return ngx_http_spdy_state_save(sc, pos, end,
1185 ngx_http_spdy_state_data);
1190 stream->in_closed = 1;
1211 return ngx_http_spdy_state_complete(sc, pos, end);
1229 return ngx_http_spdy_state_skip(sc, pos, end);
1241 ngx_http_spdy_stream_t *stream;
1244 return ngx_http_spdy_state_save(sc, pos, end,
1245 ngx_http_spdy_state_rst_stream);
1250 return ngx_http_spdy_state_protocol_error(sc);
1259 pos +=
sizeof(uint32_t);
1262 "spdy RST_STREAM sid:%ui st:%ui", sid, status);
1269 return ngx_http_spdy_state_protocol_error(sc);
1281 return ngx_http_spdy_state_protocol_error(sc);
1285 stream = ngx_http_spdy_get_stream_by_id(sc, sid);
1286 if (stream == NULL) {
1291 stream->in_closed = 1;
1292 stream->out_closed = 1;
1294 r = stream->request;
1306 return ngx_http_spdy_state_protocol_error(sc);
1310 return ngx_http_spdy_state_protocol_error(sc);
1313 return ngx_http_spdy_state_complete(sc, pos, end);
1326 return ngx_http_spdy_state_save(sc, pos, end,
1327 ngx_http_spdy_state_ping);
1332 return ngx_http_spdy_state_protocol_error(sc);
1340 if (frame == NULL) {
1341 return ngx_http_spdy_state_internal_error(sc);
1355 ngx_http_spdy_queue_frame(sc, frame);
1359 return ngx_http_spdy_state_complete(sc, pos, end);
1371 if (size < sc->length) {
1373 return ngx_http_spdy_state_save(sc, end, end,
1374 ngx_http_spdy_state_skip);
1377 return ngx_http_spdy_state_complete(sc, pos + sc->
length, end);
1391 return ngx_http_spdy_state_save(sc, pos, end,
1392 ngx_http_spdy_state_settings);
1402 return ngx_http_spdy_state_protocol_error(sc);
1406 "spdy SETTINGS frame consists of %ui entries",
1412 return ngx_http_spdy_state_save(sc, pos, end,
1413 ngx_http_spdy_state_settings);
1430 ngx_http_spdy_send_settings(sc);
1433 return ngx_http_spdy_state_skip(sc, pos, end);
1436 ngx_http_spdy_send_settings(sc);
1438 return ngx_http_spdy_state_complete(sc, pos, end);
1448 return ngx_http_spdy_state_protocol_error(sc);
1451 return ngx_http_spdy_state_complete(sc, pos, end);
1459 sc->
handler = ngx_http_spdy_state_head;
1471 "spdy state buffer overflow: "
1472 "%i bytes required", end - pos);
1473 return ngx_http_spdy_state_internal_error(sc);
1491 "spdy state protocol error");
1503 "spdy state internal error");
1524 "spdy write RST_STREAM sid:%ui st:%ui", sid, status);
1528 if (frame == NULL) {
1544 ngx_http_spdy_queue_frame(sc, frame);
1559 "spdy create GOAWAY sid:%ui", sc->
last_sid);
1563 if (frame == NULL) {
1578 ngx_http_spdy_queue_frame(sc, frame);
1596 "spdy create SETTINGS frame");
1601 if (frame == NULL) {
1624 frame->
handler = ngx_http_spdy_settings_frame_handler;
1639 + NGX_SPDY_SETTINGS_PAIR_SIZE);
1653 ngx_http_spdy_queue_frame(sc, frame);
1694 if (frame == NULL) {
1705 if (cl->
buf == NULL) {
1713 frame->
handler = ngx_http_spdy_ctl_frame_handler;
1721 "requested control frame is too big: %z", size);
1755 static ngx_http_spdy_stream_t *
1765 ngx_http_spdy_stream_t *stream;
1857 if (stream == NULL) {
1862 r->spdy_stream = stream;
1865 stream->request = r;
1867 stream->priority = priority;
1882 static ngx_http_spdy_stream_t *
1886 ngx_http_spdy_stream_t *stream;
1895 if (stream->id == sid) {
1899 stream = stream->index;
1909 u_char *p, *end, ch;
1967 if ((ch >=
'a' && ch <=
'z')
1969 || (ch >=
'0' && ch <=
'9')
1983 if (ch >=
'A' && ch <=
'Z') {
1992 state = sw_value_len;
2040 if (ch ==
CR || ch ==
LF) {
2066 ngx_http_spdy_stream_t *stream;
2070 "spdy alloc large header buffer");
2072 stream = r->spdy_stream;
2076 if (stream->header_buffers
2094 "spdy large header alloc: %p %uz",
2113 stream->header_buffers++;
2132 "client sent invalid header: \"%*s\"",
2140 sh = &ngx_http_spdy_request_headers[
i];
2185 h = &ngx_http_spdy_request_headers[
i];
2196 const u_char *p, *m;
2203 static const struct {
2205 const u_char method[11];
2235 n =
sizeof(tests) /
sizeof(tests[0]);
2238 if (len == test->len) {
2261 if ((*p < 'A' || *p >
'Z') && *p !=
'_') {
2263 "client sent invalid method");
2328 if (ch < '1' || ch >
'9') {
2338 if (ch < '0' || ch >
'9') {
2351 if (ch < '0' || ch >
'9') {
2361 if (ch < '0' || ch >
'9') {
2427 if (ngx_http_spdy_construct_request_line(r) !=
NGX_OK) {
2439 for (i = 0 ;; i++) {
2441 if (i >= part->
nelts) {
2442 if (part->
next == NULL) {
2459 "http header: \"%V: %V\"", &h[i].
key, &h[i].
value);
2487 if (r->spdy_stream->in_closed) {
2508 tf->
warn =
"a client request body is buffered to a temporary file";
2519 if (r->spdy_stream->in_closed
2532 if (rb->
rest == 0) {
2541 if (rb->
rest == 0) {
2554 if (rb->
bufs == NULL) {
2571 ngx_http_spdy_stream_t *stream;
2574 "spdy read request body");
2576 stream = r->spdy_stream;
2578 switch (stream->skip_data) {
2600 if (stream->in_closed) {
2616 ngx_http_spdy_stream_t **
index, *s;
2623 "spdy close stream %ui, processing %ui",
2626 if (!stream->out_closed) {
2627 if (ngx_http_spdy_send_rst_stream(sc, stream->id,
2656 fc = stream->request->connection;
2699 ev->
handler = ngx_http_spdy_handle_connection_handler;
2705 ngx_http_spdy_handle_connection_handler(
ngx_event_t *rev)
2709 rev->
handler = ngx_http_spdy_read_handler;
2712 ngx_http_spdy_read_handler(rev);
2718 ngx_http_spdy_handle_connection(c->
data);
2738 #if (NGX_HAVE_KQUEUE)
2744 "kevent() reported that client %V closed "
2748 c->ssl->no_send_shutdown = 1;
2768 if (sc->
pool == NULL) {
2775 *
sizeof(ngx_http_spdy_stream_t *));
2783 rev->
handler = ngx_http_spdy_read_handler;
2784 ngx_http_spdy_read_handler(rev);
2796 ngx_http_spdy_stream_t *stream;
2818 for (i = 0; i < size; i++) {
2822 r = stream->request;
2827 if (stream->waiting) {
2828 r->
blocked -= stream->waiting;
2829 stream->waiting = 0;
2836 stream = stream->
index;
2854 ngx_http_spdy_pool_cleanup(
void *data)
2865 ngx_http_spdy_zalloc(
void *opaque, u_int items, u_int size)
2874 ngx_http_spdy_zfree(
void *opaque,
void *address)
2880 "spdy zfree: %p", address);