You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ig...@apache.org on 2012/03/08 11:01:46 UTC
git commit: TS-976: Removing this rather poor example plugin as we
now have a proper deflate plugin (TS-1129)
Updated Branches:
refs/heads/master 8a06dc143 -> e1d5d0fcc
TS-976: Removing this rather poor example plugin
as we now have a proper deflate plugin (TS-1129)
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/e1d5d0fc
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/e1d5d0fc
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/e1d5d0fc
Branch: refs/heads/master
Commit: e1d5d0fcca1efa31efd207c3d1e0324fe5f513e1
Parents: 8a06dc1
Author: Igor Galić <i....@brainsware.org>
Authored: Thu Mar 8 10:05:41 2012 +0000
Committer: Igor Galić <i....@brainsware.org>
Committed: Thu Mar 8 10:05:41 2012 +0000
----------------------------------------------------------------------
example/Makefile.am | 2 +-
example/gzip-transform/Makefile.am | 29 --
example/gzip-transform/README.txt | 12 -
example/gzip-transform/gunzip.c | 545 --------------------------
example/gzip-transform/gzip.c | 632 -------------------------------
5 files changed, 1 insertions(+), 1219 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e1d5d0fc/example/Makefile.am
----------------------------------------------------------------------
diff --git a/example/Makefile.am b/example/Makefile.am
index c28e2ad..cc20f10 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -17,5 +17,5 @@
if STANDALONE_IOCORE
SUBDIRS = app-template
else
-SUBDIRS = . add-header append-transform basic-auth blacklist-0 blacklist-1 bnull-transform cache_scan file-1 gzip-transform hello null-transform output-header protocol query_remap redirect-1 remap replace-header response-header-1 server-transform session-1 thread-1 thread-pool
+SUBDIRS = . add-header append-transform basic-auth blacklist-0 blacklist-1 bnull-transform cache_scan file-1 hello null-transform output-header protocol query_remap redirect-1 remap replace-header response-header-1 server-transform session-1 thread-1 thread-pool
endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e1d5d0fc/example/gzip-transform/Makefile.am
----------------------------------------------------------------------
diff --git a/example/gzip-transform/Makefile.am b/example/gzip-transform/Makefile.am
deleted file mode 100644
index 277bdcd..0000000
--- a/example/gzip-transform/Makefile.am
+++ /dev/null
@@ -1,29 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you 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.
-
-CFLAGS+=-I$(top_srcdir)/proxy/api
-
-pkglibdir = ${pkglibexecdir}
-pkglib_LTLIBRARIES = gzip.la gunzip.la
-gzip_la_SOURCES = gzip.c
-gzip_la_LDFLAGS = -module -avoid-version -shared
-
-gunzip_la_SOURCES = gunzip.c
-gunzip_la_LDFLAGS = -module -avoid-version -shared
-
-all:
- ln -sf .libs/gzip.so
- ln -sf .libs/gunzip.so
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e1d5d0fc/example/gzip-transform/README.txt
----------------------------------------------------------------------
diff --git a/example/gzip-transform/README.txt b/example/gzip-transform/README.txt
deleted file mode 100644
index dce6c4c..0000000
--- a/example/gzip-transform/README.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Gzip / Gunzip plugins
----------------------
-
-These plugins work only in conjunction and should not be used
-separately to compress or uncompress data.
-For instance a TS child runs gunzip and parent runs gzip.
-Gzip compresses on one side and gunzip decompresses on the other.
-
-Note that gzip plugin produces a compressed file slightly different
-from what the gzip utility does (the header is different).
-Thus, file compressed by gzip utility can not be uncompressed by gunzip.
-
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e1d5d0fc/example/gzip-transform/gunzip.c
----------------------------------------------------------------------
diff --git a/example/gzip-transform/gunzip.c b/example/gzip-transform/gunzip.c
deleted file mode 100644
index 35b486e..0000000
--- a/example/gzip-transform/gunzip.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/** @file
-
- Transforms content using gzip
-
- @section license License
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you 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.
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-#include <assert.h>
-#include <ts/ts.h>
-
-#define DICT_PATH_MAX 512
-#define DICT_ENTRY_MAX 2048
-
-typedef struct
-{
- TSHttpTxn txn;
- TSVIO output_vio;
- TSIOBuffer output_buffer;
- TSIOBufferReader output_reader;
- int output_length;
- z_stream zstrm;
- uLong crc;
- int state;
- int flag;
-} GzipData;
-
-char preload_file[1024];
-uLong dictId;
-int preload = 0;
-char dictionary[800000];
-
-
-void
-load_dictionary(char *dict, uLong * adler)
-{
- FILE *fp;
- int i = 0;
-
- fp = fopen(preload_file, "r");
- if (!fp) {
- TSError("gunzip-transform: ERROR: Unable to open dict file %s\n", preload_file);
- exit(0);
- }
-
- i = 0;
- while (!feof(fp)) {
- if (fscanf(fp, "%s\n", dict + i) == 1) {
- i = strlen(dict);
- TSstrlcat(dict + i, " ", sizeof(dict) - i);
- i++;
- }
- }
- dict[i - 1] = '\0';
-
- /* TODO figure out the right way to do the adler -- this one is all messed up */
- *adler = adler32(*adler, (Byte *) dict, strlen(dict));
-}
-
-static voidpf
-gzip_alloc(voidpf opaque, uInt items, uInt size)
-{
- return (voidpf) TSmalloc(items * size);
-}
-
-
-static void
-gzip_free(voidpf opaque, voidpf address)
-{
- TSfree(address);
-}
-
-
-static GzipData *
-gzip_data_alloc()
-{
- GzipData *data;
-
- data = (GzipData *) TSmalloc(sizeof(GzipData));
- data->output_vio = NULL;
- data->output_buffer = NULL;
- data->output_reader = NULL;
- data->output_length = 0;
- data->state = 0;
- data->flag = 1;
- data->crc = crc32(0L, Z_NULL, 0);
-
- data->zstrm.next_in = Z_NULL;
- data->zstrm.avail_in = 0;
- data->zstrm.total_in = 0;
- data->zstrm.next_out = Z_NULL;
- data->zstrm.avail_out = 0;
- data->zstrm.total_out = 0;
- data->zstrm.zalloc = gzip_alloc;
- data->zstrm.zfree = gzip_free;
- data->zstrm.opaque = (voidpf) 0; /* Z_NULL */
- data->zstrm.data_type = Z_ASCII;
-
- dictId = adler32(0L, Z_NULL, 0);
-
- return data;
-}
-
-
-static void
-gzip_data_destroy(GzipData * data)
-{
- int err;
-
- if (data) {
- err = inflateEnd(&data->zstrm);
- if (err != Z_OK) {
- TSError("gunzip-transform: ERROR: inflateEnd (%d)!", err);
- }
-
- if (data->output_buffer)
- TSIOBufferDestroy(data->output_buffer);
- TSfree(data);
- }
-}
-
-
-static void
-gzip_transform_init(TSCont contp, GzipData * data)
-{
- TSVConn output_conn;
-
- data->state = 1;
-
- /* Get the output connection where we'll write data to. */
- output_conn = TSTransformOutputVConnGet(contp);
-
- data->output_buffer = TSIOBufferCreate();
- data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
- data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
-}
-
-
-static void
-gzip_transform_one(GzipData * data, TSIOBufferReader input_reader, int amount)
-{
- TSIOBufferBlock blkp;
- const char *ibuf;
- char *obuf;
- int64_t ilength, olength;
- int err = Z_OK;
-
- while (amount > 0) {
- blkp = TSIOBufferReaderStart(input_reader);
- ibuf = TSIOBufferBlockReadStart(blkp, input_reader, &ilength);
-
- if (ilength > amount) {
- ilength = amount;
- }
-
- data->zstrm.next_in = (unsigned char *) ibuf;
- data->zstrm.avail_in = ilength;
-
- if (data->flag) {
- err = inflateInit(&data->zstrm);
- data->flag = 0;
- if (err != Z_OK) {
- TSError("gunzip-transform: ERROR: inflateInit (%d)!", err);
- exit(1);
- }
- }
-
- while (data->zstrm.avail_in > 0 && err != Z_STREAM_END) {
- blkp = TSIOBufferStart(data->output_buffer);
-
- obuf = TSIOBufferBlockWriteStart(blkp, &olength);
-
- data->zstrm.next_out = (unsigned char *) obuf;
- data->zstrm.avail_out = olength;
-
- /* Uncompress */
- err = inflate(&data->zstrm, Z_NO_FLUSH);
-/*
- assert( (err == Z_OK) || (err = Z_STREAM_END) || (err = Z_NEED_DICT));
-*/
- if (err == Z_NEED_DICT) {
- assert(preload);
- TSDebug("gunzip-transform", "Transform needs dictionary");
- /* TODO assert encoding dict is same as the decoding one, else send an error page */
- /* Dont send the user binary junk! */
-
- err = inflateSetDictionary(&data->zstrm, (Bytef *) dictionary, strlen(dictionary));
- if (err != Z_OK) {
- TSError("gunzip-transform: ERROR: inflateSetDictionary (%d)!", err);
- }
- }
-
- if (olength > data->zstrm.avail_out) {
- TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
- data->output_length += (olength - data->zstrm.avail_out);
- }
-
- }
-
- /* TODO compute crc */
-
- TSIOBufferReaderConsume(input_reader, ilength);
- amount -= ilength;
- }
-}
-
-
-static void
-gzip_transform_finish(GzipData * data)
-{
- if (data->state == 1) {
- TSIOBufferBlock blkp;
- char *obuf;
- int64_t olength;
- int err;
-
- data->state = 2;
-
- for (;;) {
- blkp = TSIOBufferStart(data->output_buffer);
-
- obuf = TSIOBufferBlockWriteStart(blkp, &olength);
- data->zstrm.next_out = (unsigned char *) obuf;
- data->zstrm.avail_out = olength;
-
- /* Uncompress remaining data */
- err = inflate(&data->zstrm, Z_FINISH);
-
- if (olength > data->zstrm.avail_out) {
- TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
- data->output_length += (olength - data->zstrm.avail_out);
- }
-
- if (err == Z_OK) { /* more to uncompress */
- continue;
- }
- /* done! */
- break;
- }
-
- if (data->output_length != (data->zstrm.total_out)) {
- TSError("gunzip-transform: ERROR: output lengths don't match (%d, %ld)", data->output_length,
- data->zstrm.total_out);
- }
-
- /* TODO crc checks */
- }
-}
-
-
-static void
-gzip_transform_do(TSCont contp)
-{
- TSVIO write_vio;
- GzipData *data;
- int towrite;
- int avail;
- int length;
-
- /* Get our data structure for this operation. The private data
- structure contains the output vio and output buffer. If the
- private data structure pointer is NULL, then we'll create it
- and initialize its internals. */
- data = TSContDataGet(contp);
- if (data->state == 0) {
- gzip_transform_init(contp, data);
- }
-
- /* Get the write vio for the write operation that was performed on
- ourself. This vio contains the buffer that we are to read from
- as well as the continuation we are to call when the buffer is
- empty. */
- write_vio = TSVConnWriteVIOGet(contp);
- length = data->output_length;
-
- /* We also check to see if the write vio's buffer is non-NULL. A
- NULL buffer indicates that the write operation has been
- shutdown and that the continuation does not want us to send any
- more WRITE_READY or WRITE_COMPLETE events. For this simplistic
- transformation that means we're done. In a more complex
- transformation we might have to finish writing the transformed
- data to our output connection. */
- if (!TSVIOBufferGet(write_vio)) {
-
- gzip_transform_finish(data);
-
- TSVIONBytesSet(data->output_vio, data->output_length);
-
- TSVIOReenable(data->output_vio);
- return;
- }
-
- /* Determine how much data we have left to read. For this gzip
- transform plugin this is also the amount of data we have left
- to write to the output connection. */
- towrite = TSVIONTodoGet(write_vio);
- if (towrite > 0) {
- /* The amount of data left to read needs to be truncated by
- the amount of data actually in the read buffer. */
- avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
- if (towrite > avail) {
- towrite = avail;
- }
-
- if (towrite > 0) {
- gzip_transform_one(data, TSVIOReaderGet(write_vio), towrite);
-
- /* Modify the write vio to reflect how much data we've
- completed. */
- TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite);
- }
- }
-
- /* Now we check the write vio to see if there is data left to
- read. */
- if (TSVIONTodoGet(write_vio) > 0) {
- if (towrite > 0) {
- /* If we output some data then we reenable the output
- connection by reenabling the output vio. This will wakeup
- the output connection and allow it to consume data from the
- output buffer. */
- if (data->output_length > length) {
- TSVIOReenable(data->output_vio);
- }
-
- /* Call back the write vio continuation to let it know that we
- are ready for more data. */
- TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio);
- }
- } else {
- /* If there is no data left to read, then we modify the output
- vio to reflect how much data the output connection should
- expect. This allows the output connection to know when it
- is done reading. We then reenable the output connection so
- that it can consume the data we just gave it. */
- gzip_transform_finish(data);
-
- TSVIONBytesSet(data->output_vio, data->output_length);
-
- if (data->output_length > length) {
- TSVIOReenable(data->output_vio);
- }
-
- /* Call back the write vio continuation to let it know that we
- have completed the write operation. */
- TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio);
- }
-}
-
-
-static int
-gzip_transform(TSCont contp, TSEvent event, void *edata)
-{
- /* Check to see if the transformation has been closed by a call to
- TSVConnClose. */
- if (TSVConnClosedGet(contp)) {
- gzip_data_destroy(TSContDataGet(contp));
- TSContDestroy(contp);
- return 0;
- } else {
- switch (event) {
- case TS_EVENT_ERROR:
- {
- TSVIO write_vio;
-
- /* Get the write vio for the write operation that was
- performed on ourself. This vio contains the continuation of
- our parent transformation. */
- write_vio = TSVConnWriteVIOGet(contp);
-
- /* Call back the write vio continuation to let it know that we
- have completed the write operation. */
- TSContCall(TSVIOContGet(write_vio), TS_EVENT_ERROR, write_vio);
- }
- break;
- case TS_EVENT_VCONN_WRITE_COMPLETE:
- case TS_EVENT_VCONN_EOS:
- /* When our output connection says that it has finished
- reading all the data we've written to it then we should
- shutdown the write portion of its connection to
- indicate that we don't want to hear about it anymore. */
- TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
- break;
- case TS_EVENT_VCONN_WRITE_READY:
- default:
- /* If we get a WRITE_READY event or any other type of
- event (sent, perhaps, because we were reenabled) then
- we'll attempt to transform more data. */
- gzip_transform_do(contp);
- break;
- }
- }
-
- return 0;
-}
-
-static int
-gzip_transformable(TSHttpTxn txnp, int server)
-{
- TSMBuffer bufp;
- TSMLoc hdr_loc;
- TSMLoc field_loc;
- const char *value;
-
- if (server) {
- TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
- } else {
- TSHttpTxnCachedRespGet(txnp, &bufp, &hdr_loc);
- }
-
- /* We only want to do gunzip(inflate) on documents that have a
- content-encoding "deflate". */
-
- field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, "Content-Encoding", -1);
- if (!field_loc) {
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return -4;
- }
-
- value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, NULL);
- if (value && (strncasecmp(value, "deflate", sizeof("deflate") - 1) == 0)) {
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return 0;
- } else {
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return -5;
- }
-}
-
-
-static void
-gzip_transform_add(TSHttpTxn txnp, int flag)
-{
- TSVConn connp;
- GzipData *data;
-
- data = gzip_data_alloc();
- data->txn = txnp;
-
- connp = TSTransformCreate(gzip_transform, txnp);
- TSContDataSet(connp, data);
- TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
-}
-
-
-static int
-transform_plugin(TSCont contp, TSEvent event, void *edata)
-{
- TSHttpTxn txnp = (TSHttpTxn) edata;
- int reason;
-
- switch (event) {
- case TS_EVENT_HTTP_READ_REQUEST_HDR:
- {
- TSMBuffer bufp;
- TSMLoc hdr_loc;
- TSMLoc ae_loc; /* for the accept encoding mime field */
-
- TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc);
- TSMimeHdrFieldCreate(bufp, hdr_loc, &ae_loc); /* Probably should check for errors */
- TSMimeHdrFieldNameSet(bufp, hdr_loc, ae_loc, "Accept-Encoding", -1);
- TSMimeHdrFieldValueAppend(bufp, hdr_loc, ae_loc, -1, "deflate", -1);
- TSMimeHdrFieldAppend(bufp, hdr_loc, ae_loc);
- TSHandleMLocRelease(bufp, hdr_loc, ae_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
- TSDebug("gunzip-transform", "Changed request header to accept deflate encoding");
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
- }
- case TS_EVENT_HTTP_READ_RESPONSE_HDR:
- reason = gzip_transformable(txnp, 1);
- if (reason >= 0) {
- TSMBuffer bufp;
- TSMLoc hdr_loc;
- TSMLoc field_loc;
-
- TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
- field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, "Content-Encoding", -1);
- TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
- TSDebug("gunzip-transform", "server content transformable");
- gzip_transform_add(txnp, 1);
- } else {
- TSDebug("gunzip-transform", "server content NOT transformable [%d]", reason);
- }
-
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
-
- case TS_EVENT_HTTP_READ_CACHE_HDR:
-
- TSDebug("gunzip-transform", "Cached data");
-
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
-
- default:
- exit(1);
- }
-
- return 0;
-}
-
-
-void
-TSPluginInit(int argc, const char *argv[])
-{
- if (argc == 2) {
- TSstrlcpy(preload_file, argv[1], sizeof(preload_file));
- preload = 1;
- load_dictionary(dictionary, &dictId);
- }
-
- TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(transform_plugin, NULL));
- TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
- TSHttpHookAdd(TS_HTTP_READ_CACHE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
-}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e1d5d0fc/example/gzip-transform/gzip.c
----------------------------------------------------------------------
diff --git a/example/gzip-transform/gzip.c b/example/gzip-transform/gzip.c
deleted file mode 100644
index 7b5361e..0000000
--- a/example/gzip-transform/gzip.c
+++ /dev/null
@@ -1,632 +0,0 @@
-/** @file
-
- Transforms content using gzip
-
- @section license License
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you 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.
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-#include <assert.h>
-#include <ts/ts.h>
-
-#define DICT_PATH_MAX 512
-#define DICT_ENTRY_MAX 2048
-
-typedef struct
-{
- TSHttpTxn txn;
- TSVIO output_vio;
- TSIOBuffer output_buffer;
- TSIOBufferReader output_reader;
- int output_length;
- z_stream zstrm;
- uLong crc;
- int state;
-} GzipData;
-
-
-char preload_file[1024];
-uLong dictId;
-int preload = 0;
-char dictionary[800000];
-
-void
-load_dictionary(char *dict, uLong * adler)
-{
- FILE *fp;
- int i = 0;
-
- fp = fopen(preload_file, "r");
- if (!fp) {
- TSError("gzip-transform: ERROR: Unable to open dict file %s\n", preload_file);
- exit(0);
- }
-
- /* dict = (char *) calloc(8000,sizeof(char)); */
-
- i = 0;
- while (!feof(fp)) {
- if (fscanf(fp, "%s\n", dict + i) == 1) {
- i = strlen(dict);
- TSstrlcat(dict + i, " ", sizeof(dict) - i);
- i++;
- }
- }
- dict[i - 1] = '\0';
-
- /* TODO get the adler compute right */
- *adler = adler32(*adler, (const Byte *) dict, sizeof(dict));
-}
-
-static voidpf
-gzip_alloc(voidpf opaque, uInt items, uInt size)
-{
- return (voidpf) TSmalloc(items * size);
-}
-
-
-static void
-gzip_free(voidpf opaque, voidpf address)
-{
- TSfree(address);
-}
-
-
-static GzipData *
-gzip_data_alloc()
-{
- GzipData *data;
- int err;
-
- data = (GzipData *) TSmalloc(sizeof(GzipData));
- data->output_vio = NULL;
- data->output_buffer = NULL;
- data->output_reader = NULL;
- data->output_length = 0;
- data->state = 0;
- data->crc = crc32(0L, Z_NULL, 0);
-
- data->zstrm.next_in = Z_NULL;
- data->zstrm.avail_in = 0;
- data->zstrm.total_in = 0;
- data->zstrm.next_out = Z_NULL;
- data->zstrm.avail_out = 0;
- data->zstrm.total_out = 0;
- data->zstrm.zalloc = gzip_alloc;
- data->zstrm.zfree = gzip_free;
- data->zstrm.opaque = (voidpf) 0;
- data->zstrm.data_type = Z_ASCII;
-
- err = deflateInit(&data->zstrm, Z_BEST_COMPRESSION);
-
- if (err != Z_OK) {
- TSError("gzip-transform: ERROR: deflateInit (%d)!", err);
- exit(1);
- }
-
- if (preload) {
- assert(&data->zstrm);
- err = deflateSetDictionary(&data->zstrm, (const Bytef *) dictionary, strlen(dictionary));
- if (err != Z_OK) {
- TSError("gzip-transform: ERROR: deflateSetDictionary (%d)!", err);
- }
- }
-
- return data;
-}
-
-
-static void
-gzip_data_destroy(GzipData * data)
-{
- int err;
-
- if (data) {
- err = deflateEnd(&data->zstrm);
- if (err != Z_OK) {
- TSError("gzip-transform: ERROR: deflateEnd (%d)!", err);
- }
-
- if (data->output_buffer)
- TSIOBufferDestroy(data->output_buffer);
- TSfree(data);
- }
-}
-
-
-static void
-gzip_transform_init(TSCont contp, GzipData * data)
-{
- TSVConn output_conn;
- TSMBuffer bufp;
- TSMLoc hdr_loc;
- TSMLoc ce_loc; /* for the content encoding mime field */
-
- data->state = 1;
-
- /*
- * Mark the output data as having gzip content encoding
- */
- TSHttpTxnTransformRespGet(data->txn, &bufp, &hdr_loc);
- TSMimeHdrFieldCreate(bufp, hdr_loc, &ce_loc); /* Probably should check for errors */
- TSMimeHdrFieldNameSet(bufp, hdr_loc, ce_loc, "Content-Encoding", -1);
- TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, ce_loc, -1, "deflate", -1);
- TSMimeHdrFieldAppend(bufp, hdr_loc, ce_loc);
- TSHandleMLocRelease(bufp, hdr_loc, ce_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-
- /* Get the output connection where we'll write data to. */
- output_conn = TSTransformOutputVConnGet(contp);
-
- data->output_buffer = TSIOBufferCreate();
- data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
- data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
-}
-
-
-static void
-gzip_transform_one(GzipData * data, TSIOBufferReader input_reader, int amount)
-{
- TSIOBufferBlock blkp;
- const char *ibuf;
- char *obuf;
- int64_t ilength, olength;
- int err;
-
- while (amount > 0) {
- blkp = TSIOBufferReaderStart(input_reader);
- ibuf = TSIOBufferBlockReadStart(blkp, input_reader, &ilength);
-
- if (ilength > amount) {
- ilength = amount;
- }
-
- data->zstrm.next_in = (unsigned char *) ibuf;
- data->zstrm.avail_in = ilength;
-
- while (data->zstrm.avail_in > 0) {
- blkp = TSIOBufferStart(data->output_buffer);
-
- obuf = TSIOBufferBlockWriteStart(blkp, &olength);
-
- data->zstrm.next_out = (unsigned char *) obuf;
- data->zstrm.avail_out = olength;
-
- /* Encode */
- err = deflate(&data->zstrm, Z_NO_FLUSH);
- TSDebug("gzip-transform", "deflate() returned %d", err);
-
- if (olength > data->zstrm.avail_out) {
- TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
- data->output_length += (olength - data->zstrm.avail_out);
- }
-
- if (data->zstrm.avail_out > 0) {
- if (data->zstrm.avail_in != 0) {
- TSError("gzip-transform: ERROR: avail_in is (%d): should be 0", data->zstrm.avail_in);
- }
- }
- }
-
- /* compute CRC for error checking at client */
- data->crc = crc32(data->crc, (unsigned char *) ibuf, ilength);
-
- TSIOBufferReaderConsume(input_reader, ilength);
- amount -= ilength;
- }
-}
-
-
-static void
-gzip_transform_finish(GzipData * data)
-{
- if (data->state == 1) {
- TSIOBufferBlock blkp;
- char *obuf;
- int64_t olength;
- int err;
-
- data->state = 2;
-
- for (;;) {
- blkp = TSIOBufferStart(data->output_buffer);
-
- obuf = TSIOBufferBlockWriteStart(blkp, &olength);
- data->zstrm.next_out = (unsigned char *) obuf;
- data->zstrm.avail_out = olength;
-
- /* Encode remaining data */
- err = deflate(&data->zstrm, Z_FINISH);
-
- if (olength > data->zstrm.avail_out) {
- TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
- data->output_length += (olength - data->zstrm.avail_out);
- }
-
- if (err == Z_OK) { /* some more data to encode */
- continue;
- }
- /* done! */
- if (err != Z_STREAM_END) {
- TSDebug("gzip-transform", "deflate should report Z_STREAM_END\n");
- }
- break;
- }
-
- if (data->output_length != (data->zstrm.total_out)) {
- TSError("gzip-transform: ERROR: output lengths don't match (%d, %ld)", data->output_length,
- data->zstrm.total_out);
- }
-
- /* compute/append crc to end of stream */
-
- /*
- blkp = TSIOBufferStart (data->output_buffer);
-
- tmp = data->crc;
- buf[0] = tmp & 0xff; tmp >>= 8;
- buf[1] = tmp & 0xff; tmp >>= 8;
- buf[2] = tmp & 0xff; tmp >>= 8;
- buf[3] = tmp & 0xff;
-
- tmp = data->zstrm.total_in;
- buf[4] = tmp & 0xff; tmp >>= 8;
- buf[5] = tmp & 0xff; tmp >>= 8;
- buf[6] = tmp & 0xff; tmp >>= 8;
- buf[7] = tmp & 0xff;
-
- p = buf;
- length = 8;
-
- while (length > 0) {
- obuf = TSIOBufferBlockWriteStart (blkp, &olength);
- if (olength > length) {
- olength = length;
- }
-
- memcpy (obuf, p, olength);
- p += olength;
- length -= olength;
-
- TSIOBufferProduce (data->output_buffer, olength);
- }
-
- data->output_length += 8;
- */
- }
-}
-
-
-static void
-gzip_transform_do(TSCont contp)
-{
- TSVIO write_vio;
- GzipData *data;
- int towrite;
- int avail;
- int length;
-
- /* Get our data structure for this operation. The private data
- structure contains the output vio and output buffer. If the
- private data structure pointer is NULL, then we'll create it
- and initialize its internals. */
- data = TSContDataGet(contp);
- if (data->state == 0) {
- gzip_transform_init(contp, data);
- }
-
- /* Get the write vio for the write operation that was performed on
- ourself. This vio contains the buffer that we are to read from
- as well as the continuation we are to call when the buffer is
- empty. */
- write_vio = TSVConnWriteVIOGet(contp);
-
- length = data->output_length;
-
- /* We also check to see if the write vio's buffer is non-NULL. A
- NULL buffer indicates that the write operation has been
- shutdown and that the continuation does not want us to send any
- more WRITE_READY or WRITE_COMPLETE events. For this simplistic
- transformation that means we're done. In a more complex
- transformation we might have to finish writing the transformed
- data to our output connection. */
- if (!TSVIOBufferGet(write_vio)) {
- gzip_transform_finish(data);
-
- TSVIONBytesSet(data->output_vio, data->output_length);
- TSDebug("gzip-transform", "Compressed size %d (bytes)", data->output_length);
-
- if (data->output_length > length) {
- TSVIOReenable(data->output_vio);
- }
- return;
- }
-
- /* Determine how much data we have left to read. For this gzip
- transform plugin this is also the amount of data we have left
- to write to the output connection. */
- towrite = TSVIONTodoGet(write_vio);
- if (towrite > 0) {
- /* The amount of data left to read needs to be truncated by
- the amount of data actually in the read buffer. */
- avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
- if (towrite > avail) {
- towrite = avail;
- }
-
- if (towrite > 0) {
- gzip_transform_one(data, TSVIOReaderGet(write_vio), towrite);
-
- /* Modify the write vio to reflect how much data we've
- completed. */
- TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite);
- }
- }
-
- /* Now we check the write vio to see if there is data left to
- read. */
- if (TSVIONTodoGet(write_vio) > 0) {
- if (towrite > 0) {
- /* If we output some data then we reenable the output
- connection by reenabling the output vio. This will wakeup
- the output connection and allow it to consume data from the
- output buffer. */
- if (data->output_length > length) {
- TSVIOReenable(data->output_vio);
- }
-
- /* Call back the write vio continuation to let it know that we
- are ready for more data. */
- TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio);
- }
- } else {
- /* If there is no data left to read, then we modify the output
- vio to reflect how much data the output connection should
- expect. This allows the output connection to know when it
- is done reading. We then reenable the output connection so
- that it can consume the data we just gave it. */
- gzip_transform_finish(data);
-
- TSVIONBytesSet(data->output_vio, data->output_length);
- TSDebug("gzip-transform", "Compressed size %d (bytes)", data->output_length);
-
- if (data->output_length > length) {
- TSVIOReenable(data->output_vio);
- }
-
- /* Call back the write vio continuation to let it know that we
- have completed the write operation. */
- TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio);
- }
-}
-
-
-static int
-gzip_transform(TSCont contp, TSEvent event, void *edata)
-{
- /* Check to see if the transformation has been closed by a call to
- TSVConnClose. */
- if (TSVConnClosedGet(contp)) {
- gzip_data_destroy(TSContDataGet(contp));
- TSContDestroy(contp);
- return 0;
- } else {
- switch (event) {
- case TS_EVENT_ERROR:
- {
- TSVIO write_vio;
-
- /* Get the write vio for the write operation that was
- performed on ourself. This vio contains the continuation of
- our parent transformation. */
- write_vio = TSVConnWriteVIOGet(contp);
-
- /* Call back the write vio continuation to let it know that we
- have completed the write operation. */
- TSContCall(TSVIOContGet(write_vio), TS_EVENT_ERROR, write_vio);
- }
- break;
- case TS_EVENT_VCONN_WRITE_COMPLETE:
- /* When our output connection says that it has finished
- reading all the data we've written to it then we should
- shutdown the write portion of its connection to
- indicate that we don't want to hear about it anymore. */
- TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
- break;
- case TS_EVENT_VCONN_WRITE_READY:
- default:
- /* If we get a WRITE_READY event or any other type of
- event (sent, perhaps, because we were reenabled) then
- we'll attempt to transform more data. */
- gzip_transform_do(contp);
- break;
- }
- }
-
- return 0;
-}
-
-
-static int
-gzip_transformable(TSHttpTxn txnp, int server)
-{
- /* Server response header */
- TSMBuffer bufp;
- TSMLoc hdr_loc;
- TSMLoc field_loc;
-
- /* Client request header */
- TSMBuffer cbuf;
- TSMLoc chdr;
- TSMLoc cfield;
-
- const char *value;
- int nvalues;
- int i, deflate_flag;
-
- TSHttpTxnClientReqGet(txnp, &cbuf, &chdr);
-
- /* check if client accepts "deflate" */
-
- cfield = TSMimeHdrFieldFind(cbuf, chdr, TS_MIME_FIELD_ACCEPT_ENCODING, -1);
- if (TS_NULL_MLOC != cfield) {
- nvalues = TSMimeHdrFieldValuesCount(cbuf, chdr, cfield);
- value = TSMimeHdrFieldValueStringGet(cbuf, chdr, cfield, 0, NULL);
- deflate_flag = 0;
- i = 0;
- while (nvalues > 0) {
- if (value && (strncasecmp(value, "deflate", sizeof("deflate") - 1) == 0)) {
- deflate_flag = 1;
- break;
- }
- i++;
- value = TSMimeHdrFieldValueStringGet(cbuf, chdr, cfield, i, NULL);
- nvalues--;
- }
- if (!deflate_flag) {
- return -7;
- }
- TSHandleMLocRelease(cbuf, chdr, cfield);
- TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr);
- } else {
- TSHandleMLocRelease(cbuf, chdr, cfield);
- TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr);
- return -6;
- }
-
- if (server) {
- TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
- } else {
- TSHttpTxnCachedRespGet(txnp, &bufp, &hdr_loc);
- }
-
- /* If there already exists a content encoding then we don't want
- to do anything. */
- field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_ENCODING, -1);
- if (field_loc) {
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return -3;
- }
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
-
- /* We only want to do gzip compression on documents that have a
- content type of "text/" or "application/x-javascript". */
-
- field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_TYPE, -1);
- if (!field_loc) {
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return -4;
- }
-
- value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, NULL);
- if (value && (strncasecmp(value, "text/", sizeof("text/") - 1) == 0)) {
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return 0;
- } else if (value && (strncasecmp(value, "application/x-javascript", (sizeof("application/x-javascript") - 1)) == 0)) {
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return 0;
- } else {
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- return -5;
- }
-}
-
-
-static void
-gzip_transform_add(TSHttpTxn txnp, int server)
-{
- TSVConn connp;
- GzipData *data;
-
- connp = TSTransformCreate(gzip_transform, txnp);
-
- data = gzip_data_alloc();
- data->txn = txnp;
- TSContDataSet(connp, data);
-
- TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
-}
-
-
-static int
-transform_plugin(TSCont contp, TSEvent event, void *edata)
-{
- TSHttpTxn txnp = (TSHttpTxn) edata;
- int reason;
-
- switch (event) {
- case TS_EVENT_HTTP_READ_RESPONSE_HDR:
- reason = gzip_transformable(txnp, 1);
- if (reason >= 0) {
- TSDebug("gzip-transform", "server content transformable");
- gzip_transform_add(txnp, 1);
- } else {
- TSDebug("gzip-transform", "server content NOT transformable [%d]", reason);
- }
-
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
-
- case TS_EVENT_HTTP_READ_CACHE_HDR:
-
- reason = gzip_transformable(txnp, 0);
- if (reason >= 0) {
- TSDebug("gzip-transform", "cached content transformable");
- gzip_transform_add(txnp, 1);
- } else {
- TSDebug("gzip-transform", "cached data: forwarding unchanged (%d)", reason);
- }
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
-
- default:
- exit(1);
- }
-
- return 0;
-}
-
-
-void
-TSPluginInit(int argc, const char *argv[])
-{
- dictId = adler32(0L, Z_NULL, 0);
- if (argc == 2) {
- TSstrlcpy(preload_file, argv[1], sizeof(preload_file));
- preload = 1;
- load_dictionary(dictionary, &dictId);
- }
-
- TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
- TSHttpHookAdd(TS_HTTP_READ_CACHE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
-}
-