Annotation of embedaddon/nginx/src/http/ngx_http_spdy.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Nginx, Inc.
                      4:  * Copyright (C) Valentin V. Bartenev
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: #include <ngx_http_spdy_module.h>
                     12: 
                     13: #include <zlib.h>
                     14: 
                     15: 
                     16: #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
                     17: 
                     18: #define ngx_str5cmp(m, c0, c1, c2, c3, c4)                                    \
                     19:     *(uint32_t *) m == (c3 << 24 | c2 << 16 | c1 << 8 | c0)                   \
                     20:         && m[4] == c4
                     21: 
                     22: #else
                     23: 
                     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
                     26: 
                     27: #endif
                     28: 
                     29: 
                     30: #if (NGX_HAVE_NONALIGNED)
                     31: 
                     32: #define ngx_spdy_frame_parse_uint16(p)  ntohs(*(uint16_t *) (p))
                     33: #define ngx_spdy_frame_parse_uint32(p)  ntohl(*(uint32_t *) (p))
                     34: 
                     35: #else
                     36: 
                     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])
                     40: 
                     41: #endif
                     42: 
                     43: #define ngx_spdy_frame_parse_sid(p)                                           \
                     44:     (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)
                     45: 
                     46: 
                     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))
                     51: 
                     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)
                     55: 
                     56: 
                     57: #define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE  4096
                     58: #define NGX_SPDY_CTL_FRAME_BUFFER_SIZE     16
                     59: 
                     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
                     67: 
                     68: #define NGX_SPDY_SETTINGS_MAX_STREAMS      4
                     69: 
                     70: #define NGX_SPDY_SETTINGS_FLAG_PERSIST     0x01
                     71: 
                     72: typedef struct {
                     73:     ngx_uint_t    hash;
                     74:     u_char        len;
                     75:     u_char        header[7];
                     76:     ngx_int_t   (*handler)(ngx_http_request_t *r);
                     77: } ngx_http_spdy_request_header_t;
                     78: 
                     79: 
                     80: static void ngx_http_spdy_read_handler(ngx_event_t *rev);
                     81: static void ngx_http_spdy_write_handler(ngx_event_t *wev);
                     82: static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc);
                     83: 
                     84: static u_char *ngx_http_spdy_state_detect_settings(
                     85:     ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end);
                     86: static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc,
                     87:     u_char *pos, u_char *end);
                     88: static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc,
                     89:     u_char *pos, u_char *end);
                     90: static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc,
                     91:     u_char *pos, u_char *end);
                     92: static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
                     93:     u_char *pos, u_char *end);
                     94: static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
                     95:     u_char *pos, u_char *end);
                     96: static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
                     97:     u_char *pos, u_char *end);
                     98: static u_char *ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc,
                     99:     u_char *pos, u_char *end);
                    100: static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc,
                    101:     u_char *pos, u_char *end);
                    102: static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc,
                    103:     u_char *pos, u_char *end);
                    104: static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc,
                    105:     u_char *pos, u_char *end);
                    106: static u_char *ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc,
                    107:     u_char *pos, u_char *end);
                    108: static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc,
                    109:     u_char *pos, u_char *end);
                    110: static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
                    111:     u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler);
                    112: static u_char *ngx_http_spdy_state_protocol_error(
                    113:     ngx_http_spdy_connection_t *sc);
                    114: static u_char *ngx_http_spdy_state_internal_error(
                    115:     ngx_http_spdy_connection_t *sc);
                    116: 
                    117: static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc,
                    118:     ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority);
                    119: static ngx_int_t ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc);
                    120: static ngx_int_t ngx_http_spdy_settings_frame_handler(
                    121:     ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
                    122: static ngx_http_spdy_out_frame_t *ngx_http_spdy_get_ctl_frame(
                    123:     ngx_http_spdy_connection_t *sc, size_t size, ngx_uint_t priority);
                    124: static ngx_int_t ngx_http_spdy_ctl_frame_handler(
                    125:     ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
                    126: 
                    127: static ngx_http_spdy_stream_t *ngx_http_spdy_create_stream(
                    128:     ngx_http_spdy_connection_t *sc, ngx_uint_t id, ngx_uint_t priority);
                    129: static ngx_http_spdy_stream_t *ngx_http_spdy_get_stream_by_id(
                    130:     ngx_http_spdy_connection_t *sc, ngx_uint_t sid);
                    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)
                    134: 
                    135: static ngx_int_t ngx_http_spdy_parse_header(ngx_http_request_t *r);
                    136: static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r);
                    137: 
                    138: static ngx_int_t ngx_http_spdy_handle_request_header(ngx_http_request_t *r);
                    139: static ngx_int_t ngx_http_spdy_parse_method(ngx_http_request_t *r);
                    140: static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r);
                    141: static ngx_int_t ngx_http_spdy_parse_url(ngx_http_request_t *r);
                    142: static ngx_int_t ngx_http_spdy_parse_version(ngx_http_request_t *r);
                    143: 
                    144: static ngx_int_t ngx_http_spdy_construct_request_line(ngx_http_request_t *r);
                    145: static void ngx_http_spdy_run_request(ngx_http_request_t *r);
                    146: static ngx_int_t ngx_http_spdy_init_request_body(ngx_http_request_t *r);
                    147: 
                    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);
                    150: static void ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
                    151:     ngx_int_t rc);
                    152: 
                    153: static void ngx_http_spdy_pool_cleanup(void *data);
                    154: 
                    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);
                    157: 
                    158: 
                    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"
                    183:     "version" "url";
                    184: 
                    185: 
                    186: static ngx_http_spdy_request_header_t ngx_http_spdy_request_headers[] = {
                    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 },
                    191: };
                    192: 
                    193: #define NGX_SPDY_REQUEST_HEADERS                                              \
                    194:     (sizeof(ngx_http_spdy_request_headers)                                    \
                    195:      / sizeof(ngx_http_spdy_request_header_t))
                    196: 
                    197: 
                    198: void
                    199: ngx_http_spdy_init(ngx_event_t *rev)
                    200: {
                    201:     int                          rc;
                    202:     ngx_connection_t            *c;
                    203:     ngx_pool_cleanup_t          *cln;
                    204:     ngx_http_connection_t       *hc;
                    205:     ngx_http_spdy_srv_conf_t    *sscf;
                    206:     ngx_http_spdy_main_conf_t   *smcf;
                    207:     ngx_http_spdy_connection_t  *sc;
                    208: 
                    209:     c = rev->data;
                    210:     hc = c->data;
                    211: 
                    212:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    213:                    "init spdy request");
                    214: 
                    215:     c->log->action = "processing SPDY";
                    216: 
                    217:     smcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_spdy_module);
                    218: 
                    219:     if (smcf->recv_buffer == NULL) {
                    220:         smcf->recv_buffer = ngx_palloc(ngx_cycle->pool, smcf->recv_buffer_size);
                    221:         if (smcf->recv_buffer == NULL) {
                    222:             ngx_http_close_connection(c);
                    223:             return;
                    224:         }
                    225:     }
                    226: 
                    227:     sc = ngx_pcalloc(c->pool, sizeof(ngx_http_spdy_connection_t));
                    228:     if (sc == NULL) {
                    229:         ngx_http_close_connection(c);
                    230:         return;
                    231:     }
                    232: 
                    233:     sc->connection = c;
                    234:     sc->http_connection = hc;
                    235: 
                    236:     sc->handler = ngx_http_spdy_state_detect_settings;
                    237: 
                    238:     sc->zstream_in.zalloc = ngx_http_spdy_zalloc;
                    239:     sc->zstream_in.zfree = ngx_http_spdy_zfree;
                    240:     sc->zstream_in.opaque = sc;
                    241: 
                    242:     rc = inflateInit(&sc->zstream_in);
                    243:     if (rc != Z_OK) {
                    244:         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                    245:                       "inflateInit() failed: %d", rc);
                    246:         ngx_http_close_connection(c);
                    247:         return;
                    248:     }
                    249: 
                    250:     sc->zstream_out.zalloc = ngx_http_spdy_zalloc;
                    251:     sc->zstream_out.zfree = ngx_http_spdy_zfree;
                    252:     sc->zstream_out.opaque = sc;
                    253: 
                    254:     sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_spdy_module);
                    255: 
                    256:     rc = deflateInit2(&sc->zstream_out, (int) sscf->headers_comp,
                    257:                       Z_DEFLATED, 11, 4, Z_DEFAULT_STRATEGY);
                    258: 
                    259:     if (rc != Z_OK) {
                    260:         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                    261:                       "deflateInit2() failed: %d", rc);
                    262:         ngx_http_close_connection(c);
                    263:         return;
                    264:     }
                    265: 
                    266:     rc = deflateSetDictionary(&sc->zstream_out, ngx_http_spdy_dict,
                    267:                               sizeof(ngx_http_spdy_dict));
                    268:     if (rc != Z_OK) {
                    269:         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                    270:                       "deflateSetDictionary() failed: %d", rc);
                    271:         ngx_http_close_connection(c);
                    272:         return;
                    273:     }
                    274: 
                    275:     sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
                    276:     if (sc->pool == NULL) {
                    277:         ngx_http_close_connection(c);
                    278:         return;
                    279:     }
                    280: 
                    281:     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t));
                    282:     if (cln == NULL) {
                    283:         ngx_http_close_connection(c);
                    284:         return;
                    285:     }
                    286: 
                    287:     cln->handler = ngx_http_spdy_pool_cleanup;
                    288:     cln->data = sc;
                    289: 
                    290:     sc->streams_index = ngx_pcalloc(sc->pool,
                    291:                                     ngx_http_spdy_streams_index_size(sscf)
                    292:                                     * sizeof(ngx_http_spdy_stream_t *));
                    293:     if (sc->streams_index == NULL) {
                    294:         ngx_http_close_connection(c);
                    295:         return;
                    296:     }
                    297: 
                    298:     c->data = sc;
                    299: 
                    300:     rev->handler = ngx_http_spdy_read_handler;
                    301:     c->write->handler = ngx_http_spdy_write_handler;
                    302: 
                    303:     ngx_http_spdy_read_handler(rev);
                    304: }
                    305: 
                    306: 
                    307: static void
                    308: ngx_http_spdy_read_handler(ngx_event_t *rev)
                    309: {
                    310:     u_char                      *p, *end;
                    311:     size_t                       available;
                    312:     ssize_t                      n;
                    313:     ngx_connection_t            *c;
                    314:     ngx_http_spdy_main_conf_t   *smcf;
                    315:     ngx_http_spdy_connection_t  *sc;
                    316: 
                    317:     c = rev->data;
                    318:     sc = c->data;
                    319: 
                    320:     if (rev->timedout) {
                    321:         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
                    322:         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_REQUEST_TIME_OUT);
                    323:         return;
                    324:     }
                    325: 
                    326:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy read handler");
                    327: 
                    328:     sc->blocked = 1;
                    329: 
                    330:     smcf = ngx_http_get_module_main_conf(sc->http_connection->conf_ctx,
                    331:                                          ngx_http_spdy_module);
                    332: 
                    333:     available = smcf->recv_buffer_size - 2 * NGX_SPDY_STATE_BUFFER_SIZE;
                    334: 
                    335:     do {
                    336:         p = smcf->recv_buffer;
                    337: 
                    338:         ngx_memcpy(p, sc->buffer, NGX_SPDY_STATE_BUFFER_SIZE);
                    339:         end = p + sc->buffer_used;
                    340: 
                    341:         n = c->recv(c, end, available);
                    342: 
                    343:         if (n == NGX_AGAIN) {
                    344:             break;
                    345:         }
                    346: 
                    347:         if (n == 0 && (sc->waiting || sc->processing)) {
                    348:             ngx_log_error(NGX_LOG_INFO, c->log, 0,
                    349:                           "client closed prematurely connection");
                    350:         }
                    351: 
                    352:         if (n == 0 || n == NGX_ERROR) {
                    353:             ngx_http_spdy_finalize_connection(sc,
                    354:                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
                    355:             return;
                    356:         }
                    357: 
                    358:         end += n;
                    359: 
                    360:         sc->buffer_used = 0;
                    361:         sc->waiting = 0;
                    362: 
                    363:         do {
                    364:             p = sc->handler(sc, p, end);
                    365: 
                    366:             if (p == NULL) {
                    367:                 return;
                    368:             }
                    369: 
                    370:         } while (p != end);
                    371: 
                    372:     } while (rev->ready);
                    373: 
                    374:     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
                    375:         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
                    376:         return;
                    377:     }
                    378: 
                    379:     sc->blocked = 0;
                    380: 
                    381:     if (sc->processing) {
                    382:         if (rev->timer_set) {
                    383:             ngx_del_timer(rev);
                    384:         }
                    385:         return;
                    386:     }
                    387: 
                    388:     ngx_http_spdy_handle_connection(sc);
                    389: }
                    390: 
                    391: 
                    392: static void
                    393: ngx_http_spdy_write_handler(ngx_event_t *wev)
                    394: {
                    395:     ngx_int_t                    rc;
                    396:     ngx_connection_t            *c;
                    397:     ngx_http_spdy_stream_t      *stream, *s, *sn;
                    398:     ngx_http_spdy_connection_t  *sc;
                    399: 
                    400:     c = wev->data;
                    401:     sc = c->data;
                    402: 
                    403:     if (wev->timedout) {
                    404:         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    405:                        "spdy write event timed out");
                    406:         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
                    407:         return;
                    408:     }
                    409: 
                    410:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler");
                    411: 
                    412:     sc->blocked = 2;
                    413: 
                    414:     rc = ngx_http_spdy_send_output_queue(sc);
                    415: 
                    416:     if (rc == NGX_ERROR) {
                    417:         ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
                    418:         return;
                    419:     }
                    420: 
                    421:     stream = NULL;
                    422: 
                    423:     for (s = sc->last_stream; s; s = sn) {
                    424:          sn = s->next;
                    425:          s->next = stream;
                    426:          stream = s;
                    427:     }
                    428: 
                    429:     sc->last_stream = NULL;
                    430: 
                    431:     sc->blocked = 1;
                    432: 
                    433:     for ( /* void */ ; stream; stream = sn) {
                    434:         sn = stream->next;
                    435:         stream->handled = 0;
                    436: 
                    437:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    438:                        "spdy run stream %ui", stream->id);
                    439: 
                    440:         wev = stream->request->connection->write;
                    441:         wev->handler(wev);
                    442:     }
                    443: 
                    444:     sc->blocked = 0;
                    445: 
                    446:     if (rc == NGX_AGAIN) {
                    447:         return;
                    448:     }
                    449: 
                    450:     ngx_http_spdy_handle_connection(sc);
                    451: }
                    452: 
                    453: 
                    454: ngx_int_t
                    455: ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
                    456: {
                    457:     ngx_chain_t                *cl;
                    458:     ngx_event_t                *wev;
                    459:     ngx_connection_t           *c;
                    460:     ngx_http_core_loc_conf_t   *clcf;
                    461:     ngx_http_spdy_out_frame_t  *out, *frame, *fn;
                    462: 
                    463:     c = sc->connection;
                    464: 
                    465:     if (c->error) {
                    466:         return NGX_ERROR;
                    467:     }
                    468: 
                    469:     wev = c->write;
                    470: 
                    471:     if (!wev->ready) {
                    472:         return NGX_OK;
                    473:     }
                    474: 
                    475:     cl = NULL;
                    476:     out = NULL;
                    477: 
                    478:     for (frame = sc->last_out; frame; frame = fn) {
                    479:         frame->last->next = cl;
                    480:         cl = frame->first;
                    481: 
                    482:         fn = frame->next;
                    483:         frame->next = out;
                    484:         out = frame;
                    485: 
                    486:         ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    487:                        "spdy frame out: %p sid:%ui prio:%ui bl:%ui size:%uz",
                    488:                        out, out->stream ? out->stream->id : 0, out->priority,
                    489:                        out->blocked, out->size);
                    490:     }
                    491: 
                    492:     cl = c->send_chain(c, cl, 0);
                    493: 
                    494:     if (cl == NGX_CHAIN_ERROR) {
                    495:         c->error = 1;
                    496: 
                    497:         if (!sc->blocked) {
                    498:             ngx_post_event(wev, &ngx_posted_events);
                    499:         }
                    500: 
                    501:         return NGX_ERROR;
                    502:     }
                    503: 
                    504:     clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx,
                    505:                                         ngx_http_core_module);
                    506: 
                    507:     if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
                    508:         return NGX_ERROR; /* FIXME */
                    509:     }
                    510: 
                    511:     if (cl) {
                    512:         ngx_add_timer(wev, clcf->send_timeout);
                    513: 
                    514:     } else {
                    515:         if (wev->timer_set) {
                    516:             ngx_del_timer(wev);
                    517:         }
                    518:     }
                    519: 
                    520:     for ( /* void */ ; out; out = out->next) {
                    521:         if (out->handler(sc, out) != NGX_OK) {
                    522:             out->blocked = 1;
                    523:             out->priority = NGX_SPDY_HIGHEST_PRIORITY;
                    524:             break;
                    525:         }
                    526: 
                    527:         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    528:                        "spdy frame sent: %p sid:%ui bl:%ui size:%uz",
                    529:                        out, out->stream ? out->stream->id : 0,
                    530:                        out->blocked, out->size);
                    531:     }
                    532: 
                    533:     frame = NULL;
                    534: 
                    535:     for ( /* void */ ; out; out = fn) {
                    536:         fn = out->next;
                    537:         out->next = frame;
                    538:         frame = out;
                    539:     }
                    540: 
                    541:     sc->last_out = frame;
                    542: 
                    543:     return NGX_OK;
                    544: }
                    545: 
                    546: 
                    547: static void
                    548: ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
                    549: {
                    550:     ngx_connection_t          *c;
                    551:     ngx_http_spdy_srv_conf_t  *sscf;
                    552: 
                    553:     if (sc->last_out || sc->processing) {
                    554:         return;
                    555:     }
                    556: 
                    557:     c = sc->connection;
                    558: 
                    559:     if (c->error) {
                    560:         ngx_http_close_connection(c);
                    561:         return;
                    562:     }
                    563: 
                    564:     if (c->buffered) {
                    565:         return;
                    566:     }
                    567: 
                    568:     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                    569:                                         ngx_http_spdy_module);
                    570:     if (sc->waiting) {
                    571:         ngx_add_timer(c->read, sscf->recv_timeout);
                    572:         return;
                    573:     }
                    574: 
                    575:     if (ngx_terminate || ngx_exiting) {
                    576:         ngx_http_close_connection(c);
                    577:         return;
                    578:     }
                    579: 
                    580:     ngx_destroy_pool(sc->pool);
                    581: 
                    582:     sc->pool = NULL;
                    583:     sc->free_ctl_frames = NULL;
                    584:     sc->free_fake_connections = NULL;
                    585: 
                    586: #if (NGX_HTTP_SSL)
                    587:     if (c->ssl) {
                    588:         ngx_ssl_free_buffer(c);
                    589:     }
                    590: #endif
                    591: 
                    592:     c->destroyed = 1;
                    593:     c->idle = 1;
                    594:     ngx_reusable_connection(c, 1);
                    595: 
                    596:     c->write->handler = ngx_http_empty_handler;
                    597:     c->read->handler = ngx_http_spdy_keepalive_handler;
                    598: 
                    599:     if (c->write->timer_set) {
                    600:         ngx_del_timer(c->write);
                    601:     }
                    602: 
                    603:     ngx_add_timer(c->read, sscf->keepalive_timeout);
                    604: }
                    605: 
                    606: 
                    607: static u_char *
                    608: ngx_http_spdy_state_detect_settings(ngx_http_spdy_connection_t *sc,
                    609:     u_char *pos, u_char *end)
                    610: {
                    611:     if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
                    612:         return ngx_http_spdy_state_save(sc, pos, end,
                    613:                                         ngx_http_spdy_state_detect_settings);
                    614:     }
                    615: 
                    616:     /*
                    617:      * Since this is the first frame in a buffer,
                    618:      * then it is properly aligned
                    619:      */
                    620: 
                    621:     if (*(uint32_t *) pos == htonl(ngx_spdy_ctl_frame_head(NGX_SPDY_SETTINGS)))
                    622:     {
                    623:         sc->length = ngx_spdy_frame_length(htonl(((uint32_t *) pos)[1]));
                    624: 
                    625:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    626:                        "spdy SETTINGS frame received, size: %uz", sc->length);
                    627: 
                    628:         pos += NGX_SPDY_FRAME_HEADER_SIZE;
                    629: 
                    630:         return ngx_http_spdy_state_settings(sc, pos, end);
                    631:     }
                    632: 
                    633:     ngx_http_spdy_send_settings(sc);
                    634: 
                    635:     return ngx_http_spdy_state_head(sc, pos, end);
                    636: }
                    637: 
                    638: 
                    639: static u_char *
                    640: ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
                    641:     u_char *end)
                    642: {
                    643:     uint32_t  head, flen;
                    644: 
                    645:     if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
                    646:         return ngx_http_spdy_state_save(sc, pos, end,
                    647:                                         ngx_http_spdy_state_head);
                    648:     }
                    649: 
                    650:     head = ngx_spdy_frame_parse_uint32(pos);
                    651: 
                    652:     pos += sizeof(uint32_t);
                    653: 
                    654:     flen = ngx_spdy_frame_parse_uint32(pos);
                    655: 
                    656:     sc->flags = ngx_spdy_frame_flags(flen);
                    657:     sc->length = ngx_spdy_frame_length(flen);
                    658: 
                    659:     pos += sizeof(uint32_t);
                    660: 
                    661:     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    662:                    "spdy process frame head:%08Xd f:%ui l:%ui",
                    663:                    head, sc->flags, sc->length);
                    664: 
                    665:     if (ngx_spdy_ctl_frame_check(head)) {
                    666:         switch (ngx_spdy_ctl_frame_type(head)) {
                    667: 
                    668:         case NGX_SPDY_SYN_STREAM:
                    669:             return ngx_http_spdy_state_syn_stream(sc, pos, end);
                    670: 
                    671:         case NGX_SPDY_SYN_REPLY:
                    672:             return ngx_http_spdy_state_protocol_error(sc);
                    673: 
                    674:         case NGX_SPDY_RST_STREAM:
                    675:             return ngx_http_spdy_state_rst_stream(sc, pos, end);
                    676: 
                    677:         case NGX_SPDY_SETTINGS:
                    678:             return ngx_http_spdy_state_skip(sc, pos, end);
                    679: 
                    680:         case NGX_SPDY_NOOP:
                    681:             return ngx_http_spdy_state_noop(sc, pos, end);
                    682: 
                    683:         case NGX_SPDY_PING:
                    684:             return ngx_http_spdy_state_ping(sc, pos, end);
                    685: 
                    686:         case NGX_SPDY_GOAWAY:
                    687:             return ngx_http_spdy_state_skip(sc, pos, end); /* TODO */
                    688: 
                    689:         case NGX_SPDY_HEADERS:
                    690:             return ngx_http_spdy_state_protocol_error(sc);
                    691: 
                    692:         default: /* TODO logging */
                    693:             return ngx_http_spdy_state_skip(sc, pos, end);
                    694:         }
                    695:     }
                    696: 
                    697:     if (ngx_spdy_data_frame_check(head)) {
                    698:         sc->stream = ngx_http_spdy_get_stream_by_id(sc, head);
                    699:         return ngx_http_spdy_state_data(sc, pos, end);
                    700:     }
                    701: 
                    702: 
                    703:     /* TODO version & type check */
                    704:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    705:                    "spdy unknown frame");
                    706: 
                    707:     return ngx_http_spdy_state_protocol_error(sc);
                    708: }
                    709: 
                    710: 
                    711: static u_char *
                    712: ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
                    713:     u_char *end)
                    714: {
                    715:     ngx_uint_t                 sid, prio;
                    716:     ngx_http_spdy_stream_t    *stream;
                    717:     ngx_http_spdy_srv_conf_t  *sscf;
                    718: 
                    719:     if (end - pos < NGX_SPDY_SYN_STREAM_SIZE) {
                    720:         return ngx_http_spdy_state_save(sc, pos, end,
                    721:                                         ngx_http_spdy_state_syn_stream);
                    722:     }
                    723: 
                    724:     if (sc->length <= NGX_SPDY_SYN_STREAM_SIZE) {
                    725:         /* TODO logging */
                    726:         return ngx_http_spdy_state_protocol_error(sc);
                    727:     }
                    728: 
                    729:     sc->length -= NGX_SPDY_SYN_STREAM_SIZE;
                    730: 
                    731:     sid = ngx_spdy_frame_parse_sid(pos);
                    732:     prio = pos[8] >> 6;
                    733: 
                    734:     pos += NGX_SPDY_SYN_STREAM_SIZE;
                    735: 
                    736:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    737:                    "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio);
                    738: 
                    739:     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                    740:                                         ngx_http_spdy_module);
                    741: 
                    742:     if (sc->processing >= sscf->concurrent_streams) {
                    743: 
                    744:         ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
                    745:                       "spdy concurrent streams excessed %ui", sc->processing);
                    746: 
                    747:         if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM,
                    748:                                           prio)
                    749:             != NGX_OK)
                    750:         {
                    751:             return ngx_http_spdy_state_internal_error(sc);
                    752:         }
                    753: 
                    754:         return ngx_http_spdy_state_headers_skip(sc, pos, end);
                    755:     }
                    756: 
                    757:     stream = ngx_http_spdy_create_stream(sc, sid, prio);
                    758:     if (stream == NULL) {
                    759:         return ngx_http_spdy_state_internal_error(sc);
                    760:     }
                    761: 
                    762:     stream->in_closed = (sc->flags & NGX_SPDY_FLAG_FIN) ? 1 : 0;
                    763: 
                    764:     stream->request->request_length = NGX_SPDY_FRAME_HEADER_SIZE
                    765:                                       + NGX_SPDY_SYN_STREAM_SIZE
                    766:                                       + sc->length;
                    767: 
                    768:     sc->stream = stream;
                    769: 
                    770:     sc->last_sid = sid;
                    771: 
                    772:     return ngx_http_spdy_state_headers(sc, pos, end);
                    773: }
                    774: 
                    775: 
                    776: static u_char *
                    777: ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
                    778:     u_char *end)
                    779: {
                    780:     int                  z;
                    781:     size_t               size;
                    782:     ngx_buf_t           *buf;
                    783:     ngx_int_t            rc;
                    784:     ngx_uint_t           complete;
                    785:     ngx_http_request_t  *r;
                    786: 
                    787:     size = end - pos;
                    788: 
                    789:     if (size == 0) {
                    790:         return ngx_http_spdy_state_save(sc, pos, end,
                    791:                                         ngx_http_spdy_state_headers);
                    792:     }
                    793: 
                    794:     if (size >= sc->length) {
                    795:         size = sc->length;
                    796:         complete = 1;
                    797: 
                    798:     } else {
                    799:         complete = 0;
                    800:     }
                    801: 
                    802:     r = sc->stream->request;
                    803: 
                    804:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    805:                    "spdy process HEADERS %uz of %uz", size, sc->length);
                    806: 
                    807:     buf = r->header_in;
                    808: 
                    809:     sc->zstream_in.next_in = pos;
                    810:     sc->zstream_in.avail_in = size;
                    811:     sc->zstream_in.next_out = buf->last;
                    812:     sc->zstream_in.avail_out = buf->end - buf->last - 1;
                    813: 
                    814:     z = inflate(&sc->zstream_in, Z_NO_FLUSH);
                    815: 
                    816:     if (z == Z_NEED_DICT) {
                    817:         z = inflateSetDictionary(&sc->zstream_in, ngx_http_spdy_dict,
                    818:                                  sizeof(ngx_http_spdy_dict));
                    819:         if (z != Z_OK) {
                    820:             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                    821:                           "spdy inflateSetDictionary() failed: %d", z);
                    822:             ngx_http_spdy_close_stream(sc->stream, 0);
                    823:             return ngx_http_spdy_state_protocol_error(sc);
                    824:         }
                    825: 
                    826:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    827:                        "spdy inflateSetDictionary(): %d", z);
                    828: 
                    829:         z = sc->zstream_in.avail_in ? inflate(&sc->zstream_in, Z_NO_FLUSH)
                    830:                                     : Z_OK;
                    831:     }
                    832: 
                    833:     if (z != Z_OK) {
                    834:         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                    835:                       "spdy inflate() failed: %d", z);
                    836:         ngx_http_spdy_close_stream(sc->stream, 0);
                    837:         return ngx_http_spdy_state_protocol_error(sc);
                    838:     }
                    839: 
                    840:     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    841:                    "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
                    842:                    sc->zstream_in.next_in, sc->zstream_in.next_out,
                    843:                    sc->zstream_in.avail_in, sc->zstream_in.avail_out,
                    844:                    z);
                    845: 
                    846:     sc->length -= sc->zstream_in.next_in - pos;
                    847:     pos = sc->zstream_in.next_in;
                    848: 
                    849:     buf->last = sc->zstream_in.next_out;
                    850: 
                    851:     if (r->headers_in.headers.part.elts == NULL) {
                    852: 
                    853:         if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
                    854:             return ngx_http_spdy_state_save(sc, pos, end,
                    855:                                             ngx_http_spdy_state_headers);
                    856:         }
                    857: 
                    858:         sc->headers = ngx_spdy_frame_parse_uint16(buf->pos);
                    859: 
                    860:         buf->pos += NGX_SPDY_NV_NUM_SIZE;
                    861: 
                    862:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    863:                        "spdy headers count: %ui", sc->headers);
                    864: 
                    865:         if (ngx_list_init(&r->headers_in.headers, r->pool, sc->headers + 3,
                    866:                           sizeof(ngx_table_elt_t))
                    867:             != NGX_OK)
                    868:         {
                    869:             ngx_http_spdy_close_stream(sc->stream,
                    870:                                        NGX_HTTP_INTERNAL_SERVER_ERROR);
                    871:             return ngx_http_spdy_state_headers_error(sc, pos, end);
                    872:         }
                    873: 
                    874:         if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
                    875:                            sizeof(ngx_table_elt_t *))
                    876:             != NGX_OK)
                    877:         {
                    878:             ngx_http_spdy_close_stream(sc->stream,
                    879:                                        NGX_HTTP_INTERNAL_SERVER_ERROR);
                    880:             return ngx_http_spdy_state_headers_error(sc, pos, end);
                    881:         }
                    882:     }
                    883: 
                    884:     while (sc->headers) {
                    885: 
                    886:         rc = ngx_http_spdy_parse_header(r);
                    887: 
                    888:         switch (rc) {
                    889: 
                    890:         case NGX_DONE:
                    891:             sc->headers--;
                    892: 
                    893:         case NGX_OK:
                    894:             break;
                    895: 
                    896:         case NGX_AGAIN:
                    897: 
                    898:             if (sc->zstream_in.avail_in) {
                    899: 
                    900:                 rc = ngx_http_spdy_alloc_large_header_buffer(r);
                    901: 
                    902:                 if (rc == NGX_DECLINED) {
                    903:                     /* TODO logging */
                    904:                     ngx_http_finalize_request(r,
                    905:                                             NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
                    906:                     return ngx_http_spdy_state_headers_error(sc, pos, end);
                    907:                 }
                    908: 
                    909:                 if (rc != NGX_OK) {
                    910:                     ngx_http_spdy_close_stream(sc->stream,
                    911:                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
                    912:                     return ngx_http_spdy_state_headers_error(sc, pos, end);
                    913:                 }
                    914: 
                    915:                 buf = r->header_in;
                    916: 
                    917:                 sc->zstream_in.next_out = buf->last;
                    918:                 sc->zstream_in.avail_out = buf->end - buf->last - 1;
                    919: 
                    920:                 z = inflate(&sc->zstream_in, Z_NO_FLUSH);
                    921: 
                    922:                 if (z != Z_OK) {
                    923:                     ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                    924:                                   "spdy inflate() failed: %d", z);
                    925:                     ngx_http_spdy_close_stream(sc->stream, 0);
                    926:                     return ngx_http_spdy_state_protocol_error(sc);
                    927:                 }
                    928: 
                    929:                 sc->length -= sc->zstream_in.next_in - pos;
                    930:                 pos = sc->zstream_in.next_in;
                    931: 
                    932:                 buf->last = sc->zstream_in.next_out;
                    933: 
                    934:                 continue;
                    935:             }
                    936: 
                    937:             if (complete) {
                    938:                 /* TODO: improve error message */
                    939:                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    940:                                "spdy again while last chunk");
                    941:                 ngx_http_spdy_close_stream(sc->stream, 0);
                    942:                 return ngx_http_spdy_state_protocol_error(sc);
                    943:             }
                    944: 
                    945:             return ngx_http_spdy_state_save(sc, pos, end,
                    946:                                             ngx_http_spdy_state_headers);
                    947: 
                    948:         case NGX_HTTP_PARSE_INVALID_REQUEST:
                    949: 
                    950:             /* TODO: improve error message */
                    951:             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                    952:                           "client sent invalid header line");
                    953: 
                    954:             ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                    955: 
                    956:             return ngx_http_spdy_state_headers_error(sc, pos, end);
                    957: 
                    958:         default: /* NGX_HTTP_PARSE_INVALID_HEADER */
                    959: 
                    960:             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                    961:                           "client sent invalid HEADERS spdy frame");
                    962:             ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
                    963:             return ngx_http_spdy_state_protocol_error(sc);
                    964:         }
                    965: 
                    966:         /* a header line has been parsed successfully */
                    967: 
                    968:         rc = ngx_http_spdy_handle_request_header(r);
                    969: 
                    970:         if (rc != NGX_OK) {
                    971:             if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
                    972:                 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                    973:                               "client sent invalid HEADERS spdy frame");
                    974:                 ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
                    975:                 return ngx_http_spdy_state_protocol_error(sc);
                    976:             }
                    977: 
                    978:             if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) {
                    979:                 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                    980:             }
                    981: 
                    982:             return ngx_http_spdy_state_headers_error(sc, pos, end);
                    983:         }
                    984:     }
                    985: 
                    986:     if (buf->pos != buf->last) {
                    987:         /* TODO: improve error message */
                    988:         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    989:                        "end %ui %p %p", complete, buf->pos, buf->last);
                    990:         ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
                    991:         return ngx_http_spdy_state_protocol_error(sc);
                    992:     }
                    993: 
                    994:     if (!complete) {
                    995:         return ngx_http_spdy_state_save(sc, pos, end,
                    996:                                         ngx_http_spdy_state_headers);
                    997:     }
                    998: 
                    999:     ngx_http_spdy_run_request(r);
                   1000: 
                   1001:     return ngx_http_spdy_state_complete(sc, pos, end);
                   1002: }
                   1003: 
                   1004: 
                   1005: static u_char *
                   1006: ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1007:     u_char *end)
                   1008: {
                   1009:     if (sc->connection->error) {
                   1010:         return ngx_http_spdy_state_internal_error(sc);
                   1011:     }
                   1012: 
                   1013:     return ngx_http_spdy_state_headers_skip(sc, pos, end);
                   1014: }
                   1015: 
                   1016: 
                   1017: static u_char *
                   1018: ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1019:     u_char *end)
                   1020: {
                   1021:     int     n;
                   1022:     size_t  size;
                   1023:     u_char  buffer[NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE];
                   1024: 
                   1025:     if (sc->length == 0) {
                   1026:         return ngx_http_spdy_state_complete(sc, pos, end);
                   1027:     }
                   1028: 
                   1029:     size = end - pos;
                   1030: 
                   1031:     if (size == 0) {
                   1032:         return ngx_http_spdy_state_save(sc, pos, end,
                   1033:                                         ngx_http_spdy_state_headers_skip);
                   1034:     }
                   1035: 
                   1036:     sc->zstream_in.next_in = pos;
                   1037:     sc->zstream_in.avail_in = (size < sc->length) ? size : sc->length;
                   1038: 
                   1039:     while (sc->zstream_in.avail_in) {
                   1040:         sc->zstream_in.next_out = buffer;
                   1041:         sc->zstream_in.avail_out = NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE;
                   1042: 
                   1043:         n = inflate(&sc->zstream_in, Z_NO_FLUSH);
                   1044: 
                   1045:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1046:                        "spdy inflate(): %d", n);
                   1047: 
                   1048:         if (n != Z_OK) {
                   1049:             /* TODO: logging */
                   1050:             return ngx_http_spdy_state_protocol_error(sc);
                   1051:         }
                   1052:     }
                   1053: 
                   1054:     pos = sc->zstream_in.next_in;
                   1055: 
                   1056:     if (size < sc->length) {
                   1057:         sc->length -= size;
                   1058:         return ngx_http_spdy_state_save(sc, pos, end,
                   1059:                                         ngx_http_spdy_state_headers_skip);
                   1060:     }
                   1061: 
                   1062:     return ngx_http_spdy_state_complete(sc, pos, end);
                   1063: }
                   1064: 
                   1065: 
                   1066: static u_char *
                   1067: ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1068:     u_char *end)
                   1069: {
                   1070:     size_t                     size;
                   1071:     ssize_t                    n;
                   1072:     ngx_buf_t                 *buf;
                   1073:     ngx_int_t                  rc;
                   1074:     ngx_uint_t                 complete;
                   1075:     ngx_temp_file_t           *tf;
                   1076:     ngx_http_request_t        *r;
                   1077:     ngx_http_spdy_stream_t    *stream;
                   1078:     ngx_http_request_body_t   *rb;
                   1079:     ngx_http_core_loc_conf_t  *clcf;
                   1080: 
                   1081:     stream = sc->stream;
                   1082: 
                   1083:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1084:                    "spdy DATA frame");
                   1085: 
                   1086:     if (stream == NULL) {
                   1087:         return ngx_http_spdy_state_skip(sc, pos, end);
                   1088:     }
                   1089: 
                   1090:     if (stream->in_closed) {
                   1091:         /* TODO log */
                   1092:         return ngx_http_spdy_state_protocol_error(sc);
                   1093:     }
                   1094: 
                   1095:     if (stream->skip_data) {
                   1096: 
                   1097:         if (sc->flags & NGX_SPDY_FLAG_FIN) {
                   1098:             stream->in_closed = 1;
                   1099:         }
                   1100: 
                   1101:         /* TODO log and accounting */
                   1102:         return ngx_http_spdy_state_skip(sc, pos, end);
                   1103:     }
                   1104: 
                   1105:     size = end - pos;
                   1106: 
                   1107:     if (size >= sc->length) {
                   1108:         size = sc->length;
                   1109:         complete = 1;
                   1110: 
                   1111:     } else {
                   1112:         sc->length -= size;
                   1113:         complete = 0;
                   1114:     }
                   1115: 
                   1116:     r = stream->request;
                   1117: 
                   1118:     if (r->request_body == NULL
                   1119:         && ngx_http_spdy_init_request_body(r) != NGX_OK)
                   1120:     {
                   1121:         stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
                   1122:         return ngx_http_spdy_state_skip(sc, pos, end);
                   1123:     }
                   1124: 
                   1125:     rb = r->request_body;
                   1126:     tf = rb->temp_file;
                   1127:     buf = rb->buf;
                   1128: 
                   1129:     if (size) {
                   1130:         rb->rest += size;
                   1131: 
                   1132:         if (r->headers_in.content_length_n != -1
                   1133:             && r->headers_in.content_length_n < rb->rest)
                   1134:         {
                   1135:             /* TODO logging */
                   1136:             stream->skip_data = NGX_SPDY_DATA_ERROR;
                   1137:             goto error;
                   1138: 
                   1139:         } else {
                   1140:             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                   1141: 
                   1142:             if (clcf->client_max_body_size
                   1143:                 && clcf->client_max_body_size < rb->rest)
                   1144:             {
                   1145:                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   1146:                               "client intended to send too large chunked "
                   1147:                               "body: %O bytes",
                   1148:                               rb->rest);
                   1149: 
                   1150:                 stream->skip_data = NGX_SPDY_DATA_ERROR;
                   1151:                 goto error;
                   1152:             }
                   1153:         }
                   1154: 
                   1155:         if (tf) {
                   1156:             buf->start = pos;
                   1157:             buf->pos = pos;
                   1158: 
                   1159:             pos += size;
                   1160: 
                   1161:             buf->end = pos;
                   1162:             buf->last = pos;
                   1163: 
                   1164:             n = ngx_write_chain_to_temp_file(tf, rb->bufs);
                   1165: 
                   1166:             /* TODO: n == 0 or not complete and level event */
                   1167: 
                   1168:             if (n == NGX_ERROR) {
                   1169:                 stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
                   1170:                 goto error;
                   1171:             }
                   1172: 
                   1173:             tf->offset += n;
                   1174: 
                   1175:         } else {
                   1176:             buf->last = ngx_cpymem(buf->last, pos, size);
                   1177:             pos += size;
                   1178:         }
                   1179: 
                   1180:         r->request_length += size;
                   1181:     }
                   1182: 
                   1183:     if (!complete) {
                   1184:         return ngx_http_spdy_state_save(sc, pos, end,
                   1185:                                         ngx_http_spdy_state_data);
                   1186:     }
                   1187: 
                   1188:     if (sc->flags & NGX_SPDY_FLAG_FIN) {
                   1189: 
                   1190:         stream->in_closed = 1;
                   1191: 
                   1192:         if (tf) {
                   1193:             ngx_memzero(buf, sizeof(ngx_buf_t));
                   1194: 
                   1195:             buf->in_file = 1;
                   1196:             buf->file_last = tf->file.offset;
                   1197:             buf->file = &tf->file;
                   1198: 
                   1199:             rb->buf = NULL;
                   1200:         }
                   1201: 
                   1202:         if (r->headers_in.content_length_n < 0) {
                   1203:             r->headers_in.content_length_n = rb->rest;
                   1204:         }
                   1205: 
                   1206:         if (rb->post_handler) {
                   1207:             rb->post_handler(r);
                   1208:         }
                   1209:     }
                   1210: 
                   1211:     return ngx_http_spdy_state_complete(sc, pos, end);
                   1212: 
                   1213: error:
                   1214: 
                   1215:     if (rb->post_handler) {
                   1216: 
                   1217:         if (stream->skip_data == NGX_SPDY_DATA_ERROR) {
                   1218:             rc = (r->headers_in.content_length_n == -1)
                   1219:                  ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE
                   1220:                  : NGX_HTTP_BAD_REQUEST;
                   1221: 
                   1222:         } else {
                   1223:             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                   1224:         }
                   1225: 
                   1226:         ngx_http_finalize_request(r, rc);
                   1227:     }
                   1228: 
                   1229:     return ngx_http_spdy_state_skip(sc, pos, end);
                   1230: }
                   1231: 
                   1232: 
                   1233: static u_char *
                   1234: ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1235:     u_char *end)
                   1236: {
                   1237:     ngx_uint_t               sid, status;
                   1238:     ngx_event_t             *ev;
                   1239:     ngx_connection_t        *fc;
                   1240:     ngx_http_request_t      *r;
                   1241:     ngx_http_spdy_stream_t  *stream;
                   1242: 
                   1243:     if (end - pos < NGX_SPDY_RST_STREAM_SIZE) {
                   1244:         return ngx_http_spdy_state_save(sc, pos, end,
                   1245:                                         ngx_http_spdy_state_rst_stream);
                   1246:     }
                   1247: 
                   1248:     if (sc->length != NGX_SPDY_RST_STREAM_SIZE) {
                   1249:         /* TODO logging */
                   1250:         return ngx_http_spdy_state_protocol_error(sc);
                   1251:     }
                   1252: 
                   1253:     sid = ngx_spdy_frame_parse_sid(pos);
                   1254: 
                   1255:     pos += NGX_SPDY_SID_SIZE;
                   1256: 
                   1257:     status = ngx_spdy_frame_parse_uint32(pos);
                   1258: 
                   1259:     pos += sizeof(uint32_t);
                   1260: 
                   1261:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1262:                    "spdy RST_STREAM sid:%ui st:%ui", sid, status);
                   1263: 
                   1264: 
                   1265:     switch (status) {
                   1266: 
                   1267:     case NGX_SPDY_PROTOCOL_ERROR:
                   1268:         /* TODO logging */
                   1269:         return ngx_http_spdy_state_protocol_error(sc);
                   1270: 
                   1271:     case NGX_SPDY_INVALID_STREAM:
                   1272:         /* TODO */
                   1273:         break;
                   1274: 
                   1275:     case NGX_SPDY_REFUSED_STREAM:
                   1276:         /* TODO */
                   1277:         break;
                   1278: 
                   1279:     case NGX_SPDY_UNSUPPORTED_VERSION:
                   1280:         /* TODO logging */
                   1281:         return ngx_http_spdy_state_protocol_error(sc);
                   1282: 
                   1283:     case NGX_SPDY_CANCEL:
                   1284:     case NGX_SPDY_INTERNAL_ERROR:
                   1285:         stream = ngx_http_spdy_get_stream_by_id(sc, sid);
                   1286:         if (stream == NULL) {
                   1287:             /* TODO false cancel */
                   1288:             break;
                   1289:         }
                   1290: 
                   1291:         stream->in_closed = 1;
                   1292:         stream->out_closed = 1;
                   1293: 
                   1294:         r = stream->request;
                   1295: 
                   1296:         fc = r->connection;
                   1297:         fc->error = 1;
                   1298: 
                   1299:         ev = fc->read;
                   1300:         ev->handler(ev);
                   1301: 
                   1302:         break;
                   1303: 
                   1304:     case NGX_SPDY_FLOW_CONTROL_ERROR:
                   1305:         /* TODO logging */
                   1306:         return ngx_http_spdy_state_protocol_error(sc);
                   1307: 
                   1308:     default:
                   1309:         /* TODO */
                   1310:         return ngx_http_spdy_state_protocol_error(sc);
                   1311:     }
                   1312: 
                   1313:     return ngx_http_spdy_state_complete(sc, pos, end);
                   1314: }
                   1315: 
                   1316: 
                   1317: static u_char *
                   1318: ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1319:     u_char *end)
                   1320: {
                   1321:     u_char                     *p;
                   1322:     ngx_buf_t                  *buf;
                   1323:     ngx_http_spdy_out_frame_t  *frame;
                   1324: 
                   1325:     if (end - pos < NGX_SPDY_PING_SIZE) {
                   1326:         return ngx_http_spdy_state_save(sc, pos, end,
                   1327:                                         ngx_http_spdy_state_ping);
                   1328:     }
                   1329: 
                   1330:     if (sc->length != NGX_SPDY_PING_SIZE) {
                   1331:         /* TODO logging */
                   1332:         return ngx_http_spdy_state_protocol_error(sc);
                   1333:     }
                   1334: 
                   1335:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1336:                    "spdy PING frame");
                   1337: 
                   1338:     frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_PING_SIZE,
                   1339:                                         NGX_SPDY_HIGHEST_PRIORITY);
                   1340:     if (frame == NULL) {
                   1341:         return ngx_http_spdy_state_internal_error(sc);
                   1342:     }
                   1343: 
                   1344:     buf = frame->first->buf;
                   1345: 
                   1346:     p = buf->pos;
                   1347: 
                   1348:     p = ngx_spdy_frame_write_head(p, NGX_SPDY_PING);
                   1349:     p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_PING_SIZE);
                   1350: 
                   1351:     p = ngx_cpymem(p, pos, NGX_SPDY_PING_SIZE);
                   1352: 
                   1353:     buf->last = p;
                   1354: 
                   1355:     ngx_http_spdy_queue_frame(sc, frame);
                   1356: 
                   1357:     pos += NGX_SPDY_PING_SIZE;
                   1358: 
                   1359:     return ngx_http_spdy_state_complete(sc, pos, end);
                   1360: }
                   1361: 
                   1362: 
                   1363: static u_char *
                   1364: ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1365:     u_char *end)
                   1366: {
                   1367:     size_t  size;
                   1368: 
                   1369:     size = end - pos;
                   1370: 
                   1371:     if (size < sc->length) {
                   1372:         sc->length -= size;
                   1373:         return ngx_http_spdy_state_save(sc, end, end,
                   1374:                                         ngx_http_spdy_state_skip);
                   1375:     }
                   1376: 
                   1377:     return ngx_http_spdy_state_complete(sc, pos + sc->length, end);
                   1378: }
                   1379: 
                   1380: 
                   1381: static u_char *
                   1382: ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1383:     u_char *end)
                   1384: {
                   1385:     ngx_uint_t                 v;
                   1386:     ngx_http_spdy_srv_conf_t  *sscf;
                   1387: 
                   1388:     if (sc->headers == 0) {
                   1389: 
                   1390:         if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) {
                   1391:             return ngx_http_spdy_state_save(sc, pos, end,
                   1392:                                             ngx_http_spdy_state_settings);
                   1393:         }
                   1394: 
                   1395:         sc->headers = ngx_spdy_frame_parse_uint32(pos);
                   1396: 
                   1397:         pos += NGX_SPDY_SETTINGS_NUM_SIZE;
                   1398:         sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE;
                   1399: 
                   1400:         if (sc->length < sc->headers * NGX_SPDY_SETTINGS_PAIR_SIZE) {
                   1401:             /* TODO logging */
                   1402:             return ngx_http_spdy_state_protocol_error(sc);
                   1403:         }
                   1404: 
                   1405:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1406:                        "spdy SETTINGS frame consists of %ui entries",
                   1407:                        sc->headers);
                   1408:     }
                   1409: 
                   1410:     while (sc->headers) {
                   1411:         if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) {
                   1412:             return ngx_http_spdy_state_save(sc, pos, end,
                   1413:                                             ngx_http_spdy_state_settings);
                   1414:         }
                   1415: 
                   1416:         sc->headers--;
                   1417: 
                   1418:         if (pos[0] != NGX_SPDY_SETTINGS_MAX_STREAMS) {
                   1419:             pos += NGX_SPDY_SETTINGS_PAIR_SIZE;
                   1420:             sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;
                   1421:             continue;
                   1422:         }
                   1423: 
                   1424:         v = ngx_spdy_frame_parse_uint32(pos + NGX_SPDY_SETTINGS_IDF_SIZE);
                   1425: 
                   1426:         sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                   1427:                                             ngx_http_spdy_module);
                   1428: 
                   1429:         if (v != sscf->concurrent_streams) {
                   1430:             ngx_http_spdy_send_settings(sc);
                   1431:         }
                   1432: 
                   1433:         return ngx_http_spdy_state_skip(sc, pos, end);
                   1434:     }
                   1435: 
                   1436:     ngx_http_spdy_send_settings(sc);
                   1437: 
                   1438:     return ngx_http_spdy_state_complete(sc, pos, end);
                   1439: }
                   1440: 
                   1441: 
                   1442: static u_char *
                   1443: ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1444:     u_char *end)
                   1445: {
                   1446:     if (sc->length) {
                   1447:         /* TODO logging */
                   1448:         return ngx_http_spdy_state_protocol_error(sc);
                   1449:     }
                   1450: 
                   1451:     return ngx_http_spdy_state_complete(sc, pos, end);
                   1452: }
                   1453: 
                   1454: 
                   1455: static u_char *
                   1456: ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos,
                   1457:     u_char *end)
                   1458: {
                   1459:     sc->handler = ngx_http_spdy_state_head;
                   1460:     return pos;
                   1461: }
                   1462: 
                   1463: 
                   1464: static u_char *
                   1465: ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
                   1466:     u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler)
                   1467: {
                   1468: #if (NGX_DEBUG)
                   1469:     if (end - pos > NGX_SPDY_STATE_BUFFER_SIZE) {
                   1470:         ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
                   1471:                       "spdy state buffer overflow: "
                   1472:                       "%i bytes required", end - pos);
                   1473:         return ngx_http_spdy_state_internal_error(sc);
                   1474:     }
                   1475: #endif
                   1476: 
                   1477:     ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE);
                   1478: 
                   1479:     sc->buffer_used = end - pos;
                   1480:     sc->handler = handler;
                   1481:     sc->waiting = 1;
                   1482: 
                   1483:     return end;
                   1484: }
                   1485: 
                   1486: 
                   1487: static u_char *
                   1488: ngx_http_spdy_state_protocol_error(ngx_http_spdy_connection_t *sc)
                   1489: {
                   1490:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1491:                    "spdy state protocol error");
                   1492: 
                   1493:     /* TODO */
                   1494:     ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
                   1495:     return NULL;
                   1496: }
                   1497: 
                   1498: 
                   1499: static u_char *
                   1500: ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc)
                   1501: {
                   1502:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1503:                    "spdy state internal error");
                   1504: 
                   1505:     /* TODO */
                   1506:     ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
                   1507:     return NULL;
                   1508: }
                   1509: 
                   1510: 
                   1511: static ngx_int_t
                   1512: ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
                   1513:     ngx_uint_t status, ngx_uint_t priority)
                   1514: {
                   1515:     u_char                     *p;
                   1516:     ngx_buf_t                  *buf;
                   1517:     ngx_http_spdy_out_frame_t  *frame;
                   1518: 
                   1519:     if (sc->connection->error) {
                   1520:         return NGX_OK;
                   1521:     }
                   1522: 
                   1523:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1524:                    "spdy write RST_STREAM sid:%ui st:%ui", sid, status);
                   1525: 
                   1526:     frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_RST_STREAM_SIZE,
                   1527:                                         priority);
                   1528:     if (frame == NULL) {
                   1529:         return NGX_ERROR;
                   1530:     }
                   1531: 
                   1532:     buf = frame->first->buf;
                   1533: 
                   1534:     p = buf->pos;
                   1535: 
                   1536:     p = ngx_spdy_frame_write_head(p, NGX_SPDY_RST_STREAM);
                   1537:     p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_RST_STREAM_SIZE);
                   1538: 
                   1539:     p = ngx_spdy_frame_write_sid(p, sid);
                   1540:     p = ngx_spdy_frame_aligned_write_uint32(p, status);
                   1541: 
                   1542:     buf->last = p;
                   1543: 
                   1544:     ngx_http_spdy_queue_frame(sc, frame);
                   1545: 
                   1546:     return NGX_OK;
                   1547: }
                   1548: 
                   1549: 
                   1550: #if 0
                   1551: static ngx_int_t
                   1552: ngx_http_spdy_send_goaway(ngx_http_spdy_connection_t *sc)
                   1553: {
                   1554:     u_char                     *p;
                   1555:     ngx_buf_t                  *buf;
                   1556:     ngx_http_spdy_out_frame_t  *frame;
                   1557: 
                   1558:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1559:                    "spdy create GOAWAY sid:%ui", sc->last_sid);
                   1560: 
                   1561:     frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE,
                   1562:                                         NGX_SPDY_HIGHEST_PRIORITY);
                   1563:     if (frame == NULL) {
                   1564:         return NGX_ERROR;
                   1565:     }
                   1566: 
                   1567:     buf = frame->first->buf;
                   1568: 
                   1569:     p = buf->pos;
                   1570: 
                   1571:     p = ngx_spdy_frame_write_head(p, NGX_SPDY_GOAWAY);
                   1572:     p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_GOAWAY_SIZE);
                   1573: 
                   1574:     p = ngx_spdy_frame_write_sid(p, sc->last_sid);
                   1575: 
                   1576:     buf->last = p;
                   1577: 
                   1578:     ngx_http_spdy_queue_frame(sc, frame);
                   1579: 
                   1580:     return NGX_OK;
                   1581: }
                   1582: #endif
                   1583: 
                   1584: 
                   1585: static ngx_int_t
                   1586: ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
                   1587: {
                   1588:     u_char                     *p;
                   1589:     ngx_buf_t                  *buf;
                   1590:     ngx_pool_t                 *pool;
                   1591:     ngx_chain_t                *cl;
                   1592:     ngx_http_spdy_srv_conf_t   *sscf;
                   1593:     ngx_http_spdy_out_frame_t  *frame;
                   1594: 
                   1595:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   1596:                    "spdy create SETTINGS frame");
                   1597: 
                   1598:     pool = sc->connection->pool;
                   1599: 
                   1600:     frame = ngx_palloc(pool, sizeof(ngx_http_spdy_out_frame_t));
                   1601:     if (frame == NULL) {
                   1602:         return NGX_ERROR;
                   1603:     }
                   1604: 
                   1605:     cl = ngx_alloc_chain_link(pool);
                   1606:     if (cl == NULL) {
                   1607:         return NGX_ERROR;
                   1608:     }
                   1609: 
                   1610:     buf = ngx_create_temp_buf(pool, NGX_SPDY_FRAME_HEADER_SIZE
                   1611:                                     + NGX_SPDY_SETTINGS_NUM_SIZE
                   1612:                                     + NGX_SPDY_SETTINGS_PAIR_SIZE);
                   1613:     if (buf == NULL) {
                   1614:         return NGX_ERROR;
                   1615:     }
                   1616: 
                   1617:     buf->last_buf = 1;
                   1618: 
                   1619:     cl->buf = buf;
                   1620:     cl->next = NULL;
                   1621: 
                   1622:     frame->first = cl;
                   1623:     frame->last = cl;
                   1624:     frame->handler = ngx_http_spdy_settings_frame_handler;
                   1625: #if (NGX_DEBUG)
                   1626:     frame->stream = NULL;
                   1627:     frame->size = NGX_SPDY_FRAME_HEADER_SIZE
                   1628:                   + NGX_SPDY_SETTINGS_NUM_SIZE
                   1629:                   + NGX_SPDY_SETTINGS_PAIR_SIZE;
                   1630: #endif
                   1631:     frame->priority = NGX_SPDY_HIGHEST_PRIORITY;
                   1632:     frame->blocked = 0;
                   1633: 
                   1634:     p = buf->pos;
                   1635: 
                   1636:     p = ngx_spdy_frame_write_head(p, NGX_SPDY_SETTINGS);
                   1637:     p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_CLEAR_SETTINGS,
                   1638:                                               NGX_SPDY_SETTINGS_NUM_SIZE
                   1639:                                               + NGX_SPDY_SETTINGS_PAIR_SIZE);
                   1640: 
                   1641:     p = ngx_spdy_frame_aligned_write_uint32(p, 1);
                   1642:     p = ngx_spdy_frame_aligned_write_uint32(p,
                   1643:                                             NGX_SPDY_SETTINGS_MAX_STREAMS << 24
                   1644:                                             | NGX_SPDY_SETTINGS_FLAG_PERSIST);
                   1645: 
                   1646:     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                   1647:                                         ngx_http_spdy_module);
                   1648: 
                   1649:     p = ngx_spdy_frame_aligned_write_uint32(p, sscf->concurrent_streams);
                   1650: 
                   1651:     buf->last = p;
                   1652: 
                   1653:     ngx_http_spdy_queue_frame(sc, frame);
                   1654: 
                   1655:     return NGX_OK;
                   1656: }
                   1657: 
                   1658: 
                   1659: ngx_int_t
                   1660: ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc,
                   1661:     ngx_http_spdy_out_frame_t *frame)
                   1662: {
                   1663:     ngx_buf_t  *buf;
                   1664: 
                   1665:     buf = frame->first->buf;
                   1666: 
                   1667:     if (buf->pos != buf->last) {
                   1668:         return NGX_AGAIN;
                   1669:     }
                   1670: 
                   1671:     ngx_free_chain(sc->pool, frame->first);
                   1672: 
                   1673:     return NGX_OK;
                   1674: }
                   1675: 
                   1676: 
                   1677: static ngx_http_spdy_out_frame_t *
                   1678: ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
                   1679:     ngx_uint_t priority)
                   1680: {
                   1681:     ngx_chain_t                *cl;
                   1682:     ngx_http_spdy_out_frame_t  *frame;
                   1683: 
                   1684:     frame = sc->free_ctl_frames;
                   1685: 
                   1686:     if (frame) {
                   1687:         sc->free_ctl_frames = frame->free;
                   1688: 
                   1689:         cl = frame->first;
                   1690:         cl->buf->pos = cl->buf->start;
                   1691: 
                   1692:     } else {
                   1693:         frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
                   1694:         if (frame == NULL) {
                   1695:             return NULL;
                   1696:         }
                   1697: 
                   1698:         cl = ngx_alloc_chain_link(sc->pool);
                   1699:         if (cl == NULL) {
                   1700:             return NULL;
                   1701:         }
                   1702: 
                   1703:         cl->buf = ngx_create_temp_buf(sc->pool,
                   1704:                                       NGX_SPDY_CTL_FRAME_BUFFER_SIZE);
                   1705:         if (cl->buf == NULL) {
                   1706:             return NULL;
                   1707:         }
                   1708: 
                   1709:         cl->buf->last_buf = 1;
                   1710: 
                   1711:         frame->first = cl;
                   1712:         frame->last = cl;
                   1713:         frame->handler = ngx_http_spdy_ctl_frame_handler;
                   1714:     }
                   1715: 
                   1716:     frame->free = NULL;
                   1717: 
                   1718: #if (NGX_DEBUG)
                   1719:     if (size > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
                   1720:         ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0,
                   1721:                       "requested control frame is too big: %z", size);
                   1722:         return NULL;
                   1723:     }
                   1724: 
                   1725:     frame->stream = NULL;
                   1726:     frame->size = size;
                   1727: #endif
                   1728: 
                   1729:     frame->priority = priority;
                   1730:     frame->blocked = 0;
                   1731: 
                   1732:     return frame;
                   1733: }
                   1734: 
                   1735: 
                   1736: static ngx_int_t
                   1737: ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc,
                   1738:     ngx_http_spdy_out_frame_t *frame)
                   1739: {
                   1740:     ngx_buf_t  *buf;
                   1741: 
                   1742:     buf = frame->first->buf;
                   1743: 
                   1744:     if (buf->pos != buf->last) {
                   1745:         return NGX_AGAIN;
                   1746:     }
                   1747: 
                   1748:     frame->free = sc->free_ctl_frames;
                   1749:     sc->free_ctl_frames = frame;
                   1750: 
                   1751:     return NGX_OK;
                   1752: }
                   1753: 
                   1754: 
                   1755: static ngx_http_spdy_stream_t *
                   1756: ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id,
                   1757:     ngx_uint_t priority)
                   1758: {
                   1759:     ngx_log_t                 *log;
                   1760:     ngx_uint_t                 index;
                   1761:     ngx_event_t               *rev, *wev;
                   1762:     ngx_connection_t          *fc;
                   1763:     ngx_http_log_ctx_t        *ctx;
                   1764:     ngx_http_request_t        *r;
                   1765:     ngx_http_spdy_stream_t    *stream;
                   1766:     ngx_http_core_srv_conf_t  *cscf;
                   1767:     ngx_http_spdy_srv_conf_t  *sscf;
                   1768: 
                   1769:     fc = sc->free_fake_connections;
                   1770: 
                   1771:     if (fc) {
                   1772:         sc->free_fake_connections = fc->data;
                   1773: 
                   1774:         rev = fc->read;
                   1775:         wev = fc->write;
                   1776:         log = fc->log;
                   1777:         ctx = log->data;
                   1778: 
                   1779:     } else {
                   1780:         fc = ngx_palloc(sc->pool, sizeof(ngx_connection_t));
                   1781:         if (fc == NULL) {
                   1782:             return NULL;
                   1783:         }
                   1784: 
                   1785:         rev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
                   1786:         if (rev == NULL) {
                   1787:             return NULL;
                   1788:         }
                   1789: 
                   1790:         wev = ngx_palloc(sc->pool, sizeof(ngx_event_t));
                   1791:         if (wev == NULL) {
                   1792:             return NULL;
                   1793:         }
                   1794: 
                   1795:         log = ngx_palloc(sc->pool, sizeof(ngx_log_t));
                   1796:         if (log == NULL) {
                   1797:             return NULL;
                   1798:         }
                   1799: 
                   1800:         ctx = ngx_palloc(sc->pool, sizeof(ngx_http_log_ctx_t));
                   1801:         if (ctx == NULL) {
                   1802:             return NULL;
                   1803:         }
                   1804: 
                   1805:         ctx->connection = fc;
                   1806:         ctx->request = NULL;
                   1807:     }
                   1808: 
                   1809:     ngx_memcpy(log, sc->connection->log, sizeof(ngx_log_t));
                   1810: 
                   1811:     log->data = ctx;
                   1812: 
                   1813:     ngx_memzero(rev, sizeof(ngx_event_t));
                   1814: 
                   1815:     rev->data = fc;
                   1816:     rev->ready = 1;
                   1817:     rev->handler = ngx_http_empty_handler;
                   1818:     rev->log = log;
                   1819: 
                   1820:     ngx_memcpy(wev, rev, sizeof(ngx_event_t));
                   1821: 
                   1822:     wev->write = 1;
                   1823: 
                   1824:     ngx_memcpy(fc, sc->connection, sizeof(ngx_connection_t));
                   1825: 
                   1826:     fc->data = sc->http_connection;
                   1827:     fc->read = rev;
                   1828:     fc->write = wev;
                   1829:     fc->sent = 0;
                   1830:     fc->log = log;
                   1831:     fc->buffered = 0;
                   1832:     fc->sndlowat = 1;
                   1833:     fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
                   1834: 
                   1835:     r = ngx_http_create_request(fc);
                   1836:     if (r == NULL) {
                   1837:         return NULL;
                   1838:     }
                   1839: 
                   1840:     r->valid_location = 1;
                   1841: 
                   1842:     fc->data = r;
                   1843:     sc->connection->requests++;
                   1844: 
                   1845:     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
                   1846: 
                   1847:     r->header_in = ngx_create_temp_buf(r->pool,
                   1848:                                        cscf->client_header_buffer_size);
                   1849:     if (r->header_in == NULL) {
                   1850:         ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                   1851:         return NULL;
                   1852:     }
                   1853: 
                   1854:     r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
                   1855: 
                   1856:     stream = ngx_pcalloc(r->pool, sizeof(ngx_http_spdy_stream_t));
                   1857:     if (stream == NULL) {
                   1858:         ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                   1859:         return NULL;
                   1860:     }
                   1861: 
                   1862:     r->spdy_stream = stream;
                   1863: 
                   1864:     stream->id = id;
                   1865:     stream->request = r;
                   1866:     stream->connection = sc;
                   1867:     stream->priority = priority;
                   1868: 
                   1869:     sscf = ngx_http_get_module_srv_conf(r, ngx_http_spdy_module);
                   1870: 
                   1871:     index = ngx_http_spdy_stream_index(sscf, id);
                   1872: 
                   1873:     stream->index = sc->streams_index[index];
                   1874:     sc->streams_index[index] = stream;
                   1875: 
                   1876:     sc->processing++;
                   1877: 
                   1878:     return stream;
                   1879: }
                   1880: 
                   1881: 
                   1882: static ngx_http_spdy_stream_t *
                   1883: ngx_http_spdy_get_stream_by_id(ngx_http_spdy_connection_t *sc,
                   1884:     ngx_uint_t sid)
                   1885: {
                   1886:     ngx_http_spdy_stream_t    *stream;
                   1887:     ngx_http_spdy_srv_conf_t  *sscf;
                   1888: 
                   1889:     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                   1890:                                         ngx_http_spdy_module);
                   1891: 
                   1892:     stream = sc->streams_index[ngx_http_spdy_stream_index(sscf, sid)];
                   1893: 
                   1894:     while (stream) {
                   1895:         if (stream->id == sid) {
                   1896:             return stream;
                   1897:         }
                   1898: 
                   1899:         stream = stream->index;
                   1900:     }
                   1901: 
                   1902:     return NULL;
                   1903: }
                   1904: 
                   1905: 
                   1906: static ngx_int_t
                   1907: ngx_http_spdy_parse_header(ngx_http_request_t *r)
                   1908: {
                   1909:     u_char                     *p, *end, ch;
                   1910:     ngx_uint_t                  len, hash;
                   1911:     ngx_http_core_srv_conf_t   *cscf;
                   1912: 
                   1913:     enum {
                   1914:         sw_name_len = 0,
                   1915:         sw_name,
                   1916:         sw_value_len,
                   1917:         sw_value
                   1918:     } state;
                   1919: 
                   1920:     state = r->state;
                   1921: 
                   1922:     p = r->header_in->pos;
                   1923:     end = r->header_in->last;
                   1924: 
                   1925:     switch (state) {
                   1926: 
                   1927:     case sw_name_len:
                   1928: 
                   1929:         if (end - p < NGX_SPDY_NV_NLEN_SIZE) {
                   1930:             return NGX_AGAIN;
                   1931:         }
                   1932: 
                   1933:         len = ngx_spdy_frame_parse_uint16(p);
                   1934: 
                   1935:         if (!len) {
                   1936:             return NGX_HTTP_PARSE_INVALID_HEADER;
                   1937:         }
                   1938: 
                   1939:         p += NGX_SPDY_NV_NLEN_SIZE;
                   1940: 
                   1941:         r->header_name_end = p + len;
                   1942:         r->lowcase_index = len;
                   1943:         r->invalid_header = 0;
                   1944: 
                   1945:         state = sw_name;
                   1946: 
                   1947:         /* fall through */
                   1948: 
                   1949:     case sw_name:
                   1950: 
                   1951:         if (r->header_name_end > end) {
                   1952:             break;
                   1953:         }
                   1954: 
                   1955:         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
                   1956: 
                   1957:         r->header_name_start = p;
                   1958: 
                   1959:         hash = 0;
                   1960: 
                   1961:         for ( /* void */ ; p != r->header_name_end; p++) {
                   1962: 
                   1963:             ch = *p;
                   1964: 
                   1965:             hash = ngx_hash(hash, ch);
                   1966: 
                   1967:             if ((ch >= 'a' && ch <= 'z')
                   1968:                 || (ch == '-')
                   1969:                 || (ch >= '0' && ch <= '9')
                   1970:                 || (ch == '_' && cscf->underscores_in_headers))
                   1971:             {
                   1972:                 continue;
                   1973:             }
                   1974: 
                   1975:             switch (ch) {
                   1976:             case '\0':
                   1977:             case LF:
                   1978:             case CR:
                   1979:             case ':':
                   1980:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                   1981:             }
                   1982: 
                   1983:             if (ch >= 'A' && ch <= 'Z') {
                   1984:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                   1985:             }
                   1986: 
                   1987:             r->invalid_header = 1;
                   1988:         }
                   1989: 
                   1990:         r->header_hash = hash;
                   1991: 
                   1992:         state = sw_value_len;
                   1993: 
                   1994:         /* fall through */
                   1995: 
                   1996:     case sw_value_len:
                   1997: 
                   1998:         if (end - p < NGX_SPDY_NV_VLEN_SIZE) {
                   1999:             break;
                   2000:         }
                   2001: 
                   2002:         len = ngx_spdy_frame_parse_uint16(p);
                   2003: 
                   2004:         if (!len) {
                   2005:             return NGX_ERROR;
                   2006:         }
                   2007: 
                   2008:         p += NGX_SPDY_NV_VLEN_SIZE;
                   2009: 
                   2010:         r->header_end = p + len;
                   2011: 
                   2012:         state = sw_value;
                   2013: 
                   2014:         /* fall through */
                   2015: 
                   2016:     case sw_value:
                   2017: 
                   2018:         if (r->header_end > end) {
                   2019:             break;
                   2020:         }
                   2021: 
                   2022:         r->header_start = p;
                   2023: 
                   2024:         for ( /* void */ ; p != r->header_end; p++) {
                   2025: 
                   2026:             ch = *p;
                   2027: 
                   2028:             if (ch == '\0') {
                   2029: 
                   2030:                 if (p == r->header_start) {
                   2031:                     return NGX_ERROR;
                   2032:                 }
                   2033: 
                   2034:                 r->header_size = p - r->header_start;
                   2035:                 r->header_in->pos = p + 1;
                   2036: 
                   2037:                 return NGX_OK;
                   2038:             }
                   2039: 
                   2040:             if (ch == CR || ch == LF) {
                   2041:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                   2042:             }
                   2043:         }
                   2044: 
                   2045:         r->header_size = p - r->header_start;
                   2046:         r->header_in->pos = p;
                   2047: 
                   2048:         r->state = 0;
                   2049: 
                   2050:         return NGX_DONE;
                   2051:     }
                   2052: 
                   2053:     r->header_in->pos = p;
                   2054:     r->state = state;
                   2055: 
                   2056:     return NGX_AGAIN;
                   2057: }
                   2058: 
                   2059: 
                   2060: static ngx_int_t
                   2061: ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
                   2062: {
                   2063:     u_char                    *old, *new;
                   2064:     size_t                     rest;
                   2065:     ngx_buf_t                 *buf;
                   2066:     ngx_http_spdy_stream_t    *stream;
                   2067:     ngx_http_core_srv_conf_t  *cscf;
                   2068: 
                   2069:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   2070:                    "spdy alloc large header buffer");
                   2071: 
                   2072:     stream = r->spdy_stream;
                   2073: 
                   2074:     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
                   2075: 
                   2076:     if (stream->header_buffers
                   2077:         == (ngx_uint_t) cscf->large_client_header_buffers.num)
                   2078:     {
                   2079:         return NGX_DECLINED;
                   2080:     }
                   2081: 
                   2082:     rest = r->header_in->last - r->header_in->pos;
                   2083: 
                   2084:     if (rest >= cscf->large_client_header_buffers.size) {
                   2085:         return NGX_DECLINED;
                   2086:     }
                   2087: 
                   2088:     buf = ngx_create_temp_buf(r->pool, cscf->large_client_header_buffers.size);
                   2089:     if (buf == NULL) {
                   2090:         return NGX_ERROR;
                   2091:     }
                   2092: 
                   2093:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   2094:                    "spdy large header alloc: %p %uz",
                   2095:                    buf->pos, buf->end - buf->last);
                   2096: 
                   2097:     old = r->header_in->pos;
                   2098:     new = buf->pos;
                   2099: 
                   2100:     if (rest) {
                   2101:         buf->last = ngx_cpymem(new, old, rest);
                   2102:     }
                   2103: 
                   2104:     if (r->header_name_end > old) {
                   2105:         r->header_name_end = new + (r->header_name_end - old);
                   2106: 
                   2107:     } else if (r->header_end > old) {
                   2108:         r->header_end = new + (r->header_end - old);
                   2109:     }
                   2110: 
                   2111:     r->header_in = buf;
                   2112: 
                   2113:     stream->header_buffers++;
                   2114: 
                   2115:     return NGX_OK;
                   2116: }
                   2117: 
                   2118: 
                   2119: static ngx_int_t
                   2120: ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
                   2121: {
                   2122:     ngx_uint_t                       i;
                   2123:     ngx_table_elt_t                 *h;
                   2124:     ngx_http_core_srv_conf_t        *cscf;
                   2125:     ngx_http_spdy_request_header_t  *sh;
                   2126: 
                   2127:     if (r->invalid_header) {
                   2128:         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
                   2129: 
                   2130:         if (cscf->ignore_invalid_headers) {
                   2131:             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                   2132:                           "client sent invalid header: \"%*s\"",
                   2133:                           r->header_end - r->header_name_start,
                   2134:                           r->header_name_start);
                   2135:             return NGX_OK;
                   2136:         }
                   2137: 
                   2138:     } else {
                   2139:         for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
                   2140:             sh = &ngx_http_spdy_request_headers[i];
                   2141: 
                   2142:             if (sh->hash != r->header_hash
                   2143:                 || sh->len != r->lowcase_index
                   2144:                 || ngx_strncmp(sh->header, r->header_name_start,
                   2145:                                r->lowcase_index)
                   2146:                    != 0)
                   2147:             {
                   2148:                 continue;
                   2149:             }
                   2150: 
                   2151:             return sh->handler(r);
                   2152:         }
                   2153:     }
                   2154: 
                   2155:     h = ngx_list_push(&r->headers_in.headers);
                   2156:     if (h == NULL) {
                   2157:         ngx_http_spdy_close_stream(r->spdy_stream,
                   2158:                                    NGX_HTTP_INTERNAL_SERVER_ERROR);
                   2159:         return NGX_ERROR;
                   2160:     }
                   2161: 
                   2162:     h->hash = r->header_hash;
                   2163: 
                   2164:     h->key.len = r->lowcase_index;
                   2165:     h->key.data = r->header_name_start;
                   2166:     h->key.data[h->key.len] = '\0';
                   2167: 
                   2168:     h->value.len = r->header_size;
                   2169:     h->value.data = r->header_start;
                   2170:     h->value.data[h->value.len] = '\0';
                   2171: 
                   2172:     h->lowcase_key = h->key.data;
                   2173: 
                   2174:     return NGX_OK;
                   2175: }
                   2176: 
                   2177: 
                   2178: void
                   2179: ngx_http_spdy_request_headers_init()
                   2180: {
                   2181:     ngx_uint_t                       i;
                   2182:     ngx_http_spdy_request_header_t  *h;
                   2183: 
                   2184:     for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
                   2185:         h = &ngx_http_spdy_request_headers[i];
                   2186:         h->hash = ngx_hash_key(h->header, h->len);
                   2187:     }
                   2188: }
                   2189: 
                   2190: 
                   2191: static ngx_int_t
                   2192: ngx_http_spdy_parse_method(ngx_http_request_t *r)
                   2193: {
                   2194:     size_t         k, len;
                   2195:     ngx_uint_t     n;
                   2196:     const u_char  *p, *m;
                   2197: 
                   2198:     /*
                   2199:      * This array takes less than 256 sequential bytes,
                   2200:      * and if typical CPU cache line size is 64 bytes,
                   2201:      * it is prefetched for 4 load operations.
                   2202:      */
                   2203:     static const struct {
                   2204:         u_char            len;
                   2205:         const u_char      method[11];
                   2206:         uint32_t          value;
                   2207:     } tests[] = {
                   2208:         { 3, "GET",       NGX_HTTP_GET },
                   2209:         { 4, "POST",      NGX_HTTP_POST },
                   2210:         { 4, "HEAD",      NGX_HTTP_HEAD },
                   2211:         { 7, "OPTIONS",   NGX_HTTP_OPTIONS },
                   2212:         { 8, "PROPFIND",  NGX_HTTP_PROPFIND },
                   2213:         { 3, "PUT",       NGX_HTTP_PUT },
                   2214:         { 5, "MKCOL",     NGX_HTTP_MKCOL },
                   2215:         { 6, "DELETE",    NGX_HTTP_DELETE },
                   2216:         { 4, "COPY",      NGX_HTTP_COPY },
                   2217:         { 4, "MOVE",      NGX_HTTP_MOVE },
                   2218:         { 9, "PROPPATCH", NGX_HTTP_PROPPATCH },
                   2219:         { 4, "LOCK",      NGX_HTTP_LOCK },
                   2220:         { 6, "UNLOCK",    NGX_HTTP_UNLOCK },
                   2221:         { 5, "PATCH",     NGX_HTTP_PATCH },
                   2222:         { 5, "TRACE",     NGX_HTTP_TRACE }
                   2223:     }, *test;
                   2224: 
                   2225:     if (r->method_name.len) {
                   2226:         return NGX_HTTP_PARSE_INVALID_HEADER;
                   2227:     }
                   2228: 
                   2229:     len = r->header_size;
                   2230: 
                   2231:     r->method_name.len = len;
                   2232:     r->method_name.data = r->header_start;
                   2233: 
                   2234:     test = tests;
                   2235:     n = sizeof(tests) / sizeof(tests[0]);
                   2236: 
                   2237:     do {
                   2238:         if (len == test->len) {
                   2239:             p = r->method_name.data;
                   2240:             m = test->method;
                   2241:             k = len;
                   2242: 
                   2243:             do {
                   2244:                 if (*p++ != *m++) {
                   2245:                     goto next;
                   2246:                 }
                   2247:             } while (--k);
                   2248: 
                   2249:             r->method = test->value;
                   2250:             return NGX_OK;
                   2251:         }
                   2252: 
                   2253:     next:
                   2254:         test++;
                   2255: 
                   2256:     } while (--n);
                   2257: 
                   2258:     p = r->method_name.data;
                   2259: 
                   2260:     do {
                   2261:         if ((*p < 'A' || *p > 'Z') && *p != '_') {
                   2262:             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                   2263:                           "client sent invalid method");
                   2264:             return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2265:         }
                   2266: 
                   2267:         p++;
                   2268: 
                   2269:     } while (--len);
                   2270: 
                   2271:     return NGX_OK;
                   2272: }
                   2273: 
                   2274: 
                   2275: static ngx_int_t
                   2276: ngx_http_spdy_parse_scheme(ngx_http_request_t *r)
                   2277: {
                   2278:     if (r->schema_start) {
                   2279:         return NGX_HTTP_PARSE_INVALID_HEADER;
                   2280:     }
                   2281: 
                   2282:     r->schema_start = r->header_start;
                   2283:     r->schema_end = r->header_end;
                   2284: 
                   2285:     return NGX_OK;
                   2286: }
                   2287: 
                   2288: 
                   2289: static ngx_int_t
                   2290: ngx_http_spdy_parse_url(ngx_http_request_t *r)
                   2291: {
                   2292:     if (r->unparsed_uri.len) {
                   2293:         return NGX_HTTP_PARSE_INVALID_HEADER;
                   2294:     }
                   2295: 
                   2296:     r->uri_start = r->header_start;
                   2297:     r->uri_end = r->header_end;
                   2298: 
                   2299:     if (ngx_http_parse_uri(r) != NGX_OK) {
                   2300:         return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2301:     }
                   2302: 
                   2303:     if (ngx_http_process_request_uri(r) != NGX_OK) {
                   2304:         return NGX_ERROR;
                   2305:     }
                   2306: 
                   2307:     return NGX_OK;
                   2308: }
                   2309: 
                   2310: 
                   2311: static ngx_int_t
                   2312: ngx_http_spdy_parse_version(ngx_http_request_t *r)
                   2313: {
                   2314:     u_char  *p, ch;
                   2315: 
                   2316:     if (r->http_protocol.len) {
                   2317:         return NGX_HTTP_PARSE_INVALID_HEADER;
                   2318:     }
                   2319: 
                   2320:     p = r->header_start;
                   2321: 
                   2322:     if (r->header_size < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
                   2323:         return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2324:     }
                   2325: 
                   2326:     ch = *(p + 5);
                   2327: 
                   2328:     if (ch < '1' || ch > '9') {
                   2329:         return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2330:     }
                   2331: 
                   2332:     r->http_major = ch - '0';
                   2333: 
                   2334:     for (p += 6; p != r->header_end - 2; p++) {
                   2335: 
                   2336:         ch = *p;
                   2337: 
                   2338:         if (ch < '0' || ch > '9') {
                   2339:             return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2340:         }
                   2341: 
                   2342:         r->http_major = r->http_major * 10 + ch - '0';
                   2343:     }
                   2344: 
                   2345:     if (*p != '.') {
                   2346:         return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2347:     }
                   2348: 
                   2349:     ch = *(p + 1);
                   2350: 
                   2351:     if (ch < '0' || ch > '9') {
                   2352:         return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2353:     }
                   2354: 
                   2355:     r->http_minor = ch - '0';
                   2356: 
                   2357:     for (p += 2; p != r->header_end; p++) {
                   2358: 
                   2359:         ch = *p;
                   2360: 
                   2361:         if (ch < '0' || ch > '9') {
                   2362:             return NGX_HTTP_PARSE_INVALID_REQUEST;
                   2363:         }
                   2364: 
                   2365:         r->http_minor = r->http_minor * 10 + ch - '0';
                   2366:     }
                   2367: 
                   2368:     r->http_protocol.len = r->header_size;
                   2369:     r->http_protocol.data = r->header_start;
                   2370:     r->http_version = r->http_major * 1000 + r->http_minor;
                   2371: 
                   2372:     return NGX_OK;
                   2373: }
                   2374: 
                   2375: 
                   2376: static ngx_int_t
                   2377: ngx_http_spdy_construct_request_line(ngx_http_request_t *r)
                   2378: {
                   2379:     u_char  *p;
                   2380: 
                   2381:     if (r->method_name.len == 0
                   2382:         || r->unparsed_uri.len == 0
                   2383:         || r->http_protocol.len == 0)
                   2384:     {
                   2385:         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                   2386:         return NGX_ERROR;
                   2387:     }
                   2388: 
                   2389:     r->request_line.len = r->method_name.len + 1
                   2390:                           + r->unparsed_uri.len + 1
                   2391:                           + r->http_protocol.len;
                   2392: 
                   2393:     p = ngx_pnalloc(r->pool, r->request_line.len + 1);
                   2394:     if (p == NULL) {
                   2395:         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                   2396:         return NGX_ERROR;
                   2397:     }
                   2398: 
                   2399:     r->request_line.data = p;
                   2400: 
                   2401:     p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
                   2402: 
                   2403:     *p++ = ' ';
                   2404: 
                   2405:     p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
                   2406: 
                   2407:     *p++ = ' ';
                   2408: 
                   2409:     ngx_memcpy(p, r->http_protocol.data, r->http_protocol.len + 1);
                   2410: 
                   2411:     /* some modules expect the space character after method name */
                   2412:     r->method_name.data = r->request_line.data;
                   2413: 
                   2414:     return NGX_OK;
                   2415: }
                   2416: 
                   2417: 
                   2418: static void
                   2419: ngx_http_spdy_run_request(ngx_http_request_t *r)
                   2420: {
                   2421:     ngx_uint_t                  i;
                   2422:     ngx_list_part_t            *part;
                   2423:     ngx_table_elt_t            *h;
                   2424:     ngx_http_header_t          *hh;
                   2425:     ngx_http_core_main_conf_t  *cmcf;
                   2426: 
                   2427:     if (ngx_http_spdy_construct_request_line(r) != NGX_OK) {
                   2428:         return;
                   2429:     }
                   2430: 
                   2431:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   2432:                    "spdy http request line: \"%V\"", &r->request_line);
                   2433: 
                   2434:     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
                   2435: 
                   2436:     part = &r->headers_in.headers.part;
                   2437:     h = part->elts;
                   2438: 
                   2439:     for (i = 0 ;; i++) {
                   2440: 
                   2441:         if (i >= part->nelts) {
                   2442:             if (part->next == NULL) {
                   2443:                 break;
                   2444:             }
                   2445: 
                   2446:             part = part->next;
                   2447:             h = part->elts;
                   2448:             i = 0;
                   2449:         }
                   2450: 
                   2451:         hh = ngx_hash_find(&cmcf->headers_in_hash, h[i].hash,
                   2452:                            h[i].lowcase_key, h[i].key.len);
                   2453: 
                   2454:         if (hh && hh->handler(r, &h[i], hh->offset) != NGX_OK) {
                   2455:             return;
                   2456:         }
                   2457: 
                   2458:         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   2459:                        "http header: \"%V: %V\"", &h[i].key, &h[i].value);
                   2460:     }
                   2461: 
                   2462:     r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
                   2463: 
                   2464:     if (ngx_http_process_request_header(r) != NGX_OK) {
                   2465:         return;
                   2466:     }
                   2467: 
                   2468:     ngx_http_process_request(r);
                   2469: }
                   2470: 
                   2471: 
                   2472: static ngx_int_t
                   2473: ngx_http_spdy_init_request_body(ngx_http_request_t *r)
                   2474: {
                   2475:     ngx_buf_t                 *buf;
                   2476:     ngx_temp_file_t           *tf;
                   2477:     ngx_http_request_body_t   *rb;
                   2478:     ngx_http_core_loc_conf_t  *clcf;
                   2479: 
                   2480:     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
                   2481:     if (rb == NULL) {
                   2482:         return NGX_ERROR;
                   2483:     }
                   2484: 
                   2485:     r->request_body = rb;
                   2486: 
                   2487:     if (r->spdy_stream->in_closed) {
                   2488:         return NGX_OK;
                   2489:     }
                   2490: 
                   2491:     rb->rest = r->headers_in.content_length_n;
                   2492: 
                   2493:     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                   2494: 
                   2495:     if (r->request_body_in_file_only
                   2496:         || rb->rest > (off_t) clcf->client_body_buffer_size
                   2497:         || rb->rest < 0)
                   2498:     {
                   2499:         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
                   2500:         if (tf == NULL) {
                   2501:             return NGX_ERROR;
                   2502:         }
                   2503: 
                   2504:         tf->file.fd = NGX_INVALID_FILE;
                   2505:         tf->file.log = r->connection->log;
                   2506:         tf->path = clcf->client_body_temp_path;
                   2507:         tf->pool = r->pool;
                   2508:         tf->warn = "a client request body is buffered to a temporary file";
                   2509:         tf->log_level = r->request_body_file_log_level;
                   2510:         tf->persistent = r->request_body_in_persistent_file;
                   2511:         tf->clean = r->request_body_in_clean_file;
                   2512: 
                   2513:         if (r->request_body_file_group_access) {
                   2514:             tf->access = 0660;
                   2515:         }
                   2516: 
                   2517:         rb->temp_file = tf;
                   2518: 
                   2519:         if (r->spdy_stream->in_closed
                   2520:             && ngx_create_temp_file(&tf->file, tf->path, tf->pool,
                   2521:                                     tf->persistent, tf->clean, tf->access)
                   2522:                != NGX_OK)
                   2523:         {
                   2524:             return NGX_ERROR;
                   2525:         }
                   2526: 
                   2527:         buf = ngx_calloc_buf(r->pool);
                   2528:         if (buf == NULL) {
                   2529:             return NGX_ERROR;
                   2530:         }
                   2531: 
                   2532:     } else {
                   2533: 
                   2534:         if (rb->rest == 0) {
                   2535:             return NGX_OK;
                   2536:         }
                   2537: 
                   2538:         buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
                   2539:         if (buf == NULL) {
                   2540:             return NGX_ERROR;
                   2541:         }
                   2542:     }
                   2543: 
                   2544:     rb->buf = buf;
                   2545: 
                   2546:     rb->bufs = ngx_alloc_chain_link(r->pool);
                   2547:     if (rb->bufs == NULL) {
                   2548:         return NGX_ERROR;
                   2549:     }
                   2550: 
                   2551:     rb->bufs->buf = buf;
                   2552:     rb->bufs->next = NULL;
                   2553: 
                   2554:     rb->rest = 0;
                   2555: 
                   2556:     return NGX_OK;
                   2557: }
                   2558: 
                   2559: 
                   2560: ngx_int_t
                   2561: ngx_http_spdy_read_request_body(ngx_http_request_t *r,
                   2562:     ngx_http_client_body_handler_pt post_handler)
                   2563: {
                   2564:     ngx_http_spdy_stream_t  *stream;
                   2565: 
                   2566:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   2567:                    "spdy read request body");
                   2568: 
                   2569:     stream = r->spdy_stream;
                   2570: 
                   2571:     switch (stream->skip_data) {
                   2572: 
                   2573:     case NGX_SPDY_DATA_DISCARD:
                   2574:         post_handler(r);
                   2575:         return NGX_OK;
                   2576: 
                   2577:     case NGX_SPDY_DATA_ERROR:
                   2578:         if (r->headers_in.content_length_n == -1) {
                   2579:             return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
                   2580:         } else {
                   2581:             return NGX_HTTP_BAD_REQUEST;
                   2582:         }
                   2583: 
                   2584:     case NGX_SPDY_DATA_INTERNAL_ERROR:
                   2585:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                   2586:     }
                   2587: 
                   2588:     if (!r->request_body && ngx_http_spdy_init_request_body(r) != NGX_OK) {
                   2589:         stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR;
                   2590:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                   2591:     }
                   2592: 
                   2593:     if (stream->in_closed) {
                   2594:         post_handler(r);
                   2595:         return NGX_OK;
                   2596:     }
                   2597: 
                   2598:     r->request_body->post_handler = post_handler;
                   2599: 
                   2600:     return NGX_AGAIN;
                   2601: }
                   2602: 
                   2603: 
                   2604: void
                   2605: ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
                   2606: {
                   2607:     ngx_event_t                  *ev;
                   2608:     ngx_connection_t             *fc;
                   2609:     ngx_http_spdy_stream_t      **index, *s;
                   2610:     ngx_http_spdy_srv_conf_t     *sscf;
                   2611:     ngx_http_spdy_connection_t   *sc;
                   2612: 
                   2613:     sc = stream->connection;
                   2614: 
                   2615:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   2616:                    "spdy close stream %ui, processing %ui",
                   2617:                    stream->id, sc->processing);
                   2618: 
                   2619:     if (!stream->out_closed) {
                   2620:         if (ngx_http_spdy_send_rst_stream(sc, stream->id,
                   2621:                                           NGX_SPDY_INTERNAL_ERROR,
                   2622:                                           stream->priority)
                   2623:             != NGX_OK)
                   2624:         {
                   2625:             sc->connection->error = 1;
                   2626:         }
                   2627:     }
                   2628: 
                   2629:     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                   2630:                                         ngx_http_spdy_module);
                   2631: 
                   2632:     index = sc->streams_index + ngx_http_spdy_stream_index(sscf, stream->id);
                   2633: 
                   2634:     for ( ;; ) {
                   2635:         s = *index;
                   2636: 
                   2637:         if (s == NULL) {
                   2638:             break;
                   2639:         }
                   2640: 
                   2641:         if (s == stream) {
                   2642:             *index = s->index;
                   2643:             break;
                   2644:         }
                   2645: 
                   2646:         index = &s->index;
                   2647:     }
                   2648: 
                   2649:     fc = stream->request->connection;
                   2650: 
                   2651:     ngx_http_free_request(stream->request, rc);
                   2652: 
                   2653:     ev = fc->read;
                   2654: 
                   2655:     if (ev->active || ev->disabled) {
                   2656:         ngx_del_event(ev, NGX_READ_EVENT, 0);
                   2657:     }
                   2658: 
                   2659:     if (ev->timer_set) {
                   2660:         ngx_del_timer(ev);
                   2661:     }
                   2662: 
                   2663:     if (ev->prev) {
                   2664:         ngx_delete_posted_event(ev);
                   2665:     }
                   2666: 
                   2667:     ev = fc->write;
                   2668: 
                   2669:     if (ev->active || ev->disabled) {
                   2670:         ngx_del_event(ev, NGX_WRITE_EVENT, 0);
                   2671:     }
                   2672: 
                   2673:     if (ev->timer_set) {
                   2674:         ngx_del_timer(ev);
                   2675:     }
                   2676: 
                   2677:     if (ev->prev) {
                   2678:         ngx_delete_posted_event(ev);
                   2679:     }
                   2680: 
                   2681:     fc->data = sc->free_fake_connections;
                   2682:     sc->free_fake_connections = fc;
                   2683: 
                   2684:     sc->processing--;
                   2685: 
                   2686:     if (sc->processing || sc->blocked) {
                   2687:         return;
                   2688:     }
                   2689: 
                   2690:     ev = sc->connection->read;
                   2691: 
                   2692:     ev->handler = ngx_http_spdy_handle_connection_handler;
                   2693:     ngx_post_event(ev, &ngx_posted_events);
                   2694: }
                   2695: 
                   2696: 
                   2697: static void
                   2698: ngx_http_spdy_handle_connection_handler(ngx_event_t *rev)
                   2699: {
                   2700:     ngx_connection_t  *c;
                   2701: 
                   2702:     rev->handler = ngx_http_spdy_read_handler;
                   2703: 
                   2704:     if (rev->ready) {
                   2705:         ngx_http_spdy_read_handler(rev);
                   2706:         return;
                   2707:     }
                   2708: 
                   2709:     c = rev->data;
                   2710: 
                   2711:     ngx_http_spdy_handle_connection(c->data);
                   2712: }
                   2713: 
                   2714: 
                   2715: static void
                   2716: ngx_http_spdy_keepalive_handler(ngx_event_t *rev)
                   2717: {
                   2718:     ngx_connection_t            *c;
                   2719:     ngx_http_spdy_srv_conf_t    *sscf;
                   2720:     ngx_http_spdy_connection_t  *sc;
                   2721: 
                   2722:     c = rev->data;
                   2723: 
                   2724:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy keepalive handler");
                   2725: 
                   2726:     if (rev->timedout || c->close) {
                   2727:         ngx_http_close_connection(c);
                   2728:         return;
                   2729:     }
                   2730: 
                   2731: #if (NGX_HAVE_KQUEUE)
                   2732: 
                   2733:     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
                   2734:         if (rev->pending_eof) {
                   2735:             c->log->handler = NULL;
                   2736:             ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
                   2737:                           "kevent() reported that client %V closed "
                   2738:                           "keepalive connection", &c->addr_text);
                   2739: #if (NGX_HTTP_SSL)
                   2740:             if (c->ssl) {
                   2741:                 c->ssl->no_send_shutdown = 1;
                   2742:             }
                   2743: #endif
                   2744:             ngx_http_close_connection(c);
                   2745:             return;
                   2746:         }
                   2747:     }
                   2748: 
                   2749: #endif
                   2750: 
                   2751:     c->destroyed = 0;
                   2752:     c->idle = 0;
                   2753:     ngx_reusable_connection(c, 0);
                   2754: 
                   2755:     sc = c->data;
                   2756: 
                   2757:     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                   2758:                                         ngx_http_spdy_module);
                   2759: 
                   2760:     sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log);
                   2761:     if (sc->pool == NULL) {
                   2762:         ngx_http_close_connection(c);
                   2763:         return;
                   2764:     }
                   2765: 
                   2766:     sc->streams_index = ngx_pcalloc(sc->pool,
                   2767:                                     ngx_http_spdy_streams_index_size(sscf)
                   2768:                                     * sizeof(ngx_http_spdy_stream_t *));
                   2769:     if (sc->streams_index == NULL) {
                   2770:         ngx_http_close_connection(c);
                   2771:         return;
                   2772:     }
                   2773: 
                   2774:     c->write->handler = ngx_http_spdy_write_handler;
                   2775: 
                   2776:     rev->handler = ngx_http_spdy_read_handler;
                   2777:     ngx_http_spdy_read_handler(rev);
                   2778: }
                   2779: 
                   2780: 
                   2781: static void
                   2782: ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
                   2783:     ngx_int_t rc)
                   2784: {
                   2785:     ngx_uint_t                 i, size;
                   2786:     ngx_event_t               *ev;
                   2787:     ngx_connection_t          *c, *fc;
                   2788:     ngx_http_request_t        *r;
                   2789:     ngx_http_spdy_stream_t    *stream;
                   2790:     ngx_http_spdy_srv_conf_t  *sscf;
                   2791: 
                   2792:     c = sc->connection;
                   2793: 
                   2794:     if (!sc->processing) {
                   2795:         ngx_http_close_connection(c);
                   2796:         return;
                   2797:     }
                   2798: 
                   2799:     c->error = 1;
                   2800:     c->read->handler = ngx_http_empty_handler;
                   2801: 
                   2802:     sc->last_out = NULL;
                   2803: 
                   2804:     sc->blocked = 1;
                   2805: 
                   2806:     sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
                   2807:                                         ngx_http_spdy_module);
                   2808: 
                   2809:     size = ngx_http_spdy_streams_index_size(sscf);
                   2810: 
                   2811:     for (i = 0; i < size; i++) {
                   2812:         stream = sc->streams_index[i];
                   2813: 
                   2814:         while (stream) {
                   2815:             r = stream->request;
                   2816: 
                   2817:             fc = r->connection;
                   2818:             fc->error = 1;
                   2819: 
                   2820:             if (stream->waiting) {
                   2821:                 r->blocked -= stream->waiting;
                   2822:                 stream->waiting = 0;
                   2823:                 ev = fc->write;
                   2824: 
                   2825:             } else {
                   2826:                 ev = fc->read;
                   2827:             }
                   2828: 
                   2829:             stream = stream->index;
                   2830: 
                   2831:             ev->eof = 1;
                   2832:             ev->handler(ev);
                   2833:         }
                   2834:     }
                   2835: 
                   2836:     sc->blocked = 0;
                   2837: 
                   2838:     if (sc->processing) {
                   2839:         return;
                   2840:     }
                   2841: 
                   2842:     ngx_http_close_connection(c);
                   2843: }
                   2844: 
                   2845: 
                   2846: static void
                   2847: ngx_http_spdy_pool_cleanup(void *data)
                   2848: {
                   2849:     ngx_http_spdy_connection_t  *sc = data;
                   2850: 
                   2851:     if (sc->pool) {
                   2852:         ngx_destroy_pool(sc->pool);
                   2853:     }
                   2854: }
                   2855: 
                   2856: 
                   2857: static void *
                   2858: ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size)
                   2859: {
                   2860:     ngx_http_spdy_connection_t *sc = opaque;
                   2861: 
                   2862:     return ngx_palloc(sc->connection->pool, items * size);
                   2863: }
                   2864: 
                   2865: 
                   2866: static void
                   2867: ngx_http_spdy_zfree(void *opaque, void *address)
                   2868: {
                   2869: #if 0
                   2870:     ngx_http_spdy_connection_t *sc = opaque;
                   2871: 
                   2872:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                   2873:                    "spdy zfree: %p", address);
                   2874: #endif
                   2875: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>