Annotation of embedaddon/nginx/src/http/ngx_http_spdy_filter_module.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 <nginx.h>
                     12: #include <ngx_http_spdy_module.h>
                     13: 
                     14: #include <zlib.h>
                     15: 
                     16: 
                     17: #define NGX_SPDY_WRITE_BUFFERED  NGX_HTTP_WRITE_BUFFERED
                     18: 
                     19: #define ngx_http_spdy_nv_nsize(h)  (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1)
                     20: #define ngx_http_spdy_nv_vsize(h)  (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1)
                     21: 
                     22: #define ngx_http_spdy_nv_write_num   ngx_spdy_frame_write_uint16
                     23: #define ngx_http_spdy_nv_write_nlen  ngx_spdy_frame_write_uint16
                     24: #define ngx_http_spdy_nv_write_vlen  ngx_spdy_frame_write_uint16
                     25: 
                     26: #define ngx_http_spdy_nv_write_name(p, h)                                     \
                     27:     ngx_cpymem(ngx_http_spdy_nv_write_nlen(p, sizeof(h) - 1), h, sizeof(h) - 1)
                     28: 
                     29: #define ngx_http_spdy_nv_write_val(p, h)                                      \
                     30:     ngx_cpymem(ngx_http_spdy_nv_write_vlen(p, sizeof(h) - 1), h, sizeof(h) - 1)
                     31: 
                     32: static ngx_inline ngx_int_t ngx_http_spdy_filter_send(
                     33:     ngx_connection_t *fc, ngx_http_spdy_stream_t *stream);
                     34: 
                     35: static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame(
                     36:     ngx_http_spdy_stream_t *stream, size_t len, ngx_uint_t flags,
                     37:     ngx_chain_t *first, ngx_chain_t *last);
                     38: 
                     39: static ngx_int_t ngx_http_spdy_syn_frame_handler(
                     40:     ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
                     41: static ngx_int_t ngx_http_spdy_data_frame_handler(
                     42:     ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
                     43: static ngx_inline void ngx_http_spdy_handle_frame(
                     44:     ngx_http_spdy_stream_t *stream, ngx_http_spdy_out_frame_t *frame);
                     45: static ngx_inline void ngx_http_spdy_handle_stream(
                     46:     ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream);
                     47: 
                     48: static void ngx_http_spdy_filter_cleanup(void *data);
                     49: 
                     50: static ngx_int_t ngx_http_spdy_filter_init(ngx_conf_t *cf);
                     51: 
                     52: 
                     53: static ngx_http_module_t  ngx_http_spdy_filter_module_ctx = {
                     54:     NULL,                                  /* preconfiguration */
                     55:     ngx_http_spdy_filter_init,             /* postconfiguration */
                     56: 
                     57:     NULL,                                  /* create main configuration */
                     58:     NULL,                                  /* init main configuration */
                     59: 
                     60:     NULL,                                  /* create server configuration */
                     61:     NULL,                                  /* merge server configuration */
                     62: 
                     63:     NULL,                                  /* create location configuration */
                     64:     NULL                                   /* merge location configuration */
                     65: };
                     66: 
                     67: 
                     68: ngx_module_t  ngx_http_spdy_filter_module = {
                     69:     NGX_MODULE_V1,
                     70:     &ngx_http_spdy_filter_module_ctx,      /* module context */
                     71:     NULL,                                  /* module directives */
                     72:     NGX_HTTP_MODULE,                       /* module type */
                     73:     NULL,                                  /* init master */
                     74:     NULL,                                  /* init module */
                     75:     NULL,                                  /* init process */
                     76:     NULL,                                  /* init thread */
                     77:     NULL,                                  /* exit thread */
                     78:     NULL,                                  /* exit process */
                     79:     NULL,                                  /* exit master */
                     80:     NGX_MODULE_V1_PADDING
                     81: };
                     82: 
                     83: 
                     84: static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
                     85: static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
                     86: 
                     87: 
                     88: static ngx_int_t
                     89: ngx_http_spdy_header_filter(ngx_http_request_t *r)
                     90: {
                     91:     int                           rc;
                     92:     size_t                        len;
                     93:     u_char                       *p, *buf, *last;
                     94:     ngx_buf_t                    *b;
                     95:     ngx_str_t                     host;
                     96:     ngx_uint_t                    i, j, count, port;
                     97:     ngx_chain_t                  *cl;
                     98:     ngx_list_part_t              *part, *pt;
                     99:     ngx_table_elt_t              *header, *h;
                    100:     ngx_connection_t             *c;
                    101:     ngx_http_cleanup_t           *cln;
                    102:     ngx_http_core_loc_conf_t     *clcf;
                    103:     ngx_http_core_srv_conf_t     *cscf;
                    104:     ngx_http_spdy_stream_t       *stream;
                    105:     ngx_http_spdy_out_frame_t    *frame;
                    106:     ngx_http_spdy_connection_t   *sc;
                    107:     struct sockaddr_in           *sin;
                    108: #if (NGX_HAVE_INET6)
                    109:     struct sockaddr_in6          *sin6;
                    110: #endif
                    111:     u_char                        addr[NGX_SOCKADDR_STRLEN];
                    112: 
                    113:     if (!r->spdy_stream) {
                    114:         return ngx_http_next_header_filter(r);
                    115:     }
                    116: 
                    117:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    118:                    "spdy header filter");
                    119: 
                    120:     if (r->header_sent) {
                    121:         return NGX_OK;
                    122:     }
                    123: 
                    124:     r->header_sent = 1;
                    125: 
                    126:     if (r != r->main) {
                    127:         return NGX_OK;
                    128:     }
                    129: 
                    130:     c = r->connection;
                    131: 
                    132:     if (r->method == NGX_HTTP_HEAD) {
                    133:         r->header_only = 1;
                    134:     }
                    135: 
                    136:     switch (r->headers_out.status) {
                    137: 
                    138:     case NGX_HTTP_OK:
                    139:     case NGX_HTTP_PARTIAL_CONTENT:
                    140:         break;
                    141: 
                    142:     case NGX_HTTP_NOT_MODIFIED:
                    143:         r->header_only = 1;
                    144:         break;
                    145: 
                    146:     case NGX_HTTP_NO_CONTENT:
                    147:         r->header_only = 1;
                    148: 
                    149:         ngx_str_null(&r->headers_out.content_type);
                    150: 
                    151:         r->headers_out.content_length = NULL;
                    152:         r->headers_out.content_length_n = -1;
                    153: 
                    154:         /* fall through */
                    155: 
                    156:     default:
                    157:         r->headers_out.last_modified_time = -1;
                    158:         r->headers_out.last_modified = NULL;
                    159:     }
                    160: 
                    161:     len = NGX_SPDY_NV_NUM_SIZE
                    162:           + ngx_http_spdy_nv_nsize("version")
                    163:           + ngx_http_spdy_nv_vsize("HTTP/1.1")
                    164:           + ngx_http_spdy_nv_nsize("status")
                    165:           + ngx_http_spdy_nv_vsize("418");
                    166: 
                    167:     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    168: 
                    169:     if (r->headers_out.server == NULL) {
                    170:         len += ngx_http_spdy_nv_nsize("server");
                    171:         len += clcf->server_tokens ? ngx_http_spdy_nv_vsize(NGINX_VER)
                    172:                                    : ngx_http_spdy_nv_vsize("nginx");
                    173:     }
                    174: 
                    175:     if (r->headers_out.date == NULL) {
                    176:         len += ngx_http_spdy_nv_nsize("date")
                    177:                + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT");
                    178:     }
                    179: 
                    180:     if (r->headers_out.content_type.len) {
                    181:         len += ngx_http_spdy_nv_nsize("content-type")
                    182:                + NGX_SPDY_NV_VLEN_SIZE + r->headers_out.content_type.len;
                    183: 
                    184:         if (r->headers_out.content_type_len == r->headers_out.content_type.len
                    185:             && r->headers_out.charset.len)
                    186:         {
                    187:             len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
                    188:         }
                    189:     }
                    190: 
                    191:     if (r->headers_out.content_length == NULL
                    192:         && r->headers_out.content_length_n >= 0)
                    193:     {
                    194:         len += ngx_http_spdy_nv_nsize("content-length")
                    195:                + NGX_SPDY_NV_VLEN_SIZE + NGX_OFF_T_LEN;
                    196:     }
                    197: 
                    198:     if (r->headers_out.last_modified == NULL
                    199:         && r->headers_out.last_modified_time != -1)
                    200:     {
                    201:         len += ngx_http_spdy_nv_nsize("last-modified")
                    202:                + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT");
                    203:     }
                    204: 
                    205:     if (r->headers_out.location
                    206:         && r->headers_out.location->value.len
                    207:         && r->headers_out.location->value.data[0] == '/')
                    208:     {
                    209:         r->headers_out.location->hash = 0;
                    210: 
                    211:         if (clcf->server_name_in_redirect) {
                    212:             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
                    213:             host = cscf->server_name;
                    214: 
                    215:         } else if (r->headers_in.server.len) {
                    216:             host = r->headers_in.server;
                    217: 
                    218:         } else {
                    219:             host.len = NGX_SOCKADDR_STRLEN;
                    220:             host.data = addr;
                    221: 
                    222:             if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
                    223:                 return NGX_ERROR;
                    224:             }
                    225:         }
                    226: 
                    227:         switch (c->local_sockaddr->sa_family) {
                    228: 
                    229: #if (NGX_HAVE_INET6)
                    230:         case AF_INET6:
                    231:             sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
                    232:             port = ntohs(sin6->sin6_port);
                    233:             break;
                    234: #endif
                    235: #if (NGX_HAVE_UNIX_DOMAIN)
                    236:         case AF_UNIX:
                    237:             port = 0;
                    238:             break;
                    239: #endif
                    240:         default: /* AF_INET */
                    241:             sin = (struct sockaddr_in *) c->local_sockaddr;
                    242:             port = ntohs(sin->sin_port);
                    243:             break;
                    244:         }
                    245: 
                    246:         len += ngx_http_spdy_nv_nsize("location")
                    247:                + ngx_http_spdy_nv_vsize("https://")
                    248:                + host.len
                    249:                + r->headers_out.location->value.len;
                    250: 
                    251:         if (clcf->port_in_redirect) {
                    252: 
                    253: #if (NGX_HTTP_SSL)
                    254:             if (c->ssl)
                    255:                 port = (port == 443) ? 0 : port;
                    256:             else
                    257: #endif
                    258:                 port = (port == 80) ? 0 : port;
                    259: 
                    260:         } else {
                    261:             port = 0;
                    262:         }
                    263: 
                    264:         if (port) {
                    265:             len += sizeof(":65535") - 1;
                    266:         }
                    267: 
                    268:     } else {
                    269:         ngx_str_null(&host);
                    270:         port = 0;
                    271:     }
                    272: 
                    273:     part = &r->headers_out.headers.part;
                    274:     header = part->elts;
                    275: 
                    276:     for (i = 0; /* void */; i++) {
                    277: 
                    278:         if (i >= part->nelts) {
                    279:             if (part->next == NULL) {
                    280:                 break;
                    281:             }
                    282: 
                    283:             part = part->next;
                    284:             header = part->elts;
                    285:             i = 0;
                    286:         }
                    287: 
                    288:         if (header[i].hash == 0) {
                    289:             continue;
                    290:         }
                    291: 
                    292:         len += NGX_SPDY_NV_NLEN_SIZE + header[i].key.len
                    293:                + NGX_SPDY_NV_VLEN_SIZE  + header[i].value.len;
                    294:     }
                    295: 
                    296:     buf = ngx_alloc(len, r->pool->log);
                    297:     if (buf == NULL) {
                    298:         return NGX_ERROR;
                    299:     }
                    300: 
                    301:     last = buf + NGX_SPDY_NV_NUM_SIZE;
                    302: 
                    303:     last = ngx_http_spdy_nv_write_name(last, "version");
                    304:     last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1");
                    305: 
                    306:     last = ngx_http_spdy_nv_write_name(last, "status");
                    307:     last = ngx_spdy_frame_write_uint16(last, 3);
                    308:     last = ngx_sprintf(last, "%03ui", r->headers_out.status);
                    309: 
                    310:     count = 2;
                    311: 
                    312:     if (r->headers_out.server == NULL) {
                    313:         last = ngx_http_spdy_nv_write_name(last, "server");
                    314:         last = clcf->server_tokens
                    315:                ? ngx_http_spdy_nv_write_val(last, NGINX_VER)
                    316:                : ngx_http_spdy_nv_write_val(last, "nginx");
                    317: 
                    318:         count++;
                    319:     }
                    320: 
                    321:     if (r->headers_out.date == NULL) {
                    322:         last = ngx_http_spdy_nv_write_name(last, "date");
                    323: 
                    324:         last = ngx_http_spdy_nv_write_vlen(last, ngx_cached_http_time.len);
                    325: 
                    326:         last = ngx_cpymem(last, ngx_cached_http_time.data,
                    327:                           ngx_cached_http_time.len);
                    328: 
                    329:         count++;
                    330:     }
                    331: 
                    332:     if (r->headers_out.content_type.len) {
                    333: 
                    334:         last = ngx_http_spdy_nv_write_name(last, "content-type");
                    335: 
                    336:         p = last + NGX_SPDY_NV_VLEN_SIZE;
                    337: 
                    338:         last = ngx_cpymem(p, r->headers_out.content_type.data,
                    339:                           r->headers_out.content_type.len);
                    340: 
                    341:         if (r->headers_out.content_type_len == r->headers_out.content_type.len
                    342:             && r->headers_out.charset.len)
                    343:         {
                    344:             last = ngx_cpymem(last, "; charset=", sizeof("; charset=") - 1);
                    345: 
                    346:             last = ngx_cpymem(last, r->headers_out.charset.data,
                    347:                               r->headers_out.charset.len);
                    348: 
                    349:             /* update r->headers_out.content_type for possible logging */
                    350: 
                    351:             r->headers_out.content_type.len = last - p;
                    352:             r->headers_out.content_type.data = p;
                    353:         }
                    354: 
                    355:         (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
                    356:                                            r->headers_out.content_type.len);
                    357: 
                    358:         count++;
                    359:     }
                    360: 
                    361:     if (r->headers_out.content_length == NULL
                    362:         && r->headers_out.content_length_n >= 0)
                    363:     {
                    364:         last = ngx_http_spdy_nv_write_name(last, "content-length");
                    365: 
                    366:         p = last + NGX_SPDY_NV_VLEN_SIZE;
                    367: 
                    368:         last = ngx_sprintf(p, "%O", r->headers_out.content_length_n);
                    369: 
                    370:         (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
                    371:                                            last - p);
                    372: 
                    373:         count++;
                    374:     }
                    375: 
                    376:     if (r->headers_out.last_modified == NULL
                    377:         && r->headers_out.last_modified_time != -1)
                    378:     {
                    379:         last = ngx_http_spdy_nv_write_name(last, "last-modified");
                    380: 
                    381:         p = last + NGX_SPDY_NV_VLEN_SIZE;
                    382: 
                    383:         last = ngx_http_time(p, r->headers_out.last_modified_time);
                    384: 
                    385:         (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
                    386:                                            last - p);
                    387: 
                    388:         count++;
                    389:     }
                    390: 
                    391:     if (host.data) {
                    392: 
                    393:         last = ngx_http_spdy_nv_write_name(last, "location");
                    394: 
                    395:         p = last + NGX_SPDY_NV_VLEN_SIZE;
                    396: 
                    397:         last = ngx_cpymem(p, "http", sizeof("http") - 1);
                    398: 
                    399: #if (NGX_HTTP_SSL)
                    400:         if (c->ssl) {
                    401:             *last++ ='s';
                    402:         }
                    403: #endif
                    404: 
                    405:         *last++ = ':'; *last++ = '/'; *last++ = '/';
                    406: 
                    407:         last = ngx_cpymem(last, host.data, host.len);
                    408: 
                    409:         if (port) {
                    410:             last = ngx_sprintf(last, ":%ui", port);
                    411:         }
                    412: 
                    413:         last = ngx_cpymem(last, r->headers_out.location->value.data,
                    414:                           r->headers_out.location->value.len);
                    415: 
                    416:         /* update r->headers_out.location->value for possible logging */
                    417: 
                    418:         r->headers_out.location->value.len = last - p;
                    419:         r->headers_out.location->value.data = p;
                    420:         ngx_str_set(&r->headers_out.location->key, "location");
                    421: 
                    422:         (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
                    423:                                            r->headers_out.location->value.len);
                    424: 
                    425:         count++;
                    426:     }
                    427: 
                    428:     part = &r->headers_out.headers.part;
                    429:     header = part->elts;
                    430: 
                    431:     for (i = 0; /* void */; i++) {
                    432: 
                    433:         if (i >= part->nelts) {
                    434:             if (part->next == NULL) {
                    435:                 break;
                    436:             }
                    437: 
                    438:             part = part->next;
                    439:             header = part->elts;
                    440:             i = 0;
                    441:         }
                    442: 
                    443:         if (header[i].hash == 0 || header[i].hash == 2) {
                    444:             continue;
                    445:         }
                    446: 
                    447:         if ((header[i].key.len == 6
                    448:              && ngx_strncasecmp(header[i].key.data,
                    449:                                 (u_char *) "status", 6) == 0)
                    450:             || (header[i].key.len == 7
                    451:                 && ngx_strncasecmp(header[i].key.data,
                    452:                                    (u_char *) "version", 7) == 0))
                    453:         {
                    454:             header[i].hash = 0;
                    455:             continue;
                    456:         }
                    457: 
                    458:         last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len);
                    459: 
                    460:         ngx_strlow(last, header[i].key.data, header[i].key.len);
                    461:         last += header[i].key.len;
                    462: 
                    463:         p = last + NGX_SPDY_NV_VLEN_SIZE;
                    464: 
                    465:         last = ngx_cpymem(p, header[i].value.data, header[i].value.len);
                    466: 
                    467:         pt = part;
                    468:         h = header;
                    469: 
                    470:         for (j = i + 1; /* void */; j++) {
                    471: 
                    472:             if (j >= pt->nelts) {
                    473:                 if (pt->next == NULL) {
                    474:                     break;
                    475:                 }
                    476: 
                    477:                 pt = pt->next;
                    478:                 h = pt->elts;
                    479:                 j = 0;
                    480:             }
                    481: 
                    482:             if (h[j].hash == 0 || h[j].hash == 2
                    483:                 || h[j].key.len != header[i].key.len
                    484:                 || ngx_strncasecmp(header[i].key.data, h[j].key.data,
                    485:                                    header[i].key.len))
                    486:             {
                    487:                 continue;
                    488:             }
                    489: 
                    490:             *last++ = '\0';
                    491: 
                    492:             last = ngx_cpymem(last, h[j].value.data, h[j].value.len);
                    493: 
                    494:             h[j].hash = 2;
                    495:         }
                    496: 
                    497:         (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE,
                    498:                                            last - p);
                    499: 
                    500:         count++;
                    501:     }
                    502: 
                    503:     (void) ngx_spdy_frame_write_uint16(buf, count);
                    504: 
                    505:     stream = r->spdy_stream;
                    506:     sc = stream->connection;
                    507: 
                    508:     len = last - buf;
                    509: 
                    510:     b = ngx_create_temp_buf(r->pool, NGX_SPDY_FRAME_HEADER_SIZE
                    511:                                      + NGX_SPDY_SYN_REPLY_SIZE
                    512:                                      + deflateBound(&sc->zstream_out, len));
                    513:     if (b == NULL) {
                    514:         ngx_free(buf);
                    515:         return NGX_ERROR;
                    516:     }
                    517: 
                    518:     b->last += NGX_SPDY_FRAME_HEADER_SIZE + NGX_SPDY_SYN_REPLY_SIZE;
                    519: 
                    520:     sc->zstream_out.next_in = buf;
                    521:     sc->zstream_out.avail_in = len;
                    522:     sc->zstream_out.next_out = b->last;
                    523:     sc->zstream_out.avail_out = b->end - b->last;
                    524: 
                    525:     rc = deflate(&sc->zstream_out, Z_SYNC_FLUSH);
                    526: 
                    527:     ngx_free(buf);
                    528: 
                    529:     if (rc != Z_OK) {
                    530:         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                    531:                       "spdy deflate() failed: %d", rc);
                    532:         return NGX_ERROR;
                    533:     }
                    534: 
                    535:     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    536:                    "spdy deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
                    537:                    sc->zstream_out.next_in, sc->zstream_out.next_out,
                    538:                    sc->zstream_out.avail_in, sc->zstream_out.avail_out,
                    539:                    rc);
                    540: 
                    541:     b->last = sc->zstream_out.next_out;
                    542: 
                    543:     p = b->pos;
                    544:     p = ngx_spdy_frame_write_head(p, NGX_SPDY_SYN_REPLY);
                    545: 
                    546:     len = b->last - b->pos;
                    547: 
                    548:     r->header_size = len;
                    549: 
                    550:     if (r->header_only) {
                    551:         b->last_buf = 1;
                    552:         p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN,
                    553:                                              len - NGX_SPDY_FRAME_HEADER_SIZE);
                    554:     } else {
                    555:         p = ngx_spdy_frame_write_flags_and_len(p, 0,
                    556:                                              len - NGX_SPDY_FRAME_HEADER_SIZE);
                    557:     }
                    558: 
                    559:     (void) ngx_spdy_frame_write_sid(p, stream->id);
                    560: 
                    561:     cl = ngx_alloc_chain_link(r->pool);
                    562:     if (cl == NULL) {
                    563:         return NGX_ERROR;
                    564:     }
                    565: 
                    566:     cl->buf = b;
                    567:     cl->next = NULL;
                    568: 
                    569:     frame = ngx_palloc(r->pool, sizeof(ngx_http_spdy_out_frame_t));
                    570:     if (frame == NULL) {
                    571:         return NGX_ERROR;
                    572:     }
                    573: 
                    574:     frame->first = cl;
                    575:     frame->last = cl;
                    576:     frame->handler = ngx_http_spdy_syn_frame_handler;
                    577:     frame->free = NULL;
                    578:     frame->stream = stream;
                    579:     frame->size = len;
                    580:     frame->priority = stream->priority;
                    581:     frame->blocked = 1;
                    582:     frame->fin = r->header_only;
                    583: 
                    584:     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
                    585:                    "spdy:%ui create SYN_REPLY frame %p: size:%uz",
                    586:                    stream->id, frame, frame->size);
                    587: 
                    588:     ngx_http_spdy_queue_blocked_frame(sc, frame);
                    589: 
                    590:     r->blocked++;
                    591: 
                    592:     cln = ngx_http_cleanup_add(r, 0);
                    593:     if (cln == NULL) {
                    594:         return NGX_ERROR;
                    595:     }
                    596: 
                    597:     cln->handler = ngx_http_spdy_filter_cleanup;
                    598:     cln->data = stream;
                    599: 
                    600:     stream->waiting = 1;
                    601: 
                    602:     return ngx_http_spdy_filter_send(c, stream);
                    603: }
                    604: 
                    605: 
                    606: static ngx_int_t
                    607: ngx_http_spdy_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
                    608: {
                    609:     off_t                       size;
                    610:     ngx_buf_t                  *b;
                    611:     ngx_chain_t                *cl, *ll, *out, **ln;
                    612:     ngx_http_spdy_stream_t     *stream;
                    613:     ngx_http_spdy_out_frame_t  *frame;
                    614: 
                    615:     stream = r->spdy_stream;
                    616: 
                    617:     if (stream == NULL) {
                    618:         return ngx_http_next_body_filter(r, in);
                    619:     }
                    620: 
                    621:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    622:                    "spdy body filter \"%V?%V\"", &r->uri, &r->args);
                    623: 
                    624:     if (in == NULL || r->header_only) {
                    625: 
                    626:         if (stream->waiting) {
                    627:             return NGX_AGAIN;
                    628:         }
                    629: 
                    630:         r->connection->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
                    631: 
                    632:         return NGX_OK;
                    633:     }
                    634: 
                    635:     size = 0;
                    636:     ln = &out;
                    637:     ll = in;
                    638: 
                    639:     for ( ;; ) {
                    640:         b = ll->buf;
                    641: #if 1
                    642:         if (ngx_buf_size(b) == 0 && !ngx_buf_special(b)) {
                    643:             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    644:                           "zero size buf in spdy body filter "
                    645:                           "t:%d r:%d f:%d %p %p-%p %p %O-%O",
                    646:                           b->temporary,
                    647:                           b->recycled,
                    648:                           b->in_file,
                    649:                           b->start,
                    650:                           b->pos,
                    651:                           b->last,
                    652:                           b->file,
                    653:                           b->file_pos,
                    654:                           b->file_last);
                    655: 
                    656:             ngx_debug_point();
                    657:             return NGX_ERROR;
                    658:         }
                    659: #endif
                    660:         cl = ngx_alloc_chain_link(r->pool);
                    661:         if (cl == NULL) {
                    662:             return NGX_ERROR;
                    663:         }
                    664: 
                    665:         size += ngx_buf_size(b);
                    666:         cl->buf = b;
                    667: 
                    668:         *ln = cl;
                    669:         ln = &cl->next;
                    670: 
                    671:         if (ll->next == NULL) {
                    672:             break;
                    673:         }
                    674: 
                    675:         ll = ll->next;
                    676:     }
                    677: 
                    678:     if (size > NGX_SPDY_MAX_FRAME_SIZE) {
                    679:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    680:                       "FIXME: chain too big in spdy filter: %O", size);
                    681:         return NGX_ERROR;
                    682:     }
                    683: 
                    684:     frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size,
                    685:                                                 b->last_buf, out, cl);
                    686:     if (frame == NULL) {
                    687:         return NGX_ERROR;
                    688:     }
                    689: 
                    690:     ngx_http_spdy_queue_frame(stream->connection, frame);
                    691: 
                    692:     stream->waiting++;
                    693: 
                    694:     r->main->blocked++;
                    695: 
                    696:     return ngx_http_spdy_filter_send(r->connection, stream);
                    697: }
                    698: 
                    699: 
                    700: static ngx_http_spdy_out_frame_t *
                    701: ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
                    702:     size_t len, ngx_uint_t fin, ngx_chain_t *first, ngx_chain_t *last)
                    703: {
                    704:     u_char                     *p;
                    705:     ngx_buf_t                  *buf;
                    706:     ngx_uint_t                  flags;
                    707:     ngx_chain_t                *cl;
                    708:     ngx_http_spdy_out_frame_t  *frame;
                    709: 
                    710: 
                    711:     frame = stream->free_frames;
                    712: 
                    713:     if (frame) {
                    714:         stream->free_frames = frame->free;
                    715: 
                    716:     } else {
                    717:         frame = ngx_palloc(stream->request->pool,
                    718:                            sizeof(ngx_http_spdy_out_frame_t));
                    719:         if (frame == NULL) {
                    720:             return NULL;
                    721:         }
                    722:     }
                    723: 
                    724:     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
                    725:                    "spdy:%ui create DATA frame %p: len:%uz fin:%ui",
                    726:                    stream->id, frame, len, fin);
                    727: 
                    728:     if (len || fin) {
                    729: 
                    730:         flags = fin ? NGX_SPDY_FLAG_FIN : 0;
                    731: 
                    732:         cl = ngx_chain_get_free_buf(stream->request->pool,
                    733:                                     &stream->free_data_headers);
                    734:         if (cl == NULL) {
                    735:             return NULL;
                    736:         }
                    737: 
                    738:         buf = cl->buf;
                    739: 
                    740:         if (buf->start) {
                    741:             p = buf->start;
                    742:             buf->pos = p;
                    743: 
                    744:             p += sizeof(uint32_t);
                    745: 
                    746:             (void) ngx_spdy_frame_write_flags_and_len(p, flags, len);
                    747: 
                    748:         } else {
                    749:             p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE);
                    750:             if (p == NULL) {
                    751:                 return NULL;
                    752:             }
                    753: 
                    754:             buf->pos = p;
                    755:             buf->start = p;
                    756: 
                    757:             p = ngx_spdy_frame_write_sid(p, stream->id);
                    758:             p = ngx_spdy_frame_write_flags_and_len(p, flags, len);
                    759: 
                    760:             buf->last = p;
                    761:             buf->end = p;
                    762: 
                    763:             buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_module;
                    764:             buf->memory = 1;
                    765:         }
                    766: 
                    767:         cl->next = first;
                    768:         first = cl;
                    769:     }
                    770: 
                    771:     frame->first = first;
                    772:     frame->last = last;
                    773:     frame->handler = ngx_http_spdy_data_frame_handler;
                    774:     frame->free = NULL;
                    775:     frame->stream = stream;
                    776:     frame->size = NGX_SPDY_FRAME_HEADER_SIZE + len;
                    777:     frame->priority = stream->priority;
                    778:     frame->blocked = 0;
                    779:     frame->fin = fin;
                    780: 
                    781:     return frame;
                    782: }
                    783: 
                    784: 
                    785: static ngx_inline ngx_int_t
                    786: ngx_http_spdy_filter_send(ngx_connection_t *fc, ngx_http_spdy_stream_t *stream)
                    787: {
                    788:     if (ngx_http_spdy_send_output_queue(stream->connection) == NGX_ERROR) {
                    789:         fc->error = 1;
                    790:         return NGX_ERROR;
                    791:     }
                    792: 
                    793:     if (stream->waiting) {
                    794:         fc->buffered |= NGX_SPDY_WRITE_BUFFERED;
                    795:         fc->write->delayed = 1;
                    796:         return NGX_AGAIN;
                    797:     }
                    798: 
                    799:     fc->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
                    800: 
                    801:     return NGX_OK;
                    802: }
                    803: 
                    804: 
                    805: static ngx_int_t
                    806: ngx_http_spdy_syn_frame_handler(ngx_http_spdy_connection_t *sc,
                    807:     ngx_http_spdy_out_frame_t *frame)
                    808: {
                    809:     ngx_buf_t               *buf;
                    810:     ngx_http_spdy_stream_t  *stream;
                    811: 
                    812:     buf = frame->first->buf;
                    813: 
                    814:     if (buf->pos != buf->last) {
                    815:         return NGX_AGAIN;
                    816:     }
                    817: 
                    818:     stream = frame->stream;
                    819: 
                    820:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    821:                    "spdy:%ui SYN_REPLY frame %p was sent", stream->id, frame);
                    822: 
                    823:     ngx_free_chain(stream->request->pool, frame->first);
                    824: 
                    825:     ngx_http_spdy_handle_frame(stream, frame);
                    826: 
                    827:     ngx_http_spdy_handle_stream(sc, stream);
                    828: 
                    829:     return NGX_OK;
                    830: }
                    831: 
                    832: 
                    833: static ngx_int_t
                    834: ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
                    835:     ngx_http_spdy_out_frame_t *frame)
                    836: {
                    837:     ngx_chain_t             *cl, *ln;
                    838:     ngx_http_spdy_stream_t  *stream;
                    839: 
                    840:     stream = frame->stream;
                    841: 
                    842:     cl = frame->first;
                    843: 
                    844:     if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_module) {
                    845: 
                    846:         if (cl->buf->pos != cl->buf->last) {
                    847:             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    848:                            "spdy:%ui DATA frame %p was sent partially",
                    849:                            stream->id, frame);
                    850: 
                    851:             return NGX_AGAIN;
                    852:         }
                    853: 
                    854:         ln = cl->next;
                    855: 
                    856:         cl->next = stream->free_data_headers;
                    857:         stream->free_data_headers = cl;
                    858: 
                    859:         if (cl == frame->last) {
                    860:             goto done;
                    861:         }
                    862: 
                    863:         cl = ln;
                    864:     }
                    865: 
                    866:     for ( ;; ) {
                    867:         if (ngx_buf_size(cl->buf) != 0) {
                    868: 
                    869:             if (cl != frame->first) {
                    870:                 frame->first = cl;
                    871:                 ngx_http_spdy_handle_stream(sc, stream);
                    872:             }
                    873: 
                    874:             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    875:                            "spdy:%ui DATA frame %p was sent partially",
                    876:                            stream->id, frame);
                    877: 
                    878:             return NGX_AGAIN;
                    879:         }
                    880: 
                    881:         ln = cl->next;
                    882: 
                    883:         ngx_free_chain(stream->request->pool, cl);
                    884: 
                    885:         if (cl == frame->last) {
                    886:             goto done;
                    887:         }
                    888: 
                    889:         cl = ln;
                    890:     }
                    891: 
                    892: done:
                    893: 
                    894:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
                    895:                    "spdy:%ui DATA frame %p was sent", stream->id, frame);
                    896: 
                    897:     stream->request->header_size += NGX_SPDY_FRAME_HEADER_SIZE;
                    898: 
                    899:     ngx_http_spdy_handle_frame(stream, frame);
                    900: 
                    901:     ngx_http_spdy_handle_stream(sc, stream);
                    902: 
                    903:     return NGX_OK;
                    904: }
                    905: 
                    906: 
                    907: static ngx_inline void
                    908: ngx_http_spdy_handle_frame(ngx_http_spdy_stream_t *stream,
                    909:     ngx_http_spdy_out_frame_t *frame)
                    910: {
                    911:     ngx_http_request_t  *r;
                    912: 
                    913:     r = stream->request;
                    914: 
                    915:     r->connection->sent += frame->size;
                    916:     r->blocked--;
                    917: 
                    918:     if (frame->fin) {
                    919:         stream->out_closed = 1;
                    920:     }
                    921: 
                    922:     frame->free = stream->free_frames;
                    923:     stream->free_frames = frame;
                    924: 
                    925:     stream->waiting--;
                    926: }
                    927: 
                    928: 
                    929: static ngx_inline void
                    930: ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc,
                    931:     ngx_http_spdy_stream_t *stream)
                    932: {
                    933:     ngx_connection_t  *fc;
                    934: 
                    935:     fc = stream->request->connection;
                    936: 
                    937:     fc->write->delayed = 0;
                    938: 
                    939:     if (stream->handled) {
                    940:         return;
                    941:     }
                    942: 
                    943:     if (sc->blocked == 2) {
                    944:         stream->handled = 1;
                    945: 
                    946:         stream->next = sc->last_stream;
                    947:         sc->last_stream = stream;
                    948:     }
                    949: }
                    950: 
                    951: 
                    952: static void
                    953: ngx_http_spdy_filter_cleanup(void *data)
                    954: {
                    955:     ngx_http_spdy_stream_t *stream = data;
                    956: 
                    957:     ngx_http_request_t         *r;
                    958:     ngx_http_spdy_out_frame_t  *frame, **fn;
                    959: 
                    960:     if (stream->waiting == 0) {
                    961:         return;
                    962:     }
                    963: 
                    964:     r = stream->request;
                    965: 
                    966:     fn = &stream->connection->last_out;
                    967: 
                    968:     for ( ;; ) {
                    969:         frame = *fn;
                    970: 
                    971:         if (frame == NULL) {
                    972:             break;
                    973:         }
                    974: 
                    975:         if (frame->stream == stream && !frame->blocked) {
                    976: 
                    977:             stream->waiting--;
                    978:             r->blocked--;
                    979: 
                    980:             *fn = frame->next;
                    981:             continue;
                    982:         }
                    983: 
                    984:         fn = &frame->next;
                    985:     }
                    986: }
                    987: 
                    988: 
                    989: static ngx_int_t
                    990: ngx_http_spdy_filter_init(ngx_conf_t *cf)
                    991: {
                    992:     ngx_http_next_header_filter = ngx_http_top_header_filter;
                    993:     ngx_http_top_header_filter = ngx_http_spdy_header_filter;
                    994: 
                    995:     ngx_http_next_body_filter = ngx_http_top_body_filter;
                    996:     ngx_http_top_body_filter = ngx_http_spdy_body_filter;
                    997: 
                    998:     return NGX_OK;
                    999: }

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