Annotation of embedaddon/nginx/src/http/modules/ngx_http_chunked_filter_module.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10: #include <ngx_http.h>
! 11:
! 12:
! 13: typedef struct {
! 14: ngx_chain_t *free;
! 15: ngx_chain_t *busy;
! 16: } ngx_http_chunked_filter_ctx_t;
! 17:
! 18:
! 19: static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf);
! 20:
! 21:
! 22: static ngx_http_module_t ngx_http_chunked_filter_module_ctx = {
! 23: NULL, /* preconfiguration */
! 24: ngx_http_chunked_filter_init, /* postconfiguration */
! 25:
! 26: NULL, /* create main configuration */
! 27: NULL, /* init main configuration */
! 28:
! 29: NULL, /* create server configuration */
! 30: NULL, /* merge server configuration */
! 31:
! 32: NULL, /* create location configuration */
! 33: NULL /* merge location configuration */
! 34: };
! 35:
! 36:
! 37: ngx_module_t ngx_http_chunked_filter_module = {
! 38: NGX_MODULE_V1,
! 39: &ngx_http_chunked_filter_module_ctx, /* module context */
! 40: NULL, /* module directives */
! 41: NGX_HTTP_MODULE, /* module type */
! 42: NULL, /* init master */
! 43: NULL, /* init module */
! 44: NULL, /* init process */
! 45: NULL, /* init thread */
! 46: NULL, /* exit thread */
! 47: NULL, /* exit process */
! 48: NULL, /* exit master */
! 49: NGX_MODULE_V1_PADDING
! 50: };
! 51:
! 52:
! 53: static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
! 54: static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
! 55:
! 56:
! 57: static ngx_int_t
! 58: ngx_http_chunked_header_filter(ngx_http_request_t *r)
! 59: {
! 60: ngx_http_core_loc_conf_t *clcf;
! 61: ngx_http_chunked_filter_ctx_t *ctx;
! 62:
! 63: if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
! 64: || r->headers_out.status == NGX_HTTP_NO_CONTENT
! 65: || r->headers_out.status < NGX_HTTP_OK
! 66: || r != r->main
! 67: || (r->method & NGX_HTTP_HEAD))
! 68: {
! 69: return ngx_http_next_header_filter(r);
! 70: }
! 71:
! 72: if (r->headers_out.content_length_n == -1) {
! 73: if (r->http_version < NGX_HTTP_VERSION_11) {
! 74: r->keepalive = 0;
! 75:
! 76: } else {
! 77: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
! 78:
! 79: if (clcf->chunked_transfer_encoding) {
! 80: r->chunked = 1;
! 81:
! 82: ctx = ngx_pcalloc(r->pool,
! 83: sizeof(ngx_http_chunked_filter_ctx_t));
! 84: if (ctx == NULL) {
! 85: return NGX_ERROR;
! 86: }
! 87:
! 88: ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);
! 89:
! 90: } else {
! 91: r->keepalive = 0;
! 92: }
! 93: }
! 94: }
! 95:
! 96: return ngx_http_next_header_filter(r);
! 97: }
! 98:
! 99:
! 100: static ngx_int_t
! 101: ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
! 102: {
! 103: u_char *chunk;
! 104: off_t size;
! 105: ngx_int_t rc;
! 106: ngx_buf_t *b;
! 107: ngx_chain_t *out, *cl, *tl, **ll;
! 108: ngx_http_chunked_filter_ctx_t *ctx;
! 109:
! 110: if (in == NULL || !r->chunked || r->header_only) {
! 111: return ngx_http_next_body_filter(r, in);
! 112: }
! 113:
! 114: ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);
! 115:
! 116: out = NULL;
! 117: ll = &out;
! 118:
! 119: size = 0;
! 120: cl = in;
! 121:
! 122: for ( ;; ) {
! 123: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 124: "http chunk: %d", ngx_buf_size(cl->buf));
! 125:
! 126: size += ngx_buf_size(cl->buf);
! 127:
! 128: if (cl->buf->flush
! 129: || cl->buf->sync
! 130: || ngx_buf_in_memory(cl->buf)
! 131: || cl->buf->in_file)
! 132: {
! 133: tl = ngx_alloc_chain_link(r->pool);
! 134: if (tl == NULL) {
! 135: return NGX_ERROR;
! 136: }
! 137:
! 138: tl->buf = cl->buf;
! 139: *ll = tl;
! 140: ll = &tl->next;
! 141: }
! 142:
! 143: if (cl->next == NULL) {
! 144: break;
! 145: }
! 146:
! 147: cl = cl->next;
! 148: }
! 149:
! 150: if (size) {
! 151: tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
! 152: if (tl == NULL) {
! 153: return NGX_ERROR;
! 154: }
! 155:
! 156: b = tl->buf;
! 157: chunk = b->start;
! 158:
! 159: if (chunk == NULL) {
! 160: /* the "0000000000000000" is 64-bit hexadecimal string */
! 161:
! 162: chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
! 163: if (chunk == NULL) {
! 164: return NGX_ERROR;
! 165: }
! 166:
! 167: b->start = chunk;
! 168: b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
! 169: }
! 170:
! 171: b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
! 172: b->memory = 0;
! 173: b->temporary = 1;
! 174: b->pos = chunk;
! 175: b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
! 176:
! 177: tl->next = out;
! 178: out = tl;
! 179: }
! 180:
! 181: if (cl->buf->last_buf) {
! 182: tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
! 183: if (tl == NULL) {
! 184: return NGX_ERROR;
! 185: }
! 186:
! 187: b = tl->buf;
! 188:
! 189: b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
! 190: b->temporary = 0;
! 191: b->memory = 1;
! 192: b->last_buf = 1;
! 193: b->pos = (u_char *) CRLF "0" CRLF CRLF;
! 194: b->last = b->pos + 7;
! 195:
! 196: cl->buf->last_buf = 0;
! 197:
! 198: *ll = tl;
! 199:
! 200: if (size == 0) {
! 201: b->pos += 2;
! 202: }
! 203:
! 204: } else if (size > 0) {
! 205: tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
! 206: if (tl == NULL) {
! 207: return NGX_ERROR;
! 208: }
! 209:
! 210: b = tl->buf;
! 211:
! 212: b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
! 213: b->temporary = 0;
! 214: b->memory = 1;
! 215: b->pos = (u_char *) CRLF;
! 216: b->last = b->pos + 2;
! 217:
! 218: *ll = tl;
! 219:
! 220: } else {
! 221: *ll = NULL;
! 222: }
! 223:
! 224: rc = ngx_http_next_body_filter(r, out);
! 225:
! 226: ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
! 227: (ngx_buf_tag_t) &ngx_http_chunked_filter_module);
! 228:
! 229: return rc;
! 230: }
! 231:
! 232:
! 233: static ngx_int_t
! 234: ngx_http_chunked_filter_init(ngx_conf_t *cf)
! 235: {
! 236: ngx_http_next_header_filter = ngx_http_top_header_filter;
! 237: ngx_http_top_header_filter = ngx_http_chunked_header_filter;
! 238:
! 239: ngx_http_next_body_filter = ngx_http_top_body_filter;
! 240: ngx_http_top_body_filter = ngx_http_chunked_body_filter;
! 241:
! 242: return NGX_OK;
! 243: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>