⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_deflate.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright 2002-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * Portions of this software are based upon public domain software * (zlib functions gz_open and gzwrite) *//* * mod_deflate.c: Perform deflate transfer-encoding on the fly * * Written by Ian Holsman * */#include "httpd.h"#include "http_config.h"#include "http_log.h"#include "apr_strings.h"#include "apr_general.h"#include "util_filter.h"#include "apr_buckets.h"#include "http_request.h"#define APR_WANT_STRFUNC#include "apr_want.h"#include "zlib.h"#ifdef HAVE_ZUTIL_H#include "zutil.h"#else/* As part of the encoding process, we must send what our OS_CODE is * (or so it seems based on what I can tell of how gzip encoding works). * * zutil.h is not always included with zlib distributions (it is a private * header), so this is straight from zlib 1.1.3's zutil.h. */#ifdef OS2#define OS_CODE  0x06#endif#ifdef WIN32 /* Window 95 & Windows NT */#define OS_CODE  0x0b#endif#if defined(VAXC) || defined(VMS)#define OS_CODE  0x02#endif#ifdef AMIGA#define OS_CODE  0x01#endif#if defined(ATARI) || defined(atarist)#define OS_CODE  0x05#endif#if defined(MACOS) || defined(TARGET_OS_MAC)#define OS_CODE  0x07#endif#ifdef __50SERIES /* Prime/PRIMOS */#define OS_CODE  0x0F#endif#ifdef TOPS20#define OS_CODE  0x0a#endif#ifndef OS_CODE#define OS_CODE  0x03  /* assume Unix */#endif#endifstatic const char deflateFilterName[] = "DEFLATE";module AP_MODULE_DECLARE_DATA deflate_module;typedef struct deflate_filter_config_t{    int windowSize;    int memlevel;    int compressionlevel;    apr_size_t bufferSize;    char *note_ratio_name;    char *note_input_name;    char *note_output_name;} deflate_filter_config;/* windowsize is negative to suppress Zlib header */#define DEFAULT_COMPRESSION Z_DEFAULT_COMPRESSION#define DEFAULT_WINDOWSIZE -15#define DEFAULT_MEMLEVEL 9#define DEFAULT_BUFFERSIZE 8096/* Outputs a long in LSB order to the given file * only the bottom 4 bits are required for the deflate file format. */static void putLong(unsigned char *string, unsigned long x){    string[0] = (unsigned char)(x & 0xff);    string[1] = (unsigned char)((x & 0xff00) >> 8);    string[2] = (unsigned char)((x & 0xff0000) >> 16);    string[3] = (unsigned char)((x & 0xff000000) >> 24);}/* Inputs a string and returns a long. */static unsigned long getLong(unsigned char *string){    return ((unsigned long)string[0])          | (((unsigned long)string[1]) << 8)          | (((unsigned long)string[2]) << 16)          | (((unsigned long)string[3]) << 24);}static void *create_deflate_server_config(apr_pool_t *p, server_rec *s){    deflate_filter_config *c = apr_pcalloc(p, sizeof *c);    c->memlevel   = DEFAULT_MEMLEVEL;    c->windowSize = DEFAULT_WINDOWSIZE;    c->bufferSize = DEFAULT_BUFFERSIZE;    c->compressionlevel = DEFAULT_COMPRESSION;    return c;}static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy,                                           const char *arg){    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,                                                    &deflate_module);    int i;    i = atoi(arg);    if (i < 1 || i > 15)        return "DeflateWindowSize must be between 1 and 15";    c->windowSize = i * -1;    return NULL;}static const char *deflate_set_buffer_size(cmd_parms *cmd, void *dummy,                                           const char *arg){    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,                                                    &deflate_module);    int n = atoi(arg);    if (n <= 0) {        return "DeflateBufferSize should be positive";    }    c->bufferSize = (apr_size_t)n;    return NULL;}static const char *deflate_set_note(cmd_parms *cmd, void *dummy,                                    const char *arg1, const char *arg2){    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,                                                    &deflate_module);        if (arg2 == NULL) {        c->note_ratio_name = apr_pstrdup(cmd->pool, arg1);    }    else if (!strcasecmp(arg1, "ratio")) {        c->note_ratio_name = apr_pstrdup(cmd->pool, arg2);    }    else if (!strcasecmp(arg1, "input")) {        c->note_input_name = apr_pstrdup(cmd->pool, arg2);    }    else if (!strcasecmp(arg1, "output")) {        c->note_output_name = apr_pstrdup(cmd->pool, arg2);    }    else {        return apr_psprintf(cmd->pool, "Unknown note type %s", arg1);    }    return NULL;}static const char *deflate_set_memlevel(cmd_parms *cmd, void *dummy,                                        const char *arg){    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,                                                    &deflate_module);    int i;    i = atoi(arg);    if (i < 1 || i > 9)        return "DeflateMemLevel must be between 1 and 9";    c->memlevel = i;    return NULL;}static const char *deflate_set_compressionlevel(cmd_parms *cmd, void *dummy,                                        const char *arg){    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,                                                    &deflate_module);    int i;    i = atoi(arg);    if (i < 1 || i > 9)        return "Compression Level must be between 1 and 9";    c->compressionlevel = i;    return NULL;}/* magic header */static char deflate_magic[2] = { '\037', '\213' };typedef struct deflate_ctx_t{    z_stream stream;    unsigned char *buffer;    unsigned long crc;    apr_bucket_brigade *bb, *proc_bb;} deflate_ctx;static apr_status_t deflate_out_filter(ap_filter_t *f,                                       apr_bucket_brigade *bb){    apr_bucket *e;    request_rec *r = f->r;    deflate_ctx *ctx = f->ctx;    int zRC;    deflate_filter_config *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 *buf, *token;        const char *encoding, *accepts;        /* only work on main request/no subrequests */        if (r->main) {            ap_remove_output_filter(f);            return ap_pass_brigade(f->next, bb);        }        /* some browsers might have problems, so set no-gzip         * (with browsermatch) for them         */        if (apr_table_get(r->subprocess_env, "no-gzip")) {            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_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_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;            }        }        /* Even if we don't accept this request based on it not having         * the Accept-Encoding, we need to note that we were looking         * for this header and downstream proxies should be aware of that.         */        apr_table_setn(r->headers_out, "Vary", "Accept-Encoding");        /* if they don't have the line, then they can't play */        accepts = apr_table_get(r->headers_in, "Accept-Encoding");        if (accepts == NULL) {            ap_remove_output_filter(f);            return ap_pass_brigade(f->next, bb);        }        token = ap_get_token(r->pool, &accepts, 0);        while (token && token[0] && strcasecmp(token, "gzip")) {            /* skip parameters, XXX: ;q=foo evaluation? */            while (*accepts == ';') {                 ++accepts;                token = ap_get_token(r->pool, &accepts, 1);            }            /* retrieve next token */            if (*accepts == ',') {                ++accepts;            }            token = (*accepts) ? ap_get_token(r->pool, &accepts, 0) : NULL;        }        /* No acceptable token found. */        if (token == NULL || token[0] == '\0') {            ap_remove_output_filter(f);            return ap_pass_brigade(f->next, bb);        }        /* We're cool with filtering this. */        ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));        ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);        ctx->buffer = apr_palloc(r->pool, c->bufferSize);        zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,                           c->windowSize, c->memlevel,                           Z_DEFAULT_STRATEGY);        if (zRC != Z_OK) {            f->ctx = NULL;            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                          "unable to init Zlib: "                          "deflateInit2 returned %d: URL %s",                          zRC, r->uri);            return ap_pass_brigade(f->next, bb);        }        /* RFC 1952 Section 2.3 dictates the gzip header:         *         * +---+---+---+---+---+---+---+---+---+---+         * |ID1|ID2|CM |FLG|     MTIME     |XFL|OS |         * +---+---+---+---+---+---+---+---+---+---+         *         * If we wish to populate in MTIME (as hinted in RFC 1952), do:         * putLong(date_array, apr_time_now() / APR_USEC_PER_SEC);         * where date_array is a char[4] and then print date_array in the         * MTIME position.  WARNING: ENDIANNESS ISSUE HERE.         */        buf = apr_psprintf(r->pool, "%c%c%c%c%c%c%c%c%c%c", deflate_magic[0],                           deflate_magic[1], Z_DEFLATED, 0 /* flags */,                           0, 0, 0, 0 /* 4 chars for mtime */,                           0 /* xflags */, OS_CODE);        e = apr_bucket_pool_create(buf, 10, r->pool, f->c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(ctx->bb, e);        /* If the entire Content-Encoding is "identity", we can replace it. */        if (!encoding || !strcasecmp(encoding, "identity")) {            apr_table_setn(r->headers_out, "Content-Encoding", "gzip");        }        else {            apr_table_mergen(r->headers_out, "Content-Encoding", "gzip");        }        apr_table_unset(r->headers_out, "Content-Length");        /* initialize deflate output buffer */        ctx->stream.next_out = ctx->buffer;        ctx->stream.avail_out = c->bufferSize;    }        while (!APR_BRIGADE_EMPTY(bb))    {        const char *data;        apr_bucket *b;        apr_size_t len;        int done = 0;        e = APR_BRIGADE_FIRST(bb);        if (APR_BUCKET_IS_EOS(e)) {            char *buf;            unsigned int deflate_len;            ctx->stream.avail_in = 0; /* should be zero already anyway */            for (;;) {                deflate_len = c->bufferSize - ctx->stream.avail_out;                if (deflate_len != 0) {                    b = apr_bucket_heap_create((char *)ctx->buffer,                                               deflate_len, NULL,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -