ASF Bugzilla – Attachment 29270 Details for
Bug 52860
Support Transfer-Encoding: gzip
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch against trunk r1376741
52860.diff (text/plain), 15.48 KB, created by
Tim B
on 2012-08-23 22:45:44 UTC
(
hide
)
Description:
patch against trunk r1376741
Filename:
MIME Type:
Creator:
Tim B
Created:
2012-08-23 22:45:44 UTC
Size:
15.48 KB
patch
obsolete
>Index: modules/filters/mod_deflate.c >=================================================================== >--- modules/filters/mod_deflate.c (revision 1376741) >+++ modules/filters/mod_deflate.c (working copy) >@@ -883,6 +883,385 @@ > return APR_SUCCESS; > } > >+static apr_status_t deflate_te_filter(ap_filter_t *f, >+ apr_bucket_brigade *bb) >+{ >+ apr_bucket *e; >+ request_rec *r = f->r; >+ deflate_ctx *ctx = f->ctx; >+ int zRC; >+ apr_size_t len = 0, blen; >+ const char *data; >+ deflate_filter_config *c; >+ >+ /* No need to compress an empty brigade */ >+ if (APR_BRIGADE_EMPTY(bb)) { >+ return APR_SUCCESS; >+ } >+ >+ c = ap_get_module_config(r->server->module_config, >+ &deflate_module); >+ >+ >+ /* If we don't have a context, we need to ensure that it is okay to send >+ * the deflated content. If we have a context, that means we've done >+ * this before and we liked it. >+ * This could be not so nice if we always fail. But, if we succeed, >+ * we're in better shape. >+ */ >+ if (!ctx) { >+ char *token; >+ const char *encoding; >+ >+ if (have_ssl_compression(r)) { >+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, >+ "Compression enabled at SSL level; not compressing " >+ "at HTTP level."); >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx)); >+ >+ /* >+ * Only work on main request, not subrequests, >+ * that are not a 204 response with no content >+ * and are not tagged with the no-gzip env variable >+ * and not a partial response to a Range request. >+ */ >+ if ((r->main != NULL) || (r->status == HTTP_NO_CONTENT) || >+ apr_table_get(r->subprocess_env, "no-gzip") || >+ apr_table_get(r->headers_out, "Content-Range") >+ ) { >+ if (APLOG_R_IS_LEVEL(r, APLOG_TRACE1)) { >+ const char *reason = >+ (r->main != NULL) ? "subrequest" : >+ (r->status == HTTP_NO_CONTENT) ? "no content" : >+ apr_table_get(r->subprocess_env, "no-gzip") ? "no-gzip" : >+ "content-range"; >+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, >+ "Not compressing (%s)", reason); >+ } >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ /* >+ * Don't add gzip transfer-encoding to responses that >+ * cannot be chunked. >+ */ >+ if (!(r->proto_num >= HTTP_VERSION(1,1))) { >+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, >+ "GZIPTE ignoring non-HTTP/1.1 request"); >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ /* Some browsers might have problems with content types >+ * other than text/html, so set gzip-only-text/html >+ * (with browsermatch) for them >+ */ >+ if (r->content_type == NULL >+ || strncmp(r->content_type, "text/html", 9)) { >+ const char *env_value = apr_table_get(r->subprocess_env, >+ "gzip-only-text/html"); >+ if ( env_value && (strcmp(env_value,"1") == 0) ) { >+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, >+ "Not compressing, (gzip-only-text/html)"); >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ } >+ >+ /* Let's see what our current Content-Encoding is. >+ * If it's already encoded, don't compress again. >+ * (We could, but let's not.) >+ */ >+ encoding = apr_table_get(r->headers_out, "Content-Encoding"); >+ if (encoding) { >+ const char *err_enc; >+ >+ err_enc = apr_table_get(r->err_headers_out, "Content-Encoding"); >+ if (err_enc) { >+ encoding = apr_pstrcat(r->pool, encoding, ",", err_enc, NULL); >+ } >+ } >+ else { >+ encoding = apr_table_get(r->err_headers_out, "Content-Encoding"); >+ } >+ >+ if (r->content_encoding) { >+ encoding = encoding ? apr_pstrcat(r->pool, encoding, ",", >+ r->content_encoding, NULL) >+ : r->content_encoding; >+ } >+ >+ if (encoding) { >+ const char *tmp = encoding; >+ >+ token = ap_get_token(r->pool, &tmp, 0); >+ while (token && *token) { >+ /* stolen from mod_negotiation: */ >+ if (strcmp(token, "identity") && strcmp(token, "7bit") && >+ strcmp(token, "8bit") && strcmp(token, "binary")) { >+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, >+ "Not recompressing (content-encoding already " >+ " set: %s)", token); >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ /* Otherwise, skip token */ >+ if (*tmp) { >+ ++tmp; >+ } >+ token = (*tmp) ? ap_get_token(r->pool, &tmp, 0) : NULL; >+ } >+ } >+ >+ /* Check the TE: header now */ >+ const char *te_accepts; >+ te_accepts = apr_table_get(r->headers_in, "TE"); >+ if (te_accepts == NULL) { >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ /* check whether the Connection: header lists "TE" and, >+ * if so, overlook the TE: header from the request. >+ * >+ * Might be better done more generally, elsewhere in httpd. >+ */ >+ const char *connection; >+ connection = apr_table_get(r->headers_in, "Connection"); >+ if (!(connection == NULL)) { >+ token = ap_get_token(r->pool, &connection, 0); >+ while (token && token[0] && strcasecmp(token, "te")) { >+ /* retrieve next token */ >+ if (*connection == ',') { >+ ++connection; >+ } >+ token = (*connection) ? ap_get_token(r->pool, &connection, 0) : NULL; >+ if (0 == strcasecmp(token, "te")) { >+ /* We will never see a suitable TE: header >+ * because we know we must remove any such >+ * header that is present. >+ */ >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ } >+ } >+ >+ token = ap_get_token(r->pool, &te_accepts, 0); >+ while (token && token[0] && strcasecmp(token, "gzip")) { >+ /* skip parameters, XXX: ;q=foo evaluation? */ >+ while (*te_accepts == ';') { >+ ++te_accepts; >+ ap_get_token(r->pool, &te_accepts, 1); >+ } >+ >+ /* retrieve next token */ >+ if (*te_accepts == ',') { >+ ++te_accepts; >+ } >+ token = (*te_accepts) ? ap_get_token(r->pool, &te_accepts, 0) : NULL; >+ } >+ >+ /* No acceptable token found. */ >+ if (token == NULL || token[0] == '\0') { >+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, >+ "Not compressing (no TE: gzip)"); >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ /* At this point we have decided to filter the content. Let's try to >+ * to initialize zlib (except for 304 responses, where we will only >+ * send out the headers). >+ */ >+ >+ ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc); >+ ctx->buffer = apr_palloc(r->pool, c->bufferSize); >+ ctx->libz_end_func = deflateEnd; >+ >+ zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED, >+ c->windowSize, c->memlevel, >+ Z_DEFAULT_STRATEGY); >+ >+ if (zRC != Z_OK) { >+ deflateEnd(&ctx->stream); >+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, >+ "unable to init Zlib: " >+ "deflateInit2 returned %d: URL %s", >+ zRC, r->uri); >+ /* >+ * Remove ourselves as it does not make sense to return: >+ * We are not able to init libz and pass data down the chain >+ * uncompressed. >+ */ >+ ap_remove_output_filter(f); >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ /* >+ * Register a cleanup function to ensure that we cleanup the internal >+ * libz resources. >+ */ >+ apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup, >+ apr_pool_cleanup_null); >+ >+ /* Set the filter init flag so subsequent invocations know we are >+ * active. >+ */ >+ ctx->filter_init = 1; >+ >+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, >+ "Applying gzip Transfer-Encoding"); >+ >+ /* >+ * Zlib initialization worked, so we can now change the important >+ * response metadata before sending the response out. >+ */ >+ >+ apr_table_mergen(r->headers_out, "Transfer-Encoding", "gzip"); >+ apr_table_unset(r->headers_out, "Content-Length"); >+ >+ /* add immortal gzip header */ >+ e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header, >+ f->c->bucket_alloc); >+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e); >+ >+ /* initialize deflate output buffer */ >+ ctx->stream.next_out = ctx->buffer; >+ ctx->stream.avail_out = c->bufferSize; >+ } else if (!ctx->filter_init) { >+ /* Hmm. We've run through the filter init before as we have a ctx, >+ * but we never initialized. We probably have a dangling ref. Bail. >+ */ >+ return ap_pass_brigade(f->next, bb); >+ } >+ >+ while (!APR_BRIGADE_EMPTY(bb)) >+ { >+ apr_bucket *b; >+ >+ e = APR_BRIGADE_FIRST(bb); >+ >+ if (APR_BUCKET_IS_EOS(e)) { >+ char *buf; >+ >+ ctx->stream.avail_in = 0; /* should be zero already anyway */ >+ /* flush the remaining data from the zlib buffers */ >+ flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, Z_FINISH, >+ NO_UPDATE_CRC); >+ >+ buf = apr_palloc(r->pool, VALIDATION_SIZE); >+ putLong((unsigned char *)&buf[0], ctx->crc); >+ putLong((unsigned char *)&buf[4], ctx->stream.total_in); >+ >+ b = apr_bucket_pool_create(buf, VALIDATION_SIZE, r->pool, >+ f->c->bucket_alloc); >+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b); >+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >+ "Zlib: Compressed %ld to %ld : URL %s", >+ ctx->stream.total_in, ctx->stream.total_out, r->uri); >+ >+ deflateEnd(&ctx->stream); >+ /* No need for cleanup any longer */ >+ apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup); >+ >+ /* Remove EOS from the old list, and insert into the new. */ >+ APR_BUCKET_REMOVE(e); >+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e); >+ >+ /* Okay, we've seen the EOS. >+ * Time to pass it along down the chain. >+ */ >+ return ap_pass_brigade(f->next, ctx->bb); >+ } >+ >+ if (APR_BUCKET_IS_FLUSH(e)) { >+ apr_status_t rv; >+ >+ /* flush the remaining data from the zlib buffers */ >+ zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, >+ Z_SYNC_FLUSH, NO_UPDATE_CRC); >+ if (zRC != Z_OK) { >+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, >+ "Zlib error %d flushing zlib output buffer (%s)", >+ zRC, ctx->stream.msg); >+ return APR_EGENERAL; >+ } >+ >+ /* Remove flush bucket from old brigade anf insert into the new. */ >+ APR_BUCKET_REMOVE(e); >+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e); >+ rv = ap_pass_brigade(f->next, ctx->bb); >+ if (rv != APR_SUCCESS) { >+ return rv; >+ } >+ continue; >+ } >+ >+ if (APR_BUCKET_IS_METADATA(e)) { >+ /* >+ * Remove meta data bucket from old brigade and insert into the >+ * new. >+ */ >+ APR_BUCKET_REMOVE(e); >+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e); >+ continue; >+ } >+ >+ /* read */ >+ apr_bucket_read(e, &data, &len, APR_BLOCK_READ); >+ >+ /* This crc32 function is from zlib. */ >+ ctx->crc = crc32(ctx->crc, (const Bytef *)data, len); >+ >+ /* write */ >+ ctx->stream.next_in = (unsigned char *)data; /* We just lost const-ness, >+ * but we'll just have to >+ * trust zlib */ >+ ctx->stream.avail_in = len; >+ >+ while (ctx->stream.avail_in != 0) { >+ if (ctx->stream.avail_out == 0) { >+ apr_status_t rv; >+ >+ ctx->stream.next_out = ctx->buffer; >+ len = c->bufferSize - ctx->stream.avail_out; >+ >+ b = apr_bucket_heap_create((char *)ctx->buffer, len, >+ NULL, f->c->bucket_alloc); >+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b); >+ ctx->stream.avail_out = c->bufferSize; >+ /* Send what we have right now to the next filter. */ >+ rv = ap_pass_brigade(f->next, ctx->bb); >+ if (rv != APR_SUCCESS) { >+ return rv; >+ } >+ } >+ >+ zRC = deflate(&(ctx->stream), Z_NO_FLUSH); >+ >+ if (zRC != Z_OK) { >+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, >+ "Zlib error %d deflating data (%s)", zRC, >+ ctx->stream.msg); >+ return APR_EGENERAL; >+ } >+ } >+ >+ apr_bucket_delete(e); >+ } >+ >+ apr_brigade_cleanup(bb); >+ return APR_SUCCESS; >+} >+ >+ > /* This is the deflate input filter (inflates). */ > static apr_status_t deflate_in_filter(ap_filter_t *f, > apr_bucket_brigade *bb, >@@ -1503,7 +1882,6 @@ > return OK; > } > >- > #define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH > static void register_hooks(apr_pool_t *p) > { >@@ -1511,9 +1889,10 @@ > AP_FTYPE_CONTENT_SET); > ap_register_output_filter("INFLATE", inflate_out_filter, NULL, > AP_FTYPE_RESOURCE-1); >+ ap_register_output_filter("GZIPTE", deflate_te_filter, NULL, >+ AP_FTYPE_TRANSCODE); > ap_register_input_filter(deflateFilterName, deflate_in_filter, NULL, > AP_FTYPE_CONTENT_SET); >- ap_hook_post_config(mod_deflate_post_config, NULL, NULL, APR_HOOK_MIDDLE); > } > > static const command_rec deflate_filter_cmds[] = { >@@ -1539,3 +1918,5 @@ > deflate_filter_cmds, /* command table */ > register_hooks /* register hooks */ > }; >+ >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 52860
:
28443
| 29270