Logo Search packages:      
Sourcecode: ziproxy version File versions  Download package

text.c

/* text.c - part of ziproxy package
 *
 * Copyright (c)2003-2004 Juraj Variny<variny@naex.sk>
 * Copyright (c)2005-2009 Daniel Mealha Cabrita
 *
 * Released subject to GNU General Public License v2 or later version.
 *
 * HTML modification, text compression fuctions
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h> //for off_t
#include <zlib.h>
#include <assert.h>

#include "http.h"
#include "cfgfile.h"
#include "image.h"
#include "log.h"
#include "gzpipe.h"

#define CHUNKSIZE 4050
#define GUNZIP_BUFF 16384

static int gzip(char* inbuf, int inlen, char** outbuf, int *outlen, int out_type);
static int gunzip(char* inbuf, int inlen, char** outbuf, int *outlen, int max_growth);

enum {ONormal,OChunked, OStream, OGzipStream};

//TODO correct return value, print status into logs
/* zlib compress streaming from 'from' to 'to' */
/* returns: --> result of gzip_stream_stream() */
/* inlen and outlen will be written with the uncompressed and compressed sizes respectively */
int do_compress_stream_stream(http_headers *hdr, FILE *from, FILE *to, int *inlen, int *outlen){
      int status;
      int de_chunk = 0;

      /* if http body is chunked, de-chunk it while compressing */
      if (hdr->where_chunked > 0) {
            remove_header(hdr, hdr->where_chunked);
            de_chunk = 1;
      }
      
      /* previous content-length is invalid, discard it */
      hdr->where_content_length = -1;
      remove_header_str(hdr, "Content-Length");

      add_header(hdr, "Content-Encoding: gzip");
      add_header(hdr, "Connection: close");
      add_header(hdr, "Proxy-Connection: close");

      logputs("Gzip stream-to-stream. Out Headers:");
      send_headers_to(to, hdr);
      fflush(to);
      
      status = gzip_stream_stream(from, to, Z_BEST_COMPRESSION, inlen, outlen, de_chunk);
      fflush(to);

      logdifftime("Compression+streaming");

      return (status);
}

//TODO correct return value, print status into logs
/* similar to do_compress_stream_stream() but decompress instead */
int do_decompress_stream_stream(http_headers *hdr, FILE *from, FILE *to, int *inlen, int *outlen, int max_ratio, int min_eval){
      int status;
      int de_chunk = 0;

      /* if http body is chunked, de-chunk it while decompressing */
      if (hdr->where_chunked > 0) {
            remove_header(hdr, hdr->where_chunked);
            de_chunk = 1;
      }
      
      /* no longer gzipped, modify headers accordingly */
      hdr->content_encoding_flags = PROP_ENCODED_NONE;
      hdr->content_encoding = NULL;
      hdr->where_content_encoding = -1;
      remove_header_str(hdr, "Content-Encoding");

      /* previous content-length is invalid, discard it */
      hdr->where_content_length = -1;
      remove_header_str(hdr, "Content-Length");

      add_header(hdr, "Connection: close");
      add_header(hdr, "Proxy-Connection: close");
      
      logputs("Gunzip stream-to-stream. Out Headers:");
      send_headers_to(to, hdr);
      fflush(to);
      
      status = gunzip_stream_stream(from, to, inlen, outlen, de_chunk, max_ratio, min_eval);
      fflush(to);

      logdifftime("Decompression+streaming");

      return (status);
}

int do_compress_memory_stream(http_headers *hdr, const char *from, FILE *to, const int inlen, int *outlen){
      int status;
      int de_chunk = 0;

      /* if http body is chunked, de-chunk it while compressing */
      if (hdr->where_chunked > 0) {
            remove_header(hdr, hdr->where_chunked);
            de_chunk = 1;
      }
      
      add_header(hdr, "Content-Encoding: gzip");
      add_header(hdr, "Connection: close");
      add_header(hdr, "Proxy-Connection: close");
      
      logputs("Gzip memory-to-stream. Out Headers:");
      remove_header(hdr, hdr->where_content_length);
        hdr->where_content_length=-1;
      send_headers_to(to, hdr);
      fflush(to);
      
      status = gzip_memory_stream(from, to, Z_BEST_COMPRESSION, inlen, outlen);
      fflush(to);

      logdifftime("Compression+streaming");

      return (status);
}



/* FIXME; kludgy unpacker, rewrite that in a more elegant way */
/* *outbuf must be NULL or an allocated memory address
 * max_growth (in %) is the maximum allowable uncompressed size relative
 *    to inlen, if exceeded the compressor will stop and no data will be written in outbuf
 *    if max_growth==0 then there will be no limit (other than memory) */
static int gunzip(char* inbuf, int inlen, char** outbuf, int *outlen, int max_growth)
{
            int filedes, filedes_unpack;
            FILE *file_pack, *file_unpack;
            char filenam[] = "/tmp/ziproxy_XXXXXX";
            char filenam_unpack[] = "/tmp/ziproxy_XXXXXX";
            gzFile gzfile = Z_NULL;
            char buff_unpack[GUNZIP_BUFF];
            int len_unpack_block;
            int max_outlen;

            max_outlen = ((long long int) inlen * (long long int) max_growth) / 100;
            *outlen = 0;
            
            if((filedes = mkstemp(filenam)) < 0) return 10;
            unlink(filenam);
            if((filedes_unpack = mkstemp(filenam_unpack)) < 0) return 10;
            unlink(filenam_unpack);

            if ((file_pack = fdopen(filedes, "w+")) == NULL) return 20;
            if ((file_unpack = fdopen(filedes_unpack, "w+")) == NULL) return 20;
            
            /* dump packed data into the file */
            fwrite(inbuf, inlen, 1, file_pack);
            fseek(file_pack, 0, SEEK_SET);

            /* proceed with unpacking data into another file */
            if((gzfile = gzdopen(dup(filedes), "rb")) == Z_NULL) return 20;
            while ((len_unpack_block = gzread(gzfile, buff_unpack, GUNZIP_BUFF)) > 0) {
                  *outlen += len_unpack_block;
                  if ((max_growth != 0) && (*outlen > max_outlen))
                        return 100;
                  fwrite(buff_unpack, len_unpack_block, 1, file_unpack);
            }

            /* a smaller decompressed file is not necessarily result of broken gzip data */
            //if (*outlen < inlen)
            //    return 120;

            gzclose(gzfile);
            fclose(file_pack);

            /* load unpacked data to the memory */
            if ((*outbuf=realloc(*outbuf, *outlen)) != NULL) {
                  fseek(file_unpack, 0, SEEK_SET);
                  fread(*outbuf, *outlen, 1, file_unpack);
            }
            fclose(file_unpack);
            
            return 0;
}

/* unpacks gzipped data in inoutbuf, reallocs inoutbuf and dumps
 * unpacked data into the same inoutbuf
 * returns: new size of data,
 *    of negative value if error, value varies according to the error
 *    (in this case, inoutbuff is unchanged)
 * max_growth works in a similar way as gunzip()             */
int replace_gzipped_with_gunzipped(char **inoutbuf, int inlen, int max_growth)
{
      int outlen;
      int retcode;
      char *temp_inoutbuf = *inoutbuf;

      retcode = gunzip(*inoutbuf, inlen, &temp_inoutbuf, &outlen, max_growth);
      if (retcode == 0) {
            *inoutbuf = temp_inoutbuf;
            return (outlen);
      } else {
            return (retcode * -1);
      }
}


Generated by  Doxygen 1.6.0   Back to index