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-2007 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 "htmlmodify.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);

#ifdef JP2K
//JP2 version will further communicate with server.
static http_headers *shdr;
static http_headers *chdr;
static FILE *to_sock;
static FILE *from_sock;

#endif

enum {ONormal,OChunked, OStream, OGzipStream};

/* returns:
 *   0 ok,
 *  -1 ok, data streamed already
 *  >0 ERROR
 */
int do_modify(http_headers *serv_hdr, http_headers *client_hdr, char *inbuf, int insize, int original_size,
            char ** outbuf, int *outsize, FILE *sockrfp, FILE *sockwfp){
       int status;

#ifdef JP2K
       to_sock = sockwfp;
       from_sock = sockrfp;
       shdr = serv_hdr;
       chdr = client_hdr;
#endif

      inbuf[insize]='\0';
      if((original_size > MinTextStream) && (('1' == client_hdr->proto[7]) || !UseContentLength))
      {
            int out_type;
            is_sending_data = 1;
            if(('1' == client_hdr->proto[7]) && !(serv_hdr->flags & DO_COMPRESS)){ //use chunked
            //some browsers doesn't like chunked with HTTP/1.0
                  if('0' == serv_hdr->hdr[0][7]) serv_hdr->hdr[0][7]='1';
                  out_type = OChunked;          
            }else if(serv_hdr->flags & DO_COMPRESS)
                  out_type = OGzipStream;
                  
            else out_type = OStream;
                        
            if(out_type == OChunked) add_header(serv_hdr, "Transfer-Encoding: chunked");
            if(out_type == OGzipStream) add_header(serv_hdr, "Content-Encoding: gzip");

            add_header(serv_hdr, "Connection: close");
            add_header(serv_hdr, "Proxy-Connection: close");

            logputs("While modification, streaming "
                        "content. Out Headers:");
            send_headers_to(stdout, serv_hdr);

            status = htmlmodify(inbuf,outbuf, out_type);
            
            logdifftime("Modification+streaming");
            if (!status)
                  return (-1);
            else
                  return (status);
      }else{
            status = htmlmodify(inbuf,outbuf, ONormal);
            *outsize = strlen(*outbuf);
            return (status);
      }

}

//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);
}



int undo_name (char *path)
{
      char * tempp;

      tempp = strrchr(path,'.');
#ifdef JP2K
      if((tempp != NULL) && (!strcasecmp(tempp,suff)))
      {
            *tempp=0;
            return 1;
      }

#else
      if((tempp != NULL) && (!strcasecmp(tempp,".gif_or_jpg") ||
            !strcasecmp(tempp,".png_or_jpg")))
      {
            tempp[4]=0;
            return 1;
      }
#endif            
      return 0;
}



/* 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);
            }
            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);
      }
}

#ifdef JP2K

//IMG tags locations already processed.
typedef struct struct_imglist{
      char *location;
      int converted;
      struct struct_imglist *next;
}imglist;

static int find_img(imglist *first,char *loc){
      imglist *nextl = first;
      while(nextl){
            if(!strcmp(nextl->location, loc))
                  return nextl->converted;
            nextl = nextl->next;
      }
      
      return -1;
}

static void add_location(imglist **first, char *loc, int converted){
      imglist *newl = (imglist*)malloc(sizeof(imglist));
      newl->location = loc;
      newl->converted = converted;
      newl->next = *first;
      *first = newl;
}

char * IMGtoOBJ(char *src, char *original, int attrs, char ** img_attr, char ** img_val){
      char *ret;
      char *w = (char)0, *h = (char)0, *alt = (char)0, *tmp;
      char line[MAX_LINELEN];
      int i, jp2_i;
      long width, height;
      // float rate; // remove this
      static imglist *first =NULL;
      http_headers *request, *response = NULL;

      for(i=0;i<attrs;i++){//find useful attributes
            if(!strcasecmp(img_attr[i], "width"))
                  w = img_val[i];
            else if(!strcasecmp(img_attr[i], "height"))
                  h = img_val[i];
            else if(!strcasecmp(img_attr[i], "alt"))  
                  alt = img_val[i];
      }

      if(!w || !h)//width & height MUST be known
            return original;
      i = find_img(first, src);
      
      if(0 == i) return original;
      if(-1 == i){

            width = strtol(w,&tmp,10);
            if(tmp == w || width < 0) return original;
            if('%'== *tmp) width *= 8; //assume 800x600 screen

            height = strtol(h,&tmp,10);
            if(tmp == h || height < 0) return original;
            if('%'== *tmp) height *= 6; //assume 800x600 screen
            
            //Ask server for image size. If image is on other host (and we aren't 
            //using proxy), refrain.
            if((shdr->flags & H_KEEPALIVE) && (NextProxy || strncasecmp(src, "http://", 7))){
                  request = new_headers();
                  snprintf(line, sizeof(line), "HEAD %s HTTP/1.1", src);
                  request->hdr[0] = strdup(line);
                  request->method = "HEAD";
                  request->path = src;
                  request->proto = PROTOCOL;
                  
                  snprintf(line, sizeof(line), "Host: %s", chdr->host);
                  request->hdr[1] = strdup(line);
                  request->hdr[2] = "Connection: Keep-Alive";
                  request->hdr[3] = "Keep-Alive: 300";
                  request->lines = 4;
                  logprintf("Requesting size of '%s':",src);
                  send_headers_to(to_sock, request);
                  logputs ("Response:");
                  response = get_response_headers(from_sock);
                  if(response->status != 200) response->content_length = -1;
            }

            i = getImageQuality(width, height);
            jp2_i = getJP2ImageQuality(width, height);
            // no idea what is this for, disabled in order to compile
            //if(rate < 0.0001){
            //    add_location(&first, src, 0);
            //    return original;
            //}         

            //check if it is image type we can't handle     
            if(response->where_content_type > 0){
                  request->flags |= H_SUFF_MODIFIED;
                  decide_what_to_do(request, response);
                  if((response->type != IMG_PNG) &&
                        (response->type != IMG_GIF) &&
                        (response->type != IMG_JPEG) &&
                        (response->type != IMG_JP2K)) {
                        add_location(&first, src, 0);
                        return original;
                  }
            }
      
            if(response && response->content_length > 0){
                  //we have all information we want
                  
                  i = response->content_length * 0.85 + 30;
                  
                  // no idea what is this for, disabled in order to compile
                  add_location(&first, src, 1);
                  //if(rate*width*height*3 > i){
                  //    add_location(&first, src, 0);
                  //    return original;
                  //}else add_location(&first, src, 1);
            }
      }

      if (alt != NULL)
            snprintf(line, sizeof(line), "<object TYPE=\"image/jp2\" WIDTH=\"%s\" HEIGHT=\"%s\" "\
            "STANDBY=\"%s\"><param name=\"SRC\" value=\"%s%s\"> %s </object>",
            w, h, alt, src, suff, original);
      else
            snprintf(line, sizeof(line), "<object TYPE=\"image/jp2\" WIDTH=\"%s\" HEIGHT=\"%s\" >"\
            "<param name=\"SRC\" value=\"%s%s\"> %s </object>", w, h, src, suff, 
            original);

      ret = strdup(line);
      
      
/*    asprintf(&ret, "<embed type='image/jp2' src = \"%s%s\" %s ></embed>", 
src, suff, wh );
*/
      return ret;
}
#endif

Generated by  Doxygen 1.6.0   Back to index