initial load of upstream version 1.06.32
[xmlrpc-c] / tools / turbocharger / mod_gzip.c
1 /* ====================================================================
2  * Copyright (c) 1995-2000 The Apache Group.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the Apache Group
19  *    for use in the Apache HTTP server project (http://www.apache.org/)."
20  *
21  * 4. The names "Apache Server" and "Apache Group" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    apache@apache.org.
25  *
26  * 5. Products derived from this software may not be called "Apache"
27  *    nor may "Apache" appear in their names without prior written
28  *    permission of the Apache Group.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the Apache Group
33  *    for use in the Apache HTTP server project (http://www.apache.org/)."
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Group and was originally based
51  * on public domain software written at the National Center for
52  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
53  * For more information on the Apache Group and the Apache HTTP server
54  * project, please see <http://www.apache.org/>.
55  *
56  */
57
58 /* 
59  * mod_gzip.c
60  *
61  * Apache gzip compression module.
62  *
63  * This module adds 'on the fly' compression of HTTP content to
64  * any Apache Web Server. It uses the IETF Content-encoding standard(s).
65  *
66  * It will compress both static files and the output of any CGI
67  * program inclding shell scripts, perl scripts, executables,
68  * PHP used as CGI, etc.
69  *
70  * There is NO client-side software required for using this module
71  * other than any fully HTTP 1.1 compliant user agent.
72  *
73  * Any fully HTTP 1.1 compliant user agent will be able to receive and
74  * automatically decode the compressed content.
75  *
76  * All fully HTTP 1.1 compliant user agents that are capable of receiving
77  * gzip encoded data will indicate their ability to do so by adding the
78  * standard "Accept-Encoding: gzip" field to the inbound request header.
79  * 
80  * This module may be compiled as a stand-alone external 'plug-in'
81  * or be compiled into the Apache core server as a 'built-in' module.
82  *
83  * Sponsor: Remote Communications, Inc. http://www.RemoteCommunications.com/
84  * Authors: Konstantin Balashov, Alex Kosobrukhov and Kevin Kiley.
85  * Contact: info@RemoteCommunications.com
86  *
87  * Initial public release date: 13-Oct-2000
88  *
89  * Miscellaneous release notes:
90  *
91  * THIS IS A COMPLETELY SELF-CONTAINED MODULE. MOD_GZIP.C IS THE
92  * ONY SOURCE CODE FILE THERE IS AND THERE ARE NO MODULE SPECIFIC
93  * HEADER FILES OR THE NEED FOR ANY 3RD PARTY COMPRESSION LIBRARIES.
94  * ALL OF THE COMPRESSION CODE NEEDED BY THIS MODULE IS CONTAINED
95  * WITHIN THIS SINGLE SOURCE FILE.
96  *
97  * Many standard compression libraries are not designed or optimized
98  * for use as real-time compression codecs nor are they guaranteed
99  * to be 'thread-safe'. The internal compression code used by mod_gzip
100  * is all of those things. It is a highly-optimized and thread-safe
101  * implementation of the standard LZ77 + Huffman compression
102  * technique that has come to be known as GZIP.
103  *
104  * MOD_GZIP LOG FORMATS...
105  *
106  * mod_gzip makes a number of statistical items for each transaction
107  * available through the use of Apache's 'LogFormat' directives which
108  * can be specified in the httpd.conf Apache config file
109  *
110  * mod_gzip uses the standard Apache NOTES interface to allow compression
111  * information to be added to the Apache Web Server log files.
112  *
113  * Standard NOTES may be added to Apache logs using the following syntax
114  * in any LogFormat directive...
115  * * %...{Foobar}n:  The contents of note "Foobar" from another module.
116  *
117  * Additional notes about logging compression information...
118  *
119  * The Apache LogFormat directive is unable to actually display
120  * the 'percent' symbol since it is used exclusively as a 'pickup'
121  * character in the formatting string and cannot be 'escaped' so
122  * all logging of compression ratios cannot use the PERCENT symbol.
123  * Use ASCII 'pct.' designation instead for all PERCENTAGE values.
124  *
125  * Example: This will display the compression ratio percentage along
126  * with the standard CLF ( Common Log Format ) information...
127  *
128  * Available 'mod_gzip' compression information 'notes'...
129  *
130  * %{mod_gzip_result}n - A short 'result' message. Could be OK or DECLINED, etc.
131  * %{mod_gzip_input_size}n - The size ( in bytes ) of the requested object.
132  * %{mod_gzip_output_size}n - The size ( in bytes ) of the compressed version.
133  * %{mod_gzip_compression_ration}n - The compression rate achieved.
134  *
135  *  LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info1
136  *  LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info2
137  *
138  * If you create your own custom 'LogFormat' lines don't forget that
139  * the entire LogFormat line must be encased in quote marks or you
140  * won't get the right results. The visible effect of there not being
141  * and end-quote on a LogFormat line is that the NAME you are choosing
142  * for the LogFormat line is the only thing that will appear in the
143  * log file that tries to use the unbalanced line.
144  *
145  * Also... when using the %{mod_gzip_xxxxx}n note references in your
146  * LogFormat line don't forget to add the lowercase letter 'n' after
147  * the closing bracket to indicate that this is a module 'note' value.
148  *
149  * Once a LogFormat directive has been added to your httpd.conf file
150  * which displays whatever level of compression information desired
151  * simply use the 'name' associated with that LogFormat line in
152  * the 'CustomLog' directive for 'access.log'.
153  *
154  * Example: The line below simply changes the default access.log format
155  * for Apache to the special mog_gzip information record defined above...
156  * CustomLog logs/access.log common
157  *
158  *  CustomLog logs/access.log common_with_mod_gzip_info2
159  *
160  * Using the 'common_with_mod_gzip_info1' LogFormat line for Apache's
161  * normal access.log file produces the following results in the access.log
162  * file when a gigantic 679,188 byte online CD music collection HTML
163  * document called 'music.htm' is requested and the Server delivers the
164  * file via mod_gzip compressed 93 percent down to only 48,951 bytes...
165  *
166  * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951 mod_gzip: 93pct.
167  *
168  * The line below shows what will appear in the Apache access.log file
169  * if the more detailed 'common_with_mod_gzip_info2' LogFormat line is used.
170  * The line has been intentionally 'wrapped' for better display below
171  * but would normally appear as a single line entry in access.log.
172  *
173  * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951
174  *                          mod_gzip: OK In:679188 Out:48951:93pct.
175  *
176  * The 'OK' result string shows that the compression was successful.
177  * The 'In:' value is the size (in bytes) of the requested file and
178  * the 'Out:' value is the size (in bytes) after compression followed
179  * by a colon and a number showing that the document was compressed
180  * 93 percent before being returned to the user.
181  *
182  * Please NOTE that if you add any ASCII strings to your LogFormat
183  * string then they will appear in your log file regardless of
184  * whether this module was actually 'called' to process the
185  * transaction or not. If the module was not called to handle the
186  * transaction then the places where the statistical information
187  * associated with the 'NOTES' references would normally appear
188  * will be filled in with 'dashes' to denote 'no value available'.
189  *
190  * MOD_GZIP RUNTIME DEBUG...
191  *
192  * If you set your default Apache logging level to 'LogLevel debug'
193  * in your httpd.conf file then this module will add certain
194  * diagnostic debug messages to your error log for each and every
195  * transaction that is actually passed to the module.
196  *
197  * If Apache does not 'call' this module to handle a particular
198  * transaction then no special log information will appear in
199  * your error log(s) for that transaction.
200  *
201  * MOD_GZIP CONFIGURATION DIRECTIVES...
202  *
203  * The section that follows is a sample mod_gzip configuration
204  * section that will provide basic compression of all static
205  * TEXT and HTML files as well as dynamic compression of most
206  * standard CGI including Shell scripts, Perl, PHP, etc.
207  *
208  * The configuration directives themselves are documented in more
209  * detail in the README and INSTALL files that accompany this module.
210  *
211  * You should be able to simply 'cut and paste' the follwing section
212  * directly into the BOTTOM of your current httpd.conf Apache
213  * configuration file and be able to start using mod_gzip immediately.
214  *
215
216 #
217 # MOD_GZIP Configuration Directives
218 #
219 # All you should have to do to get up and running using
220 # mod_gzip with some basic STATIC and DYNAMIC compression
221 # capabilites is copy the mod_gzip dynamic library to your
222 # ../modules directory and then add this entire example
223 # configuration section to the BOTTOM of your httpd.conf file.
224 #
225 # Add this entire section including all lines down to where
226 # it says '# End of MOD_GZIP Configuration Directives'.
227 #
228 # The LoadModule command is included here for clarity
229 # but you may want to move it the the BOTTOM of your
230 # current LoadModule list in httpd.conf.
231 #
232 # Change the 'mod_gzip_temp_dir' to the name of a directory
233 # on your machine where temporary workfiles can be created
234 # and destroyed. This directory MUST be readable/writable
235 # by the Server itself while it is running. If the directory
236 # does not exist you must create it yourself with the right
237 # permissions before running the Server.
238 #
239 # If no 'mod_gzip_temp_dir' is specified then the default location
240 # for temporary workfiles will be 'ServerRoot' directory.
241 #
242 # The special mod_gzip log formats are, of course, optional.
243 #
244 # You must, of course, load the right module name for your OS
245 # so make sure the correct 'LoadModule' command is uncommented
246 # directly below...
247
248 # Load Win32 module...
249 LoadModule gzip_module modules/ApacheModuleGzip.dll
250
251 # Load UNIX module...
252 # LoadModule gzip_module modules/mod_gzip.so
253
254 LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info1
255 LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info2
256
257 # NOTE: This 'CustomLog' directive shows how to set your access.log file
258 # to use the mod_gzip format but please remember that for every 'CustomLog'
259 # directive that Apache finds in httpd.conf there will be corresponding
260 # line of output in the access.log file. If you only want ONE line of
261 # results in access.log for each transaction then be sure to comment out
262 # any other 'CustomLog' directives so that this is the only one.
263
264 CustomLog logs/access.log common_with_mod_gzip_info2
265
266 # Runtime control directives...
267
268 mod_gzip_on                 Yes
269 mod_gzip_do_cgi             Yes
270 mod_gzip_do_static_files    Yes
271 mod_gzip_minimum_file_size  300
272 mod_gzip_maximum_inmem_size 60000
273 mod_gzip_keep_workfiles     No
274 mod_gzip_temp_dir           "C:/Program Files/Apache Group/Apache/temp"
275
276 # Item lists...
277 #
278 # Item names can be any one of the following...
279 #
280 # cgi-script - A valid 'handler' name
281 # text/*     - A valid MIME type name ( '*' wildcard allowed )
282 # .phtml     - A valid file type extension
283
284 # Dynamic items...
285 #
286 # NOTE: FOR NOW ALL DYNAMIC ITEMS SHOULD BE
287 # DECLARED BEFORE ANY STATIC ITEMS TO PREVENT
288 # PICKUP CONFLICTS. IF YOU USE !cgi-script
289 # BE SURE IT IS DECLARED BEFORE ANY text/*
290 # MIME TYPE ENTRIES.
291 #
292 # The items listed here are the types of dynamic
293 # output that will be compressed...
294 #
295 # Dynamic items MUST have the "!" BANG character
296 # on the front of the item name.
297 #
298 mod_gzip_item_include !cgi-script
299 mod_gzip_item_include !.php
300 mod_gzip_item_include !.php3
301 mod_gzip_item_include !.phtml
302
303 # Static items...
304 #
305 # The items listed here are the types of static
306 # files that will be compressed...
307 #
308 # NOTE: FOR NOW ALL STATIC INCLUDES MUST
309 # COME AFTER DYNAMIC INCLUDES TO PREVENT
310 # PICKUP CONFLICTS
311 #
312 mod_gzip_item_include text/*
313
314 # Uncomment this line to compress graphics
315 # when graphics compression is allowed...
316 #mod_gzip_item_include image/*
317
318
319 # Exclusions... MIME types and FILE types...
320 #
321 # The items listed here will be EXCLUDED from
322 # any attempt to apply compression...
323 #
324 mod_gzip_item_exclude .js
325 mod_gzip_item_exclude .css
326
327 # Exclusions... HTTP support levels...
328 #
329 # By specifying a certain minimum level of HTTP support
330 # certain older user agents ( browsers ) can be
331 # automatically excluded from receiving compressed data.
332 #
333 # The item value should be in the same HTTP numeric format
334 # that Apache uses to designate HTTP version levels.
335 #
336 # 1001 = HTTP/1.1
337 #
338 # So 'mod_gzip_min_http 1001' means that a requesting
339 # user agent ( browser ) must report a minimum HTTP support
340 # level of 1.1 or it will not receive any compressed data.
341 #
342 mod_gzip_min_http 1001
343
344 # Debugging...
345 #
346 # If your Apache 'LogLevel' is set to 'debug' then
347 # mod_gzip will add some diagnostic and compression
348 # information to your error.log file for each request
349 # that is processed by mod_gzip.
350 #
351 # LogLevel debug
352
353 # End of MOD_GZIP Configuration Directives
354
355  * End of inline comments
356  */
357
358 #include <stdlib.h>
359 /*
360  * Apache headers...
361  */
362
363 #define CORE_PRIVATE
364
365 #include "httpd.h"
366 #include "http_config.h"
367 #include "http_core.h"
368 #include "http_log.h"
369 #include "http_main.h"
370 #include "http_protocol.h"
371 #include "util_script.h"
372
373 /*
374  * Add this header for ap_server_root[ MAX_STRING_LEN ] global...
375  *
376  * #include "http_conf_globals.h"
377  *
378  * ...or just include what we need from http_conf_globals.h
379  * since that is, in fact, only 1 item at this time.
380  */
381 extern API_VAR_EXPORT char ap_server_root[ MAX_STRING_LEN ];
382
383 /*
384  * Add this header to get 'ap_update_mtime()' prototype...
385  *
386  * #include "http_request.h"
387  *
388  * ...or just include what we need from http_request.h since
389  * that is, in fact, only 1 item at this time.
390  */
391 extern API_EXPORT(time_t)
392 ap_update_mtime(request_rec *r, time_t dependency_mtime);
393
394 /*
395  * Version information...
396  *
397  * Since this product is 'married' to the ASF Apache Web Server
398  * the version numbers should always 'match' the changing
399  * version numbers of Apache itself so users can be sure
400  * they have the 'right' module. This allows us to move the
401  * version numbers either backwards or forwards in case issues
402  * arise which require specific versions of mod_gzip for
403  * specific versions of Apache.
404  *
405  * The original code was first tested against the Apache 1.3.14
406  * release but should be compatible with the entire 1.3.x series.
407  * If earlier 1.3.x versions of Apache required special versions
408  * then the mod_gzip version number will still match the Apache
409  * version number ( As in... mod_gzip v1.3.12.1, if needed ).
410  *
411  * If a special version is required for Apache 2.0 then the
412  * version number(s) will change to match release numbers in
413  * that series. ( As in... mod_gzip v 2.0.1.1, etc. ).
414  *
415  * The first 3 numbers of the version are always the equivalent
416  * Apache release numbers. The fourth number is always the actual
417  * mod_gzip 'build' number for that version of Apache.
418  */
419
420 char mod_gzip_version[] = "1.3.14.5"; /* Global version string */
421
422 /*
423  * Declare the NAME by which this module will be known.
424  * This is the NAME that will be used in LoadModule command(s).
425  */
426 extern module MODULE_VAR_EXPORT gzip_module;
427
428 /*
429  * Allow this module to 'read' config information from
430  * ( and interact with ) the 'real' mod_cgi module...
431  */
432 extern module cgi_module;
433
434 /*
435  * Some compile-time code inclusion switches...
436  */
437
438 /*
439  * Turn MOD_GZIP_ALLOWS_INTERNAL_COMMANDS switch ON to allow
440  * information requests to be sent via any standard browser.
441  */
442
443 #define MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
444
445 /*
446  * Turn MOD_GZIP_USES_APACHE_LOGS switch ON to include the
447  * code that can update Apache logs with compression information.
448  */
449
450 #define MOD_GZIP_USES_APACHE_LOGS
451
452  /*
453   * Turn MOD_GZIP_USES_AP_SEND_MMAP switch ON to use the
454   * ap_send_mmap() method for transmitting data. If this
455   * switch is OFF then the default is to use ap_rwrite().
456   * This might need to be platform specific at some point.
457   */
458
459 #define MOD_GZIP_USES_AP_SEND_MMAP
460
461 /*
462  * Turn MOD_GZIP_DEBUG1 switch ON for verbose diags.
463  * This is normally OFF by default and should only be
464  * used for diagnosing problems. The log output is
465  * VERY detailed and the log files will be HUGE.
466  */
467
468 /*
469 #define MOD_GZIP_DEBUG1
470 */
471
472 /*
473  * Some useful instance globals...
474  */
475
476 #ifndef MOD_GZIP_MAX_PATH_LEN
477 #define MOD_GZIP_MAX_PATH_LEN 512
478 #endif
479
480 char mod_gzip_temp_dir[ MOD_GZIP_MAX_PATH_LEN + 2 ];
481
482 long mod_gzip_iusn = 0; /* Instance Unique Sequence Number */
483
484 long mod_gzip_maximum_inmem_size = 60000L;
485 long mod_gzip_minimum_file_size  = 300L;
486
487 #ifdef WIN32
488 char mod_gzip_dirsep[]="\\"; /* Dir separator is a backslash for Windows */
489 #else /* !WIN32 */
490 char mod_gzip_dirsep[]="/";  /* Dir separator is a forward slash for UNIX */
491 #endif /* WIN32 */
492
493 /*
494  * The Compressed Object Cache control structure...
495  */
496
497 #define MOD_GZIP_SEC_ONE_DAY 86400  /* Total seconds in one day */
498 #define MOD_GZIP_SEC_ONE_HR  3600   /* Total seconds in one hour */
499
500 #define MOD_GZIP_DEFAULT_CACHE_SPACE 5
501 #define MOD_GZIP_DEFAULT_CACHE_MAXEXPIRE MOD_GZIP_SEC_ONE_DAY
502 #define MOD_GZIP_DEFAULT_CACHE_EXPIRE    MOD_GZIP_SEC_ONE_HR
503 #define MOD_GZIP_DEFAULT_CACHE_LMFACTOR (0.1)
504 #define MOD_GZIP_DEFAULT_CACHE_COMPLETION (0.9)
505
506 struct mod_gzip_cache_conf {
507
508     const char *root;             /* The location of the cache directory */
509     off_t       space;            /* Maximum cache size (in 1024 bytes) */
510     char        space_set;
511     time_t      maxexpire;        /* Maximum time to keep cached files (secs) */
512     char        maxexpire_set;
513     time_t      defaultexpire;    /* Default time to keep cached file (secs) */
514     char        defaultexpire_set;
515     double      lmfactor;         /* Factor for estimating expires date */
516     char        lmfactor_set;
517     time_t      gcinterval;       /* Garbage collection interval (secs) */
518     char        gcinterval_set;
519     int         dirlevels;        /* Number of levels of subdirectories */
520     char        dirlevels_set;
521     int         dirlength;        /* Length of subdirectory names */
522     char        dirlength_set;
523 };
524
525 /*
526  * The Inclusion/Exclusion map item structure...
527  */
528
529 #define MOD_GZIP_IMAP_MAXNAMES   256
530 #define MOD_GZIP_IMAP_MAXNAMELEN 90
531
532 #define MOD_GZIP_IMAP_ISMIME     1
533 #define MOD_GZIP_IMAP_ISEXT      2
534 #define MOD_GZIP_IMAP_ISHANDLER  3
535
536 #define MOD_GZIP_IMAP_STATIC1    9001
537 #define MOD_GZIP_IMAP_DYNAMIC1   9002
538 #define MOD_GZIP_IMAP_DECLINED1  9003
539
540 typedef struct {
541
542     int  include; /* 1=Include 0=Exclude */
543     int  type;    /* _ISMIME, _ISEXT, _ISHANDLER, etc. */
544     int  action;  /* _STATIC1, _DYNAMIC1, etc. */
545
546     char name[ MOD_GZIP_IMAP_MAXNAMELEN + 2 ];
547
548 } mod_gzip_imap;
549
550 /*
551  * The primary module configuration record...
552  */
553
554 typedef struct {
555
556     struct mod_gzip_cache_conf cache; /* Compressed Object Cache control */
557
558     int  req;                /* 1=mod_gzip handles requests 0=No */
559     char req_set;            /* Mirrors the 'req' flag */
560     int  do_static_files;    /* 1=Yes 0=No */
561     int  do_cgi;             /* 1=Yes 0=No */
562     int  keep_workfiles;     /* 1=Keep workfiles 0=No */
563     int  min_http;           /* Minimum HTTP level ( 1001=HTTP/1.1 ) */
564     long minimum_file_size;  /* Minimum size in bytes for compression attempt */
565     long maximum_inmem_size; /* Maximum size in bytes for im-memory compress */
566
567     /* Inclusion/Exclusion list(s)... */
568
569     int imap_total_entries;
570
571     mod_gzip_imap imap[ MOD_GZIP_IMAP_MAXNAMES + 1 ];
572
573 } mod_gzip_conf;
574
575 /*
576  * The GZP request control structure...
577  */
578
579 #define GZIP_FORMAT    (0)
580 #define DEFLATE_FORMAT (1)
581
582 typedef struct _GZP_CONTROL {
583
584     int   decompress;  /* 0=Compress 1=Decompress */
585
586     int   compression_format;  /* GZIP_FORMAT or DEFLATE_FORMAT */
587
588     /* Input control... */
589
590     int   input_ismem;         /* Input source is memory buffer, not file */
591     char *input_ismem_ibuf;    /* Pointer to input memory buffer */
592     long  input_ismem_ibuflen; /* Total length of input data */
593
594     char  input_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Input file name */
595
596     /* Output control... */
597
598     int   output_ismem;         /* Output source is memory buffer, not file */
599     char *output_ismem_obuf;    /* Pointer to output memory buffer */
600     long  output_ismem_obuflen; /* Maximum length of output data buffer */
601
602     char  output_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Output file name */
603
604     /* Results... */
605
606     int   result_code; /* Result code */
607     long  bytes_out;   /* Total number of compressed output bytes */
608
609 } GZP_CONTROL;
610
611 /*
612  * Forward prototypes for internal routines...
613  */
614
615 int gzp_main( GZP_CONTROL *gzp ); /* Primary GZP API entry point */
616
617 int mod_gzip_request_handler( request_rec *r );
618 int mod_gzip_cgi_handler( request_rec *r );
619 int mod_gzip_static_file_handler( request_rec *r );
620 int mod_gzip_prepare_for_dynamic_call( request_rec *r );
621 int mod_gzip_imap_show_items( mod_gzip_conf *mgc );
622 int mod_gzip_get_action_flag( request_rec *r, mod_gzip_conf *conf );
623 int mod_gzip_ismatch( char *s1, char *s2, int len1, int haswilds );
624
625 FILE *mod_gzip_open_output_file(
626 request_rec *r,
627 char *output_filename,
628 int  *rc
629 );
630
631 int mod_gzip_create_unique_filename(
632 mod_gzip_conf *mgc,
633 char *target,
634 int targetmaxlen
635 );
636
637 int mod_gzip_encode_and_transmit(
638 request_rec *r,
639 char        *source,
640 int          source_is_a_file,
641 long         input_size,
642 int          nodecline
643 );
644
645
646 #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
647
648 int mod_gzip_send_html_command_response(
649 request_rec *r, /* Request record */
650 char *tmp,      /* Response to send */
651 char *ctype     /* Content type string */
652 );
653
654 #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */
655
656 /*
657  * Module routines...
658  */
659
660 #ifdef MOD_GZIP_DEBUG1
661
662 void mod_gzip_printf( const char *fmt, ... )
663 {
664  int   l;
665  FILE *log;
666
667  va_list ap;
668
669  char logname[256];
670  char log_line[4096];
671
672  /* Start... */
673
674  /* If UNIX  then mod_gzip_dirsep = '/' Backward slash */
675  /* If WIN32 then mod_gzip_dirsep = '\' Forward  slash */
676
677  #ifdef FUTURE_USE
678  /*
679  For now we need both startup and runtime diags in the same
680  log so it all goes to ServerRoot. 'mod_gzip_temp_dir' name
681  isn't even valid until late in the startup process so we
682  have to write to ServerRoot anyway until temp dir is known.
683  */
684  if ( strlen(mod_gzip_temp_dir) ) /* Use temp directory ( if specified )... */
685    {
686     sprintf( logname, "%s%smod_gzip.log", mod_gzip_temp_dir, mod_gzip_dirsep );
687    }
688  else /* Just use 'ap_server_root' Apache ServerRoot directory... */
689    {
690     sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep );
691    }
692  #endif /* FUTURE_USE */
693
694  /* Just use ServerRoot for now... */
695  sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep );
696
697  log = fopen( logname,"a" );
698
699  if ( !log ) /* Log file did not open... */
700    {
701     /* Just turn and burn... */
702
703     return; /* Void return */
704    }
705
706  /* Get the variable parameter list... */
707
708  va_start( ap, fmt );
709
710  l = vsprintf(log_line, fmt, ap);
711
712  /* See if we need to add LF... */
713
714  if ( l > 0 )
715    {
716     if ( log_line[l-1] != '\n' )
717       {
718        log_line[l]='\n';
719        l++;
720       }
721
722     log_line[l+1] = 0;
723    }
724
725  fprintf( log, "%s", log_line );
726
727  fclose( log );
728
729  va_end(ap); /* End session */
730
731  return; /* Void return */
732
733 }/* End of log_d() */
734
735 void mod_gzip_hexdump( char *buffer, int buflen )
736 {
737  int i,o1,o2,o3;
738
739  int len1;
740  int len2;
741
742  char ch1;
743  char ch2;
744  char s[40];
745  char l1[129];
746  char l2[129];
747  char l3[300];
748
749  long offset1=0L;
750
751  /* Start... */
752
753  o1=0;
754  o2=0;
755  o3=0;
756
757  l1[0] = 0;
758  l2[0] = 0;
759  l3[0] = 0;
760
761  offset1 = 0;
762
763  for ( i=0; i<buflen; i++ )
764     {
765      ch1 = (char) *buffer++;
766
767      /*------------------------------------------------------------*/
768      /* WARNING: UNIX hates anything non-printable. It can mess    */
769      /*          up the terminal output by trying to use SLASH     */
770      /*          ESCAPE substitutions...                           */
771      /*------------------------------------------------------------*/
772      /* DOUBLE WARNING!: We MUST mask the per-cent char (37 dec)   */
773      /* and the 'backslash' char ( 92 decimal ) or the UNIX        */
774      /* STDIO calls could CRASH. They are just brain-dead enough   */
775      /* to actually try to respond to these chars in the output    */
776      /* stream and convert them to HEX equivalents which could     */
777      /* lengthen the output string(s) and CRASH the output buffer. */
778      /*------------------------------------------------------------*/
779
780      /* ASTERISK         = ASC 42 */
781      /* LEFT APOSTROPHE  = ASC 96 */
782      /* RIGHT APOSTROPHE = ASC 39 */
783      /* PERIOD           = ASC 46 */
784      /* CR DUMP SYMBOL   = ASC 67 ( The letter C ) */
785      /* LF DUMP SYMBOL   = ASC 76 ( The letter L ) */
786
787      #define DUMPIT_ASTERISK    42
788      #define DUMPIT_LAPOSTROPHE 96
789      #define DUMPIT_RAPOSTROPHE 39
790      #define DUMPIT_PERIOD      46
791      #define DUMPIT_CR          67
792      #define DUMPIT_LF          76
793
794      #ifdef MASK_ONLY_CERTAIN_CHARS
795           if ( ch1 ==  0 ) ch2 = DUMPIT_PERIOD;
796      else if ( ch1 == 13 ) ch2 = DUMPIT_CR;
797      else if ( ch1 == 10 ) ch2 = DUMPIT_LF;
798      else if ( ch1 ==  9 ) ch2 = DUMPIT_LAPOSTROPHE;
799      else                  ch2 = ch1;
800      #endif
801
802      #define MASK_ALL_NON_PRINTABLE_CHARS
803      #ifdef  MASK_ALL_NON_PRINTABLE_CHARS
804
805      /* Mask all control chars and high ends chars for UNIX or */
806      /* TTY console screws up... */
807
808           if ( ch1 == 13 ) ch2 = DUMPIT_CR;
809      else if ( ch1 == 10 ) ch2 = DUMPIT_LF;
810      else if ( ch1 <  32 ) ch2 = DUMPIT_PERIOD;
811      else if ( ch1 >  126) ch2 = DUMPIT_LAPOSTROPHE;
812      else if ( ch1 == 37 ) ch2 = DUMPIT_ASTERISK; /* Mask PERCENT   for UNIX */
813      else if ( ch1 == 92 ) ch2 = DUMPIT_ASTERISK; /* Mask BACKSLASH for UNIX */
814      else                  ch2 = ch1;
815
816      /* ENDIF on MASK_ALL_NON_PRINTABLE_CHARS */
817      #endif
818
819      l2[o2++] = ch2;
820
821      sprintf( s, "%02X", ch1 );
822
823      if ( strlen(s) > 2 ) s[2]=0; /* Prevent overflow */
824
825      len1 = strlen(s);
826      len2 = strlen(l1);
827
828      if ( strlen(l1) < (sizeof(l1) - (len1+1)) )
829        {
830         strcat( l1, s   );
831         strcat( l1, " " );
832        }
833
834      if ( o2 >= 16 )
835        {
836         l2[o2]=0;
837
838         mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 );
839
840         offset1 += o2;
841
842         o1=0;
843         o2=0;
844         o3=0;
845
846         l1[0] = 0;
847         l2[0] = 0;
848         l3[0] = 0;
849        }
850
851     }/* End 'for( i=0; i<buflen; i++ )' loop... */
852
853  /* Print remainder ( if anything ) */
854
855  if ( o2 > 0  )
856    {
857     l2[o2]=0;
858
859     mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 );
860
861     offset1 += o2;
862
863     o1 = o2 = o3 = 0;
864
865     l1[0] = 0;
866     l2[0] = 0;
867     l3[0] = 0;
868    }
869
870 }/* End of mod_gzip_hexdump() */
871
872 #endif /* MOD_GZIP_DEBUG1 */
873
874 static void mod_gzip_init( server_rec *server, pool *p )
875 {
876     /*
877      * The module initialization procedure...
878      */
879
880     FILE *fh1;
881     char filename[ 512 ];
882
883     #ifdef MOD_GZIP_DEBUG1
884     char cn[]="mod_gzip_init()";
885     #endif
886
887     mod_gzip_conf *mgc;
888
889     /* Start... */
890
891     #ifdef MOD_GZIP_DEBUG1
892     mod_gzip_printf( "%s: Entry...\n", cn );
893     #endif
894
895     /*
896      * Set some instance specific globals...
897      *
898      * The default 'temp' dir, lacking an httpd.conf config file
899      * override, is the Apache 'ServerRoot'. Don't assume that /logs
900      * dir exists because some Apache installations just use syslog
901      * or stderr as their log output target.
902      *
903      * On most Apache installations 'ServerRoot' is automatically
904      * readable/writable by the Server while it is running.
905      *
906      * On systems where it is not there MUST be an override
907      * in the httpd.conf file.
908      *
909      * See the comments regarding the 'mod_gzip_temp_dir' directive
910      * in the httpd.conf configuration file.
911      */
912
913     mgc = ( mod_gzip_conf * )
914     ap_get_module_config(server->module_config, &gzip_module);
915
916     /* Make sure we can read/write the temp directory... */
917
918     sprintf( filename, "%s%smod_gzip.id", mgc->cache.root, mod_gzip_dirsep );
919
920     fh1 = fopen( filename, "wb" );
921
922     if ( !fh1 ) /* Write an ERROR to console and to log(s)... */
923       {
924        fprintf( stderr, "mod_gzip: Cannot read/write dir/file [%s]\n",filename);
925        fprintf( stderr, "mod_gzip: Make sure the directory exists and that the Server\n");
926        fprintf( stderr, "mod_gzip: has read/write permission(s) for the directory.\n");
927        fprintf( stderr, "mod_gzip: See the 'mod_gzip_temp_dir' configuration notes.\n");
928
929        /* This is a startup ERROR and has to be fixed... */
930
931        ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server,
932        "mod_gzip: Cannot read/write dir/file [%s]", filename);
933        ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server,
934        "mod_gzip: Make sure the directory exists and that the Server");
935        ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server,
936        "mod_gzip: has read/write permission(s) for the directory.");
937        ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server,
938        "mod_gzip: See the 'mod_gzip_temp_dir' configuration notes.");
939       }
940     else /* File opened OK... just add some data and close it... */
941       {
942        /*
943         * Since this is just a MARK file we could simply wipe
944         * it out but might as well print the actual version
945         * number into it and leave it there in case there is
946         * any question about which version is actually running.
947         */
948
949        fprintf( fh1, "mod_gzip version %s\n", mod_gzip_version );
950        fclose( fh1 );
951       }
952
953     #ifdef MOD_GZIP_DEBUG1
954     mod_gzip_imap_show_items( (mod_gzip_conf *) mgc ); /* Show item list */
955     mod_gzip_printf( "%s: Exit > return( void ) >\n", cn );
956     mod_gzip_printf( "\n" ); /* Separator for log file */
957     #endif
958
959 }/* End of mod_gzip_init() */
960
961 int mod_gzip_strnicmp( char *s1, char *s2, int len1 )
962 {
963  /* Behaves just like strnicmp() but IGNORES differences */
964  /* between FORWARD or BACKWARD slashes in a STRING...   */
965  /* Also uses straight pointers and avoids stdlib calls. */
966
967  int i;
968  char ch1;
969  char ch2;
970
971  /* WARNING! We MUST have a check for 'NULL' on the pointer(s) */
972  /*          themselves or we might GP ( like NETSCAPE does )  */
973  /*          if a 'NULL' pointer is passed to this routine...  */
974
975  if ( ( s1 == 0 ) || ( s2 == 0 ) )
976    {
977     /* SAFETY! If pointer itself if NULL       */
978     /* don't enter LOOP or NETSCAPE will GP... */
979
980     return( 1 ); /* Return '1' for NOMATCH...  */
981    }
982
983  for ( i=0; i<len1; i++ )
984     {
985      if ( ( *s1 == 0 ) || ( *s2 == 0 ) ) return( 1 ); /* No match! */
986
987      ch1 = *s1;
988      ch2 = *s2;
989
990      if ( ch1 > 96 ) ch1 -= 32;
991      if ( ch2 > 96 ) ch2 -= 32;
992
993      if ( ch1 == '/' ) ch1 = '\\';
994      if ( ch2 == '/' ) ch2 = '\\';
995
996      if ( ch1 != ch2 ) return( 1 ); /* No match! */
997
998      s1++;
999      s2++;
1000
1001     }/* End 'i' loop */
1002
1003  /* If we make it to here then everything MATCHED! */
1004
1005  return( 0 ); /* MATCH! */
1006
1007 }/* End mod_gzip_strnicmp() */
1008
1009 extern API_VAR_EXPORT module *top_module;
1010
1011 struct _table {
1012     array_header a;
1013 #ifdef MAKE_TABLE_PROFILE
1014     void *creator;
1015 #endif
1016 };
1017 typedef struct _table _table;
1018
1019 const char *mod_gzip_isscript( request_rec *r, _table *t, const char *key)
1020 {
1021     /*
1022      * Get a 'handler' name for a MIME type right out of
1023      * the Apache 'Action' table(s)...
1024      *
1025      * Example:
1026      *
1027      * If "key" is "applications/x-httpd-php3"
1028      * then this search will return "/php3/php.exe"
1029      * or whatever the equivalent PHP executable
1030      * pathname is as specified by an 'Action' statement
1031      * in the httpd.conf configuration file.
1032      *
1033      * This pathname might still have 'aliases' in it
1034      * so we will have to consult with mod_alias
1035      * following this call and get any aliases converted.
1036      */
1037
1038     table_entry *elts =
1039     (table_entry *) t->a.elts;
1040     int i;
1041
1042     char cn[]="mod_gzip_isscript()";
1043
1044     /*
1045      * Start...
1046      */
1047
1048     #ifdef MOD_GZIP_DEBUG1
1049     mod_gzip_printf( "%s: Entry...\n",cn);
1050     mod_gzip_printf( "%s: key=[%s]\n",cn,key );
1051     #endif
1052
1053     if ( key == NULL )
1054       {
1055        #ifdef MOD_GZIP_DEBUG1
1056        mod_gzip_printf( "%s: 'key' has no length\n",cn);
1057        mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn);
1058        #endif
1059
1060        if ( r->server->loglevel == APLOG_DEBUG )
1061          {
1062           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1063           "%s: Search key is NULL.",cn);
1064          }
1065
1066        return NULL;
1067       }
1068
1069     for (i = 0; i < t->a.nelts; ++i)
1070        {
1071         #ifdef MOD_GZIP_DEBUG1
1072         mod_gzip_printf(
1073         "%s: i=%4.4d Comparing [%s] with elts.key[%s].val[%s]\n",
1074         cn, i, key, elts[i].key, elts[i].val );
1075         #endif
1076
1077         if ( r->server->loglevel == APLOG_DEBUG )
1078           {
1079            ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1080            "%s: i=%4.4d Comparing [%s] with elts.key[%s].val[%s]",
1081            cn, i, key, elts[i].key, elts[i].val );
1082           }
1083
1084         if (!strcasecmp(elts[i].key, key))
1085           {
1086            #ifdef MOD_GZIP_DEBUG1
1087            mod_gzip_printf( "%s: MATCH FOUND!",cn);
1088            mod_gzip_printf( "%s: Exit > return(%s) >\n",cn,elts[i].val);
1089            #endif
1090
1091            if ( r->server->loglevel == APLOG_DEBUG )
1092              {
1093               ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1094               "%s: MATCH FOUND...",cn);
1095              }
1096
1097            return elts[i].val;
1098           }
1099
1100        }/* End 'i' loop */
1101
1102     if ( r->server->loglevel == APLOG_DEBUG )
1103       {
1104        ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1105        "%s: NO MATCH FOUND...",cn);
1106       }
1107
1108     #ifdef MOD_GZIP_DEBUG1
1109     mod_gzip_printf( "%s: NO MATCH FOUND!\n",cn);
1110     mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn);
1111     #endif
1112
1113     return NULL;
1114
1115 }/* End of 'mod_gzip_isscript()' */
1116
1117 typedef struct {
1118   table *action_types;       /* Added with Action... */
1119   char *scripted[METHODS];   /* Added with Script... */
1120   array_header *xmethods;    /* Added with Script -- extension methods */
1121 } mod_actions_local_config;
1122
1123 int mod_gzip_run_mod_action( request_rec *r )
1124 {
1125     module *modp;
1126     int count=0;
1127     int pass=0;
1128
1129     mod_actions_local_config *mod_actions_conf;
1130
1131     const char *t=0;
1132     const char *action=0;
1133
1134     #ifdef MOD_GZIP_DEBUG1
1135     char cn[]="mod_gzip_run_mod_action()";
1136     #endif
1137
1138     #ifdef MOD_GZIP_FUTURE_USE
1139     const handler_rec *handp;
1140     #endif
1141
1142     /* Currently 9 possible 'event' handlers. */
1143     /* Actual content handler in a module is 'extra'. */
1144     #define MOD_GZIP_NMETHODS 9
1145
1146     /*
1147      * Start...
1148      */
1149
1150     #ifdef MOD_GZIP_DEBUG1
1151     mod_gzip_printf( "%s: Entry...\n",cn);
1152     mod_gzip_printf( "%s: *IN: r->uri         =[%s]\n", cn, r->uri );
1153     mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri );
1154     mod_gzip_printf( "%s: *IN: r->filename    =[%s]\n", cn, r->filename );
1155     mod_gzip_printf( "%s: r->content_type     =[%s]\n", cn,r->content_type);
1156     mod_gzip_printf( "%s: r->handler          =[%s]\n", cn,r->handler);
1157     #endif
1158
1159     for ( modp = top_module; modp; modp = modp->next )
1160        {
1161         /* modp->name list will look like this... */
1162         /*--------------------*/
1163         /* 00 [mod_gzip.c]    */
1164         /* 01 [mod_isapi.c]   */
1165         /* 02 [mod_setenv.c]  */
1166         /* 02 [mod_actions.c] */
1167         /*    ............... */
1168         /*    ............... */
1169         /* 18 [mod_so.c]      */
1170         /* 19 [http_core.c]   <- Always bottom of list (last one called) */
1171         /*--------------------*/
1172
1173         #ifdef MOD_GZIP_DEBUG1
1174         mod_gzip_printf( "%s: count=%4.4d modp = %10.10ld modp->name=[%s]\n",
1175         cn,count,(long)modp, modp->name );
1176         #endif
1177
1178         if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )
1179         {
1180
1181         /* Module information... */
1182
1183         #ifdef MOD_GZIP_DEBUG1
1184         mod_gzip_printf( "%s: ++++++++++ MODULE FOUND!...\n",cn);
1185         mod_gzip_printf( "%s: ++++++++++ modp->module_index = %d\n",cn,(int)modp->module_index);
1186         #endif
1187
1188         /* Get a pointer to the module configuration data... */
1189
1190         mod_actions_conf = (mod_actions_local_config *)
1191         ap_get_module_config(r->per_dir_config, modp );
1192
1193         /* Get script name... */
1194
1195         /* Make 2 passes if necessary. If we don't find a   */
1196         /* program name associated with MIME type first     */
1197         /* then punt and look for a program name associated */
1198         /* with the r->handler name such as [php-script]    */
1199
1200         for ( pass = 0; pass < 2; pass++ )
1201            {
1202             if ( pass == 0 ) /* Check r->content_type first */
1203               {
1204                /* This is the first pass... */
1205
1206                /* Set 'action' search key to 'r->content_type' */
1207                /* so we search for [application/x-httpd-php3]  */
1208
1209                action = r->content_type;
1210               }
1211             else if ( pass == 1 ) /* Try r->handler */
1212               {
1213                /* This is the second pass... */
1214
1215                /* Set 'action' search key to 'r->handler' */
1216                /* so we search for [php-script]  */
1217
1218                action = r->handler;
1219               }
1220
1221             #ifdef MOD_GZIP_DEBUG1
1222             mod_gzip_printf( "%s: ++++++++++ pass            =%d\n",  cn,pass);
1223             mod_gzip_printf( "%s: ++++++++++ t               =[%s]\n",cn,t);
1224             mod_gzip_printf( "%s: ++++++++++ r->content_type =[%s]\n",cn,r->content_type);
1225             mod_gzip_printf( "%s: ++++++++++ r->handler      =[%s]\n",cn,r->handler);
1226             mod_gzip_printf( "%s: ++++++++++ action          =[%s]\n",cn,action);
1227             mod_gzip_printf( "%s: ++++++++++ r->filename     =[%s]\n",cn,r->filename);
1228             mod_gzip_printf( "%s: ++++++++++ r->uri          =[%s]\n",cn,r->uri);
1229             mod_gzip_printf( "%s: ++++++++++ Call mod_gzip_isscript()...\n",cn);
1230             #endif
1231
1232             t =
1233             mod_gzip_isscript(
1234             r,
1235             (_table *) mod_actions_conf->action_types,
1236             action ? action : ap_default_type(r)
1237             );
1238
1239             #ifdef MOD_GZIP_DEBUG1
1240             mod_gzip_printf( "%s: ++++++++++ Back mod_gzip_isscript()...\n",cn);
1241             mod_gzip_printf( "%s: ++++++++++ t               =[%s]\n",cn,t);
1242             mod_gzip_printf( "%s: ++++++++++ action          =[%s]\n",cn,action);
1243             #endif
1244
1245             if ( t )
1246               {
1247                /*
1248                 * If a program name was found then make it r->filename
1249                 * and r->uri will become the input name for the program
1250                 */
1251
1252                r->filename = ap_pstrdup(r->pool,t);
1253
1254                break;
1255               }
1256
1257            }/* End 'for( pass )' loop */
1258
1259         #ifdef MOD_GZIP_DEBUG1
1260         mod_gzip_printf( "%s: ++++++++++ r->filename=[%s]\n",cn,r->filename);
1261         mod_gzip_printf( "%s: ++++++++++ r->uri     =[%s]\n",cn,r->uri);
1262         #endif
1263
1264         /* If a handler was found we are DONE... */
1265
1266         if ( t )
1267           {
1268            #ifdef MOD_GZIP_DEBUG1
1269            mod_gzip_printf( "%s: Handler was found...\n",cn);
1270            mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn);
1271            #endif
1272
1273            return OK;
1274           }
1275
1276         #ifdef MOD_GZIP_FUTURE_USE
1277
1278         #ifdef MOD_GZIP_DEBUG1
1279         mod_gzip_printf( "%s: ++++++++++ METHODS\n",cn);
1280         mod_gzip_printf( "%s: ++++++++++ modp->translate_handler = %ld\n",cn,(long)modp->translate_handler);
1281         mod_gzip_printf( "%s: ++++++++++ modp->ap_check_user_id  = %ld\n",cn,(long)modp->ap_check_user_id);
1282         mod_gzip_printf( "%s: ++++++++++ modp->auth_checker      = %ld\n",cn,(long)modp->auth_checker);
1283         mod_gzip_printf( "%s: ++++++++++ modp->access_checker    = %ld\n",cn,(long)modp->access_checker);
1284         mod_gzip_printf( "%s: ++++++++++ modp->type_checker      = %ld\n",cn,(long)modp->type_checker);
1285         mod_gzip_printf( "%s: ++++++++++ modp->fixer_upper       = %ld\n",cn,(long)modp->fixer_upper);
1286         mod_gzip_printf( "%s: ++++++++++ modp->logger            = %ld\n",cn,(long)modp->logger);
1287         mod_gzip_printf( "%s: ++++++++++ modp->header_parser     = %ld\n",cn,(long)modp->header_parser);
1288         mod_gzip_printf( "%s: .......... CONTENT HANDLERS\n",cn);
1289         #endif /* MOD_GZIP_DEBUG1 */
1290
1291         if ( !modp->handlers )
1292           {
1293            #ifdef MOD_GZIP_DEBUG1
1294            mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn);
1295            #endif
1296           }
1297         else /* There are some handlers... */
1298           {
1299            for ( handp = modp->handlers; handp->content_type; ++handp )
1300               {
1301                #ifdef MOD_GZIP_DEBUG1
1302                mod_gzip_printf( "%s: .......... handp->content_type = [%s]\n",
1303                cn,handp->content_type);
1304                mod_gzip_printf( "%s: .......... handp->handler      = %ld\n",cn,(long)handp->handler);
1305                #endif
1306
1307               }/* End 'handp' loop */
1308
1309           }/* End 'else' */
1310
1311         #endif /* MOD_GZIP_FUTURE_USE */
1312
1313         #ifdef MOD_GZIP_DEBUG1
1314         mod_gzip_printf( "%s: No handler was found...\n",cn);
1315         mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
1316         #endif
1317
1318         return DECLINED;
1319
1320         }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */
1321
1322         count++;
1323
1324        }/* End 'modp' loop... */
1325
1326     #ifdef MOD_GZIP_DEBUG1
1327     mod_gzip_printf( "%s: No handler found...\n",cn);
1328     mod_gzip_printf( "%s: Exit > return( DECLINED ) > ERROR >\n",cn);
1329     #endif
1330
1331     return DECLINED;
1332
1333 }/* End of mod_gzip_run_mod_action() */
1334
1335
1336 int mod_gzip_run_mod_alias( request_rec *r )
1337 {
1338     /*
1339      * This calls 'translate_alias_redir()' routine in mod_alias.c
1340      * which will search/replace keywords in the URI with the correct
1341      * 'ScriptAlias' value(s) from the httpd.conf configuration file.
1342      *
1343      * 'translate_alias_redir()' is the name of routine registered
1344      * by mod_alias.c module as the 'translate' hook.
1345      */
1346
1347     module *modp;
1348     int count=0;
1349     int rc;
1350
1351     #ifdef MOD_GZIP_DEBUG1
1352     char cn[]="mod_gzip_run_mod_alias()";
1353     #endif
1354
1355     const handler_rec *handp;
1356
1357     /* Currently 9 possible 'event' handlers. */
1358     /* Actual content handler in a module is 'extra'. */
1359     #define MOD_GZIP_NMETHODS 9
1360
1361     char *save_filename     = 0;
1362     char *save_uri          = 0;
1363
1364     char nothing[256];
1365
1366     /*
1367      * Start...
1368      */
1369
1370     #ifdef MOD_GZIP_DEBUG1
1371     mod_gzip_printf( "%s: Entry...\n",cn);
1372     mod_gzip_printf( "%s: *IN: r->uri         =[%s]\n", cn, r->uri );
1373     mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri );
1374     mod_gzip_printf( "%s: *IN: r->filename    =[%s]\n", cn, r->filename );
1375     #endif
1376
1377     for ( modp = top_module; modp; modp = modp->next )
1378        {
1379         /* modp->name list will look like this... */
1380         /*--------------------*/
1381         /* 00 [mod_gzip.c]    */
1382         /* 01 [mod_isapi.c]   */
1383         /* 02 [mod_setenv.c]  */
1384         /* 02 [mod_actions.c] */
1385         /*    ............... */
1386         /*    ............... */
1387         /* 18 [mod_so.c]      */
1388         /* 19 [http_core.c]   <- Always bottom of list (last one called) */
1389         /*--------------------*/
1390
1391         #ifdef MOD_GZIP_DEBUG1
1392         mod_gzip_printf( "%s: count=%4.4d modp = %10.10ld modp->name=[%s]\n",
1393         cn,count,(long)modp, modp->name );
1394         #endif
1395
1396         /*
1397         There are only 3 modules that normally have
1398         'translate' handlers registered...
1399
1400         mod_alias
1401         mod_userdir
1402         http_core
1403         */
1404
1405         if ( ( mod_gzip_strnicmp( (char *) modp->name, "mod_alias.c",   11 ) == 0 ) ||
1406              ( mod_gzip_strnicmp( (char *) modp->name, "mod_userdir.c", 13 ) == 0 ) ||
1407              ( mod_gzip_strnicmp( (char *) modp->name, "http_core.c",   11 ) == 0 ) )
1408         {
1409
1410         /* Module information... */
1411
1412         #ifdef MOD_GZIP_DEBUG1
1413
1414         mod_gzip_printf( "%s: ++++++++++ MODULE FOUND!...\n",cn);
1415         mod_gzip_printf( "%s: ++++++++++ modp->module_index = %d\n",cn,(int)modp->module_index);
1416
1417         mod_gzip_printf( "%s: ++++++++++ METHODS\n",cn);
1418         mod_gzip_printf( "%s: ++++++++++ modp->translate_handler = %ld\n",cn,(long)modp->translate_handler);
1419         mod_gzip_printf( "%s: ++++++++++ modp->ap_check_user_id  = %ld\n",cn,(long)modp->ap_check_user_id);
1420         mod_gzip_printf( "%s: ++++++++++ modp->auth_checker      = %ld\n",cn,(long)modp->auth_checker);
1421         mod_gzip_printf( "%s: ++++++++++ modp->access_checker    = %ld\n",cn,(long)modp->access_checker);
1422         mod_gzip_printf( "%s: ++++++++++ modp->type_checker      = %ld\n",cn,(long)modp->type_checker);
1423         mod_gzip_printf( "%s: ++++++++++ modp->fixer_upper       = %ld\n",cn,(long)modp->fixer_upper);
1424         mod_gzip_printf( "%s: ++++++++++ modp->logger            = %ld\n",cn,(long)modp->logger);
1425         mod_gzip_printf( "%s: ++++++++++ modp->header_parser     = %ld\n",cn,(long)modp->header_parser);
1426         mod_gzip_printf( "%s: .......... CONTENT HANDLERS\n",cn);
1427
1428         #endif /* MOD_GZIP_DEBUG1 */
1429
1430         if ( !modp->handlers )
1431           {
1432            #ifdef MOD_GZIP_DEBUG1
1433            mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn);
1434            #endif
1435           }
1436         else /* There are some handlers... */
1437           {
1438            for ( handp = modp->handlers; handp->content_type; ++handp )
1439               {
1440                #ifdef MOD_GZIP_DEBUG1
1441                mod_gzip_printf( "%s: .......... handp->content_type = [%s]\n",
1442                cn,handp->content_type);
1443                mod_gzip_printf( "%s: .......... handp->handler      = %ld\n",cn,(long)handp->handler);
1444                #endif
1445
1446               }/* End 'handp' loop */
1447
1448           }/* End 'else' */
1449
1450         if ( modp->translate_handler )
1451           {
1452            #ifdef MOD_GZIP_DEBUG1
1453            mod_gzip_printf( "%s: modp->translate_handler is VALID...\n",cn);
1454            #endif
1455
1456            /*
1457            There are only 3 modules that normally have
1458            'translate' handlers registered...
1459
1460            mod_alias     <- Will translate /php3/xxx to c:/php3017/xx
1461            mod_userdir
1462            http_core
1463            */
1464
1465            /*
1466             * This calls 'translate_alias_redir()' routine in mod_alias.c
1467             * which will search/replace keywords in the URI with the correct
1468             * 'ScriptAlias' value(s) from the httpd.conf configuration file.
1469             *
1470             * 'translate_alias_redir()' is the name of routine registered
1471             * by mod_alias.c module as the 'translate' hook.
1472             *
1473             * The 'translate_alias_redir()' function in mod_alias.c
1474             * is really simple. All it does is check to make sure
1475             * that r->uri has some value and, if it does, it calls
1476             * another routine in mod_alias.c named 'try_alias_list()'
1477             * which replaces any 'ScriptAlias' phrases with their
1478             * real values and copies the result to r->filename.
1479             *
1480             * We must make sure the phrase we want translated is
1481             * in r->uri and check for results in r->filename.
1482             */
1483
1484            /*
1485             * Calling mod_alias.c translate handler will correctly
1486             * translate 'ScriptAlias' phrases such as...
1487             *
1488             * URI value...
1489             * /php3/php3.exe
1490             * becomes...
1491             * c:/php3017/php3.exe
1492             */
1493
1494            save_filename     = r->filename;
1495            save_uri          = r->uri;
1496            nothing[0]        = 0;
1497
1498            r->filename       = nothing;
1499            r->uri            = save_filename; /* Phrase to translate */
1500
1501            #ifdef MOD_GZIP_DEBUG1
1502            mod_gzip_printf( "%s: r->filename     = [%s]\n",cn,r->filename);
1503            mod_gzip_printf( "%s: r->uri          = [%s]\n",cn,r->uri);
1504            mod_gzip_printf( "%s: Call (modp->translate_handler)(r)...\n",cn);
1505            #endif
1506
1507            /* Call the actual translate routine in mod_action module... */
1508
1509            rc = (modp->translate_handler)( (request_rec *) r );
1510
1511            #ifdef MOD_GZIP_DEBUG1
1512            mod_gzip_printf( "%s: Back (modp->translate_handler)(r)...\n",cn);
1513            mod_gzip_printf( "%s: r->filename     = [%s]\n",cn,r->filename);
1514            mod_gzip_printf( "%s: r->uri          = [%s]\n",cn,r->uri);
1515            #endif
1516
1517            /*
1518             * If there was a successful translation then the return
1519             * code will be OK and the translated URI will be sitting
1520             * in r->filename. If there were no phrase replacements
1521             * then the return code will be DECLINED.
1522             */
1523
1524            #ifdef MOD_GZIP_DEBUG1
1525
1526            if ( rc == OK )
1527              {
1528               mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc );
1529              }
1530            else if ( rc == DECLINED )
1531              {
1532               mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc );
1533              }
1534            else if ( rc == DONE ) /* -2 means 'totally done' */
1535              {
1536               mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc );
1537              }
1538            else /* Probably an HTTP ERROR value... */
1539              {
1540               mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc );
1541              }
1542
1543            #endif /* MOD_GZIP_DEBUG */
1544
1545            /*
1546             * Evaluate the results...
1547             */
1548
1549            if ( rc == OK ) /* There was a phrase translation... */
1550              {
1551               #ifdef MOD_GZIP_DEBUG1
1552               mod_gzip_printf( "%s: There was a phrase translation...\n",cn );
1553               mod_gzip_printf( "%s: Keeping new 'r->filename'\n",cn );
1554               #endif
1555
1556               /* Do NOT restore 'r->filename' to original value... */
1557               /* Just fall-through and continue... */
1558              }
1559            else /* No phrases were replaced... */
1560              {
1561               #ifdef MOD_GZIP_DEBUG1
1562               mod_gzip_printf( "%s: There were NO phrases translated...\n",cn );
1563               mod_gzip_printf( "%s: Restoring 'r->filename' to original value...\n",cn );
1564               #endif
1565
1566               /* Restore 'r->filename' to original value... */
1567
1568               r->filename = save_filename;
1569              }
1570
1571            /* Always 'restore' URI to original value... */
1572
1573            r->uri = save_uri;
1574
1575            /* Turn and burn... */
1576
1577            #ifdef MOD_GZIP_DEBUG1
1578            mod_gzip_printf( "%s: Exit > return( rc=%d ) >\n",cn,rc);
1579            #endif
1580
1581            return rc;
1582           }
1583         else /* modp->translate_handler is NULL... */
1584           {
1585            #ifdef MOD_GZIP_DEBUG1
1586            mod_gzip_printf( "%s: modp->translate_handler is NOT VALID.\n",cn);
1587            #endif
1588           }
1589
1590         }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */
1591
1592         count++;
1593
1594        }/* End 'modp' loop... */
1595
1596     #ifdef MOD_GZIP_DEBUG1
1597     mod_gzip_printf( "%s: No handler found...\n",cn);
1598     mod_gzip_printf( "%s: Exit > return( DECLINED ) > ERROR >\n",cn);
1599     #endif
1600
1601     return DECLINED;
1602
1603 }/* End of mod_gzip_run_mod_alias() */
1604
1605
1606 static int mod_gzip_handler( request_rec *r )
1607 {
1608     /*
1609      * The primary module request handler...
1610      */
1611
1612     int  rc=0;
1613     char cn[]="mod_gzip_handler()";
1614     int access_status=0;
1615     int access_status2=0;
1616
1617     /*
1618      * Start...
1619      */
1620
1621     if ( r->server->loglevel == APLOG_DEBUG )
1622       {
1623        /*
1624         * If the user has 'LogLevel debug' set in httpd.conf then
1625         * it's ok to go ahead and strike some diagnostic information
1626         * to the Apache log(s).
1627         *
1628         * APLOG_MARK is what supplies __FILE__ and __LINE__ info and
1629         * it is actually defined in HTTP_LOG.H as...
1630         *
1631         * define APLOG_MARK  __FILE__,__LINE__
1632         *
1633         * Sometimes the original __FILE__ name is very long and is
1634         * fairly useless information cluttering up the logs when
1635         * there is only 1 possible source file name so
1636         * to NOT use it just supply 2 dummy parameters instead.
1637         *
1638         * The first parameter can be a custom message instead of
1639         * the __FILE__ string that would normally be substituted.
1640         */
1641
1642         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1643         "%s: Entry point...",cn);
1644
1645         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1646         "%s: r->the_request  = [%s]",cn,r->the_request);
1647
1648         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1649         "%s: r->protocol     = [%s]",cn,r->protocol);
1650
1651         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1652         "%s: r->proto_num    = %d",cn,(int)r->proto_num);
1653
1654         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1655         "%s: r->filename     = [%s]",cn,r->filename);
1656
1657         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1658         "%s: r->uri          = [%s]",cn,r->uri);
1659
1660         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1661         "%s: r->content_type = [%s]",cn,r->content_type);
1662
1663         ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1664         "%s: r->handler      = [%s]",cn,r->handler);
1665
1666        }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */
1667
1668     #ifdef MOD_GZIP_DEBUG1
1669     mod_gzip_printf( "\n" );
1670     mod_gzip_printf( "%s: ```` Entry...\n",cn);
1671     mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn);
1672     mod_gzip_printf( "%s: *IN: r->uri                 =[%s]\n", cn, r->uri );
1673     mod_gzip_printf( "%s: *IN: r->unparsed_uri        =[%s]\n", cn, r->unparsed_uri );
1674     mod_gzip_printf( "%s: *IN: r->filename            =[%s]\n", cn, r->filename );
1675     mod_gzip_printf( "%s: *IN: r->path_info           =[%s]\n", cn, r->path_info );
1676     mod_gzip_printf( "%s: *IN: r->args                =[%s]\n", cn, r->args );
1677     mod_gzip_printf( "%s: *IN: r->header_only         =[%s]\n", cn, r->header_only );
1678     mod_gzip_printf( "%s: *IN: r->protocol            =[%s]\n", cn, r->protocol );
1679     mod_gzip_printf( "%s: *IN: r->proto_num           =%d\n",   cn, r->proto_num );
1680     mod_gzip_printf( "%s: *IN: r->hostname            =[%s]\n", cn, r->hostname );
1681     mod_gzip_printf( "%s: *IN: r->the_request         =[%s]\n", cn, r->the_request );
1682     mod_gzip_printf( "%s: *IN: r->assbackwards        =%d\n",   cn, r->assbackwards );
1683     mod_gzip_printf( "%s: *IN: r->status_line         =[%s]\n", cn, r->status_line );
1684     mod_gzip_printf( "%s: *IN: r->status              =%d\n",   cn, r->status );
1685     mod_gzip_printf( "%s: *IN: r->method              =[%s]\n", cn, r->method );
1686     mod_gzip_printf( "%s: *IN: r->method_number       =%d\n",   cn, r->method_number );
1687     mod_gzip_printf( "%s: *IN: r->content_type        =[%s]\n", cn, r->content_type );
1688     mod_gzip_printf( "%s: *IN: r->handler             =[%s]\n", cn, r->handler );
1689     mod_gzip_printf( "%s: *IN: r->content_encoding    =[%s]\n", cn, r->content_encoding );
1690     mod_gzip_printf( "%s: *IN: r->content_language    =[%s]\n", cn, r->content_language );
1691     mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn);
1692     mod_gzip_printf( "%s: *IN: r->parsed_uri.scheme   =[%s]\n", cn, r->parsed_uri.scheme );
1693     mod_gzip_printf( "%s: *IN: r->parsed_uri.hostinfo =[%s]\n", cn, r->parsed_uri.hostinfo );
1694     mod_gzip_printf( "%s: *IN: r->parsed_uri.user     =[%s]\n", cn, r->parsed_uri.user );
1695     mod_gzip_printf( "%s: *IN: r->parsed_uri.password =[%s]\n", cn, r->parsed_uri.password );
1696     mod_gzip_printf( "%s: *IN: r->parsed_uri.hostname =[%s]\n", cn, r->parsed_uri.hostname );
1697     mod_gzip_printf( "%s: *IN: r->parsed_uri.port_str =[%s]\n", cn, r->parsed_uri.port_str );
1698     mod_gzip_printf( "%s: *IN: r->parsed_uri.port     =%u\n",   cn, r->parsed_uri.port );
1699     mod_gzip_printf( "%s: *IN: r->parsed_uri.path     =[%s]\n", cn, r->parsed_uri.path );
1700     mod_gzip_printf( "%s: *IN: r->parsed_uri.query    =[%s]\n", cn, r->parsed_uri.query );
1701     mod_gzip_printf( "%s: *IN: r->parsed_uri.fragment =[%s]\n", cn, r->parsed_uri.fragment );
1702     mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn);
1703
1704     #endif /* MOD_GZIP_DEBUG1 */
1705
1706     /*
1707      * Call the real transaction handler....
1708      */
1709
1710     #ifdef MOD_GZIP_DEBUG1
1711     mod_gzip_printf( "%s: Call mod_gzip_request_handler()...\n", cn );
1712     #endif
1713
1714     rc = mod_gzip_request_handler( (request_rec *) r );
1715
1716     #ifdef MOD_GZIP_DEBUG1
1717     mod_gzip_printf( "%s: Back mod_gzip_request_handler()... rc=%d\n",cn,rc);
1718     #endif
1719
1720     if ( r->server->loglevel == APLOG_DEBUG )
1721       {
1722        /*
1723         * If LogLevel is 'debug' then show the final return code
1724         * value in the log(s)...
1725         */
1726
1727        if ( rc == OK )
1728          {
1729           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1730           "%s: Exit: return( rc = %d = OK )", cn, rc );
1731          }
1732        else if ( rc == DECLINED )
1733          {
1734           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1735           "%s: Exit: return( rc = %d = DECLINED )", cn, rc );
1736          }
1737        else /* It's probably an HTTP error code... */
1738          {
1739           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1740           "%s: Exit: return( rc = %d = HTTP ERROR CODE? )", cn, rc );
1741          }
1742
1743       }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */
1744
1745     #ifdef MOD_GZIP_DEBUG1
1746
1747     if ( rc == OK )
1748       {
1749        mod_gzip_printf( "%s: rc = %d OK\n", cn, (int) rc);
1750       }
1751     else if ( rc == DECLINED )
1752       {
1753        mod_gzip_printf( "%s: rc = %d DECLINED\n", cn, (int) rc );
1754       }
1755     else /* It's probably an HTTP error code... */
1756       {
1757        mod_gzip_printf( "%s: rc = %d ( HTTP ERROR CODE? )\n", cn, (int) rc );
1758       }
1759
1760     mod_gzip_printf( "%s: Exit > return( rc = %d ) >\n",cn,rc );
1761
1762     #endif /* MOD_GZIP_DEBUG1 */
1763
1764     return rc;
1765
1766 }/* End of mod_gzip_handler() */
1767
1768 typedef struct {
1769     table *action_types;       /* Added with Action... */
1770     char *scripted[METHODS];   /* Added with Script... */
1771     array_header *xmethods;    /* Added with Script -- extension methods */
1772 } action_dir_config2;
1773
1774 extern module action_module;
1775
1776 int mod_gzip_request_handler( request_rec *r )
1777 {
1778     /*
1779      * Process a new request...
1780      */
1781
1782     int             rc                = 0;
1783     int             loglevel          = 0;
1784     int             do_command        = 0;
1785     int             process           = 0;
1786     int             action_flag       = 0;
1787     long            compression_ratio = 0;
1788
1789     const char*     has_encoding      = 0;
1790     const char*     accept_encoding   = 0;
1791
1792     #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
1793     char tmp[4096]; /* Scratch buffer for HTML output */
1794     #endif
1795
1796     #ifdef MOD_GZIP_DEBUG1
1797     char cn[]="mod_gzip_request_handler()";
1798     const char* the_type = 0;
1799     #endif
1800
1801     #ifdef MOD_GZIP_USES_APACHE_LOGS
1802     char log_info[40]; /* Scratch buffer */
1803     #endif
1804
1805     void *modconf = r->server->module_config;
1806
1807     mod_gzip_conf *conf = 0; /* Pointer to our own config data */
1808
1809     /*
1810      * Start...
1811      *
1812      * Establish a local pointer to module configuration data...
1813      */
1814
1815     conf = (mod_gzip_conf *)
1816     ap_get_module_config(modconf, &gzip_module);
1817
1818     /*
1819      * Get the current Apache log level...
1820      */
1821
1822     loglevel = r->server->loglevel;
1823
1824     #ifdef MOD_GZIP_USES_APACHE_LOGS
1825
1826     /*
1827      * If the MOD_GZIP_USES_APACHE_LOGS compile-time switch is ON
1828      * then the Apache log module interface code is being included.
1829      *
1830      * Reset the module 'notes' that are used by mod_gzip to
1831      * add entries to Apache standard log files...
1832      *
1833      * See the note farther below about how to add mod_gzip
1834      * compression information to any standard Apache log file.
1835      */
1836
1837     /* Default for 'mod_result' message is 'DECLINED:NOP'... */
1838
1839     ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NOP"));
1840
1841     /* Default for in/out size is 'n/a'... 'Not available'...*/
1842
1843     sprintf( log_info, "n/a" );
1844
1845     ap_table_setn( r->notes,"mod_gzip_input_size",ap_pstrdup(r->pool,log_info));
1846     ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info));
1847
1848     /* Default for compression ratio is '0' percent... */
1849
1850     ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,"0"));
1851
1852     #endif /* MOD_GZIP_USES_APACHE_LOGS */
1853
1854     #ifdef MOD_GZIP_DEBUG1
1855
1856     /* Request info... */
1857
1858     mod_gzip_printf( "%s: Entry...\n",cn);
1859     mod_gzip_printf( "%s: mod_gzip_version    =[%s]\n", cn, mod_gzip_version);
1860     mod_gzip_printf( "%s: conf->req           = %d\n",  cn, (int) conf->req);
1861     mod_gzip_printf( "%s: conf->cache.root    =[%s]\n", cn, conf->cache.root);
1862     mod_gzip_printf( "%s: *IN: r->uri         =[%s]\n", cn, r->uri);
1863     mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri);
1864     mod_gzip_printf( "%s: *IN: r->filename    =[%s]\n", cn, r->filename);
1865     mod_gzip_printf( "%s: *IN: r->handler     =[%s]\n", cn, r->handler);
1866     mod_gzip_printf( "%s: r->finfo.st_size    = %ld\n", cn, (long) r->finfo.st_size);
1867
1868     /* NOTE: The r->headers_out content type value has not normally */
1869     /* been set at this point but grab a pointer to it and show */
1870     /* it just to make sure. The r->content_type value, however, */
1871     /* normally WILL have some value at this point. */
1872
1873     the_type = ap_table_get( r->headers_out,"Content-type" );
1874
1875     mod_gzip_printf( "%s: r->headers_out, Content-type = [%s]\n",cn,the_type);
1876     mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type );
1877
1878     /* The r->handler ASCII name string is the all-important */
1879     /* jump table name for the module that will handle the */
1880     /* transaction. If this is a CGI jump then it will normally */
1881     /* have a value of 'cgi-script' at this point. */
1882
1883     mod_gzip_printf( "%s: r->handler      = [%s]\n",cn,r->handler );
1884
1885     /* Server info... */
1886
1887     mod_gzip_printf( "%s: r->server->path            = [%s]\n",cn,r->server->path );
1888     mod_gzip_printf( "%s: r->server->pathlen         = %d\n",  cn,r->server->pathlen);
1889     mod_gzip_printf( "%s: r->server->server_admin    = [%s]\n",cn,r->server->server_admin);
1890     mod_gzip_printf( "%s: r->server->server_hostname = [%s]\n",cn,r->server->server_hostname);
1891     mod_gzip_printf( "%s: r->server->error_fname     = [%s]\n",cn,r->server->error_fname);
1892
1893     /* Environment info... */
1894
1895     mod_gzip_printf( "%s: DOCUMENT_ROOT = [%s]\n",cn,ap_document_root(r));
1896
1897     #endif /* MOD_GZIP_DEBUG1 */
1898
1899     /*
1900      * Check the 'master' request control switch and see if mod_gzip
1901      * is ON (ENABLED) or OFF (DISABLED)...
1902      */
1903
1904     if ( conf->req != 1 )
1905       {
1906        /* mod_gzip is currently DISABLED so DECLINE the processing... */
1907
1908        #ifdef MOD_GZIP_DEBUG1
1909        mod_gzip_printf( "%s: conf->req = %d = OFF\n",cn,conf->req);
1910        mod_gzip_printf( "%s: The module is currently DISABLED\n",cn);
1911        mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
1912        #endif
1913
1914        #ifdef MOD_GZIP_USES_APACHE_LOGS
1915
1916        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
1917
1918        ap_table_setn(
1919        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:DISABLED"));
1920
1921        #endif /* MOD_GZIP_USES_APACHE_LOGS */
1922
1923        return DECLINED;
1924
1925       }/* End 'if( conf->req != 1 )' */
1926
1927     /*
1928      * Check for a default HTTP support level ( if used ).
1929      * If no value for conf->min_http was supplied in the
1930      * httpd.conf file then the default value will be 0
1931      * so that ALL levels of HTTP will be OK...
1932      */
1933
1934     #ifdef MOD_GZIP_DEBUG1
1935     mod_gzip_printf( "%s: *HTTP CHECK:conf->min_http = %d\n",   cn, conf->min_http );
1936     mod_gzip_printf( "%s: *HTTP CHECK:r->proto_num   = %d\n",   cn, r->proto_num );
1937     mod_gzip_printf( "%s: *HTTP CHECK:r->protocol    = [%s]\n", cn, r->protocol );
1938     #endif
1939
1940     if ( r->proto_num < conf->min_http )
1941       {
1942        /* The HTTPx/x version number does not meet the minimum requirement */
1943
1944        #ifdef MOD_GZIP_DEBUG1
1945        mod_gzip_printf( "%s: Request HTTP level does not meet minimum requirement\n",cn);
1946        mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
1947        #endif
1948
1949        #ifdef MOD_GZIP_USES_APACHE_LOGS
1950
1951        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
1952
1953        sprintf( log_info, "DECLINED:%s:%d", r->protocol, r->proto_num );
1954
1955        ap_table_setn(
1956        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,log_info));
1957
1958        #endif /* MOD_GZIP_USES_APACHE_LOGS */
1959
1960        return DECLINED;
1961
1962       }/* End 'if ( r->proto_num < conf->min_http )' */
1963
1964     else /* Protocol level is OK... */
1965       {
1966        #ifdef MOD_GZIP_DEBUG1
1967        mod_gzip_printf( "%s: Request HTTP level is OK...\n",cn);
1968        #endif
1969       }
1970
1971     #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
1972
1973     /*
1974      * Internal command pickups...
1975      *
1976      * If this module was compiled with the
1977      * MOD_GZIP_ALLOWS_INTERNAL_COMMANDS switch ON
1978      * then the first thing we do is check for valid
1979      * URL-based internal commands.
1980      *
1981      * Rather than check for all possible commands each time
1982      * just do 1 quick check for the command prefix and set
1983      * a flag to indicate if there is any need to enter the
1984      * actual command handler...
1985      */
1986
1987     if ( strstr( r->filename, "mod_gzip_command_" ) )
1988       {
1989        do_command = 1; /* Process the command */
1990       }
1991
1992     #ifdef MOD_GZIP_DEBUG1
1993     mod_gzip_printf( "%s: do_command = %d\n",cn,do_command);
1994     #endif
1995
1996     if ( do_command )
1997       {
1998        /* Determine the exact command and respond... */
1999
2000        if ( strstr( r->filename, "mod_gzip_command_version" ) )
2001          {
2002           /*------------------------------------------------------*/
2003           /* Command: 'mod_gzip_command_version'                  */
2004           /* Purpose: Return the current mod_gzip version number. */
2005           /* Comment: Allows anyone to query any Apache Server at */
2006           /*          any URL with a browser and discover if      */
2007           /*          mod_gzip is in use at that site.            */
2008           /*------------------------------------------------------*/
2009
2010           #ifdef MOD_GZIP_DEBUG1
2011           mod_gzip_printf( "%s: 'mod_gzip_command_version' seen...\n",cn);
2012           #endif
2013
2014           /* NOTE: mod_gzip command results are not sent compressed */
2015
2016           /* Build the response buffer... */
2017
2018           sprintf( tmp,
2019           "<html><body><pre>"
2020           "mod_gzip is available on this Server\r\n"
2021           "mod_gzip version = %s\r\n"
2022           "</pre></body></html>",
2023           mod_gzip_version
2024           );
2025
2026           /* For all mod_gzip commands that are intercepted we */
2027           /* simply return OK. */
2028
2029           return( mod_gzip_send_html_command_response( r, tmp, "text/html" ));
2030          }
2031        else if ( strstr( r->filename, "mod_gzip_command_showstats" ) )
2032          {
2033           /*------------------------------------------------------*/
2034           /* Command: 'mod_gzip_command_showstats'                */
2035           /* Purpose: Display compression statistics.             */
2036           /* Comment: Allows anyone to query any Apache Server at */
2037           /*          any URL with a browser and get a report     */
2038           /*          about compression results.                  */
2039           /*------------------------------------------------------*/
2040
2041           #ifdef MOD_GZIP_DEBUG1
2042           mod_gzip_printf( "%s: 'mod_gzip_command_showstats' seen...\n",cn);
2043           #endif
2044
2045           /* NOTE: mod_gzip command results are not sent compressed */
2046
2047           /* Build the response buffer... */
2048
2049           /* NOTE: This command has been temporarily removed */
2050
2051           sprintf( tmp,
2052           "<html><body><pre>"
2053           "mod_gzip is available on this Server\r\n"
2054           "mod_gzip version = %s\r\n\r\n"
2055           "The 'mod_gzip_command_showstats' command has been temporarily removed.\r\n"
2056           "</pre></body></html>",
2057           mod_gzip_version
2058           );
2059
2060           /* For all mod_gzip commands that are intercepted we */
2061           /* simply return OK. */
2062
2063           return( mod_gzip_send_html_command_response( r, tmp, "text/html" ));
2064          }
2065        else if ( strstr( r->filename, "mod_gzip_command_resetstats" ) )
2066          {
2067           /*------------------------------------------------------*/
2068           /* Command: 'mod_gzip_command_resetstats'               */
2069           /* Purpose: Resets the compression statistics.          */
2070           /* Comment: Allows the compression statistics to be     */
2071           /*          reset using only a browser.                 */
2072           /*------------------------------------------------------*/
2073
2074           #ifdef MOD_GZIP_DEBUG1
2075           mod_gzip_printf( "%s: 'mod_gzip_command_resetstats' seen...\n",cn);
2076           #endif
2077
2078           /* NOTE: mod_gzip command results are not sent compressed */
2079
2080           /* Build the response buffer... */
2081
2082           /* NOTE: This command has been temporarily removed */
2083
2084           sprintf( tmp,
2085           "<html><body><pre>"
2086           "mod_gzip is available on this Server\r\n"
2087           "mod_gzip version = %s\r\n\r\n"
2088           "The 'mod_gzip_command_resetstats' command has been temporarily removed.\r\n"
2089           "</pre></body></html>",
2090           mod_gzip_version
2091           );
2092
2093           /* For all mod_gzip commands that are intercepted we */
2094           /* simply return OK. */
2095
2096           return( mod_gzip_send_html_command_response( r, tmp, "text/html" ));
2097          }
2098        else /* Unrecognized command... */
2099          {
2100           /* The command prefix was 'seen' and the 'do_command' flag */
2101           /* was TRUE but either the command was mis-typed or there */
2102           /* is no such command available. This is not an ERROR and */
2103           /* we should simply fall-through and assume that the URL */
2104           /* is valid for the local Server. A 404 will be returned */
2105           /* if there is no object that actually matches the name. */
2106          }
2107
2108       }/* End 'if( do_command )' */
2109
2110     #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */
2111
2112     /*
2113      * Sanity checks...
2114      */
2115
2116     /*
2117      * If the requested file already contains the .gz designation
2118      * then we must assume it is pre-compressed and let the
2119      * default logic take care of sending the file. This module
2120      * doesn't really care if a .gz file was actually requested
2121      * or if it is the source target because of a successful
2122      * Server side 'negotiation'. Doesn't matter.
2123      */
2124
2125     if ( ( r->filename ) && ( strstr( r->filename, ".gz" ) ) )
2126       {
2127        #ifdef MOD_GZIP_DEBUG1
2128        mod_gzip_printf( "%s: r->filename already contains '.gz'.\n",cn);
2129        mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn);
2130        mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2131        #endif
2132
2133        #ifdef MOD_GZIP_USES_APACHE_LOGS
2134
2135        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2136
2137        ap_table_setn(
2138        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS.GZ"));
2139
2140        if ( r->server->loglevel == APLOG_DEBUG )
2141          {
2142           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2143           "mod_gzip: Files with .gz file extension are skipped.");
2144          }
2145
2146        #endif /* MOD_GZIP_USES_APACHE_LOGS */
2147
2148        return DECLINED;
2149       }
2150     else /* r->filename doesn not contain '.gz' designator... */
2151       {
2152        #ifdef MOD_GZIP_DEBUG1
2153        mod_gzip_printf( "%s: r->filename does NOT contain '.gz'.\n",cn);
2154        mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn);
2155        #endif
2156       }
2157
2158     /*
2159      * For now just block all attempts to compress 'image/*' MIME
2160      * type even if user is trying to do so. Too many issues with
2161      * broken browsers when it comes to decoding compressed images.
2162      *
2163      * WARNING: Don't submit r->content_type to strstr() it if is
2164      * NULL or the API call will GP fault. Go figure.
2165      */
2166
2167     if ( ( r->content_type ) && ( strstr( r->content_type, "image/" ) ) )
2168       {
2169        #ifdef MOD_GZIP_DEBUG1
2170        mod_gzip_printf( "%s: r->content_type contains 'image/'.\n",cn);
2171        mod_gzip_printf( "%s: Image compression is temporaily BLOCKED\n",cn);
2172        mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2173        #endif
2174
2175        #ifdef MOD_GZIP_USES_APACHE_LOGS
2176
2177        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2178
2179        ap_table_setn(
2180        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:IMAGE"));
2181
2182        if ( r->server->loglevel == APLOG_DEBUG )
2183          {
2184           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2185           "mod_gzip: Graphics image compression option is temporarily disabled.");
2186          }
2187
2188        #endif /* MOD_GZIP_USES_APACHE_LOGS */
2189
2190        return DECLINED;
2191       }
2192
2193     /*
2194      * Safeguard against situations where some other module or
2195      * filter has gotten to this request BEFORE us and has already
2196      * added the 'Content-encoding: gzip' field to the output header.
2197      * It must be assumed that whoever added the header prior to this
2198      * point also took care of the compression itself.
2199      *
2200      * If the output header already contains "Content-encoding: gzip"
2201      * then simply DECLINE the processing and let the default chain
2202      * take care of it...
2203      */
2204
2205     has_encoding = ap_table_get( r->headers_out, "Content-encoding" );
2206
2207     #ifdef MOD_GZIP_DEBUG1
2208     mod_gzip_printf( "%s: has_encoding = [%s]\n",cn,has_encoding);
2209     #endif
2210
2211     if ( has_encoding ) /* 'Content-encoding' field is present... */
2212       {
2213        #ifdef MOD_GZIP_DEBUG1
2214        mod_gzip_printf( "%s: Output header already contains 'Content-encoding:' field\n",cn);
2215        mod_gzip_printf( "%s: Checking for 'gzip' designator...\n",cn);
2216        #endif
2217
2218        if ( strstr( has_encoding, "gzip" ) ||
2219                         strstr( has_encoding, "deflate" ) )
2220          {
2221           #ifdef MOD_GZIP_DEBUG1
2222           mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' or 'deflate' designator...\n",cn);
2223           mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn);
2224           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2225           #endif
2226
2227           #ifdef MOD_GZIP_USES_APACHE_LOGS
2228
2229           /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2230
2231           ap_table_setn(
2232           r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS_CE:GZIP"));
2233
2234           if ( r->server->loglevel == APLOG_DEBUG )
2235             {
2236              ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2237              "mod_gzip: Header already has 'Content-encoding: gzip'");
2238             }
2239
2240           #endif /* MOD_GZIP_USES_APACHE_LOGS */
2241
2242           return DECLINED;
2243          }
2244        else /* 'gzip' designator not found... */
2245          {
2246           #ifdef MOD_GZIP_DEBUG1
2247           mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' or 'deflate' designator...\n",cn);
2248           mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn);
2249           #endif
2250          }
2251
2252       }/* End 'if( has_encoding )' */
2253
2254     else /* Output header does NOT contain 'Content-encoding:' field... */
2255       {
2256        #ifdef MOD_GZIP_DEBUG1
2257        mod_gzip_printf( "%s: Output header does NOT contain 'Content-encoding:' field.\n",cn);
2258        mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn);
2259        #endif
2260       }
2261
2262     /*
2263      * Basic sanity checks completed and we are still here.
2264      *
2265      * Now we must determine if the User-Agent is capable of receiving
2266      * compressed data...
2267      *
2268      * There are, currently, many reasons why it is actually never
2269      * enough to simply trust the 'Accept-encoding: foo, bar'
2270      * request header field when it comes to actually determining
2271      * if a User-agent is capable of receiving content or transfer
2272      * encodings.
2273      *
2274      * Some of them are...
2275      *
2276      * 1. There have been several major releases of popular browsers
2277      *    that actually send the 'Accept-encoding:' request field but
2278      *    are, in reality, unable to perform the specified decoding(s).
2279      *    In some cases the result will be that the browser screen
2280      *    simply fills with garbage ( the binary compressed data
2281      *    itself ) but in some cases the browser will actually crash.
2282      *
2283      * 2. There have been other major releases of browsers that are
2284      *    specifying multiple 'Accept-encoding' techniques with no
2285      *    'Q' values whatsoever and they are actually only able to
2286      *    handle one of the multiple types specified. There is no
2287      *    way to know which type is 'real' other than by using other
2288      *    empiricial data extracted from the 'User-agent' field
2289      *    or other inbound request headers.
2290      *
2291      * 3. Same as 1 and 2 but relates to SIZE. Some major browser
2292      *    releases can handle the encoded content but only up to
2293      *    a certain 'SIZE' limit and then they will fail. There
2294      *    is no way for a User-agent to specify this limitation
2295      *    via HTTP so empirical header analysis is the only option.
2296      *
2297      * 4. The HTTP specification has no way for a Server to distinguish
2298      *    from the 'Accept encoding: foo, bar' input request field
2299      *    whether the user agent can only support the specified encodings
2300      *    as either a Content-encoding OR a Transfer-encoding, but
2301      *    not both. There is also no way of knowing if the user
2302      *    agent is able to handle any of the specified types being
2303      *    used as both a Content-encoding AND a Transfer-encoding
2304      *    for the same message body. All the Server can do is assume
2305      *    that the encodings are valid in any/all combinations
2306      *    and that the user agent can 'Accept' them as either
2307      *    'Content' encodings and/or 'Transfer' encodings under
2308      *    any and all circumstances. This blanket assumption will
2309      *    cause problems with some release versions of some browsers
2310      *    because the assumed 'do all' capability is simply not a
2311      *    reality.
2312      *
2313      * 5. Many browsers ( such as Netscape 4.75 for UNIX ) are unable
2314      *    to handle Content-encoding only for specific kinds of HTML
2315      *    transactions such as Style Sheets even though the browser
2316      *    says it is HTTP 1.1 compliant and is suppying the standard
2317      *    'Accept-encoding: gzip' field. According to the IETF
2318      *    specifications any user-agent that says it can accept
2319      *    encodings should be able to do so for all types of HTML
2320      *    transactions but this is simply not the current reality.
2321      *    Some will, some won't... even if they say they can.
2322      *
2323      * This version of this module takes the 'What, me worry' approach
2324      * and simply uses the accepted method of relying solely on the
2325      * 'Accept-encoding: foo, bar' field and also assumes this means
2326      * that the User-agent can accept the specified encodings as
2327      * either Content-encodings (CE) and/or Transfer-encodings (TE)
2328      * under all circumstances and in any combinations that the
2329      * Server decides to send.
2330      *
2331      * It also assumes that the caller has no preference and should
2332      * be able to decode any of the specified encodings equally well.
2333      * Most user-agents sending the 'Accept-encoding:' field do NOT
2334      * supply any 'Q' values to help with determining preferences.
2335      */
2336
2337     accept_encoding = ap_table_get( r->headers_in, "Accept-Encoding" );
2338
2339     #ifdef MOD_GZIP_DEBUG1
2340
2341     if ( accept_encoding )
2342       {
2343        mod_gzip_printf( "%s: 'Accept Encoding:' field seen.\n",cn);
2344       }
2345     else
2346       {
2347        mod_gzip_printf( "%s: 'Accept Encoding' field NOT seen.\n",cn);
2348       }
2349
2350     #endif /* MOD_GZIP_DEBUG1 */
2351
2352     /* If Accept-Encoding is applicable to this request...*/
2353
2354     if ( accept_encoding )
2355       {
2356        /* ...and if it has the right 'gzip' indicator... */
2357            /* We record the compression format in a request note, so we
2358         * can get it again later, and so it can potentially be logged.
2359         */
2360        if ( strstr( accept_encoding, "gzip" ) )
2361          {
2362           process = 1; /* ...set the 'process' flag TRUE */
2363           ap_table_setn( r->notes,"mod_gzip_compression_format",
2364                                                  ap_pstrdup(r->pool,"gzip"));
2365
2366          }
2367        else if ( strstr( accept_encoding, "deflate" ) )
2368          {
2369           process = 1; /* ...set the 'process' flag TRUE */
2370           ap_table_setn( r->notes,"mod_gzip_compression_format",
2371                                                  ap_pstrdup(r->pool,"deflate"));
2372          }
2373
2374       }/* End 'if( accept_encoding )' */
2375
2376     #ifdef MOD_GZIP_DEBUG1
2377     mod_gzip_printf( "%s: 'process' flag = %d\n",cn,process);
2378     #endif
2379
2380     if ( !process ) /* Request does not meet criteria for processing... */
2381       {
2382        #ifdef MOD_GZIP_DEBUG1
2383        mod_gzip_printf( "%s: No 'gzip' capability specified by user-agent.\n",cn);
2384        mod_gzip_printf( "%s: 'process' flag is FALSE.\n",cn);
2385        mod_gzip_printf( "%s: This request will not be processed.\n",cn);
2386        mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2387        #endif
2388
2389        #ifdef MOD_GZIP_USES_APACHE_LOGS
2390
2391        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2392
2393        ap_table_setn(
2394        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_GZIP"));
2395
2396        if ( r->server->loglevel == APLOG_DEBUG )
2397          {
2398           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2399           "mod_gzip: The inbound request header does not have 'Accept-encoding: gzip'");
2400          }
2401
2402        #endif /* MOD_GZIP_USES_APACHE_LOGS */
2403
2404        return DECLINED;
2405       }
2406     else /* 'gzip' designator was seen in 'Accept-Encoding:' field */
2407       {
2408        #ifdef MOD_GZIP_DEBUG1
2409        mod_gzip_printf( "%s: 'gzip' or 'deflate' capability specified by user-agent.\n",cn);
2410        mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn);
2411        #endif
2412       }
2413
2414     /*
2415      * Handle the transaction...
2416      *
2417      * At this point the inbound header analysis has been completed
2418      * and we are assuming that the user agent is capable of accepting
2419      * the content encodings we can provide.
2420      *
2421      * We must now 'do the right thing' based on what type of
2422      * request it actually is...
2423      */
2424
2425      #ifdef MOD_GZIP_DEBUG1
2426      mod_gzip_printf( "%s: r->handler      = [%s]\n",cn,r->handler);
2427      mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type);
2428      mod_gzip_printf( "%s: Call mod_gzip_get_action_flag()...\n",cn);
2429      #endif
2430
2431      action_flag =
2432      mod_gzip_get_action_flag(
2433      (request_rec   *) r,
2434      (mod_gzip_conf *) conf
2435      );
2436
2437      #ifdef MOD_GZIP_DEBUG1
2438      mod_gzip_printf( "%s: Back mod_gzip_get_action_flag()...\n",cn);
2439      mod_gzip_printf( "%s: action_flag           = %d\n",cn,action_flag);
2440      mod_gzip_printf( "%s: conf->do_static_files = %d\n",cn,(int)conf->do_static_files);
2441      mod_gzip_printf( "%s: conf->do_cgi          = %d\n",cn,(int)conf->do_cgi);
2442      #endif
2443
2444      /*
2445       * Perform the right 'action' for this transaction...
2446       */
2447
2448      if ( action_flag == MOD_GZIP_IMAP_DECLINED1 )
2449        {
2450         /*
2451          * If the transaction is to be DECLINED then just set the final
2452          * return code to DECLINED, fall through, and return.
2453          */
2454
2455         #ifdef MOD_GZIP_DEBUG1
2456         mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DECLINED1\n",cn);
2457         #endif
2458
2459         if ( r->server->loglevel == APLOG_DEBUG )
2460           {
2461            ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2462            "mod_gzip: action_flag = MOD_GZIP_IMAP_DECLINED1 ");
2463           }
2464
2465         rc = DECLINED;
2466        }
2467      else if ( action_flag == MOD_GZIP_IMAP_DYNAMIC1 )
2468        {
2469         #ifdef MOD_GZIP_DEBUG1
2470         mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DYNAMIC1\n",cn);
2471         #endif
2472
2473         if ( r->server->loglevel == APLOG_DEBUG )
2474           {
2475            ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2476            "mod_gzip: action_flag = MOD_GZIP_IMAP_DYNAMIC1 ");
2477           }
2478
2479         /*
2480          * Check the flag that can control whether or not the
2481          * CGI dynamic output handler is ever called...
2482          */
2483
2484         if ( conf->do_cgi != 1 ) /* CGI handler is OFF for now... */
2485           {
2486            if ( r->server->loglevel == APLOG_DEBUG )
2487              {
2488               ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2489               "mod_gzip: Calls to CGI handler currently DISABLED ");
2490              }
2491
2492            #ifdef MOD_GZIP_USES_APACHE_LOGS
2493            /* Update the result string for Apache log(s)... */
2494            ap_table_setn(
2495            r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:CGI_OFF"));
2496            #endif
2497
2498            rc = DECLINED; /* Just set final return code and fall through */
2499
2500           }/* End 'if( conf->do_cgi == 0 )' */
2501
2502         else /* It's OK to call the handler... */
2503           {
2504            if ( r->server->loglevel == APLOG_DEBUG )
2505              {
2506               ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2507               "mod_gzip: Calling cgi_handler for r->uri=[%s]",r->uri);
2508              }
2509
2510            /* Take care of some business BEFORE calling the */
2511            /* dynamic handler... */
2512
2513            mod_gzip_prepare_for_dynamic_call( r );
2514
2515            /* PHP NOTE */
2516            /* r->path_info must be set before ap_add_cgi_vars() */
2517            /* is called from within the upcoming hander or we */
2518            /* won't get PATH_INFO or PATH_TRANSLATED environment */
2519            /* variables set and PHP.EXE will return 'No input file' */
2520            /* error message since it depends on both of these being */
2521            /* set. r->path_info must be set to r->uri */
2522
2523            #ifdef MOD_GZIP_DEBUG1
2524            mod_gzip_printf( "%s: 1 r->uri       = [%s]\n", cn, r->uri );
2525            mod_gzip_printf( "%s: 1 r->path_info = [%s]\n", cn, r->path_info );
2526            mod_gzip_printf( "%s: Setting r->path_info to r->uri for CGI...\n", cn );
2527            #endif
2528
2529            r->path_info = r->uri;
2530
2531            #ifdef MOD_GZIP_DEBUG1
2532            mod_gzip_printf( "%s: 2 r->uri       = [%s]\n", cn, r->uri );
2533            mod_gzip_printf( "%s: 2 r->path_info = [%s]\n", cn, r->path_info );
2534            #endif
2535
2536            /* Call the actual handler... */
2537
2538            #ifdef MOD_GZIP_DEBUG1
2539            mod_gzip_printf( "%s: Call mod_gzip_cgi_handler()...\n",cn);
2540            #endif
2541
2542            rc = mod_gzip_cgi_handler( (request_rec *) r );
2543
2544            #ifdef MOD_GZIP_DEBUG1
2545            mod_gzip_printf( "%s: Back mod_gzip_cgi_handler()... rc=%d\n",cn,rc);
2546            #endif
2547
2548           }/* End 'else' - OK to call handler */
2549        }
2550      else if ( action_flag == MOD_GZIP_IMAP_STATIC1 )
2551        {
2552         #ifdef MOD_GZIP_DEBUG1
2553         mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_STATIC1\n",cn);
2554         #endif
2555
2556         if ( r->server->loglevel == APLOG_DEBUG )
2557           {
2558            ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2559            "mod_gzip: action_flag = MOD_GZIP_IMAP_STATIC1 ");
2560           }
2561
2562         /*
2563          * Check the flag that can control whether or not the
2564          * static handler is ever called...
2565          */
2566
2567         if ( conf->do_static_files != 1 ) /* Static handler is OFF for now... */
2568           {
2569            if ( r->server->loglevel == APLOG_DEBUG )
2570              {
2571               ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2572               "mod_gzip: Calls to static handler currently DISABLED ");
2573              }
2574
2575            #ifdef MOD_GZIP_USES_APACHE_LOGS
2576            /* Update the result string for Apache log(s)... */
2577            ap_table_setn(
2578            r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:STATIC_OFF"));
2579            #endif
2580
2581            rc = DECLINED; /* Just set final return code and fall through */
2582
2583           }/* End 'if( conf->do_static == 0 )' */
2584
2585         else /* It's OK to call the handler... */
2586           {
2587            if ( r->server->loglevel == APLOG_DEBUG )
2588              {
2589               ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2590               "mod_gzip: Calling static_handler for r->uri=[%s]",r->uri);
2591              }
2592
2593            #ifdef MOD_GZIP_DEBUG1
2594            mod_gzip_printf( "%s: Call mod_gzip_static_file_handler()...\n",cn);
2595            #endif
2596
2597            rc = mod_gzip_static_file_handler( (request_rec *) r );
2598
2599            #ifdef MOD_GZIP_DEBUG1
2600            mod_gzip_printf( "%s: Back mod_gzip_static_file_handler()... rc=%d\n",cn,rc);
2601            #endif
2602
2603           }/* End 'else' - OK to call the handler */
2604        }
2605      else /* Safety catch... No pickup for the 'action' flag... */
2606        {
2607         if ( r->server->loglevel == APLOG_DEBUG )
2608           {
2609            ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2610            "mod_gzip: action_flag = MOD_GZIP_IMAP_????? Unknown value");
2611           }
2612
2613         if ( r->server->loglevel == APLOG_DEBUG )
2614           {
2615            ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2616            "mod_gzip: No pickup for specified 'action' flag.");
2617           }
2618
2619         #ifdef MOD_GZIP_DEBUG1
2620         mod_gzip_printf( "%s: action_flag = MOD_GZIP_??? Unknown value\n",cn);
2621         #endif
2622
2623         rc = DECLINED;
2624        }
2625
2626      /*
2627       * Record results to logs, if applicable, and return...
2628       *
2629       * The 'r->notes' values that can be used to disply result
2630       * information in the standard Apache log files should have
2631       * already been updated by the handler that was actually
2632       * used to process the transaction.
2633       */
2634
2635      #ifdef MOD_GZIP_DEBUG1
2636
2637      if ( rc == OK )
2638        {
2639         mod_gzip_printf( "%s: Exit > return( rc=%d OK ) >\n",cn,rc);
2640        }
2641      else if ( rc == DECLINED )
2642        {
2643         mod_gzip_printf( "%s: Exit > return( rc=%d DECLINED ) >\n",cn,rc);
2644        }
2645      else /* HTTP ERROR VALUE... */
2646        {
2647         mod_gzip_printf( "%s: Exit > return( rc=%d HTTP_ERROR ) >\n",cn,rc);
2648        }
2649
2650      #endif /* MOD_GZIP_DEBUG1 */
2651
2652      return rc; /* Could be OK or DECLINED or HTTP_ERROR */
2653
2654 }/* End of mod_gzip_request_handler() */
2655
2656 int mod_gzip_prepare_for_dynamic_call( request_rec *r )
2657 {
2658     int rc;
2659
2660     #ifdef MOD_GZIP_DEBUG1
2661     char cn[]="mod_gzip_prepare_for_dynamic_call()";
2662     #endif
2663
2664     /*
2665      * Start...
2666      */
2667
2668     #ifdef MOD_GZIP_DEBUG1
2669     mod_gzip_printf( "%s: Entry...\n",cn);
2670     #endif
2671
2672     /*
2673      * mod_gzip can run other modules directly...
2674      */
2675
2676     /*
2677      * First run mod_action and see it there's a SCRIPT
2678      * for this mime type...
2679      */
2680
2681     #ifdef MOD_GZIP_DEBUG1
2682     mod_gzip_printf( "%s: 1 ***: r->uri         =[%s]\n", cn, r->uri );
2683     mod_gzip_printf( "%s: 1 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri );
2684     mod_gzip_printf( "%s: 1 ***: r->filename    =[%s]\n", cn, r->filename );
2685     mod_gzip_printf( "%s: 1 ***: r->content_type=[%s]\n", cn, r->content_type );
2686     mod_gzip_printf( "%s: 1 ***: r->handler     =[%s]\n", cn, r->handler );
2687     mod_gzip_printf( "%s: Call mod_gzip_run_mod_action(r)...\n",cn);
2688     #endif
2689
2690     rc = mod_gzip_run_mod_action( (request_rec *) r  );
2691
2692     #ifdef MOD_GZIP_DEBUG1
2693
2694     mod_gzip_printf( "%s: Back mod_gzip_run_mod_action(r)...\n",cn);
2695
2696     if ( rc == OK )
2697       {
2698        mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc );
2699       }
2700     else if ( rc == DECLINED )
2701       {
2702        mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc );
2703       }
2704     else if ( rc == DONE ) /* -2 means 'totally done' */
2705       {
2706        mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc );
2707       }
2708     else /* Probably an HTTP ERROR value... */
2709       {
2710        mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc );
2711       }
2712
2713     mod_gzip_printf( "%s: 2 ***: r->uri         =[%s]\n", cn, r->uri );
2714     mod_gzip_printf( "%s: 2 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri );
2715     mod_gzip_printf( "%s: 2 ***: r->filename    =[%s]\n", cn, r->filename );
2716     mod_gzip_printf( "%s: 2 ***: r->content_type=[%s]\n", cn, r->content_type );
2717     mod_gzip_printf( "%s: 2 ***: r->handler     =[%s]\n", cn, r->handler );
2718
2719     #endif /* MOD_GZIP_DEBUG1 */
2720
2721     /*
2722      * Now run mod_alias and get any aliases converted
2723      * to real pathnames...
2724      */
2725
2726     #ifdef MOD_GZIP_DEBUG1
2727     mod_gzip_printf( "%s: Call mod_gzip_run_mod_alias(r)...\n",cn);
2728     #endif
2729
2730     rc = mod_gzip_run_mod_alias( (request_rec *) r  );
2731
2732     #ifdef MOD_GZIP_DEBUG1
2733     mod_gzip_printf( "%s: Back mod_gzip_run_mod_alias(r)...\n",cn);
2734
2735     if ( rc == OK )
2736       {
2737        mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc );
2738       }
2739     else if ( rc == DECLINED )
2740       {
2741        mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc );
2742       }
2743     else if ( rc == DONE ) /* -2 means 'totally done' */
2744       {
2745        mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc );
2746       }
2747     else /* Probably an HTTP ERROR value... */
2748       {
2749        mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc );
2750       }
2751
2752     mod_gzip_printf( "%s: 3 ***: r->uri         =[%s]\n", cn, r->uri );
2753     mod_gzip_printf( "%s: 3 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri );
2754     mod_gzip_printf( "%s: 3 ***: r->filename    =[%s]\n", cn, r->filename );
2755     mod_gzip_printf( "%s: 3 ***: r->content_type=[%s]\n", cn, r->content_type );
2756     mod_gzip_printf( "%s: 3 ***: r->handler     =[%s]\n", cn, r->handler );
2757
2758     #endif /* MOD_GZIP_DEBUG1 */
2759
2760     return OK;
2761
2762 }/* End of mod_gzip_prepare_for_dynamic_call() */
2763
2764
2765 int mod_gzip_static_file_handler( request_rec *r )
2766 {
2767     int             rc         = 0;
2768     long            input_size = 0;
2769     FILE*           ifh1       = 0;
2770
2771     #ifdef MOD_GZIP_DEBUG1
2772     char cn[]="mod_gzip_static_file_handler()";
2773     #endif
2774
2775     /*
2776      * Start...
2777      */
2778
2779     #ifdef MOD_GZIP_DEBUG1
2780     mod_gzip_printf( "%s: Processing file [%s]\n",cn,r->filename);
2781     mod_gzip_printf( "%s: r->finfo.st_size = %ld\n",
2782                cn, (long) r->finfo.st_size);
2783     #endif
2784
2785     /*
2786      * If there is a valid file size already associated with
2787      * the request then we can assume the core stat() call succeeded
2788      * and that r->filename actually exists. We shouldn't need
2789      * to waste a call to 'fopen()' just to find out for ourselves
2790      * if the file exists.
2791      *
2792      * If the inbound file size was '0' then we need to do some
2793      * verifications of our own before we give up since the
2794      * absence of size might just be a simple bug in the parent code.
2795      */
2796
2797     if ( r->finfo.st_size > 0 )
2798       {
2799        #ifdef MOD_GZIP_DEBUG1
2800        mod_gzip_printf( "%s: Source file length already known...\n",cn);
2801        #endif
2802
2803        input_size = (long) r->finfo.st_size;
2804       }
2805     else /* Do our own checking... */
2806       {
2807        /*
2808         * See if the requested source file exists...
2809         * Be SURE to open the file in BINARY mode...
2810         */
2811
2812        ifh1 = fopen( r->filename, "rb" );
2813
2814        if ( !ifh1 ) /* The file cannot be found or opened... */
2815          {
2816           #ifdef MOD_GZIP_DEBUG1
2817           mod_gzip_printf( "%s: The requested source file was NOT FOUND.\n",cn);
2818           mod_gzip_printf( "%s: Exit > return( HTTP_NOT_FOUND ) >\n",cn);
2819           #endif
2820
2821           #ifdef MOD_GZIP_USES_APACHE_LOGS
2822
2823           /* HTTP ERROR conditions provides a short ':WHYTAG' for logs */
2824
2825           ap_table_setn(
2826           r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HTTP_NOT_FOUND"));
2827
2828           #endif /* MOD_GZIP_USES_APACHE_LOGS */
2829
2830           return HTTP_NOT_FOUND;
2831          }
2832        else /* The file was found and opened OK... */
2833          {
2834           #ifdef MOD_GZIP_DEBUG1
2835           mod_gzip_printf( "%s: The requested source file is now OPEN...\n",cn);
2836           #endif
2837          }
2838
2839        /*
2840         * Move the current file pointer to the end of the file...
2841         */
2842
2843        if ( fseek( ifh1, 0, SEEK_END ) )
2844          {
2845           #ifdef MOD_GZIP_DEBUG1
2846           mod_gzip_printf( "%s: ERROR: fseek() call failed...\n",cn);
2847           #endif
2848
2849           fclose( ifh1 ); /* FILE is still open so CLOSE it... */
2850
2851           /* fseek() failure could be a platform issue so log the event... */
2852
2853           ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
2854           "mod_gzip: fseek() failed for r->filename=[%s]",r->filename );
2855
2856           /* Return DECLINED and let default logic finish the request... */
2857
2858           #ifdef MOD_GZIP_DEBUG1
2859           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2860           #endif
2861
2862           #ifdef MOD_GZIP_USES_APACHE_LOGS
2863
2864           /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2865
2866           ap_table_setn(
2867           r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FSEEK_FAIL"));
2868
2869           #endif /* MOD_GZIP_USES_APACHE_LOGS */
2870
2871           return DECLINED;
2872          }
2873
2874        /*
2875         * Get the current SIZE of the requested file...
2876         */
2877
2878        input_size = (long) ftell( ifh1 );
2879
2880        if ( input_size == -1l )
2881          {
2882           #ifdef MOD_GZIP_DEBUG1
2883           mod_gzip_printf( "%s: ERROR: ftell() call failed...\n",cn);
2884           #endif
2885
2886           fclose( ifh1 ); /* FILE is still open so CLOSE it... */
2887
2888           /* ftell() failure could be a platform issue so log the event... */
2889
2890           ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
2891           "mod_gzip: ftell() failed for r->filename=[%s]", r->filename );
2892
2893           /* Return DECLINED and let default logic finish the request... */
2894
2895           #ifdef MOD_GZIP_DEBUG1
2896           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2897           #endif
2898
2899           #ifdef MOD_GZIP_USES_APACHE_LOGS
2900
2901           /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2902
2903           ap_table_setn(
2904           r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FTELL_FAIL"));
2905
2906           #endif /* MOD_GZIP_USES_APACHE_LOGS */
2907
2908           return DECLINED;
2909          }
2910
2911        /*
2912         * Once we have the length just close the file...
2913         */
2914
2915        if ( fclose( ifh1 ) == EOF )
2916          {
2917           #ifdef MOD_GZIP_DEBUG1
2918           mod_gzip_printf( "%s: ERROR: fclose() following ftell() call failed...\n",cn);
2919           #endif
2920
2921           /* fclose() failure could be a platform issue so log the event... */
2922
2923           ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
2924           "mod_gzip: fclose() failed for r->filename=[%s]",r->filename );
2925
2926           /* Return DECLINED and let default logic finish the request... */
2927
2928           #ifdef MOD_GZIP_DEBUG1
2929           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2930           #endif
2931
2932           #ifdef MOD_GZIP_USES_APACHE_LOGS
2933
2934           /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2935
2936           ap_table_setn(
2937           r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FCLOSE_FAIL"));
2938
2939           #endif /* MOD_GZIP_USES_APACHE_LOGS */
2940
2941           return DECLINED;
2942          }
2943
2944       }/* End 'else' */
2945
2946     /*
2947      * We have the static filename and the length.
2948      * That's pretty much all we need at this point so
2949      * go ahead and encode/transmit the object...
2950      */
2951
2952     #ifdef MOD_GZIP_DEBUG1
2953     mod_gzip_printf( "%s: Call mod_gzip_encode_and_transmit()...\n",cn);
2954     #endif
2955
2956     rc =
2957     mod_gzip_encode_and_transmit(
2958     (request_rec *) r,           /* request_rec */
2959     (char        *) r->filename, /* source ( Filename or Memory buffer ) */
2960     (int          ) 1,           /* 1=Source is a file 0=Memory buffer */
2961     (long         ) input_size,  /* input_size */
2962     (int          ) 0            /* nodecline flag 0=Ok to DECLINE 1=No */
2963     );
2964
2965     #ifdef MOD_GZIP_DEBUG1
2966     mod_gzip_printf( "%s: Back mod_gzip_encode_and_transmit()...\n",cn);
2967     #endif
2968
2969     /*
2970      * The encode/transmit path should have already updated
2971      * any relevant 'r->note' values ( if used ) for the transaction
2972      * to reflect the results of the operation.
2973      *
2974      * Just return the result code and finish the transaction.
2975      */
2976
2977     #ifdef MOD_GZIP_DEBUG1
2978     if ( rc == OK )
2979       {
2980        mod_gzip_printf( "%s: Exit > return( rc = %d OK ) >\n",cn,rc);
2981       }
2982     else if ( rc == DECLINED )
2983       {
2984        mod_gzip_printf( "%s: Exit > return( rc = %d DECLINED ) >\n",cn,rc);
2985       }
2986     else /* HTTP ERROR */
2987       {
2988        mod_gzip_printf( "%s: Exit > return( rc = %d HTTP_ERROR ) >\n",cn,rc);
2989       }
2990     #endif /* MOD_GZIP_DEBUG1 */
2991
2992     return( rc );
2993
2994 }/* End of mod_gzip_static_file_handler() */
2995
2996 int mod_gzip_create_unique_filename(
2997 mod_gzip_conf *mgc,
2998 char *target,
2999 int targetmaxlen
3000 )
3001 {
3002  /*
3003   * Creates a unique work file name.
3004   */
3005
3006  long  process_id = 0;  /* Current Process ID */
3007  long  thread_id  = 0;  /* Current thread  ID */
3008
3009  #ifdef MOD_GZIP_DEBUG1
3010  char cn[]="mod_gzip_create_unique_filename()";
3011  #endif
3012
3013  /* Start... */
3014
3015  #ifdef WIN32
3016  process_id = (long) GetCurrentProcessId();
3017  thread_id  = (long) GetCurrentThreadId();
3018  #else /* !WIN32 */
3019  process_id = (long) getpid();
3020  thread_id  = (long) process_id; /* TODO: Add pthreads call */
3021  #endif /* WIN32 */
3022
3023  #ifdef MOD_GZIP_DEBUG1
3024  mod_gzip_printf( "%s: Entry...\n",cn );
3025  mod_gzip_printf( "%s: target            = %ld\n",cn,(long)target);
3026  mod_gzip_printf( "%s: targetmaxlen      = %ld\n",cn,(long)targetmaxlen);
3027  mod_gzip_printf( "%s: process_id        = %ld\n",cn,(long)process_id );
3028  mod_gzip_printf( "%s: thread_id         = %ld\n",cn,(long)thread_id  );
3029  mod_gzip_printf( "%s: mod_gzip_iusn     = %ld\n",cn,(long)mod_gzip_iusn );
3030  #endif
3031
3032  /*
3033   * Sanity checks...
3034   */
3035
3036  if ( ( !target ) || ( targetmaxlen == 0 ) )
3037    {
3038     #ifdef MOD_GZIP_DEBUG1
3039     mod_gzip_printf( "%s: Invalid target or targetmaxlen value.\n",cn);
3040     mod_gzip_printf( "%s: Exit > return( 1 ) > ERROR >\n",cn );
3041     #endif
3042
3043     return 1;
3044    }
3045
3046  /*
3047   * Use the PROCESS + THREAD ID's and the current IUSN
3048   * ( Instance Unique Sequence Number ) transaction ID to
3049   * create a one-time only unique output workfile name...
3050   */
3051
3052  sprintf(
3053  target,
3054  "%s%s_%ld_%ld_%ld.wrk",
3055  mgc->cache.root,     /* Either ServerRoot or Config specified dir. */
3056  mod_gzip_dirsep,     /* Forward slash for UNIX, backslash for WIN32 */
3057  (long) process_id,   /* Current process ID */
3058  (long) thread_id,    /* Current thread  ID */
3059  (long) mod_gzip_iusn /* Instance Unique Sequence Number */
3060  );
3061
3062  mod_gzip_iusn++; /* Increment Instance Unique Sequence Number */
3063
3064  if ( mod_gzip_iusn > 999999999L ) mod_gzip_iusn = 1; /* Wrap */
3065
3066  #ifdef MOD_GZIP_DEBUG1
3067  mod_gzip_printf( "%s: target = [%s]\n",cn,target);
3068  mod_gzip_printf( "%s: Exit > return( 0 ) >\n",cn );
3069  #endif
3070
3071  return 0;
3072
3073 }/* End of mod_gzip_create_unique_filename() */
3074
3075
3076 #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
3077
3078 int mod_gzip_send_html_command_response(
3079 request_rec *r, /* Request record */
3080 char *tmp,      /* Response to send */
3081 char *ctype     /* Content type string */
3082 )
3083 {
3084  /* Generic command response transmitter... */
3085
3086  int  tmplen=0;
3087  char content_length[20];
3088
3089  #ifdef MOD_GZIP_DEBUG1
3090  char cn[]="mod_gzip_send_html_command_response()";
3091  #endif
3092
3093  /* Start... */
3094
3095  #ifdef MOD_GZIP_DEBUG1
3096  mod_gzip_printf( "%s: Entry...\n",cn);
3097  mod_gzip_printf( "%s: ctype=[%s]\n",cn,ctype);
3098  #endif
3099
3100  /* Add the length of the response to the output header... */
3101  /* The third parameter to ap_table_set() MUST be a string. */
3102
3103  tmplen = strlen( tmp );
3104
3105  sprintf( content_length, "%d", tmplen );
3106
3107  #ifdef MOD_GZIP_DEBUG1
3108  mod_gzip_printf( "%s: content_length = [%s]\n",cn,content_length);
3109  #endif
3110
3111  ap_table_set( r->headers_out, "Content-Length", content_length );
3112
3113  /* Make sure the content type matches this response... */
3114
3115  r->content_type = ctype; /* Actual type passed by caller */
3116
3117  #ifdef MOD_GZIP_DEBUG1
3118  mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type);
3119  #endif
3120
3121  /* Start a timer... */
3122
3123  #ifdef MOD_GZIP_DEBUG1
3124  mod_gzip_printf( "%s: Call ap_soft_timeout()...\n",cn);
3125  #endif
3126
3127  ap_soft_timeout( "mod_gzip_send_html_command", r );
3128
3129  #ifdef MOD_GZIP_DEBUG1
3130  mod_gzip_printf( "%s: Back ap_soft_timeout()...\n",cn);
3131  #endif
3132     
3133  #ifdef MOD_GZIP_COMMANDS_USE_LAST_MODIFIED
3134
3135  /* Be sure to update the modifcation 'time' to current */
3136  /* time before calling 'ap_set_last_modified()'. All that */
3137  /* call does is set the r->xxxx value into the output */
3138  /* header. It doesn't actually update the time itself. */
3139
3140  #ifdef MOD_GZIP_DEBUG1
3141  mod_gzip_printf( "%s: Call ap_update_mtime(r,r-finfo.st_mtime)...\n",cn);
3142  #endif
3143
3144  ap_update_mtime( r, r->finfo.st_mtime );
3145
3146  #ifdef MOD_GZIP_DEBUG1
3147  mod_gzip_printf( "%s: Back ap_update_mtime(r,r-finfo.st_mtime)...\n",cn);
3148  #endif
3149
3150  /* Update the 'Last modified' stamp in output header... */
3151
3152  #ifdef MOD_GZIP_DEBUG1
3153  mod_gzip_printf( "%s: Call ap_set_last_modified()...\n",cn);
3154  #endif
3155
3156  ap_set_last_modified(r);
3157
3158  /* TODO: Add 'no-cache' option(s) to mod_gzip command responses */
3159  /* so user doesn't have hit reload to get fresh data. */
3160
3161  #ifdef MOD_GZIP_DEBUG1
3162  mod_gzip_printf( "%s: Back ap_set_last_modified()...\n",cn);
3163  #endif
3164
3165  #endif /* MOD_GZIP_COMMANDS_USE_LAST_MODIFIED */
3166
3167  /* Send the HTTP response header... */
3168
3169  #ifdef MOD_GZIP_DEBUG1
3170  mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn);
3171  #endif
3172
3173  ap_send_http_header(r);
3174
3175  #ifdef MOD_GZIP_DEBUG1
3176  mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn);
3177  #endif
3178
3179  /* Send the response BODY... */
3180
3181  #ifdef MOD_GZIP_DEBUG1
3182  mod_gzip_printf( "%s: Sending response...\n%s\n",cn,tmp);
3183  #endif
3184
3185  #ifdef MOD_GZIP_USES_AP_SEND_MMAP
3186
3187  /* Use ap_send_mmap() call to send the data... */
3188
3189  ap_send_mmap( tmp, r, 0, tmplen );
3190
3191  #else /* !MOD_GZIP_USES_AP_SEND_MMAP */
3192
3193  /* Use ap_rwrite() call to send the data... */
3194
3195  ap_rwrite( tmp, tmplen, r );
3196
3197  #endif /* MOD_GZIP_USES_AP_SEND_MMAP */
3198
3199  /* Clean up and exit... */
3200
3201  #ifdef MOD_GZIP_DEBUG1
3202  mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn);
3203  #endif
3204
3205  ap_kill_timeout(r);
3206
3207  #ifdef MOD_GZIP_DEBUG1
3208  mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn);
3209  mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn);
3210  #endif
3211
3212  return OK;
3213
3214 }/* End of mod_gzip_send_html_command_response() */
3215
3216 #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */
3217
3218 static void *
3219 mod_gzip_create_config( pool *p, server_rec *s )
3220 {
3221     int i;
3222
3223     mod_gzip_conf *ps = 0;
3224
3225     #ifdef MOD_GZIP_DEBUG1
3226     char cn[]="mod_gzip_create_config()";
3227     #endif
3228
3229     /*
3230      * Set all the configuration default values...
3231      */
3232
3233     #ifdef MOD_GZIP_DEBUG1
3234     mod_gzip_printf( "%s: Entry\n", cn );
3235     #endif
3236
3237     /*
3238      * Allocate a new config structure...
3239      */
3240
3241     ps = ( mod_gzip_conf * ) ap_pcalloc( p, sizeof( mod_gzip_conf ) );
3242
3243     /*
3244      * Set all default values...
3245      */
3246
3247     ps->req                = 1; /* Default is ON */
3248     ps->req_set            = 1; /* Default is ON */
3249     ps->do_static_files    = 1; /* Default is ON */
3250     ps->do_cgi             = 1; /* Default is ON */
3251     ps->keep_workfiles     = 0; /* 1=Keep workfiles 0=No */
3252     ps->min_http           = 0; /* 1001=HTTP/1.1 Default=All HTTP levels */
3253
3254     ps->minimum_file_size  = (long) mod_gzip_minimum_file_size;
3255                              /* Minimum file size in bytes */
3256     ps->maximum_inmem_size = (long) mod_gzip_maximum_inmem_size;
3257                              /* Maximum size for in-memory compression */
3258
3259     /* Compressed object cache control variables... */
3260
3261     /* Using these default values the compressed object cache
3262     /* can have 2^18 directories (256,000) */
3263
3264     ps->cache.root = ap_server_root; /* Default DIR is ServerRoot */
3265
3266     ps->cache.space                = MOD_GZIP_DEFAULT_CACHE_SPACE;
3267     ps->cache.space_set            = 0;
3268     ps->cache.maxexpire            = MOD_GZIP_DEFAULT_CACHE_MAXEXPIRE;
3269     ps->cache.maxexpire_set        = 0;
3270     ps->cache.defaultexpire        = MOD_GZIP_DEFAULT_CACHE_EXPIRE;
3271     ps->cache.defaultexpire_set    = 0;
3272     ps->cache.lmfactor             = MOD_GZIP_DEFAULT_CACHE_LMFACTOR;
3273     ps->cache.lmfactor_set         = 0;
3274     ps->cache.gcinterval           = -1;
3275     ps->cache.gcinterval_set       = 0;
3276     ps->cache.dirlevels            = 3;
3277     ps->cache.dirlevels_set        = 0;
3278     ps->cache.dirlength            = 1;
3279     ps->cache.dirlength_set        = 0;
3280
3281     /* Initialize the include/exclude item map list... */
3282
3283     /* For now all init values are ZERO but don't use */
3284     /* memset() since this may not always be the case. */
3285
3286     ps->imap_total_entries = 0;
3287
3288     for ( i=0; i<MOD_GZIP_IMAP_MAXNAMES; i++ )
3289        {
3290         ps->imap[i].include = 0;
3291         ps->imap[i].type    = 0;
3292         ps->imap[i].action  = 0;
3293         ps->imap[i].name[0] = 0;
3294
3295        }/* End 'i' loop */
3296
3297     #ifdef MOD_GZIP_DEBUG1
3298     mod_gzip_printf( "%s: ps->imap_total_entries = %d\n", cn, ps->imap_total_entries );
3299     mod_gzip_printf( "%s: Exit > return( ps ) >\n", cn );
3300     #endif
3301
3302     return ps;
3303
3304 }/* End of mod_gzip_create_config() */
3305
3306 static void *
3307 mod_gzip_merge_config( pool *p, void *basev, void *overridesv )
3308 {
3309     mod_gzip_conf *ps        = ap_pcalloc(p, sizeof(mod_gzip_conf));
3310     mod_gzip_conf *base      = (mod_gzip_conf *) basev;
3311     mod_gzip_conf *overrides = (mod_gzip_conf *) overridesv;
3312
3313     ps->req                  = (overrides->req_set == 0) ? base->req : overrides->req;
3314     ps->cache.root           = (overrides->cache.root == NULL) ? base->cache.root : overrides->cache.root;
3315     ps->cache.space          = (overrides->cache.space_set == 0) ? base->cache.space : overrides->cache.space;
3316     ps->cache.maxexpire      = (overrides->cache.maxexpire_set == 0) ? base->cache.maxexpire : overrides->cache.maxexpire;
3317     ps->cache.defaultexpire  = (overrides->cache.defaultexpire_set == 0) ? base->cache.defaultexpire : overrides->cache.defaultexpire;
3318     ps->cache.lmfactor       = (overrides->cache.lmfactor_set == 0) ? base->cache.lmfactor : overrides->cache.lmfactor;
3319     ps->cache.gcinterval     = (overrides->cache.gcinterval_set == 0) ? base->cache.gcinterval : overrides->cache.gcinterval;
3320     ps->cache.dirlevels      = (overrides->cache.dirlevels_set == 0) ? base->cache.dirlevels : overrides->cache.dirlevels;
3321     ps->cache.dirlength      = (overrides->cache.dirlength_set == 0) ? base->cache.dirlength : overrides->cache.dirlength;
3322
3323     return ps;
3324
3325 }/* End of mod_gzip_merge_config() */
3326
3327 /*
3328  * Module configuration directive handlers...
3329  */
3330
3331 static const char *
3332 mod_gzip_set_on(cmd_parms *parms, void *dummy, char *arg)
3333 {
3334     mod_gzip_conf *mgc;
3335
3336     #ifdef MOD_GZIP_DEBUG1
3337     char cn[]="mod_gzip_set_on()";
3338     #endif
3339
3340     /* Start... */
3341
3342     #ifdef MOD_GZIP_DEBUG1
3343     mod_gzip_printf( "%s: Entry\n", cn );
3344     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3345     #endif
3346
3347     mgc = ( mod_gzip_conf * )
3348     ap_get_module_config(parms->server->module_config, &gzip_module);
3349
3350     if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3351       {
3352        /* Set the master 'request control' switches ON... */
3353
3354        mgc->req     = 1; /* Yes */
3355        mgc->req_set = 1; /* Yes */
3356       }
3357     else /* Set the master 'request control' switches OFF... */
3358       {
3359        mgc->req     = 0; /* No */
3360        mgc->req_set = 0; /* No */
3361       }
3362
3363     #ifdef MOD_GZIP_DEBUG1
3364     mod_gzip_printf( "%s: mgc->req     = %ld\n", cn, (long) mgc->req );
3365     mod_gzip_printf( "%s: mgc->req_set = %ld\n", cn, (long) mgc->req_set );
3366     #endif
3367
3368     return NULL;
3369 }
3370
3371 static const char *
3372 mod_gzip_set_keep_workfiles(cmd_parms *parms, void *dummy, char *arg)
3373 {
3374     mod_gzip_conf *mgc;
3375
3376     #ifdef MOD_GZIP_DEBUG1
3377     char cn[]="mod_gzip_set_keep_workfiles()";
3378     #endif
3379
3380     /* Start... */
3381
3382     #ifdef MOD_GZIP_DEBUG1
3383     mod_gzip_printf( "%s: Entry\n", cn );
3384     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3385     #endif
3386
3387     mgc = ( mod_gzip_conf * )
3388     ap_get_module_config(parms->server->module_config, &gzip_module);
3389
3390     if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3391       {
3392        mgc->keep_workfiles = 1; /* Yes */
3393       }
3394     else
3395       {
3396        mgc->keep_workfiles = 0; /* No */
3397       }
3398
3399     #ifdef MOD_GZIP_DEBUG1
3400     mod_gzip_printf( "%s: mgc->keep_workfiles = %ld\n", cn,
3401                    (long) mgc->keep_workfiles );
3402     #endif
3403
3404     return NULL;
3405 }
3406
3407 static const char *
3408 mod_gzip_set_min_http(cmd_parms *parms, void *dummy, char *arg)
3409 {
3410     mod_gzip_conf *mgc;
3411
3412     #ifdef MOD_GZIP_DEBUG1
3413     char cn[]="mod_gzip_set_min_http()";
3414     #endif
3415
3416     /* Start... */
3417
3418     #ifdef MOD_GZIP_DEBUG1
3419     mod_gzip_printf( "%s: Entry\n", cn );
3420     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3421     #endif
3422
3423     mgc = ( mod_gzip_conf * )
3424     ap_get_module_config(parms->server->module_config, &gzip_module);
3425
3426     mgc->min_http = (int) atoi( arg );
3427
3428     #ifdef MOD_GZIP_DEBUG1
3429     mod_gzip_printf( "%s: mgc->min_http = %ld\n", cn,
3430                    (long) mgc->min_http );
3431     #endif
3432
3433     return NULL;
3434 }
3435
3436
3437 static const char *
3438 mod_gzip_imap_add_item( mod_gzip_conf *mgc, char *arg, int flag1 )
3439 {
3440     int  x;
3441     char *p1;
3442     int  ch1;
3443     int  this_type=0;
3444     int  this_action=0;
3445     int  this_include=flag1;
3446
3447     #ifdef MOD_GZIP_DEBUG1
3448     char cn[]="mod_gzip_imap_add_item()";
3449     #endif
3450
3451     /* Start... */
3452
3453     #ifdef MOD_GZIP_DEBUG1
3454
3455     mod_gzip_printf( "%s: Entry\n", cn );
3456     mod_gzip_printf( "%s: 1 arg=[%s]\n", cn, arg );
3457
3458     if ( flag1 == 1 )
3459       {
3460        mod_gzip_printf( "%s: flag1 = %d = INCLUDE\n", cn, flag1 );
3461       }
3462     else if ( flag1 == 0 )
3463       {
3464        mod_gzip_printf( "%s: flag1 = %d = EXCLUDE\n", cn, flag1 );
3465       }
3466     else
3467       {
3468        mod_gzip_printf( "%s: flag1 = %d = ??? Unknown value\n", cn, flag1 );
3469       }
3470
3471     mod_gzip_printf( "%s: MOD-GZIP_IMAP_MAXNAMES  = %d\n",
3472                       cn, MOD_GZIP_IMAP_MAXNAMES );
3473
3474     mod_gzip_printf( "%s: mgc->imap_total_entries = %d\n",
3475                       cn, mgc->imap_total_entries );
3476
3477     #endif /* MOD_GZIP_DEBUG1 */
3478
3479     /*
3480      * Parse the config line...
3481      */
3482
3483     p1 = arg;
3484     while((*p1!=0)&&(*p1<33)) p1++;
3485     ch1 = *p1;
3486
3487     this_type   = MOD_GZIP_IMAP_ISHANDLER;
3488     this_action = MOD_GZIP_IMAP_DYNAMIC1;
3489
3490     if ( ch1 == '!' )
3491       {
3492        arg++;
3493        p1 = arg;
3494        while((*p1!=0)&&(*p1<33)) p1++;
3495        ch1 = *p1;
3496       }
3497     else
3498       {
3499        this_action = MOD_GZIP_IMAP_STATIC1;
3500       }
3501
3502     if ( ch1 == '.' )
3503       {
3504        this_type = MOD_GZIP_IMAP_ISEXT;
3505       }
3506     else
3507       {
3508        p1 = arg;
3509        while (*p1!=0)
3510          {
3511           if ( *p1 == '/' )
3512             {
3513              this_type = MOD_GZIP_IMAP_ISMIME;
3514             }
3515           p1++;
3516          }
3517       }
3518
3519     /*
3520      * Safety checks...
3521      */
3522
3523     if ( ( this_type != MOD_GZIP_IMAP_ISMIME    ) &&
3524          ( this_type != MOD_GZIP_IMAP_ISEXT     ) &&
3525          ( this_type != MOD_GZIP_IMAP_ISHANDLER ) )
3526       {
3527        #ifdef MOD_GZIP_DEBUG1
3528        mod_gzip_printf( "%s: this_type = %d = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,this_type);
3529        mod_gzip_printf( "%s: return( mod_gzip: ERROR: Unrecognized item 'type'\n",cn);
3530        #endif
3531
3532        return( "mod_gzip: ERROR: Unrecognized item 'type'" );
3533       }
3534
3535     if ( ( this_action != MOD_GZIP_IMAP_DYNAMIC1 ) &&
3536          ( this_action != MOD_GZIP_IMAP_STATIC1  ) )
3537       {
3538        #ifdef MOD_GZIP_DEBUG1
3539        mod_gzip_printf( "%s: this_action = %d = MOD_GZIP_IMAP_??? Unknown action\n",cn,this_action);
3540        mod_gzip_printf( "%s: return( mod_gzip: ERROR: Unrecognized item 'action'\n",cn);
3541        #endif
3542
3543        return( "mod_gzip: ERROR: Unrecognized item 'action'" );
3544       }
3545
3546     /*
3547      * Wildcards...
3548      */
3549
3550      if ( this_type != MOD_GZIP_IMAP_ISMIME )
3551        {
3552         /*
3553          * Wildcards are only allowed in MIME strings such as 'image/*'
3554          */
3555
3556         p1 = arg;
3557         while (*p1!=0)
3558           {
3559            if ( *p1 == '*' )
3560              {
3561               return( "mod_gzip: ERROR: Wildcards are only allowed in MIME strings." );
3562              }
3563            p1++;
3564           }
3565        }
3566
3567     /*
3568      * If there is room for a new record then add it...
3569      */
3570
3571     if ( mgc->imap_total_entries < MOD_GZIP_IMAP_MAXNAMES )
3572       {
3573        if ( strlen( arg ) < MOD_GZIP_IMAP_MAXNAMELEN )
3574          {
3575           x = mgc->imap_total_entries;
3576
3577           p1 = arg;
3578           while((*p1!=0)&&(*p1<33)) p1++;
3579
3580           strcpy( mgc->imap[x].name, p1 );
3581
3582           mgc->imap[x].include = this_include;
3583           mgc->imap[x].type    = this_type;
3584           mgc->imap[x].action  = this_action;
3585
3586           mgc->imap_total_entries++; /* Increase onboard items */
3587          }
3588        else /* ERROR: Name is too long */
3589          {
3590           #ifdef MOD_GZIP_DEBUG1
3591           mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item name is too long\n",cn);
3592           #endif
3593
3594           return( "mod_gzip: ERROR: Item name is too long" );
3595          }
3596       }
3597     else /* ERROR: INDEX is FULL */
3598       {
3599        #ifdef MOD_GZIP_DEBUG1
3600        mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item index is full\n",cn);
3601        #endif
3602
3603        return( "mod_gzip: ERROR: Item index is full" );
3604       }
3605
3606     #ifdef MOD_GZIP_DEBUG1
3607     mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn);
3608     #endif
3609
3610     return NULL;
3611
3612 }/* End of mod_gzip_imap_add_item() */
3613
3614 #ifdef MOD_GZIP_DEBUG1
3615
3616 int mod_gzip_imap_show_items( mod_gzip_conf *mgc )
3617 {
3618     /*
3619      * DEBUG only. Show the complete include/exclude list.
3620      * This is normally called from mod_gzip_init()
3621      * after all the configuration routines have executed.
3622      */
3623
3624     int  i;
3625     int  x;
3626     char cn[]="mod_gzip_imap_show_items()";
3627
3628     /* Start... */
3629
3630     mod_gzip_printf( "\n");
3631     mod_gzip_printf( "%s: Entry\n", cn );
3632
3633     mod_gzip_printf( "%s: mgc->imap_total_entries= %d\n", cn,
3634                    (long) mgc->imap_total_entries );
3635
3636     for ( i=0; i<mgc->imap_total_entries; i++ )
3637        {
3638         x = i; /* Work variable */
3639
3640         mod_gzip_printf( "\n");
3641         mod_gzip_printf( "%s: mgc->imap[%3.3d].include = %d\n",  cn,x,mgc->imap[x].include);
3642         mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = %d\n",  cn,x,mgc->imap[x].type);
3643
3644         if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME )
3645           {
3646            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_ISMIME\n",cn,x);
3647           }
3648         else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT )
3649           {
3650            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_ISEXT\n",cn,x);
3651           }
3652         else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER )
3653           {
3654            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_ISHANDLER\n",cn,x);
3655           }
3656         else /* Unrecognized item type... */
3657           {
3658            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x);
3659           }
3660
3661         mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = %d\n",  cn,x,mgc->imap[x].action);
3662
3663         if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 )
3664           {
3665            mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x);
3666           }
3667         else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 )
3668           {
3669            mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = MOD_GZIP_IMAP_STATIC1\n",cn,x);
3670           }
3671         else /* Unrecognized action type... */
3672           {
3673            mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = MOD_GZIP_IMAP_??? Unknown action\n",cn,x);
3674           }
3675
3676         mod_gzip_printf( "%s: mgc->imap[%3.3d].name    = [%s]\n",cn,x,mgc->imap[x].name);
3677
3678        }/* End 'i' loop */
3679
3680     mod_gzip_printf( "\n");
3681
3682     return 0;
3683
3684 }/* End of mod_gzip_imap_show_items() */
3685
3686 #endif /* MOD_GZIP_DEBUG1 */
3687
3688 static const char *
3689 mod_gzip_set_item_include(cmd_parms *parms, void *dummy, char *arg)
3690 {
3691     mod_gzip_conf *mgc;
3692
3693     #ifdef MOD_GZIP_DEBUG1
3694     char cn[]="mod_gzip_set_item_include()";
3695     #endif
3696
3697     /* Start... */
3698
3699     #ifdef MOD_GZIP_DEBUG1
3700     mod_gzip_printf( "%s: Entry\n", cn );
3701     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3702     #endif
3703
3704     mgc = ( mod_gzip_conf * )
3705     ap_get_module_config(parms->server->module_config, &gzip_module);
3706
3707     /* Pass pre-determined pointer to config structure... */
3708     /* Pass '1' for parm 3 to INCLUDE this item... */
3709
3710     return( mod_gzip_imap_add_item( mgc, arg, 1 ) );
3711 }
3712
3713 static const char *
3714 mod_gzip_set_item_exclude(cmd_parms *parms, void *dummy, char *arg)
3715 {
3716     mod_gzip_conf *mgc;
3717
3718     #ifdef MOD_GZIP_DEBUG1
3719     char cn[]="mod_gzip_set_item_exclude()";
3720     #endif
3721
3722     /* Start... */
3723
3724     #ifdef MOD_GZIP_DEBUG1
3725     mod_gzip_printf( "%s: Entry\n", cn );
3726     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3727     #endif
3728
3729     mgc = ( mod_gzip_conf * )
3730     ap_get_module_config(parms->server->module_config, &gzip_module);
3731
3732     /* Pass pre-determined pointer to config structure... */
3733     /* Pass '0' for parm 3 to EXCLUDE this item... */
3734
3735     return( mod_gzip_imap_add_item( mgc, arg, 0 ) );
3736 }
3737
3738 static const char *
3739 mod_gzip_set_temp_dir(cmd_parms *parms, void *dummy, char *arg)
3740 {
3741     mod_gzip_conf *mgc;
3742
3743     char cn[]="mod_gzip_set_temp_dir()";
3744
3745     /* Start... */
3746
3747     #ifdef MOD_GZIP_DEBUG1
3748     mod_gzip_printf( "%s: Entry\n", cn );
3749     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3750     #endif
3751
3752     mgc = ( mod_gzip_conf * )
3753     ap_get_module_config(parms->server->module_config, &gzip_module);
3754
3755     mgc->cache.root = arg; /* For now temp dir is used as cache root */
3756
3757     strcpy( mod_gzip_temp_dir, arg );
3758     mgc->cache.root = mod_gzip_temp_dir;
3759
3760     #ifdef MOD_GZIP_DEBUG1
3761     mod_gzip_printf( "%s: mgc->cache.root=[%s]\n", cn, mgc->cache.root );
3762     #endif
3763
3764     return NULL;
3765 }
3766
3767 static const char *
3768 mod_gzip_set_minimum_file_size(cmd_parms *parms, void *dummy, char *arg)
3769 {
3770     mod_gzip_conf *mgc;
3771     long lval;
3772
3773     #ifdef MOD_GZIP_DEBUG1
3774     char cn[]="mod_gzip_set_minimum_file_size()";
3775     #endif
3776
3777     /* Start... */
3778
3779     #ifdef MOD_GZIP_DEBUG1
3780     mod_gzip_printf( "%s: Entry\n", cn );
3781     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3782     #endif
3783
3784     mgc = ( mod_gzip_conf * )
3785     ap_get_module_config(parms->server->module_config, &gzip_module);
3786
3787     lval = (long) atol(arg);
3788
3789     /* 300 bytes is the minimum at all times */
3790     if ( lval < 300L ) lval = 300L;
3791
3792         mgc->minimum_file_size = (long) lval; /* Set config */
3793     mod_gzip_minimum_file_size = (long) lval; /* Set global */
3794
3795     #ifdef MOD_GZIP_DEBUG1
3796     mod_gzip_printf( "%s: ....mgc->minimum_file_size = %ld\n", cn,
3797                    (long)     mgc->minimum_file_size );
3798     mod_gzip_printf( "%s: mod_gzip_minimum_file_size = %ld\n", cn,
3799                    (long) mod_gzip_minimum_file_size );
3800     #endif
3801
3802     return NULL;
3803 }
3804
3805 static const char *
3806 mod_gzip_set_maximum_inmem_size(cmd_parms *parms, void *dummy, char *arg)
3807 {
3808     mod_gzip_conf *mgc;
3809     long lval=0;
3810
3811     #ifdef MOD_GZIP_DEBUG1
3812     char cn[]="mod_gzip_set_maximum_inmem_size()";
3813     #endif
3814
3815     /* Start... */
3816
3817     #ifdef MOD_GZIP_DEBUG1
3818     mod_gzip_printf( "%s: Entry\n", cn );
3819     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3820     #endif
3821
3822     mgc = ( mod_gzip_conf * )
3823     ap_get_module_config(parms->server->module_config, &gzip_module);
3824
3825     lval = (long) atol(arg);
3826
3827     /* 60000 bytes is the current maximum since a malloc() call is used */
3828     if ( lval > 60000L ) lval = 60000L;
3829
3830         mgc->maximum_inmem_size = (long) lval; /* Set config */
3831     mod_gzip_maximum_inmem_size = (long) lval; /* Set global */
3832
3833     #ifdef MOD_GZIP_DEBUG1
3834     mod_gzip_printf( "%s: ....mgc->maximum_inmem_size = %ld\n", cn,
3835                    (long)     mgc->maximum_inmem_size );
3836     mod_gzip_printf( "%s: mod_gzip_maximum_inmem_size = %ld\n", cn,
3837                    (long) mod_gzip_maximum_inmem_size );
3838     #endif
3839
3840     return NULL;
3841 }
3842
3843 static const char *
3844 mod_gzip_set_do_static_files(cmd_parms *parms, void *dummy, char *arg)
3845 {
3846     mod_gzip_conf *mgc;
3847
3848     #ifdef MOD_GZIP_DEBUG1
3849     char cn[]="mod_gzip_set_do_static_files()";
3850     #endif
3851
3852     /* Start... */
3853
3854     #ifdef MOD_GZIP_DEBUG1
3855     mod_gzip_printf( "%s: Entry\n", cn );
3856     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3857     #endif
3858
3859     mgc = ( mod_gzip_conf * )
3860     ap_get_module_config(parms->server->module_config, &gzip_module);
3861
3862     if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3863       {
3864        mgc->do_static_files = 1; /* Yes */
3865       }
3866     else
3867       {
3868        mgc->do_static_files = 0; /* No */
3869       }
3870
3871     #ifdef MOD_GZIP_DEBUG1
3872     mod_gzip_printf( "%s: mgc->do_static_files = %ld\n", cn,
3873                    (long) mgc->do_static_files );
3874     #endif
3875
3876     return NULL;
3877 }
3878
3879 static const char *
3880 mod_gzip_set_do_cgi(cmd_parms *parms, void *dummy, char *arg)
3881 {
3882     mod_gzip_conf *mgc;
3883
3884     #ifdef MOD_GZIP_DEBUG1
3885     char cn[]="mod_gzip_set_do_cgi()";
3886     #endif
3887
3888     /* Start... */
3889
3890     #ifdef MOD_GZIP_DEBUG1
3891     mod_gzip_printf( "%s: Entry\n", cn );
3892     mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3893     #endif
3894
3895     mgc = ( mod_gzip_conf * )
3896     ap_get_module_config(parms->server->module_config, &gzip_module);
3897
3898     if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3899       {
3900        mgc->do_cgi = 1; /* Yes */
3901       }
3902     else
3903       {
3904        mgc->do_cgi = 0; /* No */
3905       }
3906
3907     #ifdef MOD_GZIP_DEBUG1
3908     mod_gzip_printf( "%s: mgc->do_cgi = %ld\n", cn,
3909                    (long) mgc->do_cgi );
3910     #endif
3911
3912     return NULL;
3913 }
3914
3915 static const handler_rec mod_gzip_handlers[] =
3916 {
3917     /*
3918      * This is where we associate an ASCII NAME for our 'handler'
3919      * which is what gets set into the r->handler field for a
3920      * request and allows the function name associated with the
3921      * ASCII name to be called and handle the request...
3922      */
3923
3924     /* Add a 'name' and some types to our handler... */
3925
3926     {"mod_gzip_handler", mod_gzip_handler},
3927     {CGI_MAGIC_TYPE,     mod_gzip_handler},
3928     {"cgi-script",       mod_gzip_handler},
3929     {"*",                mod_gzip_handler},
3930     {NULL}
3931 };
3932
3933
3934 static const command_rec mod_gzip_cmds[] =
3935 {
3936     /*
3937      * Define our httpd.conf configuration diectives and
3938      * the local routines that are responsible for processing
3939      * those directives when the time comes...
3940      */
3941
3942     {"mod_gzip_on", mod_gzip_set_on, NULL, RSRC_CONF, TAKE1,
3943      "Yes=mod_gzip will handle requests No=mod_gzip runs in 'passthrough' mode"},
3944
3945     {"mod_gzip_do_static_files", mod_gzip_set_do_static_files, NULL, RSRC_CONF, TAKE1,
3946      "'Yes' means mod_gzip will compress static files."},
3947
3948     {"mod_gzip_do_cgi", mod_gzip_set_do_cgi, NULL, RSRC_CONF, TAKE1,
3949      "'Yes' means mod_gzip will compress dynamic CGI script output."},
3950
3951     {"mod_gzip_keep_workfiles", mod_gzip_set_keep_workfiles, NULL, RSRC_CONF, TAKE1,
3952      "On=Keep work files Off=No"},
3953
3954     {"mod_gzip_min_http", mod_gzip_set_min_http, NULL, RSRC_CONF, TAKE1,
3955      "Minimum HTTP support level to receive compression. 1001=HTTP/1.1"},
3956
3957     {"mod_gzip_minimum_file_size", mod_gzip_set_minimum_file_size, NULL, RSRC_CONF, TAKE1,
3958      "The minimum size ( in bytes ) before compression will be attempted"},
3959
3960     {"mod_gzip_maximum_inmem_size", mod_gzip_set_maximum_inmem_size, NULL, RSRC_CONF, TAKE1,
3961      "The maximum size ( in bytes ) to use for in-memory compression."},
3962
3963     {"mod_gzip_temp_dir", mod_gzip_set_temp_dir, NULL, RSRC_CONF, TAKE1,
3964      "The directory to use for work files and compression cache"},
3965
3966     {"mod_gzip_item_include", mod_gzip_set_item_include, NULL, RSRC_CONF, TAKE1,
3967      "Add the item the inclusion list"},
3968
3969     {"mod_gzip_item_exclude", mod_gzip_set_item_exclude, NULL, RSRC_CONF, TAKE1,
3970      "Add the item the exclusion list"},
3971
3972     {NULL}
3973 };
3974
3975 /*
3976  * The actual module 'jump' table...
3977  *
3978  * If one of the fixed 'call' points has a valid function
3979  * address then Apache will 'call' into it at the appropriate time.
3980  *
3981  * When the compressed object cache is engaged we will need to
3982  * simply add some handlers for the URI detection and translation
3983  * call point(s).
3984  */
3985
3986 module MODULE_VAR_EXPORT gzip_module =
3987 {
3988     STANDARD_MODULE_STUFF,
3989     mod_gzip_init,          /* initializer */
3990     NULL,                   /* create per-directory config structure */
3991     NULL,                   /* merge per-directory config structures */
3992     mod_gzip_create_config, /* create per-server config structure */
3993     mod_gzip_merge_config,  /* merge per-server config structures */
3994     mod_gzip_cmds,          /* command table */
3995     mod_gzip_handlers,      /* handlers */
3996     NULL,                   /* translate_handler */
3997     NULL,                   /* check_user_id */
3998     NULL,                   /* check auth */
3999     NULL,                   /* check access */
4000     NULL,                   /* type_checker */
4001     NULL,                   /* pre-run fixups */
4002     NULL,                   /* logger */
4003     NULL,                   /* header parser */
4004     NULL,                   /* child_init */
4005     NULL,                   /* child_exit */
4006     NULL                    /* post read-request */
4007 };
4008
4009 #ifdef NETWARE
4010 int main(int argc, char *argv[]) 
4011 {
4012     ExitThread(TSR_THREAD, 0);
4013 }
4014 #endif
4015
4016 FILE *mod_gzip_open_output_file(
4017 request_rec *r,
4018 char *output_filename,
4019 int  *rc
4020 )
4021 {
4022  FILE *ifh;
4023
4024  #ifdef MOD_GZIP_DEBUG1
4025  char cn[]="mod_gzip_open_output_file():::";
4026  #endif
4027
4028  /*
4029   * Start...
4030   */
4031
4032  #ifdef MOD_GZIP_DEBUG1
4033  mod_gzip_printf( "%s: Entry...\n",cn);
4034  mod_gzip_printf( "%s: output_filename=[%s]\n",cn,output_filename);
4035  #endif
4036
4037  ifh = fopen( output_filename, "rb" ); /* Open in BINARY mode */
4038
4039  if ( !ifh ) /* The file failed to open... */
4040    {
4041     #ifdef MOD_GZIP_DEBUG1
4042     mod_gzip_printf( "%s: ERROR: Cannot open file [%s]\n",
4043                       cn,output_filename);
4044     #endif
4045
4046     /*
4047      * The workfile was created OK but now will not re-open.
4048      * This is worth a strike in the ERROR log.
4049      */
4050
4051     ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
4052     "mod_gzip: Cannot re-open output_filename=[%s]",
4053     output_filename );
4054
4055     /* Return DECLINED and let default logic finish the request... */
4056
4057     #ifdef MOD_GZIP_DEBUG1
4058     mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn);
4059     #endif
4060
4061     #ifdef MOD_GZIP_USES_APACHE_LOGS
4062
4063     /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4064
4065     ap_table_setn(
4066     r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:WORK_OPENFAIL"));
4067
4068     #endif /* MOD_GZIP_USES_APACHE_LOGS */
4069
4070     *rc = DECLINED; /* Update caller's result code... */
4071
4072     return NULL;
4073
4074    }/* End 'if ( !ifh )' */
4075
4076  #ifdef MOD_GZIP_DEBUG1
4077  mod_gzip_printf( "%s: File is now open...\n",cn);
4078  mod_gzip_printf( "%s: Exit > return( FILE *ifh ) >\n",cn);
4079  #endif
4080
4081  *rc = OK; /* Update caller's result code */
4082
4083  return ifh; /* Return the file handle */
4084
4085 }/* End of mod_gzip_open_output_file() */
4086
4087 int mod_gzip_encode_and_transmit(
4088 request_rec *r,
4089 char        *source,
4090 int          source_is_a_file,
4091 long         input_size,
4092 int          nodecline
4093 )
4094 {
4095     GZP_CONTROL   gzc;
4096     GZP_CONTROL*  gzp = &gzc;
4097
4098     int             rc                = 0;
4099     FILE           *ifh               = 0;
4100     int             bytesread         = 0;
4101     long            output_size       = 0;
4102     long            compression_ratio = 0;
4103     char*           gz1_ismem_obuf    = 0;
4104     int             finalize_stats    = 1;
4105
4106     int             gz1_ismem_obuf_was_allocated = 0;
4107
4108     char content_length[20]; /* For Content-length updates */
4109
4110     #define MOD_GZIP_LARGE_BUFFER_SIZE 8192
4111
4112     char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */
4113
4114     char *actual_content_encoding_name = "gzip"; /* Adjustable */
4115         const char *compression_format;
4116
4117     #ifdef MOD_GZIP_DEBUG1
4118     char cn[]="mod_gzip_encode_and_transmit()";
4119     #endif
4120
4121     void *modconf = r->server->module_config;
4122
4123     #ifdef MOD_GZIP_USES_APACHE_LOGS
4124     char log_info[40]; /* Scratch buffer */
4125     #endif
4126
4127     /*
4128      * Start...
4129      *
4130      * Establish a local pointer to module configuration data...
4131      */
4132
4133     mod_gzip_conf *conf =
4134     (mod_gzip_conf *) ap_get_module_config( modconf, &gzip_module );
4135
4136     #ifdef MOD_GZIP_DEBUG1
4137
4138     mod_gzip_printf( "%s: Entry...\n", cn);
4139     mod_gzip_printf( "%s: source_is_a_file = %d\n", cn, source_is_a_file);
4140     mod_gzip_printf( "%s: nodecline        = %d\n", cn, nodecline);
4141
4142     if ( source_is_a_file ) /* Show the filename... */
4143       {
4144        mod_gzip_printf( "%s: source = [%s]\n", cn, source);
4145       }
4146     else /* Don't try to print the memory buffer... */
4147       {
4148        mod_gzip_printf( "%s: source = MEMORY BUFFER\n", cn );
4149       }
4150
4151     mod_gzip_printf( "%s: input_size = %ld\n", cn,(long)input_size);
4152
4153     #endif /* MOD_GZIP_DEBUG1 */
4154
4155
4156     #ifdef MOD_GZIP_USES_APACHE_LOGS
4157
4158     /* This routine 'assumes' that the final result is 'OK' */
4159     /* and lets the remainder of the processing set the result */
4160     /* string to some other value, if necessary. */
4161
4162     /* Since we are now using the 'nodecline' flag and might */
4163     /* have to 'stand and deliver' then this allows the right */
4164     /* result code to appear in the log files even if we */
4165     /* cannot DECLINE the processing. */
4166
4167     ap_table_setn(
4168     r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK"));
4169
4170     /* We can also update the 'input' size right away since it is known */
4171
4172     sprintf( log_info,"%d", (int) input_size );
4173     ap_table_setn( r->notes,"mod_gzip_input_size",ap_pstrdup(r->pool,log_info));
4174
4175     #endif /* MOD_GZIP_USES_APACHE_LOGS */
4176
4177     /*
4178      * If the source has no length then DECLINE the processing...
4179      */
4180
4181     if ( input_size < 1 )
4182       {
4183        #ifdef MOD_GZIP_DEBUG1
4184        mod_gzip_printf( "%s: ERROR: Input source has no valid length.\n",cn);
4185        mod_gzip_printf( "%s: This request will not be processed...\n",cn);
4186        #endif
4187
4188        /* An existing request object with no length is worth a warning... */
4189
4190        ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_WARNING, r->server,
4191        "mod_gzip: r->filename=[%s] has no length",r->filename );
4192
4193        #ifdef MOD_GZIP_DEBUG1
4194        mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
4195        #endif
4196
4197        #ifdef MOD_GZIP_USES_APACHE_LOGS
4198
4199        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4200
4201        ap_table_setn(
4202        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_I_LEN"));
4203
4204        #endif /* MOD_GZIP_USES_APACHE_LOGS */
4205
4206        return DECLINED;
4207       }
4208
4209         /*
4210      * If we're only supposed to send header information (HEAD request)
4211      * then all we need to do is call ap_send_http_header() at this point
4212      * and then return 'OK'...
4213      */
4214
4215     if ( r->header_only )
4216       {
4217        #ifdef MOD_GZIP_DEBUG1
4218        mod_gzip_printf( "%s: HEAD request only... ignore body data...\n",cn);
4219        #endif
4220
4221        /*
4222         * Set outbound response header fields...
4223         *
4224         * NOTE: If this is just a HEAD request then
4225         * there is no need to make the API call...
4226         *
4227         * ap_update_mtime( r, r->finfo.st_mtime );
4228         *
4229         * ...and update the actual time. Use the time
4230         * that's currently associated with the object.
4231         */
4232
4233        ap_set_last_modified(r);
4234        ap_set_etag(r);
4235        ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
4236
4237        /* Start a timer for this transaction... */
4238
4239        ap_soft_timeout( "mod_gzip: HEAD request handler", r );
4240
4241        #ifdef MOD_GZIP_DEBUG1
4242        mod_gzip_printf( "%s: r->content_type=[%s]\n",cn,r->content_type);
4243        mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn);
4244        #endif
4245
4246        ap_send_http_header(r);
4247
4248        #ifdef MOD_GZIP_DEBUG1
4249        mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn);
4250        mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn);
4251        #endif
4252
4253        ap_kill_timeout(r);
4254
4255        #ifdef MOD_GZIP_DEBUG1
4256        mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn);
4257        mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn);
4258        #endif
4259
4260        #ifdef MOD_GZIP_USES_APACHE_LOGS
4261
4262        /* Return OK but distinguish it from a 'GET' request in logs...  */
4263
4264        ap_table_setn(
4265        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK:HEAD_ONLY"));
4266
4267        #endif /* MOD_GZIP_USES_APACHE_LOGS */
4268
4269        return OK;
4270
4271       }/* End 'if( r->header_only )' */
4272
4273     /*
4274      * See if the source meets the MINUMUM SIZE requirement...
4275      *
4276      * Default to 300 bytes as a minimum size requirement for it
4277      * to even be worth a compression attempt. This works well as a
4278      * minimum for both GZIP and ZLIB which are both LZ77 based and,
4279      * as such, always have the potential to actually increase the
4280      * size of the file.
4281      *
4282      * The value is a module global that can be adjusted 'on the fly'
4283      * as load conditions change or as required for other reasons.
4284      */
4285
4286     #ifdef MOD_GZIP_DEBUG1
4287     mod_gzip_printf( "%s: conf->minimum_file_size = %ld\n",
4288                cn, (long) conf->minimum_file_size );
4289     #endif
4290
4291     if ( input_size < (long) conf->minimum_file_size )
4292       {
4293        #ifdef MOD_GZIP_DEBUG1
4294        mod_gzip_printf( "%s: Source does not meet the minimum size requirement...\n",cn);
4295        mod_gzip_printf( "%s: nodecline = %d\n",cn,nodecline);
4296        #endif
4297
4298        /* Set the 'mod_gzip_result' note value to something */
4299        /* that indicates this was too small... */
4300
4301        #ifdef MOD_GZIP_USES_APACHE_LOGS
4302
4303        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4304
4305        ap_table_setn(
4306        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:TOO_SMALL"));
4307
4308        #endif /* MOD_GZIP_USES_APACHE_LOGS */
4309
4310        /* Is it OK to DECLINE?... */
4311
4312        if ( nodecline ) /* We have been told NOT to DECLINE */
4313          {
4314           #ifdef MOD_GZIP_DEBUG1
4315           mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn);
4316           #endif
4317
4318           /* Skip the compression phase and just set the output */
4319           /* control skid up to send the real input data... */
4320
4321           output_size = input_size;
4322
4323           if ( source_is_a_file ) /* Source is a workfile... */
4324             {
4325              #ifdef MOD_GZIP_DEBUG1
4326              mod_gzip_printf( "%s: Force send - source = FILE[%s]\n",
4327                               cn,source);
4328              #endif
4329
4330              strcpy( gzp->output_filename, source );
4331              gzp->output_ismem         = 0; /* Output is a disk file */
4332              gz1_ismem_obuf            = 0; /* Make sure this is NULL */
4333              gzp->output_ismem_obuf    = 0; /* Not used for this method */
4334              gzp->output_ismem_obuflen = 0; /* Not used for this method */
4335
4336              ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4337
4338              if ( !ifh ) /* The file failed to open... */
4339                {
4340                 /* We really MUST decline... */
4341                 /* Logs have already been updated... */
4342
4343                 return( rc );
4344                }
4345             }
4346           else /* Source is just a memory buffer... */
4347             {
4348              #ifdef MOD_GZIP_DEBUG1
4349              mod_gzip_printf( "%s: Force send - source = MEMORY BUFFER\n",cn);
4350              #endif
4351
4352              gzp->output_ismem = 1;
4353              gz1_ismem_obuf    = source;
4354
4355              gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */
4356             }
4357
4358           #ifdef MOD_GZIP_DEBUG1
4359           mod_gzip_printf( "%s: No compression attempt was made.\n",cn);
4360           mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn);
4361           #endif
4362
4363           goto mod_gzip_encode_and_transmit_send_start; /* Jump */
4364          }
4365        else /* It's OK to DECLINE the processing... */
4366          {
4367           #ifdef MOD_GZIP_DEBUG1
4368           mod_gzip_printf( "%s: DECLINE is allowed...\n",cn);
4369           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
4370           #endif
4371
4372           return DECLINED;
4373          }
4374       }
4375     else /* The source is larger than the minimum size requirement... */
4376       {
4377        #ifdef MOD_GZIP_DEBUG1
4378        mod_gzip_printf( "%s: Source meets the minimum size requirement.\n",cn);
4379        mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn);
4380        #endif
4381       }
4382
4383     /*
4384      * We must now encode the requested object...
4385      *
4386      * Statistically speaking, most 'text/*' pages are
4387      * less than 60k. XML documents are an exception.
4388      *
4389      * If the size of the requested object is less than 60k
4390      * then go ahead and compress the source directly to a
4391      * small memory buffer. If the requested object is greater
4392      * than 60k then go ahead and swap the results to an output
4393      * disk file and then send the contents of the result file.
4394      *
4395      * We can't ever allocate all the memory we want inside of
4396      * a Server task thread so there must always be this kind
4397      * of 'decision' making about when we can compress to
4398      * a memory buffer ( Less than 60k ) and when we must
4399      * compress to DISK. ( Greater than 60k ).
4400      *
4401      * There is a trade-off here between running the risk of
4402      * too many tasks stealing away all the heap space and
4403      * still maintaining performance. Given all the variables
4404      * involved such as the true efficiency of the compression
4405      * algorithm(s) and the speed of the CPU and the amount of
4406      * memory/disk space available there is no 'real' answer to
4407      * this dilemma other than relying on statistical data
4408      * and empirical observations. The 60k limit on in-memory
4409      * compression seems to strike a good balance and performs
4410      * incredibly well under the heaviest of loads.
4411      *
4412      * At all times, the greatest benefit being gained is the
4413      * appreciable reduction of data that must actually be
4414      * sent by the TCP/IP sub-system and the reduced usage
4415      * of those resources to perform the transmission task(s),
4416      *
4417      * The key, then, is to always strive for a balance where
4418      * the time and resource usage it takes to compress a
4419      * deliverable object will always be less than the processor
4420      * burden that would otherwise be realized by handing the
4421      * full, uncompressed object to the TCP/IP sub-system which
4422      * always extend the time that the thread and all its
4423      * locked resources must be maintained as well as the
4424      * overhead for keeping a connection active any longer
4425      * than is absolutely necessary.
4426      *
4427      * As long as the resource usage it takes to accomplish
4428      * a significant reduction in the amount of data that
4429      * must actually be processed by the remainder of the
4430      * HTTP task thread and the TCP/IP sub-system itself
4431      * is always less than the processor burden seen by
4432      * NOT doing so then we are always 'ahead of the game'.
4433      */
4434
4435     /*
4436      * See if the object size exceeds the current MAXIMUM size
4437      * to use for in-memory compression...
4438      *
4439      * See notes above about a range of 60k or so being the best
4440      * value for heavy load conditions.
4441      *
4442      * This number is currently a global so it can be changed
4443      * 'on the fly' and can 'breathe' as the load changes.
4444      * It should probably become a thread specific variable
4445      * so each task can have its 'own' max value depending
4446      * on current load conditions.
4447      */
4448
4449     #ifdef MOD_GZIP_DEBUG1
4450     mod_gzip_printf( "%s: conf->maximum_inmem_size = %ld\n",
4451                cn, (long) conf->maximum_inmem_size );
4452     #endif
4453
4454     /*
4455      * Set up the INPUT target...
4456      */
4457
4458     /* The size and type of the input source is always known */
4459     /* and was passed by the caller... */
4460
4461     if ( source_is_a_file )
4462       {
4463        #ifdef MOD_GZIP_DEBUG1
4464        mod_gzip_printf( "%s: Input source is file[%s]\n",cn,source);
4465        #endif
4466
4467        strcpy( gzp->input_filename, source );
4468
4469        gzp->input_ismem         = 0; /* Input is a disk file */
4470        gzp->input_ismem_ibuf    = 0; /* Source buffer */
4471        gzp->input_ismem_ibuflen = 0; /* Length of data */
4472       }
4473     else
4474       {
4475        #ifdef MOD_GZIP_DEBUG1
4476        mod_gzip_printf( "%s: Input source is a MEMORY BUFFER\n",cn);
4477        #endif
4478
4479        *gzp->input_filename = 0; /* Not used */
4480
4481        gzp->input_ismem         = 1;          /* Input is a memory buffer */
4482        gzp->input_ismem_ibuf    = source;     /* Source buffer */
4483        gzp->input_ismem_ibuflen = input_size; /* Length of data */
4484       }
4485
4486     /*
4487      * Set up the OUTPUT target...
4488      */
4489
4490     gzp->decompress = 0; /* Perform encoding */
4491
4492         /* Recover the compression format we're supposed to use. */
4493         compression_format = ap_table_get(r->notes, "mod_gzip_compression_format");
4494         if (compression_format && strcmp(compression_format, "deflate") == 0)
4495           {
4496            actual_content_encoding_name = "deflate";
4497            gzp->compression_format = DEFLATE_FORMAT;
4498       }
4499     else
4500           {
4501            gzp->compression_format = GZIP_FORMAT;
4502       }
4503
4504     if ( input_size <= (long) conf->maximum_inmem_size )
4505       {
4506        /* The input source is small enough to compress directly */
4507        /* to an in-memory output buffer... */
4508
4509        #ifdef MOD_GZIP_DEBUG1
4510        mod_gzip_printf( "%s: Input source is small enough for in-memory compression.\n",cn);
4511        #endif
4512
4513        *gzp->output_filename = 0; /* Not used */
4514         gzp->output_ismem    = 1; /* Output is a memory buffer */
4515
4516        /*
4517         * Allocate a memory buffer to hold compressed output.
4518         *
4519         * For now this is borrowed from the heap for only
4520         * the lifetime of this function call. If the stack
4521         * can handle the current in-memory MAXSIZE then
4522         * that will work just as well.
4523         *
4524         * Add at least 1000 bytes in case the compression
4525         * algorithm(s) actually expands the source ( which is
4526         * not likely but is always a possibility when using
4527         * any LZ77 based compression such as GZIP or ZLIB )
4528         */
4529
4530        gz1_ismem_obuf = (char *) malloc( input_size + 1000 );
4531
4532        if ( !gz1_ismem_obuf )
4533          {
4534           /*
4535            * There wasn't enough memory left for another
4536            * in-memory compression buffer so default to using
4537            * an output disk file instead...
4538            */
4539
4540           #ifdef MOD_GZIP_DEBUG1
4541           mod_gzip_printf( "%s: ERROR: Cannot allocate GZP memory...\n",cn);
4542           mod_gzip_printf( "%s: Defaulting to output file method... \n",cn);
4543           #endif
4544
4545           gzp->output_ismem = 0; /* Switch to using a disk file */
4546          }
4547
4548        else /* We got the memory we need for in-memory compression... */
4549          {
4550           /* Set the local flag which tells the exit logic */
4551           /* that 'gz1_ismem_obuf' was actually allocated */
4552           /* and not simply set to 'source' so that the */
4553           /* allocation can be 'freed' on exit... */
4554
4555           gz1_ismem_obuf_was_allocated = 1; /* 'free' is required */
4556
4557           /* Compression codecs require a 'clean' buffer so */
4558           /* we need to spend the cycles for a memset() call. */
4559
4560           memset( gz1_ismem_obuf, 0, ( input_size + 1000 ) );
4561
4562           /* Set OUTPUT buffer control variables... */
4563
4564           gzp->output_ismem_obuf    = gz1_ismem_obuf;
4565           gzp->output_ismem_obuflen = input_size + 1000;
4566          }
4567
4568       }/* End 'if ( input_size <= conf->maximum_inmem_size )' */
4569
4570     /*
4571      * If we are unable ( or it is unadvisable ) to use
4572      * an in-memory output buffer at this time then the
4573      * 'gzp->output_ismem' flag will still be ZERO at this point.
4574      */
4575
4576     if ( gzp->output_ismem != 1 )
4577       {
4578        /*
4579         * The input source is NOT small enough to compress to an
4580         * in-memory output buffer or it is unadvisable to do
4581         * so at this time so just use an output file...
4582         */
4583
4584        #ifdef MOD_GZIP_DEBUG1
4585        mod_gzip_printf( "%s: Input source too big for in-memory compression.\n",cn);
4586        #endif
4587
4588        /*
4589         * Create the GZP output target name...
4590         */
4591
4592        mod_gzip_create_unique_filename(
4593        (mod_gzip_conf *) conf,
4594        (char *) gzp->output_filename,
4595        MOD_GZIP_MAX_PATH_LEN
4596        );
4597
4598        /*
4599         * COMPRESSION OBJECT CACHE
4600         *
4601         * TODO: Obviously one place to add the compression cache
4602         * logic is right here. If there is already a pre-compressed
4603         * version of the requested entity sitting in the special
4604         * compression cache and it is 'fresh' then go ahead and
4605         * send it as the actual response. Add a CRC/MD5 checksum
4606         * to the stored compression object(s) so we can quickly
4607         * determine if the compressed object is 'fresh'. Relying
4608         * on Content-length and/or modification time/date won't handle
4609         * all possible expiration scenarios for compressed objects.
4610         */
4611
4612        gzp->output_ismem = 0; /* Output is a disk file */
4613
4614        gz1_ismem_obuf    = 0; /* Make sure this is NULL */
4615
4616        /* Set OUTPUT buffer control variables... */
4617
4618        gzp->output_ismem_obuf    = 0; /* Not used for this method */
4619        gzp->output_ismem_obuflen = 0; /* Not used for this method */
4620
4621       }/* End 'else' */
4622
4623     #ifdef MOD_GZIP_DEBUG1
4624     mod_gzip_printf( "%s: gzp->decompress      = %d\n"  ,cn,gzp->decompress);
4625     mod_gzip_printf( "%s: gzp->compression_format = %d\n",cn,gzp->compression_format);
4626     mod_gzip_printf( "%s: gzp->input_ismem     = %d\n",  cn,gzp->input_ismem);
4627     mod_gzip_printf( "%s: gzp->output_ismem    = %d\n",  cn,gzp->output_ismem);
4628     mod_gzip_printf( "%s: gzp->input_filename  = [%s]\n",cn,gzp->input_filename);
4629     mod_gzip_printf( "%s: gzp->output_filename = [%s]\n",cn,gzp->output_filename);
4630     mod_gzip_printf( "%s: Call gzp_main()...\n",cn);
4631     #endif
4632
4633     rc = gzp_main( gzp ); /* Perform the compression... */
4634
4635     output_size = (long) gzp->bytes_out;
4636
4637     #ifdef MOD_GZIP_DEBUG1
4638     mod_gzip_printf( "%s: Back gzp_main()...\n",cn);
4639     mod_gzip_printf( "%s: input_size     = %ld\n",cn,(long)input_size);
4640     mod_gzip_printf( "%s: output_size    = %ld\n",cn,(long)output_size);
4641     mod_gzip_printf( "%s: gzp->bytes_out = %ld\n",cn,(long)gzp->bytes_out);
4642     mod_gzip_printf( "%s: Bytes saved    = %ld\n",cn,
4643                      (long)input_size-gzp->bytes_out );
4644     #endif
4645
4646     /* Compute the compresion ratio for access.log and */
4647     /* internal statistics update... */
4648
4649     compression_ratio = 0; /* Reset */
4650
4651     /* Prevent 'Divide by zero' error... */
4652
4653     if ( ( input_size  > 0 ) &&
4654          ( output_size > 0 ) )
4655       {
4656        compression_ratio = 100 - (int)
4657        ( output_size * 100L / input_size );
4658       }
4659
4660     #ifdef MOD_GZIP_DEBUG1
4661     mod_gzip_printf( "%s: Compression ratio = %ld percent\n",cn,
4662              (long) compression_ratio );
4663     #endif
4664
4665     /*
4666      * Update the logs with output size information
4667      * as soon as it is known in case there was an
4668      * error or we must DECLINE. At least the logs
4669      * will then show the sizes and the results.
4670      */
4671
4672     #ifdef MOD_GZIP_USES_APACHE_LOGS
4673
4674     sprintf( log_info,"%d", (int) output_size );
4675     ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info));
4676
4677     sprintf( log_info,"%d", (int) compression_ratio );
4678     ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info));
4679
4680     #endif /* MOD_GZIP_USES_APACHE_LOGS */
4681
4682     /*
4683      * Evaluate the compression result(s)...
4684      *
4685      * If the compression pass failed then the output length
4686      * will be ZERO bytes...
4687      */
4688
4689     if ( output_size < 1 )
4690       {
4691        #ifdef MOD_GZIP_DEBUG1
4692        mod_gzip_printf( "%s: Compressed version has no length.\n",cn);
4693        mod_gzip_printf( "%s: Sending the original version uncompressed...\n",cn);
4694        #endif
4695
4696        finalize_stats = 0; /* Don't update stats again */
4697
4698        if ( r->server->loglevel == APLOG_DEBUG )
4699          {
4700           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
4701           "mod_gzip: gzp_main(ERR): r->uri=[%s] input_size=%ld output_size=%ld gzp->output_filename=[%s]",
4702            r->uri,(long)input_size,(long)output_size,gzp->output_filename);
4703          }
4704
4705        /*
4706         * NOTE: It's perfectly possible that we have made it all
4707         * the way to here and the straight execution of the
4708         * compressor is the first time there has been a check for
4709         * the actual existence of the requested object. This will
4710         * be especially true for STATIC requests.
4711         *
4712         * The compressor itself will fail if/when it can't find
4713         * the input target so 'DECLINED:NO_O_LEN' could simply
4714         * means the file was not found. In these cases the Apache
4715         * logs should also contain the correct '404 Not Found' code.
4716         */
4717
4718        #ifdef MOD_GZIP_USES_APACHE_LOGS
4719
4720        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4721
4722        ap_table_setn(
4723        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_O_LEN"));
4724
4725        #endif /* MOD_GZIP_USES_APACHE_LOGS */
4726
4727        /* Is it OK to DECLINE?... */
4728
4729        if ( nodecline ) /* We have been told NOT to DECLINE... */
4730          {
4731           #ifdef MOD_GZIP_DEBUG1
4732           mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn);
4733           #endif
4734
4735           /* Just set the output control skid */
4736           /* to send the real input data... */
4737
4738           output_size = input_size;
4739
4740           if ( source_is_a_file ) /* Source is a workfile... */
4741             {
4742              strcpy( gzp->output_filename, source );
4743
4744              gzp->output_ismem         = 0; /* Output is a disk file */
4745              gz1_ismem_obuf            = 0; /* Make sure this is NULL */
4746              gzp->output_ismem_obuf    = 0; /* Not used for this method */
4747              gzp->output_ismem_obuflen = 0; /* Not used for this method */
4748
4749              ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4750
4751              if ( !ifh ) /* We really must DECLINE... */
4752                {
4753                 return( rc );
4754                }
4755             }
4756           else /* Source is just a memory buffer... */
4757             {
4758              gzp->output_ismem = 1;
4759              gz1_ismem_obuf    = source;
4760             }
4761
4762           #ifdef MOD_GZIP_DEBUG1
4763           mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn);
4764           #endif
4765
4766           goto mod_gzip_encode_and_transmit_send_start; /* Jump */
4767          }
4768        else /* It's OK to DECLINE the processing... */
4769          {
4770           #ifdef MOD_GZIP_DEBUG1
4771           mod_gzip_printf( "%s: DECLINE is allowed...\n",cn);
4772           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
4773           #endif
4774
4775           /* Free the local memory buffer allocation ( if necessary )... */
4776
4777           if ( gz1_ismem_obuf )
4778             {
4779              /* The pointer may have been 'borrowed' and was */
4780              /* not actually 'allocated' so check the flag... */
4781
4782              if ( gz1_ismem_obuf_was_allocated )
4783                {
4784                 free( gz1_ismem_obuf );
4785
4786                 gz1_ismem_obuf = 0;
4787                 gz1_ismem_obuf_was_allocated = 0;
4788
4789                }/* End 'if( gz1_ismem_obuf_was_allocated )' */
4790
4791             }/* End 'if( gz1_ismem_obuf )' */
4792
4793           /* Return... */
4794
4795           return DECLINED;
4796          }
4797
4798       }/* End 'if( output_size < 1 )' */
4799
4800     /*
4801      * If we reach this point then the compressed version has
4802      * a valid length. Time to see if it it's worth sending.
4803      *
4804      * If the original source is SMALLER than the COMPRESSED
4805      * version ( not likely but possible with LZ77 ) then
4806      * just punt and send the original source...
4807      */
4808
4809     if ( output_size > input_size )
4810       {
4811        #ifdef MOD_GZIP_DEBUG1
4812        mod_gzip_printf( "%s: Compressed version is larger than original.\n",cn);
4813        mod_gzip_printf( "%s: Sending the original version uncompressed...\n",cn);
4814        #endif
4815
4816        finalize_stats = 0; /* Don't update stats again */
4817
4818        #ifdef MOD_GZIP_USES_APACHE_LOGS
4819
4820        /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4821
4822        ap_table_setn(
4823        r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:ORIGINAL_SMALLER"));
4824
4825        #endif /* MOD_GZIP_USES_APACHE_LOGS */
4826
4827        /* Is it OK to DECLINE?... */
4828
4829        if ( nodecline ) /* We have been told NOT to DECLINE... */
4830          {
4831           #ifdef MOD_GZIP_DEBUG1
4832           mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn);
4833           #endif
4834
4835           /* Just set the output control skid */
4836           /* to send the real input data... */
4837
4838           output_size = input_size;
4839
4840           if ( source_is_a_file ) /* Source is a workfile... */
4841             {
4842              strcpy( gzp->output_filename, source );
4843
4844              gzp->output_ismem         = 0; /* Output is a disk file */
4845              gz1_ismem_obuf            = 0; /* Make sure this is NULL */
4846              gzp->output_ismem_obuf    = 0; /* Not used for this method */
4847              gzp->output_ismem_obuflen = 0; /* Not used for this method */
4848
4849              ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4850
4851              if ( !ifh ) /* We really must DECLINE... */
4852                {
4853                 return( rc );
4854                }
4855             }
4856           else /* Source is just a memory buffer... */
4857             {
4858              gzp->output_ismem = 1;
4859              gz1_ismem_obuf    = source;
4860
4861              gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */
4862             }
4863
4864           #ifdef MOD_GZIP_DEBUG1
4865           mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn);
4866           #endif
4867
4868           goto mod_gzip_encode_and_transmit_send_start; /* Jump */
4869          }
4870        else /* It's OK to DECLINE the processing... */
4871          {
4872           #ifdef MOD_GZIP_DEBUG1
4873           mod_gzip_printf( "%s: DECLINE is allowed...\n",cn);
4874           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
4875           #endif
4876
4877           /* Free the local memory buffer allocation ( if necessary )... */
4878
4879           if ( gz1_ismem_obuf )
4880             {
4881              /* The pointer may have been 'borrowed' and was */
4882              /* not actually 'allocated' so check the flag... */
4883
4884              if ( gz1_ismem_obuf_was_allocated )
4885                {
4886                 free( gz1_ismem_obuf );
4887
4888                 gz1_ismem_obuf = 0;
4889                 gz1_ismem_obuf_was_allocated = 0;
4890
4891                }/* End 'if( gz1_ismem_obuf_was_allocated )' */
4892
4893             }/* End 'if( gz1_ismem_obuf )' */
4894
4895           /* Return... */
4896
4897           return DECLINED;
4898          }
4899       }
4900     else /* Compressed version is smaller than original... */
4901       {
4902        #ifdef MOD_GZIP_DEBUG1
4903        mod_gzip_printf( "%s: Compressed version is smaller than original.\n",cn);
4904        mod_gzip_printf( "%s: Sending the compressed version...\n",cn);
4905        #endif
4906       }
4907
4908     /*
4909      * If an output workfile was used then make SURE it is going
4910      * to reopen before beginning the transmit phase.
4911      *
4912      * If we begin the transmit phase before discovering a problem
4913      * re-opening the workfile then we have lost the chance to
4914      * DECLINE the processing and allow the default logic to
4915      * deliver the requested object.
4916      *
4917      * This only matters for 'static' files or times when the
4918      * 'nodecline' flag is FALSE and it is actually OK to DECLINE.
4919      */
4920
4921     if ( !gzp->output_ismem ) /* Workfile was used... */
4922       {
4923        #ifdef MOD_GZIP_DEBUG1
4924        mod_gzip_printf( "%s: Opening compressed output file [%s]...\n",
4925                 cn, gzp->output_filename );
4926        #endif
4927
4928        ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4929
4930        if ( !ifh ) /* The file failed to open... */
4931          {
4932           #ifdef MOD_GZIP_DEBUG1
4933           mod_gzip_printf( "%s: ERROR: Cannot re-open file [%s]\n",
4934                    cn,gzp->output_filename);
4935           #endif
4936
4937           /* We really must DECLINE... */
4938           /* Logs have already been updated... */
4939
4940           #ifdef MOD_GZIP_DEBUG1
4941           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
4942           #endif
4943
4944           return DECLINED;
4945
4946          }/* End 'if ( !ifh )' */
4947
4948        #ifdef MOD_GZIP_DEBUG1
4949        mod_gzip_printf( "%s: Workile re-opened OK...\n",cn);
4950        #endif
4951
4952       }/* End 'if ( !gzp->output_ismem )' */
4953
4954     /*
4955      * IMPORTANT
4956      *
4957      * If we have made it to here then all is well and only
4958      * now can we set the encoding for this response...
4959      *
4960      * We must do this 'above' any jump points that might
4961      * be sending the 'untouched' data or the browser will
4962      * get confused regarding the actual content.
4963      */
4964
4965     r->content_encoding = actual_content_encoding_name;
4966
4967     #ifdef MOD_GZIP_DEBUG1
4968     mod_gzip_printf( "%s: r->content_encoding is now [%s]\n",
4969                       cn, r->content_encoding );
4970     #endif
4971
4972     /*
4973      * Begin the transmission phase...
4974      *
4975      * Even if the 'nodecline' flag is TRUE if we encounter
4976      * any fatal errors at this point we must 'DECLINE'.
4977      */
4978
4979     mod_gzip_encode_and_transmit_send_start: ; /* <<-- Jump point */
4980
4981     #ifdef MOD_GZIP_DEBUG1
4982     mod_gzip_printf( "%s: Starting transmit phase...\n",cn);
4983     #endif
4984
4985     /*
4986      * We are ready to send content so update the "Content-length:"
4987      * response field and send the HTTP header. We don't need to
4988      * worry about setting the "Content-type:" field since we are
4989      * simply accepting the value that was passed to us as indicated
4990      * by the inbound r->content_type string. The "Content-type:"
4991      * field never changes even when multiple encodings have been
4992      * applied to the content itself.
4993      *
4994      * This version does not make any attempt to use 'Chunked'
4995      * transfer encoding since there are so many user agents that
4996      * do not support it and when Content-length is known prior
4997      * to header transmission ( as is always the case with this
4998      * code ) then there is simply no reason to even think about
4999      * using the slower and more problematic 'Chunked' encoding
5000      * transfer method.
5001      */
5002
5003     /*
5004      * Set relevant outbound response header fields...
5005      *
5006      * Be sure to call ap_update_mtime() before calling
5007      * ap_set_last_modified() to be sure the 'current'
5008      * time is actually updated in outbound response header.
5009      */
5010
5011     ap_update_mtime( r, r->finfo.st_mtime );
5012     ap_set_last_modified(r);
5013     ap_set_etag(r);
5014     ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
5015
5016     /*
5017      * Start a timer for this transaction...
5018      */
5019
5020     ap_soft_timeout( "mod_gzip: Encoded data transmit", r );
5021
5022     /*
5023      * Return the length of the compressed output in
5024      * the response header.
5025      *
5026      * See notes above about there never being a requirement
5027      * to use 'Chunked' transfer encoding since the content
5028      * length is always 'known' prior to transmission.
5029      */
5030
5031     sprintf( content_length, "%ld", output_size );
5032     ap_table_set (r->headers_out, "Content-Length", content_length );
5033
5034     #ifdef MOD_GZIP_DEBUG1
5035     mod_gzip_printf( "%s: output_size     = %ld\n",cn,(long)output_size);
5036     mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type);
5037     mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn);
5038     #endif
5039
5040     ap_send_http_header(r);
5041
5042     #ifdef MOD_GZIP_DEBUG1
5043     mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn);
5044     #endif
5045
5046         /*
5047      * Send the response...
5048      *
5049      * If the requested object was small enough to fit into
5050      * our special in-memory output space then send the result
5051      * directly from memory. If the requested object exceeded
5052      * the minimum size for in-memory compression then an output
5053      * file was used so re-open and send the results file...
5054      */
5055
5056     if ( gzp->output_ismem )
5057       {
5058        /* Send the in-memory output buffer... */
5059
5060        #ifdef MOD_GZIP_DEBUG1
5061
5062        mod_gzip_printf( "%s: Sending the in-memory output buffer...\n",cn);
5063        mod_gzip_printf( "%s: output_size = %ld\n",cn,(long)output_size);
5064
5065        /* Turn this 'on' for VERY verbose diagnostics...
5066        #define MOD_GZIP_DUMP_JUST_BEFORE_SENDING
5067        */
5068        #ifdef  MOD_GZIP_DUMP_JUST_BEFORE_SENDING
5069        mod_gzip_hexdump( gz1_ismem_obuf, output_size );
5070        #endif
5071
5072        #endif /* MOD_GZIP_DEBUG1 */
5073
5074        /* This module can use either ap_send_mmap() or ap_rwrite()... */
5075
5076        #ifdef MOD_GZIP_USES_AP_SEND_MMAP
5077
5078        /* Use ap_send_mmap() call to send the data... */
5079
5080        #ifdef MOD_GZIP_DEBUG1
5081        mod_gzip_printf( "%s: Call ap_send_mmap( gz1_ismem_obuf, bytes=%ld )...\n",
5082                 cn, (long)output_size );
5083        #endif
5084
5085        ap_send_mmap( gz1_ismem_obuf, r, 0, output_size );
5086
5087        #ifdef MOD_GZIP_DEBUG1
5088        mod_gzip_printf( "%s: Back ap_send_mmap( gz1_ismem_obuf, bytes=%ld )...\n",
5089                 cn, (long)output_size );
5090        #endif
5091
5092        #else /* !MOD_GZIP_USES_AP_SEND_MMAP */
5093
5094        /* Use ap_rwrite() call to send the data... */
5095
5096        #ifdef MOD_GZIP_DEBUG1
5097        mod_gzip_printf( "%s: Call ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n",
5098                 cn, (long)output_size );
5099        #endif
5100
5101        ap_rwrite( gz1_ismem_obuf, output_size, r );
5102
5103        #ifdef MOD_GZIP_DEBUG1
5104        mod_gzip_printf( "%s: Back ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n",
5105                 cn, (long)output_size );
5106        #endif
5107
5108        #endif /* MOD_GZIP_USES_AP_SEND_MMAP */
5109
5110        /* Stop the timer... */
5111
5112        #ifdef MOD_GZIP_DEBUG1
5113        mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn);
5114        #endif
5115
5116        ap_kill_timeout(r);
5117
5118        #ifdef MOD_GZIP_DEBUG1
5119        mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn);
5120        #endif
5121
5122        /* Free the local memory buffer allocation ( if necessary )... */
5123
5124        if ( gz1_ismem_obuf )
5125          {
5126           /* The pointer may have been 'borrowed' and was */
5127           /* not actually 'allocated' so check the flag... */
5128
5129           if ( gz1_ismem_obuf_was_allocated )
5130             {
5131              free( gz1_ismem_obuf );
5132
5133              gz1_ismem_obuf = 0;
5134              gz1_ismem_obuf_was_allocated = 0;
5135
5136             }/* End 'if( gz1_ismem_obuf_was_allocated )' */
5137
5138          }/* End 'if( gz1_ismem_obuf )' */
5139       }
5140     else /* Output workfile was used so send the contents... */
5141       {
5142        /*
5143         * NOTE: The workfile was already 're-opened' up above
5144         * before the transmit phase began so that we still had
5145         * the chance to return DECLINED if, for some reason, the
5146         * workfile could not be re-opened.
5147         */
5148
5149        #ifdef MOD_GZIP_DEBUG1
5150        mod_gzip_printf( "%s: sizeof( tmp )        = %d\n",cn,sizeof(tmp));
5151        mod_gzip_printf( "%s: Transmit buffer size = %d\n",cn,sizeof(tmp));
5152        mod_gzip_printf( "%s: Sending compressed output file...\n",cn);
5153        #endif
5154
5155        for (;;)
5156           {
5157            bytesread = fread( tmp, 1, sizeof( tmp ), ifh );
5158
5159            #ifdef MOD_GZIP_DEBUG1
5160            mod_gzip_printf( "%s: Back fread(): bytesread=%d\n",cn,bytesread);
5161            #endif
5162
5163            if ( bytesread < 1 ) break; /* File is exhausted... We are done...*/
5164
5165            /* This module can use either ap_send_mmap() or ap_rwrite()... */
5166
5167            #ifdef MOD_GZIP_USES_AP_SEND_MMAP
5168
5169            /* Use ap_send_mmap() call to send the data... */
5170
5171            ap_send_mmap( tmp, r, 0, bytesread );
5172
5173            #else /* !MOD_GZIP_USES_AP_SEND_MMAP */
5174
5175            /* Use ap_rwrite() call to send the data... */
5176
5177            ap_rwrite( tmp, bytesread, r );
5178
5179            #endif /* MOD_GZIP_USES_AP_SEND_MMAP */
5180           }
5181
5182        #ifdef MOD_GZIP_DEBUG1
5183        mod_gzip_printf( "%s: Done Sending compressed output file...\n",cn);
5184        mod_gzip_printf( "%s: Closing workfile [%s]...\n",
5185                 cn, gzp->output_filename );
5186        #endif
5187
5188        fclose( ifh ); /* Close the input file */
5189
5190        /* Stop the timer before attempting to delete the workfile... */
5191
5192        #ifdef MOD_GZIP_DEBUG1
5193        mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn);
5194        #endif
5195
5196        ap_kill_timeout(r);
5197
5198        #ifdef MOD_GZIP_DEBUG1
5199        mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn);
5200        #endif
5201
5202        /* Delete the workfile if 'keep' flag is OFF... */
5203
5204        #ifdef MOD_GZIP_DEBUG1
5205        mod_gzip_printf( "%s: conf->keep_workfiles = %d\n",
5206                          cn, conf->keep_workfiles );
5207        #endif
5208
5209        if ( !conf->keep_workfiles ) /* Default is OFF */
5210          {
5211           #ifdef MOD_GZIP_DEBUG1
5212           mod_gzip_printf( "%s: Deleting workfile [%s]...\n",
5213                    cn, gzp->output_filename );
5214           #endif
5215
5216           #ifdef WIN32
5217           DeleteFile( gzp->output_filename );
5218           #else /* !WIN32 */
5219           unlink( gzp->output_filename );
5220           #endif /* WIN32 */
5221          }
5222        else /* Keep all work files... */
5223          {
5224           #ifdef MOD_GZIP_DEBUG1
5225           mod_gzip_printf( "%s: Keeping workfile [%s]...\n",
5226                    cn, gzp->output_filename );
5227           #endif
5228          }
5229
5230       }/* End 'else' that sends compressed workfile */
5231
5232     /*
5233      * The compressed object has been sent...
5234      */
5235
5236     #ifdef MOD_GZIP_USES_APACHE_LOGS
5237
5238     if ( finalize_stats )
5239       {
5240        sprintf( log_info,"%d", (int) output_size );
5241        ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info));
5242
5243        sprintf( log_info,"%d", (int) compression_ratio );
5244        ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info));
5245
5246       }
5247     #endif /* MOD_GZIP_USES_APACHE_LOGS */
5248
5249     if ( r->server->loglevel == APLOG_DEBUG )
5250       {
5251        /*
5252         * If LogLevel is 'debug' then show the compression results
5253         * in the log(s)...
5254         */
5255
5256        ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5257        "mod_gzip: r->uri=[%s] OK: Bytes In:%ld Out:%ld Compression: %ld pct.",
5258        r->uri,
5259        (long) input_size,
5260        (long) output_size,
5261        (long) compression_ratio
5262        );
5263
5264       }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */
5265
5266     /*
5267      * Return OK to the Server to indicate SUCCESS...
5268      */
5269
5270     #ifdef MOD_GZIP_DEBUG1
5271     mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn);
5272     #endif
5273
5274     return OK;
5275
5276 }/* End of mod_gzip_encode_and_transmit() */
5277
5278 int mod_gzip_ismatch( char *s1, char *s2, int len1, int haswilds )
5279 {
5280  /* Behaves just like strncmp() but IGNORES differences     */
5281  /* between FORWARD or BACKWARD slashes in a STRING, allows */
5282  /* wildcard matches, and can ignore length value.          */
5283  /* It uses pointers and is faster than using lib calls.    */
5284
5285  /* Unlike strncmp() this routine returns TRUE (1) if the   */
5286  /* strings match and FALSE (0) if they do not...           */
5287
5288  int  i;
5289  int  l1;
5290  int  l2;
5291  int  distance;
5292  char ch1;
5293  char ch2;
5294
5295  /* WARNING! We MUST have a check for 'NULL' on the pointer(s) */
5296  /*          themselves or we might GP */
5297
5298  if ( ( s1 == 0 ) || ( s2 == 0 ) )
5299    {
5300     /* SAFETY! If pointer itself if NULL */
5301     /* don't enter LOOP... */
5302
5303     return( 0 ); /* Return FALSE for NOMATCH...  */
5304    }
5305
5306  distance = len1; /* Default to value passed... */
5307
5308  /* If no length was given then the 2 strings must already */
5309  /* have the same length or this is a 'no match'... */
5310  /* Exception to this is if wildcards are present. */
5311
5312  if ( len1 == 0 )
5313    {
5314     l1 = strlen( s1 );
5315     l2 = strlen( s2 );
5316
5317     /* If either string had a valid pointer but is EMPTY */
5318     /* then this is an automatic 'no match'... */
5319
5320     if ((l1==0)||(l2==0))
5321       {
5322        return( 0 ); /* Return FALSE for NOMATCH...  */
5323       }
5324
5325     if ( l1 != l2  )
5326       {
5327        if ( haswilds == 0 )
5328          {
5329           return( 0 ); /* Return FALSE for NOMATCH...  */
5330          }
5331       }
5332
5333     /* If the lengths ARE equal then this is a possible */
5334     /* match. Use the smaller of the 2 values for scan...*/
5335
5336     if ( l1 < l2 ) distance = l1;
5337     else           distance = l2;
5338    }
5339
5340  /* Final check... if distance is still 0 then this */
5341  /* is an automatic 'no match'... */
5342
5343  if ( distance == 0 )
5344    {
5345     return( 0 ); /* Return FALSE for NOMATCH...  */
5346    }
5347
5348  /* Do the deed... */
5349
5350  for ( i=0; i<distance; i++ )
5351     {
5352      /* If we encounter a null in either string before we */
5353      /* have 'gone the distance' then the strings don't match... */
5354
5355      if ( ( *s1 == 0 ) || ( *s2 == 0 ) ) return( 0 ); /* No match! */
5356
5357      ch1 = *s1;
5358      ch2 = *s2;
5359
5360      if ( ( ch1 == '*' ) || ( ch2 == '*' ) )
5361        {
5362         /* If we are still here and wildcards are allowed */
5363         /* then the first one seen in either string causes */
5364         /* us to return SUCCESS... */
5365
5366         if ( haswilds )
5367           {
5368            return( 1 ); /* Wildcard match was OK this time... */
5369           }
5370        }
5371
5372      if ( ch1 == '/' ) ch1 = '\\';
5373      if ( ch2 == '/' ) ch2 = '\\';
5374
5375      if ( ch1 != ch2 ) return( 0 ); /* No match! */
5376
5377      s1++;
5378      s2++;
5379
5380     }/* End 'i' loop */
5381
5382  /* If we make it to here then everything MATCHED! */
5383
5384  return( 1 ); /* MATCH! */
5385
5386 }/* End mod_gzip_ismatch() */
5387
5388 int mod_gzip_get_action_flag( request_rec *r, mod_gzip_conf *mgc )
5389 {
5390     int   x    = 0;
5391     int   pass = 0;
5392     int   clen = 0;
5393     int   hlen = 0;
5394     int   flen = 0;
5395
5396     int   pass_result        = 0;
5397     int   filter_value       = 0;
5398     int   item_is_included   = 0;
5399     int   item_is_excluded   = 0;
5400     int   action_flag        = 0;
5401     int   this_type          = 0;
5402     int   this_action        = 0;
5403     char *this_name          = 0;
5404     char *file_extension     = 0;
5405     int   file_extension_len = 0;
5406     char *p1                 = 0;
5407
5408     #ifdef MOD_GZIP_DEBUG1
5409     char cn[]="mod_gzip_get_action_flag()";
5410     #endif
5411
5412     /*
5413      * Start...
5414      */
5415
5416     if ( r->content_type ) clen = strlen( r->content_type );
5417     if ( r->handler      ) hlen = strlen( r->handler );
5418
5419     if ( r->filename )
5420       {
5421        flen = strlen( r->filename );
5422        p1   = r->filename;
5423        while(*p1!=0){if (*p1=='.') file_extension=p1; p1++;}
5424        if ( file_extension ) file_extension_len = strlen( file_extension );
5425       }
5426
5427     #ifdef MOD_GZIP_DEBUG1
5428
5429     mod_gzip_printf( "%s: Entry...\n",cn);
5430     mod_gzip_printf( "%s: r->content_type    = [%s]\n",cn,r->content_type);
5431     mod_gzip_printf( "%s: clen               = %d\n",  cn,clen);
5432     mod_gzip_printf( "%s: r->handler         = [%s]\n",cn,r->handler);
5433     mod_gzip_printf( "%s: hlen               = %d\n",  cn,hlen);
5434     mod_gzip_printf( "%s: r->filename        = [%s]\n",cn,r->filename);
5435     mod_gzip_printf( "%s: flen               = %d\n",  cn,flen);
5436     mod_gzip_printf( "%s: file_extension     = [%s]\n",cn,file_extension);
5437     mod_gzip_printf( "%s: file_extension_len = %d\n",  cn,file_extension_len);
5438
5439     #endif /* MOD_GZIP_DEBUG1 */
5440
5441     /*
5442      * Sanity checks...
5443      */
5444
5445     if ( ( hlen == 0 ) && ( clen == 0 ) )
5446       {
5447        /*
5448         * If the header analysis and/or negotiation phase has
5449         * determined this to be a CGI script then the r->content_type
5450         * field will be (null) but r->handler will contain "cgi-script".
5451         * or "php-script" or the like.
5452         *
5453         * If the analysis has determined this is a static file
5454         * then r->handler will be (null) but the r->content_type
5455         * field will be "text/html" or "text/plain" or whatever.
5456         *
5457         * Both the r->content_type field and the r->handler
5458         * field are empty. Ignore this one...
5459         */
5460
5461        #ifdef MOD_GZIP_DEBUG1
5462        mod_gzip_printf( "%s: Both hlen and clen are ZERO...\n",cn);
5463        mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn);
5464        #endif
5465
5466        if ( r->server->loglevel == APLOG_DEBUG )
5467          {
5468           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5469           "mod_gzip: There is no valid r->handler or r->content_length ");
5470          }
5471
5472        return( MOD_GZIP_IMAP_DECLINED1 );
5473       }
5474
5475     /*
5476      * Perform 2 passes at the Include/Exclude list...
5477      *
5478      * The first  pass is the higher-priority EXCLUSION check.
5479      * The second pass is the lower-priority  INCLUSION check.
5480      */
5481
5482     for ( pass=0; pass<2; pass++ )
5483     {
5484
5485     pass_result = 0; /* Reset result */
5486
5487     if ( pass == 0 ) /* EXCLUSION CHECK */
5488       {
5489        filter_value = 0;
5490
5491        #ifdef MOD_GZIP_DEBUG1
5492        mod_gzip_printf( "%s: EXCLUSION CHECK...\n",cn);
5493        #endif
5494       }
5495     else if ( pass == 1 ) /* INCLUSION CHECK */
5496       {
5497        filter_value = 1;
5498
5499        #ifdef MOD_GZIP_DEBUG1
5500        mod_gzip_printf( "%s: INCLUSION CHECK...\n",cn);
5501        #endif
5502       }
5503
5504     #ifdef MOD_GZIP_DEBUG1
5505     mod_gzip_printf( "%s: pass = %d\n", cn, pass );
5506     mod_gzip_printf( "%s: filter_value = %d\n", cn, filter_value );
5507     mod_gzip_printf( "%s: mgc->imap_total_entries = %d\n", cn,
5508                     (int) mgc->imap_total_entries );
5509     #endif
5510
5511     for ( x=0; x<mgc->imap_total_entries; x++ )
5512        {
5513         if ( r->server->loglevel == APLOG_DEBUG )
5514           {
5515            /* Show the lookups in the Apache ERROR log if DEBUG is on */
5516
5517            ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5518            "mod_gzip: mgc->imap[%3.3d] = i%2.2d t%4.4d a%4.4d n[%s]",
5519             x,
5520             mgc->imap[x].include,
5521             mgc->imap[x].type,
5522             mgc->imap[x].action,
5523             mgc->imap[x].name
5524             );
5525           }
5526
5527         #ifdef MOD_GZIP_DEBUG1
5528
5529         mod_gzip_printf( "%s: --------------------------------------------\n",cn);
5530         mod_gzip_printf( "%s: r->handler      = [%s]\n",cn,r->handler);
5531         mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type);
5532         mod_gzip_printf( "%s: r->filename     = [%s]\n",cn,r->filename);
5533         mod_gzip_printf( "%s: file_extension  = [%s]\n",cn,file_extension);
5534         mod_gzip_printf( "%s: mgc->imap[%3.3d].include = %d\n",cn,x,mgc->imap[x].include);
5535         mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = %d\n",cn,x,mgc->imap[x].type);
5536
5537         if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME )
5538           {
5539            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_ISMIME\n",cn,x);
5540           }
5541         else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT )
5542           {
5543            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_ISEXT\n",cn,x);
5544           }
5545         else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER )
5546           {
5547            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_ISHANDLER\n",cn,x);
5548           }
5549         else /* Unrecognized item type... */
5550           {
5551            mod_gzip_printf( "%s: mgc->imap[%3.3d].type    = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x);
5552           }
5553
5554         mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = %d\n",  cn,x,mgc->imap[x].action);
5555
5556         if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 )
5557           {
5558            mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x);
5559           }
5560         else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 )
5561           {
5562            mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = MOD_GZIP_IMAP_STATIC1\n",cn,x);
5563           }
5564         else /* Unrecognized action type... */
5565           {
5566            mod_gzip_printf( "%s: mgc->imap[%3.3d].action  = MOD_GZIP_IMAP_??? Unknown action\n",cn,x);
5567           }
5568
5569         mod_gzip_printf( "%s: mgc->imap[%3.3d].name    = [%s]\n",cn,x,mgc->imap[x].name);
5570
5571         #endif /* MOD_GZIP_DEBUG1 */
5572
5573         /* 'filter_value' mirrors 'pass' value for now but this might */
5574         /* not always be true. First pass is EXCLUDE and second is INCLUDE */
5575
5576         if ( mgc->imap[x].include == filter_value )
5577           {
5578            #ifdef MOD_GZIP_DEBUG1
5579            mod_gzip_printf( "%s: This record matches filter_value %d\n",
5580                              cn, filter_value );
5581            mod_gzip_printf( "%s: The record will be checked...\n",cn);
5582            #endif
5583
5584            /*
5585             * Set work values for this record...
5586             */
5587
5588            this_type   = mgc->imap[x].type;
5589            this_action = mgc->imap[x].action;
5590            this_name   = mgc->imap[x].name;
5591
5592            /*
5593             * If the header analysis and/or negotiation phase has
5594             * determined this to be a CGI script then the r->content_type
5595             * field will be (null) but r->handler will contain "cgi-script".
5596             *
5597             * If the analysis has determined this is a static file
5598             * then r->handler will be (null) but the r->content_type
5599             * field will be "text/html" or "text/plain" or whatever.
5600             */
5601
5602            if ( hlen > 0 ) /* r->handler field has a value... */
5603              {
5604               #ifdef MOD_GZIP_DEBUG1
5605               mod_gzip_printf( "%s: hlen has value...\n",cn);
5606               #endif
5607
5608               if ( this_type == MOD_GZIP_IMAP_ISHANDLER )
5609                 {
5610                  #ifdef MOD_GZIP_DEBUG1
5611                  mod_gzip_printf( "%s: this_type = ISHANDLER\n",cn);
5612                  mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,0)...\n",
5613                                    cn, this_name, r->handler );
5614                  #endif
5615
5616                  /* mod_gzip_ismatch()... */
5617
5618                  /* The 2 strings must match exactly so  */
5619                  /* pass '0' for parm 3...               */
5620
5621                  /* Wildcard matches are not allowed for */
5622                  /* handler strings like 'cgi-script' so */
5623                  /* Fourth parm should be 0..            */
5624
5625                  if ( mod_gzip_ismatch(
5626                       this_name, (char *)r->handler,0,0) )
5627                    {
5628                     pass_result = 1;           /* We found a match */
5629                     action_flag = this_action; /* What to do */
5630                     break;                     /* Stop now */
5631                    }
5632
5633                 }/* End 'if ( this_type == MOD_GZIP_IMAP_ISHANDLER )' */
5634
5635              }/* End 'if( hlen > 0 )' */
5636
5637            if ( clen > 0 ) /* r->content_type field has a value... */
5638              {
5639               #ifdef MOD_GZIP_DEBUG1
5640               mod_gzip_printf( "%s: clen has value...\n",cn);
5641               #endif
5642
5643               if ( this_type == MOD_GZIP_IMAP_ISMIME )
5644                 {
5645                  #ifdef MOD_GZIP_DEBUG1
5646                  mod_gzip_printf( "%s: this_type = ISMIME\n",cn);
5647                  mod_gzip_printf( "%s: Wildcards matches are OK for MIME types.\n",cn);
5648                  mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,1)...\n",
5649                                    cn, this_name, r->content_type );
5650                  #endif
5651
5652                  /* mod_gzip_ismatch()... */
5653
5654                  /* Wildcard matches are ALLOWED for    */
5655                  /* MIME type strings like 'cgi-script' */
5656                  /* so fourth parm should be 1...       */
5657
5658                  if ( mod_gzip_ismatch(
5659                       this_name, (char *)r->content_type, 0, 1 ) )
5660                    {
5661                     pass_result = 1;           /* We found a match */
5662                     action_flag = this_action; /* What to do */
5663                     break;                     /* Stop now */
5664                    }
5665
5666                 }/* End 'if ( this_type == MOD_GZIP_IMAP_ISMIME )' */
5667
5668              }/* End 'if( clen > 0 )' */
5669
5670            if ( flen > 0 ) /* r->filename field has a value... */
5671              {
5672               #ifdef MOD_GZIP_DEBUG1
5673               mod_gzip_printf( "%s: flen has value...\n",cn);
5674               #endif
5675
5676               if ( this_type == MOD_GZIP_IMAP_ISEXT )
5677                 {
5678                  #ifdef MOD_GZIP_DEBUG1
5679                  mod_gzip_printf( "%s: this_type = ISEXT\n",cn);
5680                  #endif
5681
5682                  if ( file_extension_len > 0 ) /* There is a file extension */
5683                    {
5684                     #ifdef MOD_GZIP_DEBUG1
5685                     mod_gzip_printf( "%s: file_extension_len has value...\n",cn);
5686                     mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,0)...\n",
5687                                       cn, this_name, file_extension );
5688                     #endif
5689
5690                     /* mod_gzip_ismatch()... */
5691
5692                     /* The 2 strings must match exactly so  */
5693                     /* pass '0' for parm 3...               */
5694
5695                     /* Wildcard matches are not allowed for */
5696                     /* file extensions like '.html' so      */
5697                     /* Fourth parm should be 0..            */
5698
5699                     if ( mod_gzip_ismatch(
5700                          this_name, file_extension, 0, 0 ) )
5701                       {
5702                        pass_result = 1;           /* We found a match */
5703                        action_flag = this_action; /* What to do */
5704                        break;                     /* Stop now */
5705                       }
5706
5707                    }/* End 'if( file_extension_len > 0 )' */
5708
5709                 }/* End 'if( this_type == MOD_GZIP)IMAP_ISEXT )' */
5710
5711              }/* End 'if( flen > 0 )' */
5712
5713           }/* End 'if ( mgc->imap[x].include == filter )' */
5714
5715         else /* The record did not match the current 'filter' value... */
5716           {
5717            #ifdef MOD_GZIP_DEBUG1
5718            mod_gzip_printf( "%s: This record does NOT match filter_value %d\n",
5719                              cn, filter_value );
5720            mod_gzip_printf( "%s: The record has been SKIPPED...\n",cn);
5721            #endif
5722           }
5723
5724        }/* End 'x' loop that looks at 'filtered' records... */
5725
5726     #ifdef MOD_GZIP_DEBUG1
5727     mod_gzip_printf( "%s: --------------------------------------------\n",cn);
5728     mod_gzip_printf( "%s: pass_result = %d\n",cn,pass_result);
5729     #endif
5730
5731     if ( pass_result ) /* We are done... */
5732       {
5733        if ( pass == 0 ) item_is_excluded = 1;
5734        else             item_is_included = 1;
5735
5736        break; /* Break out of 'pass' loop now... */
5737       }
5738
5739     }/* End 'pass' loop */
5740
5741     #ifdef MOD_GZIP_DEBUG1
5742     mod_gzip_printf( "%s: item_is_excluded = %d\n",cn,item_is_excluded);
5743     mod_gzip_printf( "%s: item_is_included = %d\n",cn,item_is_included);
5744     mod_gzip_printf( "%s: action_flag      = %d\n",cn,action_flag);
5745     #endif
5746
5747     if ( item_is_excluded )
5748       {
5749        #ifdef MOD_GZIP_DEBUG1
5750        mod_gzip_printf( "%s: The item is excluded...\n",cn);
5751        mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn);
5752        #endif
5753
5754        if ( r->server->loglevel == APLOG_DEBUG )
5755          {
5756           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5757           "mod_gzip: This item is EXCLUDED as per httpd.conf");
5758          }
5759
5760        return( MOD_GZIP_IMAP_DECLINED1 );
5761       }
5762
5763     else if ( item_is_included )
5764       {
5765        #ifdef MOD_GZIP_DEBUG1
5766        mod_gzip_printf( "%s: The item is included...\n",cn);
5767        mod_gzip_printf( "%s: Exit > return( action_flag = %d ) >\n",cn,action_flag);
5768        #endif
5769
5770        if ( r->server->loglevel == APLOG_DEBUG )
5771          {
5772           ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5773           "mod_gzip: This item is INCLUDED as per httpd.conf");
5774          }
5775
5776        return( action_flag ); /* STATIC1 or DYNAMIC1 */
5777       }
5778
5779     /*
5780      * Default action is to DECLINE processing...
5781      */
5782
5783     #ifdef MOD_GZIP_DEBUG1
5784     mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn);
5785     #endif
5786
5787     if ( r->server->loglevel == APLOG_DEBUG )
5788       {
5789        ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5790        "mod_gzip: This item was NOT FOUND in any mod_gzip httpd item record.");
5791        ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5792        "mod_gzip: This item will NOT be processed.");
5793       }
5794
5795     return( MOD_GZIP_IMAP_DECLINED1 );
5796
5797 }/* End of mod_gzip_get_action_flag() */
5798
5799 /*--------------------------------------------------------------------------*/
5800 /* ALL SOURCE CODE BELOW THIS POINT IS COMPRESSION SPECIFIC...              */
5801 /*--------------------------------------------------------------------------*/
5802
5803 #define USE_GATHER
5804 extern MODULE_VAR_EXPORT int ap_suexec_enabled;
5805 extern API_EXPORT(void)
5806 ap_internal_redirect_handler(const char *new_uri, request_rec *);
5807 long mod_gzip_ap_send_fb(
5808 BUFF *fb,
5809 request_rec *r,
5810 int *final_return_code
5811 );
5812 long mod_gzip_ap_send_fb_length(
5813 BUFF *fb,
5814 request_rec *r,
5815 long length,
5816 int *final_return_code
5817 );
5818 #define DEFAULT_LOGBYTES 10385760
5819 #define DEFAULT_BUFBYTES 1024
5820 static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo);
5821 typedef struct {
5822     char *logname;
5823     long logbytes;
5824     int bufbytes;
5825 } cgi_server_conf;
5826 struct mod_gzip_cgi_child_stuff {
5827 #ifdef TPF
5828     TPF_FORK_CHILD t;
5829 #endif
5830     request_rec *r;
5831     int nph;
5832     int debug;
5833     char *argv0;
5834 };
5835 static int is_scriptaliased( request_rec *r )
5836 {
5837  const char *t = ap_table_get(r->notes, "alias-forced-type");
5838  return t && (!strcasecmp(t, "cgi-script"));
5839 }
5840 static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret,
5841            int show_errno, char *error)
5842 {
5843     FILE *f;
5844     struct stat finfo;
5845     ap_log_rerror(APLOG_MARK, show_errno|APLOG_ERR, r, 
5846                 "%s: %s", error, r->filename);
5847     if (!conf->logname ||
5848         ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0)
5849          &&   (finfo.st_size > conf->logbytes)) ||
5850          ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname),
5851                       "a")) == NULL)) {
5852         return ret;
5853     }
5854     fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri,
5855             r->args ? "?" : "", r->args ? r->args : "", r->protocol);
5856     fprintf(f, "%%%% %d %s\n", ret, r->filename);
5857     fprintf(f, "%%error\n%s\n", error);
5858     ap_pfclose(r->pool, f);
5859     return ret;
5860 }
5861 static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
5862                   char *dbuf, const char *sbuf, BUFF *script_in, BUFF *script_err)
5863 {
5864     array_header *hdrs_arr = ap_table_elts(r->headers_in);
5865     table_entry *hdrs = (table_entry *) hdrs_arr->elts;
5866     char argsbuffer[HUGE_STRING_LEN];
5867     FILE *f;
5868     int i;
5869     struct stat finfo;
5870     if (!conf->logname ||
5871         ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0)
5872          &&   (finfo.st_size > conf->logbytes)) ||
5873          ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname),
5874                       "a")) == NULL)) {
5875         while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0)
5876             continue;
5877 #if defined(WIN32) || defined(NETWARE)
5878         while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) {
5879             ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, r, 
5880                           "%s", argsbuffer);            
5881         }
5882 #else
5883         while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0)
5884             continue;
5885 #endif
5886         return ret;
5887     }
5888     fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri,
5889             r->args ? "?" : "", r->args ? r->args : "", r->protocol);
5890     fprintf(f, "%%%% %d %s\n", ret, r->filename);
5891     fputs("%request\n", f);
5892     for (i = 0; i < hdrs_arr->nelts; ++i) {
5893         if (!hdrs[i].key)
5894             continue;
5895         fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
5896     }
5897     if ((r->method_number == M_POST || r->method_number == M_PUT)
5898         && *dbuf) {
5899         fprintf(f, "\n%s\n", dbuf);
5900     }
5901     fputs("%response\n", f);
5902     hdrs_arr = ap_table_elts(r->err_headers_out);
5903     hdrs = (table_entry *) hdrs_arr->elts;
5904     for (i = 0; i < hdrs_arr->nelts; ++i) {
5905         if (!hdrs[i].key)
5906             continue;
5907         fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
5908     }
5909     if (sbuf && *sbuf)
5910         fprintf(f, "%s\n", sbuf);
5911     if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) {
5912         fputs("%stdout\n", f);
5913         fputs(argsbuffer, f);
5914         while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0)
5915             fputs(argsbuffer, f);
5916         fputs("\n", f);
5917     }
5918     if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) {
5919         fputs("%stderr\n", f);
5920         fputs(argsbuffer, f);
5921         while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0)
5922             fputs(argsbuffer, f);
5923         fputs("\n", f);
5924     }
5925     ap_bclose( script_in  );
5926     ap_bclose( script_err );
5927     ap_pfclose(r->pool, f);
5928     return ret;
5929 }
5930 int mod_gzip_cgi_handler( request_rec *r )
5931 {
5932     int bytesread;
5933     int retval, nph, dbpos = 0;
5934     char *argv0, *dbuf = NULL;
5935     BUFF *script_out, *script_in, *script_err;
5936     char argsbuffer[HUGE_STRING_LEN];
5937     int is_included = !strcmp(r->protocol, "INCLUDED");
5938     void *sconf = r->server->module_config;
5939     int final_result = DECLINED;
5940     #define MOD_GZIP_ENGAGED
5941     #ifdef  MOD_GZIP_ENGAGED
5942     cgi_server_conf conf_local;
5943     cgi_server_conf *conf = &conf_local;
5944     char cgi_logname[]="";
5945     #else
5946     cgi_server_conf *conf =
5947     (cgi_server_conf *) ap_get_module_config(sconf, &cgi_module);
5948     #endif
5949     const char *location;
5950     struct mod_gzip_cgi_child_stuff cld;
5951     #ifdef MOD_GZIP_ENGAGED
5952     conf->logname  = cgi_logname;
5953     conf->logbytes = (long) 60000L;
5954     conf->bufbytes = (int)  20000;
5955     #endif 
5956     if ( r->method_number == M_OPTIONS )
5957       {
5958        r->allowed |= (1 << M_GET);
5959        r->allowed |= (1 << M_POST);
5960        return DECLINED;
5961       }
5962     if ((argv0 = strrchr(r->filename, '/')) != NULL)
5963       {
5964        argv0++;
5965       }
5966     else
5967       {
5968        argv0 = r->filename;
5969       }
5970     nph = !(strncmp(argv0, "nph-", 4));
5971     if ( !(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r) )
5972       {
5973        return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
5974               "Options ExecCGI is off in this directory");
5975       }
5976     if ( nph && is_included )
5977       {
5978        return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
5979               "attempt to include NPH CGI script");
5980       }
5981     #if defined(OS2) || defined(WIN32)
5982     if ( r->finfo.st_mode == 0 )
5983       {
5984        struct stat statbuf;
5985        char *newfile;
5986        newfile = ap_pstrcat(r->pool, r->filename, ".EXE", NULL);
5987        if ((stat(newfile, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
5988          {
5989           return log_scripterror(r, conf, NOT_FOUND, 0,
5990                  "script not found or unable to stat");
5991          }
5992        else 
5993          {
5994           r->filename = newfile;
5995          }
5996       }
5997     #else 
5998     if ( r->finfo.st_mode == 0 )
5999       {
6000        return log_scripterror(r, conf, NOT_FOUND, APLOG_NOERRNO,
6001               "script not found or unable to stat");
6002       }
6003     #endif 
6004     if ( S_ISDIR( r->finfo.st_mode ) )
6005       {
6006        return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
6007               "attempt to invoke directory as script");
6008       }
6009     if ( !ap_suexec_enabled )
6010       {
6011        if ( !ap_can_exec( &r->finfo ) )
6012          {
6013           return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
6014                  "file permissions deny server execution");
6015          }
6016       }
6017     if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
6018       {
6019        return retval;
6020       }
6021     ap_add_common_vars(r);
6022     cld.argv0 = argv0;
6023     cld.r     = r;
6024     cld.nph   = nph;
6025     cld.debug = conf->logname ? 1 : 0;
6026     #ifdef TPF
6027     cld.t.filename       = r->filename;
6028     cld.t.subprocess_env = r->subprocess_env;
6029     cld.t.prog_type      = FORK_FILE;
6030     #endif 
6031     #ifdef CHARSET_EBCDIC
6032     ap_bsetflag( r->connection->client, B_EBCDIC2ASCII, 1 );
6033     #endif 
6034     if ( !ap_bspawn_child(
6035           r->main ? r->main->pool : r->pool, 
6036           mod_gzip_cgi_child, 
6037           (void *) &cld,      
6038           kill_after_timeout, 
6039           &script_out, 
6040           &script_in,  
6041           &script_err  
6042           )
6043        )
6044       {
6045        ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
6046        "couldn't spawn child process: %s", r->filename);
6047        return HTTP_INTERNAL_SERVER_ERROR;
6048       }
6049     else 
6050       {
6051       }
6052     if ( ap_should_client_block(r) )
6053       {
6054        int dbsize, len_read;
6055        if ( conf->logname )
6056          {
6057           dbuf  = ap_pcalloc( r->pool, conf->bufbytes + 1 );
6058           dbpos = 0; 
6059          }
6060        ap_hard_timeout("copy script args", r);
6061        for (;;)
6062           {
6063            len_read =
6064            ap_get_client_block( r, argsbuffer, HUGE_STRING_LEN );
6065            if ( len_read < 1 ) 
6066              {
6067               break; 
6068              }
6069            if (conf->logname)
6070              {
6071               if ((dbpos + len_read) > conf->bufbytes)
6072                 {
6073                  dbsize = conf->bufbytes - dbpos;
6074                 }
6075               else
6076                 {
6077                  dbsize = len_read;
6078                 }
6079               memcpy(dbuf + dbpos, argsbuffer, dbsize);
6080               dbpos += dbsize;
6081              }
6082            ap_reset_timeout(r);
6083            if ( ap_bwrite(script_out, argsbuffer, len_read) < len_read )
6084              {
6085               while ( len_read=
6086                       ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0)
6087                 {
6088                 }
6089               break;
6090              }
6091            else 
6092              {
6093              }
6094           }
6095        ap_bflush( script_out );
6096        ap_kill_timeout(r);
6097       }
6098     else 
6099       {
6100       }
6101     ap_bclose( script_out );
6102     if ( script_in && !nph )
6103       {
6104        char sbuf[MAX_STRING_LEN];
6105        int ret;
6106        if ((ret = ap_scan_script_header_err_buff(r, script_in, sbuf)))
6107          {
6108           return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err);
6109          }
6110        #ifdef CHARSET_EBCDIC
6111        ap_checkconv(r);
6112        #endif 
6113        location = ap_table_get( r->headers_out, "Location" );
6114        if ( location && location[0] == '/' && r->status == 200 )
6115          {
6116           ap_hard_timeout("read from script", r);
6117           while ( ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0 )
6118             {
6119              continue;
6120             }
6121           while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0)
6122             {
6123              continue;
6124             }
6125           ap_kill_timeout(r);
6126           r->method = ap_pstrdup(r->pool, "GET");
6127           r->method_number = M_GET;
6128           ap_table_unset( r->headers_in, "Content-Length" );
6129           ap_internal_redirect_handler( location, r );
6130           return OK;
6131          }
6132        else if ( location && r->status == 200 )
6133          {
6134           return REDIRECT;
6135          }
6136        #ifdef USE_GATHER
6137        if ( r->header_only )
6138          {
6139           ap_send_http_header(r);
6140          }
6141        else
6142          {
6143          }
6144        #else /* !USE_GATHER */
6145        ap_send_http_header(r);
6146        #endif /* USE_GATHER */
6147        if (!r->header_only)
6148          {
6149           mod_gzip_ap_send_fb( script_in, r, &final_result );
6150          }
6151        ap_bclose( script_in );
6152        ap_soft_timeout("soaking script stderr", r);
6153        for (;;)
6154           {
6155            bytesread = ap_bgets( argsbuffer, HUGE_STRING_LEN, script_err );
6156            if ( bytesread < 1 )
6157              {
6158               break;
6159              }
6160           }
6161        ap_kill_timeout(r);
6162        ap_bclose( script_err );
6163       }
6164     else 
6165       {
6166       }
6167     if ( script_in && nph )
6168       {
6169        #ifdef RUSSIAN_APACHE
6170        if (ra_charset_active(r))
6171          {
6172           r->ra_codep=NULL;
6173          }
6174        #endif 
6175        mod_gzip_ap_send_fb( script_in, r, &final_result );
6176       }
6177     else 
6178       {
6179       }
6180     #ifdef ORIGINAL
6181     return OK; 
6182     #endif
6183     return final_result;
6184 }
6185 static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo)
6186 {
6187     struct mod_gzip_cgi_child_stuff *cld = (struct mod_gzip_cgi_child_stuff *) child_stuff;
6188     request_rec *r = cld->r;
6189     char *argv0 = cld->argv0;
6190     int child_pid;
6191
6192 /* WARNING! If the following DEBUG_CGI switch is ON you may need to */
6193 /* run Apache with the -X switch or the dynamic compression */
6194 /* of some CGI output ( most notable Zope ) will start to fail. */
6195 /* This DEBUG_CGI switch should NEVER be on for production runs. */
6196 /*
6197 #define DEBUG_CGI
6198 */
6199
6200 #ifdef DEBUG_CGI
6201 #ifdef OS2
6202     FILE *dbg = fopen("con", "w");
6203 #else
6204     #ifdef WIN32
6205     FILE *dbg = fopen("c:\\script.dbg", "a" );
6206     #else
6207     FILE *dbg = fopen("/dev/tty", "w");
6208     #endif
6209 #endif
6210     int i;
6211 #endif
6212     char **env;
6213     RAISE_SIGSTOP(CGI_CHILD);
6214 #ifdef DEBUG_CGI
6215     fprintf(dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n",
6216             r->filename, cld->nph ? "NPH " : "", argv0);
6217 #endif
6218     ap_add_cgi_vars(r);
6219     env = ap_create_environment(r->pool, r->subprocess_env);
6220 #ifdef DEBUG_CGI
6221     fprintf(dbg, "Environment: \n");
6222     for (i = 0; env[i]; ++i)
6223         fprintf(dbg, "'%s'\n", env[i]);
6224 #endif
6225 #ifndef WIN32
6226     #ifdef DEBUG_CGI
6227     fprintf(dbg, "Call ap_chdir_file(r->filename=[%s]\n",r->filename);
6228     #endif
6229     ap_chdir_file(r->filename);
6230     #ifdef DEBUG_CGI
6231     fprintf(dbg, "Back ap_chdir_file(r->filename=[%s]\n",r->filename);
6232     #endif
6233 #endif
6234     if (!cld->debug)
6235         ap_error_log2stderr(r->server);
6236 #ifdef TPF
6237     #ifdef DEBUG_CGI
6238     #ifdef WIN32
6239     fprintf(dbg, "TPF defined... return( 0 ) now...\n");
6240     if ( dbg ) { fclose(dbg); dbg=0; }
6241     #endif
6242     #endif
6243     return (0);
6244 #else
6245     #ifdef DEBUG_CGI
6246     fprintf(dbg, "Call ap_cleanup_for_exec()...\n");
6247     #endif
6248     ap_cleanup_for_exec();
6249     #ifdef DEBUG_CGI
6250     fprintf(dbg, "Back ap_cleanup_for_exec()...\n");
6251     fprintf(dbg, "Call ap_call_exec()...\n");
6252     #endif
6253     child_pid = ap_call_exec(r, pinfo, argv0, env, 0);
6254     #ifdef DEBUG_CGI
6255     fprintf(dbg, "Back ap_call_exec()...\n");
6256     #endif
6257 #if defined(WIN32) || defined(OS2)
6258     #ifdef DEBUG_CGI
6259     #ifdef WIN32
6260     fprintf(dbg, "WIN32 or OS2 defined... return( child_pid ) now...\n");
6261     if ( dbg ) { fclose(dbg); dbg=0; }
6262     #endif
6263     #endif
6264     return (child_pid);
6265 #else
6266     ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename);
6267     exit(0);
6268     #ifdef DEBUG_CGI
6269     #ifdef WIN32
6270     if ( dbg ) { fclose(dbg); dbg=0; }
6271     #endif
6272     #endif
6273     return (0);
6274 #endif
6275 #endif  
6276 }
6277 #define MOD_GZIP_SET_BYTES_SENT(r) \
6278   do { if (r->sent_bodyct) \
6279           ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
6280   } while (0)
6281 long mod_gzip_ap_send_fb( BUFF *fb, request_rec *r, int *final_return_code )
6282 {
6283  long lrc;
6284  int  return_code=DECLINED;
6285  lrc = (long ) mod_gzip_ap_send_fb_length( fb, r, -1, &return_code );
6286  *final_return_code = return_code;
6287  return lrc;
6288 }
6289 #ifdef USE_TPF_SELECT
6290 #define mod_gzip_ap_select(_a, _b, _c, _d, _e)   \
6291         tpf_select(_a, _b, _c, _d, _e)
6292 #elif defined(SELECT_NEEDS_CAST)
6293 #define mod_gzip_ap_select(_a, _b, _c, _d, _e)   \
6294     select((_a), (int *)(_b), (int *)(_c), (int *)(_d), (_e))
6295 #else
6296 #define mod_gzip_ap_select(_a, _b, _c, _d, _e)   \
6297         select(_a, _b, _c, _d, _e)
6298 #endif
6299 long mod_gzip_ap_send_fb_length(
6300 BUFF *fb,
6301 request_rec *r,
6302 long length,
6303 int *final_return_code
6304 )
6305 {
6306     char cn[]="mod_gzip_ab_send_fb_length()";
6307     char buf[IOBUFSIZE];
6308     long total_bytes_sent = 0;
6309     register int n;
6310     register int len;
6311     register int fd;
6312     fd_set   fds;
6313     int      rc;
6314     #ifndef  USE_GATHER
6315     register int w;
6316     register int o;
6317     #endif
6318     #ifdef USE_GATHER
6319     int   gather_on           = 0;
6320     int   gather_todisk       = 0;
6321     int   gather_origin       = 0;
6322     char *gather_bufstart     = 0;
6323     char *gather_source       = 0;
6324     char *gather_buf          = 0;
6325     int   gather_bufmaxlen    = 60000; 
6326     int   gather_byteswritten = 0;
6327     int   gather_length       = 0;
6328     int   gather_maxlen       = 0;
6329     long  gather_totlen       = 0; 
6330     FILE *gather_fh1          = 0;
6331     char  gather_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ];
6332     #endif 
6333     void *modconf = r->server->module_config;
6334     mod_gzip_conf *conf;
6335     *final_return_code = DECLINED; 
6336     conf = (mod_gzip_conf *) ap_get_module_config( modconf, &gzip_module );
6337     if ( length == 0 )
6338       {
6339        return 0;
6340       }
6341     ap_bsetflag( fb, B_RD, 0 );
6342     #ifndef TPF
6343     ap_bnonblock( fb, B_RD );
6344     #endif 
6345     fd = ap_bfileno( fb, B_RD );
6346     #ifdef CHECK_FD_SETSIZE
6347     if ( fd >= FD_SETSIZE )
6348       {
6349        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
6350        "send body: filedescriptor (%u) larger than FD_SETSIZE (%u) "
6351        "found, you probably need to rebuild Apache with a "
6352        "larger FD_SETSIZE", fd, FD_SETSIZE);
6353        return 0;
6354       }
6355     else 
6356       {
6357       }
6358     #else 
6359     #endif 
6360     ap_soft_timeout("send body", r);
6361     FD_ZERO( &fds );
6362     #ifdef USE_GATHER
6363     gather_on = 0; 
6364     if ( (long) conf->maximum_inmem_size < (long) gather_bufmaxlen )
6365       {
6366        gather_maxlen = (int) conf->maximum_inmem_size;
6367       }
6368     else
6369       {
6370        gather_maxlen = (int) gather_bufmaxlen;
6371       }
6372     gather_bufstart = malloc( (int)(gather_maxlen + 2) );
6373     if ( gather_bufstart )
6374       {
6375        gather_on     = 1; 
6376        gather_buf    = gather_bufstart;  
6377        gather_source = gather_bufstart;  
6378        gather_origin = 0;                
6379       }
6380     else 
6381       {
6382       }
6383     #endif 
6384     while( !r->connection->aborted )
6385       {
6386        #ifdef NDELAY_PIPE_RETURNS_ZERO
6387        int afterselect = 0;
6388        #endif
6389        if ( (length > 0) && (total_bytes_sent + IOBUFSIZE) > length )
6390          {
6391           len = length - total_bytes_sent;
6392          }
6393        else
6394          {
6395           len = IOBUFSIZE;
6396          }
6397        do {
6398            n = ap_bread( fb, buf, len );
6399            #ifdef NDELAY_PIPE_RETURNS_ZERO
6400            if ((n > 0) || (n == 0 && afterselect))
6401              {
6402               break;
6403              }
6404            #else 
6405            if (n >= 0)
6406              {
6407               break;
6408              }
6409            #endif 
6410            if ( r->connection->aborted )
6411              {
6412               break;
6413              }
6414            if ( n < 0 && errno != EAGAIN )
6415              {
6416               break;
6417              }
6418            if ( ap_bflush( r->connection->client ) < 0 )
6419              {
6420               ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
6421               "client stopped connection before send body completed");
6422               ap_bsetflag( r->connection->client, B_EOUT, 1 );
6423               r->connection->aborted = 1; 
6424               break; 
6425              }
6426            #ifdef WIN32
6427            FD_SET( (unsigned) fd, &fds );
6428            #else
6429            FD_SET( fd, &fds );
6430            #endif
6431            #ifdef FUTURE_USE
6432            mod_gzip_ap_select(fd + 1, &fds, NULL, NULL, NULL);
6433            #endif
6434            #ifdef NDELAY_PIPE_RETURNS_ZERO
6435            afterselect = 1;
6436            #endif
6437           } while ( !r->connection->aborted );
6438        if ( n < 1 || r->connection->aborted )
6439          {
6440           break; 
6441          }
6442        #ifdef USE_GATHER
6443        if ( gather_on )
6444          {
6445           if ( ( gather_length + n ) >= gather_maxlen )
6446             {
6447              if ( !gather_fh1 ) 
6448                {
6449                 mod_gzip_create_unique_filename(
6450                 (mod_gzip_conf *) conf,
6451                 (char *) gather_filename,
6452                 sizeof(  gather_filename )
6453                 );
6454                 gather_fh1 = fopen( gather_filename, "wb" );
6455                 if ( gather_fh1 )
6456                   {
6457                    gather_source = gather_filename; 
6458                    gather_origin = 1;               
6459                   }
6460                 else
6461                   {
6462                    gather_on = 0; 
6463                   }
6464                }
6465              if ( ( gather_fh1 ) && ( gather_length > 0 ) )
6466                {
6467                 gather_byteswritten =
6468                 fwrite( gather_bufstart, 1, gather_length, gather_fh1 );
6469                 if ( gather_byteswritten != gather_length )
6470                   {
6471                    gather_on = 0; 
6472                   }
6473                }
6474              if ( ( gather_fh1 ) && ( n > 0 ) )
6475                {
6476                 gather_byteswritten =
6477                 fwrite( buf, 1, n, gather_fh1 );
6478                 if ( gather_byteswritten != n )
6479                   {
6480                    gather_on = 0; 
6481                   }
6482                }
6483              gather_buf    = gather_bufstart;
6484              gather_length = 0;
6485             }
6486           else 
6487             {
6488              if ( gather_on )
6489                {
6490                 memcpy( gather_buf, buf, n );
6491                 gather_buf    += n; 
6492                 gather_length += n; 
6493                }
6494             }
6495           gather_totlen += n; 
6496          }
6497        #endif 
6498        #ifdef FUTURE_USE
6499        o = 0;
6500        while ( n && !r->connection->aborted )
6501          {
6502           #ifdef RUSSIAN_APACHE
6503           unsigned char *newbuf,*p;
6504           int newlen=0;
6505           if ( ra_charset_active(r) )
6506             {
6507              if ( ra_flag( r, RA_WIDE_CHARS_SC ) )
6508                {
6509                 ra_data_server2client(r,&buf[o],n,&newbuf,&newlen);
6510                 p=newbuf;
6511                 while( newlen > 0 )
6512                   {
6513                    w = ap_bwrite( r->connection->client, p, newlen );
6514                    if(w<=0) goto RECODE_DONE;
6515                    newlen-=w;
6516                    p+=w;
6517                   }
6518                 w=n;
6519                }
6520              else 
6521                {
6522                 unsigned char *t   = r->ra_codep->cp_otabl_p;
6523                 unsigned char *b   = (unsigned char *)&buf[o];
6524                 unsigned char *end = b+n;
6525                 while( b < end )
6526                   {
6527                    *b = t[*b];
6528                    b++;
6529                   }
6530                 w = ap_bwrite( r->connection->client, &buf[o], n );
6531                }
6532             }
6533           else 
6534             {
6535              w = ap_bwrite( r->connection->client, &buf[o], n );
6536             }
6537           RECODE_DONE:; 
6538           #else 
6539           w = ap_bwrite( r->connection->client, &buf[o], n );
6540           #endif 
6541           if ( w > 0 ) 
6542             {
6543              ap_reset_timeout(r);
6544              total_bytes_sent += w;
6545              n -= w;
6546              o += w;
6547             }
6548           else if ( w < 0 ) 
6549             {
6550              if ( !r->connection->aborted )
6551                {
6552                 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
6553                 "client stopped connection before send body completed");
6554                 ap_bsetflag(r->connection->client, B_EOUT, 1);
6555                 r->connection->aborted = 1;
6556                }
6557              break;
6558             }
6559          }
6560        #endif 
6561       }
6562     ap_kill_timeout(r);
6563     MOD_GZIP_SET_BYTES_SENT(r); 
6564     #ifdef USE_GATHER
6565     if ( gather_fh1 ) 
6566       {
6567        if ( gather_length > 0 )
6568          {
6569           gather_byteswritten =
6570           fwrite( gather_bufstart, 1, gather_length, gather_fh1 );
6571           if ( gather_byteswritten != gather_length )
6572             {
6573              gather_on = 0; 
6574             }
6575          }
6576        fclose( gather_fh1 );
6577                gather_fh1 = 0;
6578       }
6579     if ( gather_totlen > 0 )
6580       {
6581        rc =
6582        mod_gzip_encode_and_transmit(
6583        (request_rec *) r,               
6584        (char        *) gather_source,   
6585        (int          ) gather_origin,   
6586        (long         ) gather_totlen,
6587        (int          ) 1 
6588        );
6589        *final_return_code = rc;
6590       }
6591     if ( gather_bufstart ) 
6592       {
6593        free( gather_bufstart );
6594              gather_bufstart = 0;
6595       }
6596     gather_on = 0; 
6597     #endif 
6598     return total_bytes_sent;
6599 }
6600
6601 /*--------------------------------------------------------------------------*/
6602 /* COMPRESSION SUPPORT ROUTINES                                             */
6603 /*--------------------------------------------------------------------------*/
6604
6605 #define BIG_MEM
6606
6607 typedef unsigned       uns;
6608 typedef unsigned int   uni;
6609 typedef unsigned char  uch;
6610 typedef unsigned short ush;
6611 typedef unsigned long  ulg;
6612 typedef int            gz1_file_t;
6613
6614 #ifdef __STDC__
6615    typedef void *voidp;
6616 #else
6617    typedef char *voidp;
6618 #endif
6619
6620 #if defined(__MSDOS__) && !defined(MSDOS)
6621 #  define MSDOS
6622 #endif
6623
6624 #if defined(__OS2__) && !defined(OS2)
6625 #  define OS2
6626 #endif
6627
6628 #if defined(OS2) && defined(MSDOS)
6629 #  undef MSDOS
6630 #endif
6631
6632 #ifdef MSDOS
6633 #  ifdef __GNUC__
6634 #    define near
6635 #  else
6636 #    define MAXSEG_64K
6637 #    ifdef __TURBOC__
6638 #      define NO_OFF_T
6639 #      ifdef __BORLANDC__
6640 #        define DIRENT
6641 #      else
6642 #        define NO_UTIME
6643 #      endif
6644 #    else
6645 #      define HAVE_SYS_UTIME_H
6646 #      define NO_UTIME_H
6647 #    endif
6648 #  endif
6649 #  define PATH_SEP2 '\\'
6650 #  define PATH_SEP3 ':'
6651 #  define MAX_PATH_LEN  128
6652 #  define NO_MULTIPLE_DOTS
6653 #  define MAX_EXT_CHARS 3
6654 #  define Z_SUFFIX "z"
6655 #  define NO_CHOWN
6656 #  define PROTO
6657 #  define STDC_HEADERS
6658 #  define NO_SIZE_CHECK
6659 #  define casemap(c) tolow(c)
6660 #  include <io.h>
6661 #  undef  OS_CODE
6662 #  define OS_CODE  0x00
6663 #  define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
6664 #  if !defined(NO_ASM) && !defined(ASMV)
6665 #    define ASMV
6666 #  endif
6667 #else
6668 #  define near
6669 #endif
6670
6671 #ifdef OS2
6672 #  define PATH_SEP2 '\\'
6673 #  define PATH_SEP3 ':'
6674 #  define MAX_PATH_LEN  260
6675 #  ifdef OS2FAT
6676 #    define NO_MULTIPLE_DOTS
6677 #    define MAX_EXT_CHARS 3
6678 #    define Z_SUFFIX "z"
6679 #    define casemap(c) tolow(c)
6680 #  endif
6681 #  define NO_CHOWN
6682 #  define PROTO
6683 #  define STDC_HEADERS
6684 #  include <io.h>
6685 #  undef  OS_CODE
6686 #  define OS_CODE  0x06
6687 #  define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
6688 #  ifdef _MSC_VER
6689 #    define HAVE_SYS_UTIME_H
6690 #    define NO_UTIME_H
6691 #    define MAXSEG_64K
6692 #    undef near
6693 #    define near _near
6694 #  endif
6695 #  ifdef __EMX__
6696 #    define HAVE_SYS_UTIME_H
6697 #    define NO_UTIME_H
6698 #    define DIRENT
6699 #    define EXPAND(argc,argv) \
6700        {_response(&argc, &argv); _wildcard(&argc, &argv);}
6701 #  endif
6702 #  ifdef __BORLANDC__
6703 #    define DIRENT
6704 #  endif
6705 #  ifdef __ZTC__
6706 #    define NO_DIR
6707 #    define NO_UTIME_H
6708 #    include <dos.h>
6709 #    define EXPAND(argc,argv) \
6710        {response_expand(&argc, &argv);}
6711 #  endif
6712 #endif
6713
6714 #ifdef WIN32
6715 #  define HAVE_SYS_UTIME_H
6716 #  define NO_UTIME_H
6717 #  define PATH_SEP2 '\\'
6718 #  define PATH_SEP3 ':'
6719 #  undef  MAX_PATH_LEN
6720 #  define MAX_PATH_LEN  260
6721 #  define NO_CHOWN
6722 #  define PROTO
6723 #  define STDC_HEADERS
6724 #  define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
6725 #  include <io.h>
6726 #  ifdef NTFAT
6727 #    define NO_MULTIPLE_DOTS
6728 #    define MAX_EXT_CHARS 3
6729 #    define Z_SUFFIX "z"
6730 #    define casemap(c) tolow(c)
6731 #  endif
6732 #  undef  OS_CODE
6733
6734 #  define OS_CODE  0x00
6735
6736 #endif
6737
6738 #ifdef MSDOS
6739 #  ifdef __TURBOC__
6740 #    include <alloc.h>
6741 #    define DYN_ALLOC
6742      void * fcalloc (unsigned items, unsigned size);
6743      void fcfree (void *ptr);
6744 #  else
6745 #    define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
6746 #    define fcfree(ptr) hfree(ptr)
6747 #  endif
6748 #else
6749 #  ifdef MAXSEG_64K
6750 #    define fcalloc(items,size) calloc((items),(size))
6751 #  else
6752 #    define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
6753 #  endif
6754 #  define fcfree(ptr) free(ptr)
6755 #endif
6756
6757 #if defined(VAXC) || defined(VMS)
6758 #  define PATH_SEP ']'
6759 #  define PATH_SEP2 ':'
6760 #  define SUFFIX_SEP ';'
6761 #  define NO_MULTIPLE_DOTS
6762 #  define Z_SUFFIX "-gz"
6763 #  define RECORD_IO 1
6764 #  define casemap(c) tolow(c)
6765 #  undef  OS_CODE
6766 #  define OS_CODE  0x02
6767 #  define OPTIONS_VAR "GZIP_OPT"
6768 #  define STDC_HEADERS
6769 #  define NO_UTIME
6770 #  define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
6771 #  include <file.h>
6772 #  define unlink delete
6773 #  ifdef VAXC
6774 #    define NO_FCNTL_H
6775 #    include <unixio.h>
6776 #  endif
6777 #endif
6778
6779 #ifdef AMIGA
6780 #  define PATH_SEP2 ':'
6781 #  define STDC_HEADERS
6782 #  undef  OS_CODE
6783 #  define OS_CODE  0x01
6784 #  define ASMV
6785 #  ifdef __GNUC__
6786 #    define DIRENT
6787 #    define HAVE_UNISTD_H
6788 #  else
6789 #    define NO_STDIN_FSTAT
6790 #    define SYSDIR
6791 #    define NO_SYMLINK
6792 #    define NO_CHOWN
6793 #    define NO_FCNTL_H
6794 #    include <fcntl.h>
6795 #    define direct dirent
6796      extern void _expand_args(int *argc, char ***argv);
6797 #    define EXPAND(argc,argv) _expand_args(&argc,&argv);
6798 #    undef  O_BINARY
6799 #  endif
6800 #endif
6801
6802 #if defined(ATARI) || defined(atarist)
6803 #  ifndef STDC_HEADERS
6804 #    define STDC_HEADERS
6805 #    define HAVE_UNISTD_H
6806 #    define DIRENT
6807 #  endif
6808 #  define ASMV
6809 #  undef  OS_CODE
6810 #  define OS_CODE  0x05
6811 #  ifdef TOSFS
6812 #    define PATH_SEP2 '\\'
6813 #    define PATH_SEP3 ':'
6814 #    define MAX_PATH_LEN  128
6815 #    define NO_MULTIPLE_DOTS
6816 #    define MAX_EXT_CHARS 3
6817 #    define Z_SUFFIX "z"
6818 #    define NO_CHOWN
6819 #    define casemap(c) tolow(c)
6820 #    define NO_SYMLINK
6821 #  endif
6822 #endif
6823
6824 #ifdef MACOS
6825 #  define PATH_SEP ':'
6826 #  define DYN_ALLOC
6827 #  define PROTO
6828 #  define NO_STDIN_FSTAT
6829 #  define NO_CHOWN
6830 #  define NO_UTIME
6831 #  define chmod(file, mode) (0)
6832 #  define OPEN(name, flags, mode) open(name, flags)
6833 #  undef  OS_CODE
6834 #  define OS_CODE  0x07
6835 #  ifdef MPW
6836 #    define isatty(fd) ((fd) <= 2)
6837 #  endif
6838 #endif
6839
6840 #ifdef __50SERIES
6841 #  define PATH_SEP '>'
6842 #  define STDC_HEADERS
6843 #  define NO_MEMORY_H
6844 #  define NO_UTIME_H
6845 #  define NO_UTIME
6846 #  define NO_CHOWN 
6847 #  define NO_STDIN_FSTAT 
6848 #  define NO_SIZE_CHECK 
6849 #  define NO_SYMLINK
6850 #  define RECORD_IO  1
6851 #  define casemap(c)  tolow(c)
6852 #  define put_char(c) put_byte((c) & 0x7F)
6853 #  define get_char(c) ascii2pascii(get_byte())
6854 #  undef  OS_CODE
6855 #  define OS_CODE  0x0F
6856 #  ifdef SIGTERM
6857 #    undef SIGTERM
6858 #  endif
6859 #endif
6860
6861 #if defined(pyr) && !defined(NOMEMCPY)
6862 #  define NOMEMCPY
6863 #endif
6864
6865 #ifdef TOPS20
6866 #  undef  OS_CODE
6867 #  define OS_CODE  0x0a
6868 #endif
6869
6870 #ifndef unix
6871 #  define NO_ST_INO
6872 #endif
6873
6874 #ifndef OS_CODE
6875 #  undef  OS_CODE
6876 #  define OS_CODE  0x03
6877 #endif
6878
6879 #ifndef PATH_SEP
6880 #  define PATH_SEP '/'
6881 #endif
6882
6883 #ifndef casemap
6884 #  define casemap(c) (c)
6885 #endif
6886
6887 #ifndef OPTIONS_VAR
6888 #  define OPTIONS_VAR "GZIP"
6889 #endif
6890
6891 #ifndef Z_SUFFIX
6892 #  define Z_SUFFIX ".gz"
6893 #endif
6894
6895 #ifdef MAX_EXT_CHARS
6896 #  define MAX_SUFFIX  MAX_EXT_CHARS
6897 #else
6898 #  define MAX_SUFFIX  30
6899 #endif
6900
6901 #ifndef MIN_PART
6902 #  define MIN_PART 3
6903 #endif
6904
6905 #ifndef EXPAND
6906 #  define EXPAND(argc,argv)
6907 #endif
6908
6909 #ifndef RECORD_IO
6910 #  define RECORD_IO 0
6911 #endif
6912
6913 #ifndef SET_BINARY_MODE
6914 #  define SET_BINARY_MODE(fd)
6915 #endif
6916
6917 #ifndef OPEN
6918 #  define OPEN(name, flags, mode) open(name, flags, mode)
6919 #endif
6920
6921 #ifndef get_char
6922 #  define get_char() get_byte()
6923 #endif
6924
6925 #ifndef put_char
6926 #  define put_char(c) put_byte(c)
6927 #endif
6928
6929 #ifndef O_BINARY
6930 #define O_BINARY 0
6931 #endif
6932
6933 #define OK          0
6934 #define LZ1_ERROR   1
6935 #define WARNING     2
6936 #define STORED      0
6937 #define COMPRESSED  1
6938 #define PACKED      2
6939 #define LZHED       3
6940 #define DEFLATED    8
6941 #define MAX_METHODS 9
6942
6943 #ifndef O_CREAT
6944 #include <sys/file.h>
6945 #ifndef O_CREAT
6946 #define O_CREAT FCREAT
6947 #endif
6948 #ifndef O_EXCL
6949 #define O_EXCL FEXCL
6950 #endif
6951 #endif
6952
6953 #ifndef S_IRUSR
6954 #define S_IRUSR 0400
6955 #endif
6956 #ifndef S_IWUSR
6957 #define S_IWUSR 0200
6958 #endif
6959 #define RW_USER (S_IRUSR | S_IWUSR)
6960
6961 #ifndef MAX_PATH_LEN
6962 #define MAX_PATH_LEN 256
6963 #endif
6964
6965 #ifndef SEEK_END
6966 #define SEEK_END 2
6967 #endif
6968
6969 #define PACK_MAGIC     "\037\036"
6970 #define GZIP_MAGIC     "\037\213"
6971 #define OLD_GZIP_MAGIC "\037\236"
6972 #define LZH_MAGIC      "\037\240"
6973 #define PKZIP_MAGIC    "\120\113\003\004"
6974 #define ASCII_FLAG   0x01 
6975 #define CONTINUATION 0x02 
6976 #define EXTRA_FIELD  0x04 
6977 #define ORIG_NAME    0x08 
6978 #define COMMENT      0x10 
6979 #define ENCRYPTED    0x20 
6980 #define RESERVED     0xC0 
6981 #define UNKNOWN 0xffff
6982 #define BINARY  0
6983 #define ASCII   1
6984
6985 #ifndef WSIZE
6986 #define WSIZE 0x8000
6987 #endif
6988
6989 #ifndef INBUFSIZ
6990 #ifdef  SMALL_MEM
6991 #define INBUFSIZ  0x2000
6992 #else
6993 #define INBUFSIZ  0x8000
6994 #endif
6995 #endif
6996 #define INBUF_EXTRA 64
6997
6998 #ifndef OUTBUFSIZ
6999 #ifdef SMALL_MEM
7000 #define OUTBUFSIZ   8192
7001 #else
7002 #define OUTBUFSIZ  0x4000
7003 #endif
7004 #endif
7005 #define OUTBUF_EXTRA 2048
7006
7007 #ifndef DIST_BUFSIZE
7008 #ifdef  SMALL_MEM
7009 #define DIST_BUFSIZE 0x2000
7010 #else
7011 #define DIST_BUFSIZE 0x8000
7012 #endif
7013 #endif
7014
7015 #ifndef BITS
7016 #define BITS 16
7017 #endif
7018
7019 #define LZW_MAGIC  "\037\235"
7020
7021 #define MIN_MATCH  3
7022 #define MAX_MATCH  258
7023
7024 #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
7025 #define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
7026
7027 #ifdef  SMALL_MEM
7028 #define HASH_BITS  13
7029 #endif
7030 #ifdef  MEDIUM_MEM
7031 #define HASH_BITS  14
7032 #endif
7033 #ifndef HASH_BITS
7034 #define HASH_BITS  15
7035 #endif
7036
7037 #define HASH_SIZE (unsigned)(1<<HASH_BITS)
7038 #define HASH_MASK (HASH_SIZE-1)
7039 #define WMASK     (WSIZE-1)
7040 #define H_SHIFT   ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
7041
7042 #ifndef TOO_FAR
7043 #define TOO_FAR 4096
7044 #endif
7045
7046 #define NIL          0
7047 #define FAST         4
7048 #define SLOW         2
7049 #define REP_3_6      16
7050 #define REPZ_3_10    17
7051 #define REPZ_11_138  18
7052 #define MAX_BITS     15
7053 #define MAX_BL_BITS  7
7054 #define D_CODES      30
7055 #define BL_CODES     19
7056 #define SMALLEST     1
7057 #define LENGTH_CODES 29
7058 #define LITERALS     256
7059 #define END_BLOCK    256
7060 #define L_CODES (LITERALS+1+LENGTH_CODES)
7061
7062 #ifndef LIT_BUFSIZE
7063 #ifdef  SMALL_MEM
7064 #define LIT_BUFSIZE  0x2000
7065 #else
7066 #ifdef  MEDIUM_MEM
7067 #define LIT_BUFSIZE  0x4000
7068 #else
7069 #define LIT_BUFSIZE  0x8000
7070 #endif
7071 #endif
7072 #endif
7073
7074 #define HEAP_SIZE (2*L_CODES+1)
7075 #define STORED_BLOCK 0
7076 #define STATIC_TREES 1
7077 #define DYN_TREES    2
7078 #define NO_FILE  (-1) 
7079
7080 #define BMAX 16         
7081 #define N_MAX 288       
7082
7083 #define LOCSIG 0x04034b50L      
7084 #define LOCFLG 6                
7085 #define CRPFLG 1                
7086 #define EXTFLG 8                
7087 #define LOCHOW 8                
7088 #define LOCTIM 10               
7089 #define LOCCRC 14               
7090 #define LOCSIZ 18               
7091 #define LOCLEN 22               
7092 #define LOCFIL 26               
7093 #define LOCEXT 28               
7094 #define LOCHDR 30               
7095 #define EXTHDR 16               
7096 #define RAND_HEAD_LEN  12
7097 #define BUFSIZE (8 * 2*sizeof(char))
7098
7099 #define translate_eol 0  
7100
7101 #define FLUSH_BLOCK(eof) \
7102    flush_block(gz1,gz1->block_start >= 0L ? (char*)&gz1->window[(unsigned)gz1->block_start] : \
7103          (char*)NULL, (long)gz1->strstart - gz1->block_start, (eof))
7104
7105 #ifdef DYN_ALLOC
7106 #  define ALLOC(type, array, size) { \
7107       array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
7108       if (array == NULL) error("insufficient memory"); \
7109    }
7110 #  define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
7111 #else
7112 #  define ALLOC(type, array, size)
7113 #  define FREE(array)
7114 #endif
7115
7116 #define GZ1_MAX(a,b) (a >= b ? a : b)
7117
7118 #define tolow(c)  (isupper(c) ? (c)-'A'+'a' : (c))    
7119
7120 #define smaller(tree, n, m) \
7121    (tree[n].fc.freq < tree[m].fc.freq || \
7122    (tree[n].fc.freq == tree[m].fc.freq && gz1->depth[n] <= gz1->depth[m]))
7123
7124 #define send_code(c, tree) send_bits(gz1,tree[c].fc.code, tree[c].dl.len)
7125
7126 #define put_byte(c) {gz1->outbuf[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==OUTBUFSIZ)\
7127                      flush_outbuf(gz1);}
7128
7129 #define put_short(w) \
7130 { if (gz1->outcnt < OUTBUFSIZ-2) { \
7131     gz1->outbuf[gz1->outcnt++] = (uch) ((w) & 0xff); \
7132     gz1->outbuf[gz1->outcnt++] = (uch) ((ush)(w) >> 8); \
7133   } else { \
7134     put_byte((uch)((w) & 0xff)); \
7135     put_byte((uch)((ush)(w) >> 8)); \
7136   } \
7137 }
7138
7139 #define put_long(n) { \
7140     put_short((n) & 0xffff); \
7141     put_short(((ulg)(n)) >> 16); \
7142 }
7143
7144 #ifdef CRYPT
7145
7146 #  define NEXTBYTE() \
7147      (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
7148 #else
7149 #  define NEXTBYTE() (uch)get_byte()
7150 #endif
7151
7152 #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
7153 #define DUMPBITS(n) {b>>=(n);k-=(n);}
7154
7155 #define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
7156 #define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
7157
7158 #define put_ubyte(c) {gz1->window[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==WSIZE)\
7159    flush_window(gz1);}
7160
7161 #define WARN(msg) { if (gz1->exit_code == OK) gz1->exit_code = WARNING; }
7162
7163 #define get_byte()  (gz1->inptr < gz1->insize ? gz1->inbuf[gz1->inptr++] : fill_inbuf(gz1,0))
7164 #define try_byte()  (gz1->inptr < gz1->insize ? gz1->inbuf[gz1->inptr++] : fill_inbuf(gz1,1))
7165
7166 #define d_code(dist) \
7167    ((dist) < 256 ? gz1->dist_code[dist] : gz1->dist_code[256+((dist)>>7)])
7168
7169 typedef struct config {
7170    ush good_length; 
7171    ush max_lazy;    
7172    ush nice_length; 
7173    ush max_chain;
7174 } config;
7175
7176 config configuration_table[10] = {
7177
7178  {0,    0,  0,    0},  
7179  {4,    4,  8,    4},  
7180  {4,    5, 16,    8},
7181  {4,    6, 32,   32},
7182  {4,    4, 16,   16},  
7183  {8,   16, 32,   32},
7184  {8,   16, 128, 128},
7185  {8,   32, 128, 256},
7186  {32, 128, 258, 1024},
7187  {32, 258, 258, 4096}}; 
7188
7189 typedef struct ct_data {
7190
7191     union {
7192         ush  freq; 
7193         ush  code; 
7194     } fc;
7195     union {
7196         ush  dad;  
7197         ush  len;  
7198     } dl;
7199
7200 } ct_data;
7201
7202 typedef struct tree_desc {
7203     ct_data *dyn_tree;    
7204     ct_data *static_tree; 
7205     int     *extra_bits;  
7206     int     extra_base;   
7207     int     elems;        
7208     int     max_length;   
7209     int     max_code;     
7210 } tree_desc;
7211
7212 struct huft {
7213   uch e;                
7214   uch b;                
7215   union {
7216     ush n;              
7217     struct huft *t;     
7218   } v;
7219 };
7220
7221 uch bl_order[BL_CODES]
7222    = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
7223
7224 int extra_lbits[LENGTH_CODES]
7225    = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
7226
7227 int extra_dbits[D_CODES]
7228    = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
7229
7230 int extra_blbits[BL_CODES]
7231    = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
7232
7233 ulg crc_32_tab[] = {
7234   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
7235   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
7236   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
7237   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
7238   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
7239   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
7240   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
7241   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
7242   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
7243   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
7244   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
7245   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
7246   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
7247   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
7248   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
7249   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
7250   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
7251   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
7252   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
7253   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
7254   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
7255   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
7256   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
7257   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
7258   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
7259   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
7260   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
7261   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
7262   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
7263   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
7264   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
7265   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
7266   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
7267   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
7268   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
7269   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
7270   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
7271   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
7272   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
7273   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
7274   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
7275   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
7276   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
7277   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
7278   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
7279   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
7280   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
7281   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
7282   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
7283   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
7284   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
7285   0x2d02ef8dL
7286 };
7287
7288 typedef struct _GZ1 {
7289  long     compression_format;
7290
7291  long     versionid1;
7292  int      state;
7293  int      done;
7294  int      deflate1_initialized;     
7295  unsigned deflate1_hash_head;       
7296  unsigned deflate1_prev_match;      
7297  int      deflate1_flush;           
7298  int      deflate1_match_available; 
7299  unsigned deflate1_match_length;    
7300
7301  char ifname[MAX_PATH_LEN]; 
7302  char ofname[MAX_PATH_LEN]; 
7303
7304  struct stat istat;     
7305  gz1_file_t  zfile;
7306  
7307  int   input_ismem;     
7308  char *input_ptr;       
7309  long  input_bytesleft; 
7310  
7311  int   output_ismem;    
7312  char *output_ptr;      
7313  uns   output_maxlen;   
7314
7315  int  compr_level;      
7316  long time_stamp;       
7317  long ifile_size;       
7318  int  ifd;              
7319  int  ofd;              
7320  int  part_nb;          
7321  int  last_member;      
7322  int  save_orig_name;   
7323  long header_bytes;     
7324  long bytes_in;         
7325  long bytes_out;        
7326  uns  insize;           
7327  uns  inptr;            
7328  uns  outcnt;           
7329  uns  ins_h;            
7330  long block_start;      
7331  uns  good_match;       
7332  uni  max_lazy_match;   
7333  uni  prev_length;      
7334  uns  max_chain_length; 
7335  uns  strstart;         
7336  uns  match_start;      
7337  int  eofile;           
7338  uns  lookahead;        
7339  ush *file_type;        
7340  int *file_method;      
7341  ulg  opt_len;          
7342  ulg  static_len;       
7343  ulg  compressed_len;   
7344  ulg  input_len;        
7345  uns  last_flags;       
7346  uch  flags;            
7347  uns  last_lit;         
7348  uns  last_dist;        
7349  uch  flag_bit;         
7350  int  heap_len;         
7351  int  heap_max;         
7352  ulg  bb;               
7353  uns  bk;               
7354  ush  bi_buf;           
7355  int  bi_valid;         
7356  uns  hufts;            
7357  int  decrypt;          
7358  int  ascii;            
7359  int  msg_done;         
7360  int  abortflag;        
7361  int  decompress;       
7362  int  do_lzw;           
7363  int  to_stdout;        
7364  int  force;            
7365  int  verbose;
7366  int  quiet;
7367  int  list;             
7368  int  test;             
7369  int  ext_header;       
7370  int  pkzip;            
7371  int  method;           
7372  int  level;            
7373  int  no_time;          
7374  int  no_name;          
7375  int  exit_code;        
7376  int  lbits;            
7377  int  dbits;            
7378  ulg  window_size;      
7379  ulg  crc;              
7380  ulg  adler;
7381
7382  uch  dist_code[512];
7383  uch  length_code[MAX_MATCH-MIN_MATCH+1];
7384  int  heap[2*L_CODES+1];
7385  uch  depth[2*L_CODES+1];
7386  int  base_length[LENGTH_CODES];
7387  int  base_dist[D_CODES];
7388  ush  bl_count[MAX_BITS+1];
7389  uch  flag_buf[(LIT_BUFSIZE/8)];
7390
7391  #ifdef DYN_ALLOC
7392  uch *inbuf;
7393  uch *outbuf;
7394  ush *d_buf;
7395  uch *window;
7396  #else
7397  uch inbuf [INBUFSIZ +INBUF_EXTRA];
7398  uch outbuf[OUTBUFSIZ+OUTBUF_EXTRA];
7399  ush d_buf [DIST_BUFSIZE];
7400  uch window[2L*WSIZE];
7401  #endif
7402
7403  #ifdef FULL_SEARCH
7404  #define nice_match MAX_MATCH
7405  #else
7406  int nice_match;
7407  #endif
7408
7409  #ifdef CRYPT
7410  uch cc;
7411  #endif
7412
7413  ct_data static_ltree[L_CODES+2];
7414  ct_data static_dtree[D_CODES];
7415  ct_data dyn_dtree[(2*D_CODES+1)];
7416  ct_data dyn_ltree[HEAP_SIZE];
7417  ct_data bl_tree[2*BL_CODES+1];
7418
7419  tree_desc l_desc;
7420  tree_desc d_desc;
7421  tree_desc bl_desc;
7422
7423  #ifndef MAXSEG_64K
7424
7425  ush prev2[1L<<BITS];
7426
7427  #define prev gz1->prev2
7428  #define head (gz1->prev2+WSIZE)
7429
7430  #else
7431
7432  ush * prev2;
7433  ush * tab_prefix1;
7434
7435  #define prev gz1->prev2
7436  #define head gz1->tab_prefix1
7437
7438  #endif
7439
7440 } GZ1;
7441 typedef GZ1 *PGZ1;
7442 int gz1_size = sizeof( GZ1 );
7443
7444 /* Declare some local function protypes... */
7445
7446 /* Any routine name that can/might conflict with */
7447 /* other modules or object code should simply have */
7448 /* the standard prefix 'gz1_' added to the front. */
7449 /* This will only usually be any kind of problem at all */
7450 /* if the code is being compiled directly into the parent */
7451 /* instead of being built as a standalone DLL or DSO library. */
7452
7453 PGZ1  gz1_init        ( void     );
7454 int   gz1_cleanup     ( PGZ1 gz1 );
7455 ulg   gz1_deflate     ( PGZ1 gz1 );
7456 ulg   gz1_deflate_fast( PGZ1 gz1 );
7457
7458 /* The rest of the routines should not need the 'gz1_' prefix. */
7459 /* No conflicts reported at this time. */
7460
7461 int   inflate        ( PGZ1 gz1 );
7462 int   inflate_dynamic( PGZ1 gz1 );
7463 int   inflate_stored ( PGZ1 gz1 );
7464 int   inflate_fixed  ( PGZ1 gz1 );
7465 void  fill_window    ( PGZ1 gz1 );
7466 void  flush_outbuf   ( PGZ1 gz1 );
7467 void  flush_window   ( PGZ1 gz1 );
7468 void  bi_windup      ( PGZ1 gz1 );
7469 void  set_file_type  ( PGZ1 gz1 );
7470 void  init_block     ( PGZ1 gz1 );
7471 int   build_bl_tree  ( PGZ1 gz1 );
7472 void  read_error     ( PGZ1 gz1 );
7473 void  write_error    ( PGZ1 gz1 );
7474 int   get_header     ( PGZ1 gz1, int in );
7475 int   inflate_block  ( PGZ1 gz1, int *e );
7476 int   fill_inbuf     ( PGZ1 gz1, int eof_ok );
7477 char *gz1_basename   ( PGZ1 gz1, char *fname );
7478 int   longest_match  ( PGZ1 gz1, unsigned cur_match );
7479 void  bi_init        ( PGZ1 gz1, gz1_file_t zipfile );
7480 int   file_read      ( PGZ1 gz1, char *buf, unsigned size );
7481 void  write_buf      ( PGZ1 gz1, int fd, voidp buf, unsigned cnt );
7482
7483 void  error( char *msg   );
7484
7485 /* XXX - Precomputed zlib header. If you change the window size or
7486  * compression level from the defaults, this will break badly. The
7487  * algorithm to build this is fairly complex; you can find it in
7488  * the file deflate.c from the zlib distribution.
7489  */
7490 #define ZLIB_HEADER "\170\9c"
7491
7492 ulg adler32(ulg adler, uch *buf, unsigned len);
7493
7494 int zip(
7495 PGZ1 gz1, 
7496 int  in,  
7497 int  out  
7498 );
7499
7500 ulg flush_block(
7501 PGZ1  gz1,        
7502 char *buf,        
7503 ulg   stored_len, 
7504 int   eof         
7505 );
7506
7507 void copy_block(
7508 PGZ1      gz1,    
7509 char     *buf,    
7510 unsigned  len,    
7511 int       header  
7512 );
7513
7514 int ct_tally(
7515 PGZ1 gz1,  
7516 int  dist, 
7517 int  lc    
7518 );
7519
7520 void send_bits(
7521 PGZ1 gz1,   
7522 int  value, 
7523 int  length 
7524 );
7525
7526 void send_tree(
7527 PGZ1      gz1,     
7528 ct_data  *tree,    
7529 int       max_code 
7530 );
7531
7532 void send_all_trees(
7533 PGZ1 gz1,    
7534 int  lcodes, 
7535 int  dcodes, 
7536 int  blcodes 
7537 );
7538
7539 void ct_init(
7540 PGZ1  gz1,    
7541 ush  *attr,   
7542 int  *methodp 
7543 );
7544
7545 void lm_init(
7546 PGZ1 gz1,        
7547 int  pack_level, 
7548 ush *flags       
7549 );
7550
7551 void build_tree(
7552 PGZ1        gz1, 
7553 tree_desc  *desc 
7554 );
7555
7556 void compress_block(
7557 PGZ1      gz1,   
7558 ct_data  *ltree, 
7559 ct_data  *dtree  
7560 );
7561
7562 void gen_bitlen(
7563 PGZ1        gz1, 
7564 tree_desc  *desc 
7565 );
7566
7567 void pqdownheap(
7568 PGZ1      gz1,  
7569 ct_data  *tree, 
7570 int       k     
7571 );
7572
7573 int huft_build(
7574 PGZ1          gz1, 
7575 unsigned     *b,   
7576 unsigned      n,   
7577 unsigned      s,   
7578 ush          *d,   
7579 ush          *e,   
7580 struct huft **t,   
7581 int          *m    
7582 );
7583
7584 ulg updcrc(
7585 PGZ1      gz1, 
7586 uch      *s,   
7587 unsigned  n    
7588 );
7589
7590 int inflate_codes(
7591 PGZ1         gz1,  
7592 struct huft *tl,   
7593 struct huft *td,   
7594 int          bl,   
7595 int          bd    
7596 );
7597
7598 void gen_codes(
7599 PGZ1      gz1,     
7600 ct_data  *tree,    
7601 int       max_code 
7602 );
7603
7604 void scan_tree(
7605 PGZ1     gz1,     
7606 ct_data *tree,    
7607 int      max_code 
7608 );
7609
7610 unsigned bi_reverse(
7611 PGZ1     gz1,  
7612 unsigned code, 
7613 int      len   
7614 );
7615
7616 int huft_free(
7617 PGZ1         gz1, 
7618 struct huft *t    
7619 );
7620
7621 PGZ1 gz1_init()
7622 {
7623  PGZ1 gz1=0; 
7624
7625  gz1 = (PGZ1) malloc( gz1_size );
7626
7627  if ( !gz1 ) 
7628    {
7629     return 0; 
7630    }
7631
7632  memset( gz1, 0, gz1_size );
7633
7634  ALLOC(uch, gz1->inbuf,  INBUFSIZ +INBUF_EXTRA);
7635
7636  if ( !gz1->inbuf ) 
7637    {
7638     free( gz1 ); 
7639     return 0;    
7640    }
7641
7642  ALLOC(uch, gz1->outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
7643  
7644  if ( !gz1->outbuf ) 
7645    {
7646     FREE( gz1->inbuf  ); 
7647     free( gz1         ); 
7648     return 0;            
7649    }
7650
7651  ALLOC(ush, gz1->d_buf,  DIST_BUFSIZE);
7652
7653  if ( !gz1->d_buf ) 
7654    {
7655     FREE( gz1->outbuf ); 
7656     FREE( gz1->inbuf  ); 
7657     free( gz1         ); 
7658     return 0;            
7659    }
7660
7661  ALLOC(uch, gz1->window, 2L*WSIZE);
7662
7663  if ( !gz1->window ) 
7664    {
7665     FREE( gz1->d_buf  ); 
7666     FREE( gz1->outbuf ); 
7667     FREE( gz1->inbuf  ); 
7668     free( gz1         ); 
7669     return 0;            
7670    }
7671
7672  #ifndef MAXSEG_64K
7673  
7674  #else 
7675  
7676  ALLOC(ush, gz1->prev2, 1L<<(BITS-1) );
7677
7678  if ( !gz1->prev2 ) 
7679    {
7680     FREE( gz1->window ); 
7681     FREE( gz1->d_buf  ); 
7682     FREE( gz1->outbuf ); 
7683     FREE( gz1->inbuf  ); 
7684     free( gz1         ); 
7685     return 0;            
7686    }
7687
7688  ALLOC(ush, gz1->tab_prefix1, 1L<<(BITS-1) );
7689
7690  if ( !gz1->tab_prefix1 ) 
7691    {
7692     FREE( gz1->prev2  ); 
7693     FREE( gz1->window ); 
7694     FREE( gz1->d_buf  ); 
7695     FREE( gz1->outbuf ); 
7696     FREE( gz1->inbuf  ); 
7697     free( gz1         ); 
7698     return 0;            
7699    }
7700
7701  #endif 
7702
7703  gz1->method      = DEFLATED;     
7704  gz1->level       = 6;            
7705  gz1->no_time     = -1;           
7706  gz1->no_name     = -1;           
7707  gz1->exit_code   = OK;           
7708  gz1->lbits       = 9;            
7709  gz1->dbits       = 6;            
7710
7711  gz1->window_size = (ulg)2*WSIZE;     
7712  gz1->crc         = (ulg)0xffffffffL; 
7713
7714  gz1->d_desc.dyn_tree     = (ct_data *) gz1->dyn_dtree;
7715  gz1->d_desc.static_tree  = (ct_data *) gz1->static_dtree;
7716  gz1->d_desc.extra_bits   = (int     *) extra_dbits; 
7717  gz1->d_desc.extra_base   = (int      ) 0;
7718  gz1->d_desc.elems        = (int      ) D_CODES;
7719  gz1->d_desc.max_length   = (int      ) MAX_BITS;
7720  gz1->d_desc.max_code     = (int      ) 0;
7721
7722  gz1->l_desc.dyn_tree     = (ct_data *) gz1->dyn_ltree;
7723  gz1->l_desc.static_tree  = (ct_data *) gz1->static_ltree;
7724  gz1->l_desc.extra_bits   = (int     *) extra_lbits; 
7725  gz1->l_desc.extra_base   = (int      ) LITERALS+1;
7726  gz1->l_desc.elems        = (int      ) L_CODES;
7727  gz1->l_desc.max_length   = (int      ) MAX_BITS;
7728  gz1->l_desc.max_code     = (int      ) 0;
7729
7730  gz1->bl_desc.dyn_tree    = (ct_data *) gz1->bl_tree;
7731  gz1->bl_desc.static_tree = (ct_data *) 0;
7732  gz1->bl_desc.extra_bits  = (int     *) extra_blbits; 
7733  gz1->bl_desc.extra_base  = (int      ) 0;
7734  gz1->bl_desc.elems       = (int      ) BL_CODES;
7735  gz1->bl_desc.max_length  = (int      ) MAX_BL_BITS;
7736  gz1->bl_desc.max_code    = (int      ) 0;
7737
7738  return (PGZ1) gz1;
7739
7740 }
7741
7742 int gz1_cleanup( PGZ1 gz1 )
7743 {
7744  
7745  #ifndef MAXSEG_64K
7746  
7747  #else
7748  
7749  FREE( gz1->tab_prefix1 );
7750  FREE( gz1->prev2       );
7751  #endif 
7752
7753  FREE( gz1->window ); 
7754  FREE( gz1->d_buf  ); 
7755  FREE( gz1->outbuf ); 
7756  FREE( gz1->inbuf  ); 
7757
7758  free( gz1 ); 
7759  gz1 = 0;     
7760
7761  return 0;
7762 }
7763
7764 int (*read_buf)(PGZ1 gz1, char *buf, unsigned size);
7765
7766 void error( char *msg )
7767 {
7768  msg = msg;
7769 }
7770
7771 int (*work)( PGZ1 gz1, int infile, int outfile ) = 0; 
7772
7773 #ifdef __BORLANDC__
7774 #pragma argsused
7775 #endif
7776
7777 int get_header( PGZ1 gz1, int in )
7778 {
7779  uch       flags;    
7780  char      magic[2]; 
7781  ulg       stamp;    
7782  unsigned  len;      
7783  unsigned  part;     
7784
7785  if ( gz1->force && gz1->to_stdout )
7786    {
7787     magic[0] = (char)try_byte();
7788     magic[1] = (char)try_byte();
7789    }
7790  else
7791    {
7792     magic[0] = (char)get_byte();
7793     magic[1] = (char)get_byte();
7794    }
7795
7796  gz1->method       = -1;        
7797  gz1->header_bytes = 0;         
7798  gz1->last_member  = RECORD_IO; 
7799  gz1->part_nb++;                
7800
7801  if ( memcmp(magic, GZIP_MAGIC,     2 ) == 0 ||
7802       memcmp(magic, OLD_GZIP_MAGIC, 2 ) == 0 )
7803    {
7804     gz1->method = (int)get_byte();
7805
7806     if ( gz1->method != DEFLATED )
7807       {
7808        gz1->exit_code = LZ1_ERROR;
7809
7810        return -1;
7811       }
7812
7813     return -1;
7814
7815     if ((flags & ENCRYPTED) != 0)
7816       {
7817        gz1->exit_code = LZ1_ERROR;
7818        return -1;
7819       }
7820
7821     if ((flags & CONTINUATION) != 0)
7822       {
7823        gz1->exit_code = LZ1_ERROR;
7824        if ( gz1->force <= 1) return -1;
7825       }
7826
7827     if ((flags & RESERVED) != 0)
7828       {
7829        gz1->exit_code = LZ1_ERROR;
7830        if ( gz1->force <= 1)
7831           return -1;
7832       }
7833
7834     stamp  = (ulg)get_byte();
7835         stamp |= ((ulg)get_byte()) << 8;
7836         stamp |= ((ulg)get_byte()) << 16;
7837         stamp |= ((ulg)get_byte()) << 24;
7838
7839     if ( stamp != 0 && !gz1->no_time )
7840       {
7841        gz1->time_stamp = stamp;
7842       }
7843
7844     (void)get_byte(); 
7845     (void)get_byte(); 
7846
7847     if ((flags & CONTINUATION) != 0)
7848       {
7849        part  = (unsigned)  get_byte();
7850        part |= ((unsigned) get_byte())<<8;
7851       }
7852
7853     if ((flags & EXTRA_FIELD) != 0)
7854       {
7855         len  = (unsigned)  get_byte();
7856         len |= ((unsigned) get_byte())<<8;
7857
7858         while (len--) (void)get_byte();
7859       }
7860
7861     if ((flags & COMMENT) != 0)
7862       {
7863        while (get_char() != 0)  ;
7864       }
7865
7866     if ( gz1->part_nb == 1 )
7867       {
7868        gz1->header_bytes = gz1->inptr + 2*sizeof(long);
7869       }
7870    }
7871
7872  return gz1->method;
7873 }
7874
7875 int fill_inbuf( PGZ1 gz1, int eof_ok )
7876 {
7877  int len;
7878  int bytes_to_copy;
7879
7880  gz1->insize = 0;
7881  errno       = 0;
7882
7883  do {
7884      if ( gz1->input_ismem )
7885        {
7886         if ( gz1->input_bytesleft > 0 )
7887           {
7888            bytes_to_copy = INBUFSIZ - gz1->insize;
7889
7890            if ( bytes_to_copy > gz1->input_bytesleft )
7891              {
7892               bytes_to_copy = gz1->input_bytesleft;
7893              }
7894
7895            memcpy(
7896            (char*)gz1->inbuf+gz1->insize,
7897            gz1->input_ptr,
7898            bytes_to_copy
7899            );
7900
7901            gz1->input_ptr       += bytes_to_copy;
7902            gz1->input_bytesleft -= bytes_to_copy;
7903
7904            len = bytes_to_copy;
7905           }
7906         else 
7907           {
7908            len = 0; 
7909           }
7910        }
7911      else 
7912        {
7913         len =
7914         read(
7915         gz1->ifd,
7916         (char*)gz1->inbuf+gz1->insize,
7917         INBUFSIZ-gz1->insize
7918         );
7919        }
7920
7921      if (len == 0 || len == EOF) break;
7922
7923      gz1->insize += len;
7924
7925     } while( gz1->insize < INBUFSIZ );
7926
7927  if ( gz1->insize == 0 )
7928    {
7929     if( eof_ok ) return EOF;
7930     read_error( gz1 );
7931    }
7932
7933  gz1->bytes_in += (ulg) gz1->insize;
7934  gz1->inptr     = 1;
7935
7936  return gz1->inbuf[0];
7937 }
7938
7939 ulg updcrc(
7940 PGZ1      gz1, 
7941 uch      *s,   
7942 unsigned  n    
7943 )
7944 {
7945  register ulg c; 
7946
7947  if ( s == NULL )
7948    {
7949     c = 0xffffffffL;
7950    }
7951  else
7952    {
7953     c = gz1->crc;
7954
7955     if ( n )
7956       {
7957        do{
7958           c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
7959
7960          } while( --n );
7961       }
7962    }
7963
7964  gz1->crc = c;
7965
7966  return( c ^ 0xffffffffL ); 
7967 }
7968
7969 void read_error( PGZ1 gz1 )
7970 {
7971  gz1->abortflag = 1;
7972 }
7973
7974 void mod_gzip_strlwr( char *s )
7975 {
7976  char *p1=s;
7977
7978  if ( s == 0 ) return;
7979
7980  while ( *p1 != 0 )
7981    {
7982     if ( *p1 > 96 ) *p1 = *p1 - 32;
7983     p1++;
7984    }
7985 }
7986
7987 #ifdef __BORLANDC__
7988 #pragma argsused
7989 #endif
7990
7991 char *gz1_basename( PGZ1 gz1, char *fname )
7992 {
7993  char *p;
7994
7995  if ((p = strrchr(fname, PATH_SEP))  != NULL) fname = p+1;
7996
7997  #ifdef PATH_SEP2
7998  if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
7999  #endif
8000
8001  #ifdef PATH_SEP3
8002  if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
8003  #endif
8004
8005  #ifdef SUFFIX_SEP
8006  if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
8007  #endif
8008
8009  if (casemap('A') == 'a') mod_gzip_strlwr(fname);
8010
8011  return fname;
8012 }
8013
8014 void write_buf( PGZ1 gz1, int fd, voidp buf, unsigned cnt )
8015 {
8016  unsigned n;
8017
8018  if ( gz1->output_ismem )
8019    {
8020     if ( ( gz1->bytes_out + cnt ) < gz1->output_maxlen )
8021       {
8022        memcpy( gz1->output_ptr, buf, cnt );
8023        gz1->output_ptr += cnt;
8024       }
8025     else
8026       {
8027        write_error( gz1 );
8028       }
8029    }
8030  else
8031    {
8032     while ((n = write(fd, buf, cnt)) != cnt)
8033       {
8034        if (n == (unsigned)(-1))
8035          {
8036           write_error( gz1 );
8037          }
8038        cnt -= n;
8039        buf = (voidp)((char*)buf+n);
8040       }
8041    }
8042 }
8043
8044 void write_error( PGZ1 gz1 )
8045 {
8046  gz1->abortflag = 1;
8047 }
8048
8049 #ifdef __TURBOC__
8050 #ifndef BC55
8051
8052 static ush ptr_offset = 0;
8053
8054 void * fcalloc(
8055 unsigned items, 
8056 unsigned size   
8057 )
8058 {
8059  void * buf = farmalloc((ulg)items*size + 16L);
8060
8061  if (buf == NULL) return NULL;
8062
8063  if (ptr_offset == 0)
8064    {
8065     ptr_offset = (ush)((uch*)buf-0);
8066    }
8067  else if (ptr_offset != (ush)((uch*)buf-0))
8068    {
8069     error("inconsistent ptr_offset");
8070    }
8071
8072  *((ush*)&buf+1) += (ptr_offset + 15) >> 4;
8073  *(ush*)&buf = 0;
8074
8075  return buf;
8076 }
8077
8078 void fcfree( void *ptr )
8079 {
8080  *((ush*)&ptr+1) -= (ptr_offset + 15) >> 4;
8081  *(ush*)&ptr = ptr_offset;
8082
8083  farfree(ptr);
8084 }
8085
8086 #endif 
8087 #endif 
8088
8089 int zip(
8090 PGZ1 gz1, 
8091 int in,   
8092 int out   
8093 )
8094 {
8095  uch  flags = 0;         
8096  ush  attr  = 0;         
8097  ush  deflate_flags = 0; 
8098
8099  gz1->ifd    = in;
8100  gz1->ofd    = out;
8101  gz1->outcnt = 0;
8102
8103  gz1->method = DEFLATED;
8104
8105  put_byte(GZIP_MAGIC[0]); 
8106  put_byte(GZIP_MAGIC[1]);
8107  put_byte(DEFLATED);      
8108
8109  if ( gz1->save_orig_name )
8110    {
8111         flags |= ORIG_NAME;
8112    }
8113
8114  put_byte(flags);           
8115  put_long(gz1->time_stamp); 
8116
8117  gz1->crc = -1; 
8118
8119  updcrc( gz1, NULL, 0 ); 
8120
8121  bi_init( gz1, out );
8122  ct_init( gz1, &attr, &gz1->method );
8123  lm_init( gz1, gz1->level, &deflate_flags );
8124
8125  put_byte((uch)deflate_flags); 
8126
8127  put_byte(OS_CODE); 
8128
8129  if ( gz1->save_orig_name )
8130    {
8131     char *p = gz1_basename( gz1, gz1->ifname );
8132
8133     do {
8134             put_char(*p);
8135
8136        } while (*p++);
8137    }
8138
8139  gz1->header_bytes = (long)gz1->outcnt;
8140
8141  (void) gz1_deflate( gz1 );
8142
8143  put_long( gz1->crc      );
8144  put_long( gz1->bytes_in );
8145
8146  gz1->header_bytes += 2*sizeof(long);
8147
8148  flush_outbuf( gz1 );
8149
8150  return OK;
8151 }
8152
8153 ulg gz1_deflate( PGZ1 gz1 )
8154 {
8155     unsigned hash_head;      
8156     unsigned prev_match;     
8157     int flush;               
8158     int match_available = 0; 
8159     register unsigned match_length = MIN_MATCH-1; 
8160 #ifdef DEBUG
8161     long isize;        
8162 #endif
8163
8164     if (gz1->compr_level <= 3)
8165       {
8166        return gz1_deflate_fast(gz1);
8167       }
8168
8169     while (gz1->lookahead != 0)
8170       {
8171        gz1->ins_h =
8172        (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK;
8173
8174        prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ];
8175
8176        head[ gz1->ins_h ] = gz1->strstart;
8177
8178         gz1->prev_length = match_length, prev_match = gz1->match_start;
8179         match_length = MIN_MATCH-1;
8180
8181         if (hash_head != NIL && gz1->prev_length < gz1->max_lazy_match &&
8182             gz1->strstart - hash_head <= MAX_DIST) {
8183             
8184             match_length = longest_match( gz1, hash_head );
8185             
8186             if (match_length > gz1->lookahead) match_length = gz1->lookahead;
8187
8188             if (match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR){
8189                 
8190                 match_length--;
8191             }
8192         }
8193         
8194         if (gz1->prev_length >= MIN_MATCH && match_length <= gz1->prev_length) {
8195
8196             flush = ct_tally(gz1,gz1->strstart-1-prev_match, gz1->prev_length - MIN_MATCH);
8197
8198             gz1->lookahead        -= ( gz1->prev_length - 1 );
8199             gz1->prev_length -= 2;
8200
8201             do {
8202                 gz1->strstart++;
8203
8204                 gz1->ins_h =
8205                 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
8206
8207                 prev[ gz1->strstart & WMASK ] = hash_head = head[gz1->ins_h];
8208
8209                 head[ gz1->ins_h ] = gz1->strstart;
8210
8211             } while (--gz1->prev_length != 0);
8212             match_available = 0;
8213             match_length = MIN_MATCH-1;
8214             gz1->strstart++;
8215             if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
8216
8217         } else if (match_available) {
8218             
8219             if (ct_tally( gz1, 0, gz1->window[gz1->strstart-1] )) {
8220                 FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
8221             }
8222             gz1->strstart++;
8223             gz1->lookahead--;
8224         } else {
8225             
8226             match_available = 1;
8227             gz1->strstart++;
8228             gz1->lookahead--;
8229         }
8230         
8231         while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1);
8232     }
8233     if (match_available) ct_tally( gz1, 0, gz1->window[gz1->strstart-1] );
8234
8235     return FLUSH_BLOCK(1); 
8236
8237  return 0;
8238 }
8239
8240 void flush_outbuf( PGZ1 gz1 )
8241 {
8242  if ( gz1->outcnt == 0 )
8243    {
8244     return;
8245    }
8246
8247  write_buf( gz1, gz1->ofd, (char *)gz1->outbuf, gz1->outcnt );
8248
8249  gz1->bytes_out += (ulg)gz1->outcnt;
8250  gz1->outcnt = 0;
8251 }
8252
8253 void lm_init(
8254 PGZ1 gz1,        
8255 int  pack_level, 
8256 ush *flags       
8257 )
8258 {
8259  register unsigned j;
8260
8261  if ( pack_level < 1 || pack_level > 9 )
8262    {
8263     error("bad pack level");
8264    }
8265
8266  gz1->compr_level = pack_level;
8267
8268  #if defined(MAXSEG_64K) && HASH_BITS == 15
8269  for (j = 0;  j < HASH_SIZE; j++) head[j] = NIL;
8270  #else
8271  memset( (char*)head, 0, (HASH_SIZE*sizeof(*head)) );
8272  #endif
8273
8274  gz1->max_lazy_match   = configuration_table[pack_level].max_lazy;
8275  gz1->good_match       = configuration_table[pack_level].good_length;
8276  #ifndef FULL_SEARCH
8277  gz1->nice_match       = configuration_table[pack_level].nice_length;
8278  #endif
8279  gz1->max_chain_length = configuration_table[pack_level].max_chain;
8280
8281  if ( pack_level == 1 )
8282    {
8283     *flags |= FAST;
8284    }
8285  else if ( pack_level == 9 )
8286    {
8287     *flags |= SLOW;
8288    }
8289
8290  gz1->strstart    = 0;
8291  gz1->block_start = 0L;
8292  #ifdef ASMV
8293  match_init(); 
8294  #endif
8295
8296  gz1->lookahead = read_buf(gz1,(char*)gz1->window,
8297                   sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE);
8298
8299  if (gz1->lookahead == 0 || gz1->lookahead == (unsigned)EOF)
8300    {
8301     gz1->eofile = 1, gz1->lookahead = 0;
8302     return;
8303    }
8304
8305  gz1->eofile = 0;
8306
8307  while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile)
8308    {
8309     fill_window(gz1);
8310    }
8311
8312  gz1->ins_h = 0;
8313
8314  for ( j=0; j<MIN_MATCH-1; j++ )
8315     {
8316      gz1->ins_h =
8317      (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[j])) & HASH_MASK;
8318     }
8319 }
8320
8321 void fill_window( PGZ1 gz1 )
8322 {
8323  register unsigned n, m;
8324
8325  unsigned more =
8326  (unsigned)( gz1->window_size - (ulg)gz1->lookahead - (ulg)gz1->strstart );
8327
8328  if ( more == (unsigned)EOF)
8329    {
8330     more--;
8331    }
8332  else if ( gz1->strstart >= WSIZE+MAX_DIST )
8333    {
8334     memcpy((char*)gz1->window, (char*)gz1->window+WSIZE, (unsigned)WSIZE);
8335
8336     gz1->match_start -= WSIZE;
8337     gz1->strstart    -= WSIZE; 
8338
8339     gz1->block_start -= (long) WSIZE;
8340
8341     for ( n = 0; n < HASH_SIZE; n++ )
8342        {
8343         m = head[n];
8344         head[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL);
8345        }
8346
8347     for ( n = 0; n < WSIZE; n++ )
8348        {
8349         m = prev[n];
8350
8351         prev[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL);
8352        }
8353
8354     more += WSIZE;
8355    }
8356
8357  if ( !gz1->eofile )
8358    {
8359     n = read_buf(gz1,(char*)gz1->window+gz1->strstart+gz1->lookahead, more);
8360
8361     if ( n == 0 || n == (unsigned)EOF )
8362       {
8363        gz1->eofile = 1;
8364       }
8365     else
8366       {
8367        gz1->lookahead += n;
8368       }
8369    }
8370 }
8371
8372 ulg gz1_deflate_fast( PGZ1 gz1 )
8373 {
8374     unsigned hash_head; 
8375     int flush;      
8376     unsigned match_length = 0;  
8377
8378     gz1->prev_length = MIN_MATCH-1;
8379
8380     while (gz1->lookahead != 0)
8381       {
8382        gz1->ins_h =
8383        (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
8384        
8385        prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ];
8386
8387        head[ gz1->ins_h ] = gz1->strstart;
8388
8389         if (hash_head != NIL && gz1->strstart - hash_head <= MAX_DIST) {
8390             
8391             match_length = longest_match( gz1, hash_head );
8392             
8393             if (match_length > gz1->lookahead) match_length = gz1->lookahead;
8394         }
8395         if (match_length >= MIN_MATCH) {
8396
8397             flush = ct_tally(gz1,gz1->strstart-gz1->match_start, match_length - MIN_MATCH);
8398
8399             gz1->lookahead -= match_length;
8400
8401             if (match_length <= gz1->max_lazy_match )
8402               {
8403                 match_length--; 
8404
8405                 do {
8406                     gz1->strstart++;
8407
8408                     gz1->ins_h =
8409                     (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
8410                     
8411                     prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ];
8412
8413                     head[ gz1->ins_h ] = gz1->strstart;
8414
8415                 } while (--match_length != 0);
8416             gz1->strstart++;
8417             } else {
8418             gz1->strstart += match_length;
8419                 match_length = 0;
8420             gz1->ins_h = gz1->window[gz1->strstart];
8421
8422             gz1->ins_h =
8423             (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[gz1->strstart+1])) & HASH_MASK;
8424             
8425 #if MIN_MATCH != 3
8426                 Call UPDATE_HASH() MIN_MATCH-3 more times
8427 #endif
8428             }
8429         } else {
8430             
8431             flush = ct_tally(gz1, 0, gz1->window[gz1->strstart]);
8432             gz1->lookahead--;
8433         gz1->strstart++;
8434         }
8435         if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
8436
8437         while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1);
8438     }
8439
8440  return FLUSH_BLOCK(1);
8441 }
8442
8443 void ct_init(
8444 PGZ1  gz1,    
8445 ush  *attr,   
8446 int  *methodp 
8447 )
8448 {
8449  #ifdef DD1
8450  int i,ii;
8451  #endif
8452
8453  int n;      
8454  int bits;   
8455  int length; 
8456  int code;   
8457  int dist;   
8458
8459  gz1->file_type      = attr;
8460  gz1->file_method    = methodp;
8461  gz1->compressed_len = gz1->input_len = 0L;
8462         
8463  if ( gz1->static_dtree[0].dl.len != 0 )
8464    {
8465     return;
8466    }
8467
8468  length = 0;
8469
8470  for ( code = 0; code < LENGTH_CODES-1; code++ )
8471     {
8472      gz1->base_length[code] = length;
8473
8474      for ( n = 0; n < (1<<extra_lbits[code]); n++ )
8475         {
8476          gz1->length_code[length++] = (uch)code;
8477         }
8478     }
8479
8480  gz1->length_code[length-1] = (uch)code;
8481
8482  dist = 0;
8483
8484  for ( code = 0 ; code < 16; code++ )
8485     {
8486      gz1->base_dist[code] = dist;
8487
8488      for ( n = 0; n < (1<<extra_dbits[code]); n++ )
8489         {
8490          gz1->dist_code[dist++] = (uch)code;
8491         }
8492     }
8493
8494  dist >>= 7; 
8495
8496  for ( ; code < D_CODES; code++ )
8497     {
8498      gz1->base_dist[code] = dist << 7;
8499
8500      for ( n = 0; n < (1<<(extra_dbits[code]-7)); n++ )
8501         {
8502          gz1->dist_code[256 + dist++] = (uch)code;
8503         }
8504     }
8505
8506  for ( bits = 0; bits <= MAX_BITS; bits++ )
8507     {
8508      gz1->bl_count[bits] = 0;
8509     }
8510
8511  n = 0;
8512
8513  while (n <= 143) gz1->static_ltree[n++].dl.len = 8, gz1->bl_count[8]++;
8514  while (n <= 255) gz1->static_ltree[n++].dl.len = 9, gz1->bl_count[9]++;
8515  while (n <= 279) gz1->static_ltree[n++].dl.len = 7, gz1->bl_count[7]++;
8516  while (n <= 287) gz1->static_ltree[n++].dl.len = 8, gz1->bl_count[8]++;
8517
8518  gen_codes(gz1,(ct_data *)gz1->static_ltree, L_CODES+1);
8519
8520  for ( n = 0; n < D_CODES; n++ )
8521     {
8522      gz1->static_dtree[n].dl.len  = 5;
8523      gz1->static_dtree[n].fc.code = bi_reverse( gz1, n, 5 );
8524     }
8525
8526  init_block( gz1 );
8527 }
8528
8529 ulg flush_block(
8530 PGZ1  gz1,        
8531 char *buf,        
8532 ulg   stored_len, 
8533 int   eof         
8534 )
8535 {
8536  ulg opt_lenb;     
8537  ulg static_lenb;  
8538  int max_blindex;  
8539
8540  gz1->flag_buf[gz1->last_flags] = gz1->flags;
8541
8542  if (*gz1->file_type == (ush)UNKNOWN) set_file_type(gz1);
8543
8544  build_tree( gz1, (tree_desc *)(&gz1->l_desc) );
8545  build_tree( gz1, (tree_desc *)(&gz1->d_desc) );
8546
8547  max_blindex = build_bl_tree( gz1 );
8548
8549  opt_lenb         = (gz1->opt_len+3+7)>>3;
8550  static_lenb      = (gz1->static_len+3+7)>>3;
8551  gz1->input_len  += stored_len; 
8552
8553  if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
8554
8555 #ifdef FORCE_METHOD
8556  
8557  if ( level == 1 && eof && gz1->compressed_len == 0L )
8558 #else
8559  if (stored_len <= opt_lenb && eof && gz1->compressed_len == 0L && 0 )
8560 #endif
8561    {
8562     if (buf == (char*)0) error ("block vanished");
8563
8564     copy_block( gz1, buf, (unsigned)stored_len, 0 ); 
8565
8566     gz1->compressed_len = stored_len << 3;
8567     *gz1->file_method   = STORED;
8568
8569 #ifdef FORCE_METHOD
8570  } else if (level == 2 && buf != (char*)0) { 
8571 #else
8572  } else if (stored_len+4 <= opt_lenb && buf != (char*)0) {
8573                     
8574 #endif
8575      
8576      send_bits(gz1,(STORED_BLOCK<<1)+eof, 3);  
8577      gz1->compressed_len = (gz1->compressed_len + 3 + 7) & ~7L;
8578      gz1->compressed_len += (stored_len + 4) << 3;
8579
8580      copy_block(gz1, buf, (unsigned)stored_len, 1); 
8581
8582 #ifdef FORCE_METHOD
8583  } else if (level == 3) { 
8584 #else
8585  } else if (static_lenb == opt_lenb) {
8586 #endif
8587      send_bits(gz1,(STATIC_TREES<<1)+eof, 3);
8588
8589      compress_block(
8590      gz1,
8591      (ct_data *)gz1->static_ltree,
8592      (ct_data *)gz1->static_dtree
8593      );
8594
8595      gz1->compressed_len += 3 + gz1->static_len;
8596     }
8597   else
8598     {
8599      send_bits(gz1,(DYN_TREES<<1)+eof, 3);
8600
8601      send_all_trees(
8602      gz1,
8603      gz1->l_desc.max_code+1,
8604      gz1->d_desc.max_code+1,
8605      max_blindex+1
8606      );
8607
8608      compress_block(
8609      gz1,
8610      (ct_data *)gz1->dyn_ltree,
8611      (ct_data *)gz1->dyn_dtree
8612      );
8613
8614      gz1->compressed_len += 3 + gz1->opt_len;
8615     }
8616
8617  init_block( gz1 );
8618
8619  if ( eof )
8620    {
8621     bi_windup( gz1 );
8622
8623     gz1->compressed_len += 7;  
8624    }
8625
8626  return gz1->compressed_len >> 3;
8627 }
8628
8629 #ifdef __BORLANDC__
8630 #pragma argsused
8631 #endif
8632
8633 unsigned bi_reverse(
8634 PGZ1     gz1,  
8635 unsigned code, 
8636 int      len   
8637 )
8638 {
8639  register unsigned res = 0;
8640
8641  do {
8642      res |= code & 1;
8643      code >>= 1, res <<= 1;
8644
8645     } while (--len > 0);
8646
8647  return res >> 1;
8648 }
8649
8650 void set_file_type( PGZ1 gz1 )
8651 {
8652  int n = 0;
8653  unsigned ascii_freq = 0;
8654  unsigned bin_freq = 0;
8655
8656  while (n < 7)        bin_freq += gz1->dyn_ltree[n++].fc.freq;
8657  while (n < 128)    ascii_freq += gz1->dyn_ltree[n++].fc.freq;
8658  while (n < LITERALS) bin_freq += gz1->dyn_ltree[n++].fc.freq;
8659
8660  *gz1->file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
8661 }
8662
8663 void init_block( PGZ1 gz1 )
8664 {
8665  int n; 
8666
8667  for (n = 0; n < L_CODES;  n++) gz1->dyn_ltree[n].fc.freq = 0;
8668  for (n = 0; n < D_CODES;  n++) gz1->dyn_dtree[n].fc.freq = 0;
8669  for (n = 0; n < BL_CODES; n++) gz1->bl_tree[n].fc.freq   = 0;
8670
8671  gz1->dyn_ltree[END_BLOCK].fc.freq = 1;
8672
8673  gz1->opt_len    = 0L;
8674  gz1->static_len = 0L;
8675  gz1->last_lit   = 0;
8676  gz1->last_dist  = 0;
8677  gz1->last_flags = 0;
8678  gz1->flags      = 0;
8679  gz1->flag_bit   = 1;
8680 }
8681
8682 void bi_init( PGZ1 gz1, gz1_file_t zipfile )
8683 {
8684  gz1->zfile    = zipfile;
8685  gz1->bi_buf   = 0;
8686  gz1->bi_valid = 0;
8687
8688  if ( gz1->zfile != NO_FILE )
8689    {
8690     read_buf = file_read;
8691    }
8692 }
8693
8694 int ct_tally(
8695 PGZ1 gz1,  
8696 int  dist, 
8697 int  lc    
8698 )
8699 {
8700  int dcode;
8701
8702  gz1->inbuf[gz1->last_lit++] = (uch)lc;
8703
8704  if ( dist == 0 )
8705    {
8706     gz1->dyn_ltree[lc].fc.freq++; 
8707    }
8708  else
8709    {
8710     dist--; 
8711
8712     gz1->dyn_ltree[gz1->length_code[lc]+LITERALS+1].fc.freq++;
8713     gz1->dyn_dtree[d_code(dist)].fc.freq++;
8714     gz1->d_buf[gz1->last_dist++] = (ush)dist;
8715     gz1->flags |= gz1->flag_bit;
8716    }
8717
8718  gz1->flag_bit <<= 1;
8719
8720  if ( (gz1->last_lit & 7) == 0 )
8721    {
8722     gz1->flag_buf[gz1->last_flags++] = gz1->flags;
8723     gz1->flags = 0, gz1->flag_bit = 1;
8724    }
8725
8726  if ( gz1->level > 2 && (gz1->last_lit & 0xfff) == 0)
8727    {
8728     ulg out_length = (ulg) ( gz1->last_lit * 8L );
8729     ulg in_length  = (ulg) ( gz1->strstart - gz1->block_start );
8730
8731     for ( dcode = 0; dcode < D_CODES; dcode++ )
8732        {
8733         out_length += (ulg) ((gz1->dyn_dtree[dcode].fc.freq)*(5L+extra_dbits[dcode]));
8734        }
8735
8736     out_length >>= 3;
8737
8738     if ( gz1->last_dist < gz1->last_lit/2 && out_length < in_length/2 )
8739       {
8740        return 1;
8741       }
8742    }
8743
8744  return( gz1->last_lit == LIT_BUFSIZE-1 || gz1->last_dist == DIST_BUFSIZE );
8745 }
8746
8747 void compress_block(
8748 PGZ1     gz1,   
8749 ct_data *ltree, 
8750 ct_data *dtree  
8751 )
8752 {
8753  unsigned dist;   
8754  int lc;          
8755  unsigned lx = 0; 
8756  unsigned dx = 0; 
8757  unsigned fx = 0; 
8758  uch flag = 0;    
8759  unsigned code;   
8760  int extra;       
8761
8762  if (gz1->last_lit != 0) do {
8763      if ((lx & 7) == 0) flag = gz1->flag_buf[fx++];
8764      lc = gz1->inbuf[lx++];
8765      if ((flag & 1) == 0) {
8766          send_code(lc, ltree); 
8767      } else {
8768          
8769          code = gz1->length_code[lc];
8770          send_code(code+LITERALS+1, ltree); 
8771          extra = extra_lbits[code];
8772          if (extra != 0) {
8773              lc -= gz1->base_length[code];
8774              send_bits(gz1,lc, extra); 
8775          }
8776          dist = gz1->d_buf[dx++];
8777          
8778          code = d_code(dist);
8779
8780          send_code(code, dtree);       
8781          extra = extra_dbits[code];
8782          if (extra != 0) {
8783              dist -= gz1->base_dist[code];
8784              send_bits(gz1,dist, extra); 
8785          }
8786      } 
8787      flag >>= 1;
8788  } while (lx < gz1->last_lit);
8789
8790  send_code(END_BLOCK, ltree);
8791 }
8792
8793 #ifndef ASMV
8794
8795 int longest_match( PGZ1 gz1, unsigned cur_match )
8796 {
8797  unsigned chain_length = gz1->max_chain_length;   
8798  register uch *scan = gz1->window + gz1->strstart;     
8799  register uch *match;                        
8800  register int len;                           
8801  int best_len = gz1->prev_length;                 
8802  unsigned limit = gz1->strstart > (unsigned)MAX_DIST ? gz1->strstart - (unsigned)MAX_DIST : NIL;
8803  
8804 #if HASH_BITS < 8 || MAX_MATCH != 258
8805    error: Code too clever
8806 #endif
8807
8808 #ifdef UNALIGNED_OK
8809     
8810     register uch *strend    = gz1->window + gz1->strstart + MAX_MATCH - 1;
8811     register ush scan_start = *(ush*)scan;
8812     register ush scan_end   = *(ush*)(scan+best_len-1);
8813 #else
8814     register uch *strend    = gz1->window + gz1->strstart + MAX_MATCH;
8815     register uch scan_end1  = scan[best_len-1];
8816     register uch scan_end   = scan[best_len];
8817 #endif
8818
8819     if (gz1->prev_length >= gz1->good_match) {
8820         chain_length >>= 2;
8821     }
8822
8823     do {
8824         match = gz1->window + cur_match;
8825
8826 #if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
8827         
8828         if (*(ush*)(match+best_len-1) != scan_end ||
8829             *(ush*)match != scan_start) continue;
8830
8831         scan++, match++;
8832         do {
8833         } while (*(ush*)(scan+=2) == *(ush*)(match+=2) &&
8834                  *(ush*)(scan+=2) == *(ush*)(match+=2) &&
8835                  *(ush*)(scan+=2) == *(ush*)(match+=2) &&
8836                  *(ush*)(scan+=2) == *(ush*)(match+=2) &&
8837                  scan < strend);
8838         
8839         if (*scan == *match) scan++;
8840
8841         len = (MAX_MATCH - 1) - (int)(strend-scan);
8842         scan = strend - (MAX_MATCH-1);
8843 #else 
8844         if (match[best_len]   != scan_end  ||
8845             match[best_len-1] != scan_end1 ||
8846             *match            != *scan     ||
8847             *++match          != scan[1])      continue;
8848
8849         scan += 2, match++;
8850
8851         do {
8852         } while (*++scan == *++match && *++scan == *++match &&
8853                  *++scan == *++match && *++scan == *++match &&
8854                  *++scan == *++match && *++scan == *++match &&
8855                  *++scan == *++match && *++scan == *++match &&
8856                  scan < strend);
8857
8858         len = MAX_MATCH - (int)(strend - scan);
8859         scan = strend - MAX_MATCH;
8860 #endif 
8861         if (len > best_len) {
8862             gz1->match_start = cur_match;
8863             best_len = len;
8864             if (len >= gz1->nice_match) break;
8865 #ifdef UNALIGNED_OK
8866             scan_end = *(ush*)(scan+best_len-1);
8867 #else
8868             scan_end1  = scan[best_len-1];
8869             scan_end   = scan[best_len];
8870 #endif
8871         }
8872     } while ((cur_match = prev[cur_match & WMASK]) > limit
8873              && --chain_length != 0);
8874
8875     return best_len;
8876 }
8877 #endif 
8878
8879 void send_bits(
8880 PGZ1 gz1,   
8881 int  value, 
8882 int  length 
8883 )
8884 {
8885  if ( gz1->bi_valid > (int) BUFSIZE - length )
8886    {
8887     gz1->bi_buf |= (value << gz1->bi_valid);
8888
8889     put_short(gz1->bi_buf);
8890
8891     gz1->bi_buf = (ush)value >> (BUFSIZE - gz1->bi_valid);
8892     gz1->bi_valid += length - BUFSIZE;
8893    }
8894  else
8895    {
8896     gz1->bi_buf |= value << gz1->bi_valid;
8897     gz1->bi_valid += length;
8898    }
8899 }
8900
8901 void build_tree(
8902 PGZ1       gz1, 
8903 tree_desc *desc 
8904 )
8905 {
8906  int elems      = desc->elems;
8907  ct_data *tree  = desc->dyn_tree;
8908  ct_data *stree = desc->static_tree;
8909
8910  int n;             
8911  int m;             
8912  int max_code = -1; 
8913  int node = elems;  
8914  int new1;          
8915
8916     gz1->heap_len = 0, gz1->heap_max = HEAP_SIZE;
8917
8918     for (n = 0; n < elems; n++) {
8919         if (tree[n].fc.freq != 0) {
8920             gz1->heap[++gz1->heap_len] = max_code = n;
8921             gz1->depth[n] = 0;
8922         } else {
8923             tree[n].dl.len = 0;
8924         }
8925     }
8926
8927     while (gz1->heap_len < 2) {
8928         new1 = gz1->heap[++gz1->heap_len] = (max_code < 2 ? ++max_code : 0);
8929         tree[new1].fc.freq = 1;
8930         gz1->depth[new1] = 0;
8931         gz1->opt_len--; if (stree) gz1->static_len -= stree[new1].dl.len;
8932     }
8933     desc->max_code = max_code;
8934
8935     for (n = gz1->heap_len/2; n >= 1; n--) pqdownheap(gz1, tree, n);
8936
8937     do {
8938         n = gz1->heap[SMALLEST];
8939         gz1->heap[SMALLEST] = gz1->heap[gz1->heap_len--];
8940         pqdownheap(gz1, tree, SMALLEST);
8941         m = gz1->heap[SMALLEST];
8942         gz1->heap[--gz1->heap_max] = n;
8943         gz1->heap[--gz1->heap_max] = m;
8944         tree[node].fc.freq = tree[n].fc.freq + tree[m].fc.freq;
8945         gz1->depth[node] = (uch) (GZ1_MAX(gz1->depth[n], gz1->depth[m]) + 1);
8946         tree[n].dl.dad = tree[m].dl.dad = (ush)node;
8947         gz1->heap[SMALLEST] = node++;
8948         pqdownheap(gz1, tree, SMALLEST);
8949
8950     } while (gz1->heap_len >= 2);
8951
8952     gz1->heap[--gz1->heap_max] = gz1->heap[SMALLEST];
8953
8954     gen_bitlen(gz1,(tree_desc *)desc);
8955
8956     gen_codes(gz1,(ct_data *)tree, max_code);
8957 }
8958
8959 int build_bl_tree( PGZ1 gz1 )
8960 {
8961  int max_blindex; 
8962
8963  scan_tree( gz1, (ct_data *)gz1->dyn_ltree, gz1->l_desc.max_code );
8964  scan_tree( gz1, (ct_data *)gz1->dyn_dtree, gz1->d_desc.max_code );
8965
8966  build_tree( gz1, (tree_desc *)(&gz1->bl_desc) );
8967
8968  for ( max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex-- )
8969     {
8970      if (gz1->bl_tree[bl_order[max_blindex]].dl.len != 0) break;
8971     }
8972
8973  gz1->opt_len += 3*(max_blindex+1) + 5+5+4;
8974
8975  return max_blindex;
8976 }
8977
8978 void gen_codes(
8979 PGZ1     gz1,     
8980 ct_data *tree,    
8981 int      max_code 
8982 )
8983 {
8984  ush next_code[MAX_BITS+1]; 
8985  ush code = 0;              
8986  int bits;                  
8987  int n;                     
8988
8989  for ( bits = 1; bits <= MAX_BITS; bits++ )
8990     {
8991      next_code[bits] = code = (code + gz1->bl_count[bits-1]) << 1;
8992     }
8993
8994  for ( n = 0;  n <= max_code; n++ )
8995     {
8996      int len = tree[n].dl.len;
8997      if (len == 0) continue;
8998
8999      tree[n].fc.code = bi_reverse( gz1, next_code[len]++, len );
9000     }
9001
9002  return;
9003 }
9004
9005 void gen_bitlen(
9006 PGZ1       gz1, 
9007 tree_desc *desc 
9008 )
9009 {
9010  ct_data *tree   = desc->dyn_tree;
9011  int *extra      = desc->extra_bits;
9012  int base             = desc->extra_base;
9013  int max_code         = desc->max_code;
9014  int max_length       = desc->max_length;
9015  ct_data *stree  = desc->static_tree;
9016  int h;              
9017  int n, m;           
9018  int bits;           
9019  int xbits;          
9020  ush f;              
9021  int overflow = 0;   
9022
9023  for (bits = 0; bits <= MAX_BITS; bits++) gz1->bl_count[bits] = 0;
9024
9025  tree[gz1->heap[gz1->heap_max]].dl.len = 0;
9026
9027  for (h = gz1->heap_max+1; h < HEAP_SIZE; h++) {
9028      n = gz1->heap[h];
9029      bits = tree[tree[n].dl.dad].dl.len + 1;
9030      if (bits > max_length) bits = max_length, overflow++;
9031      tree[n].dl.len = (ush)bits;
9032      
9033      if (n > max_code) continue; 
9034
9035      gz1->bl_count[bits]++;
9036      xbits = 0;
9037      if (n >= base) xbits = extra[n-base];
9038      f = tree[n].fc.freq;
9039      gz1->opt_len += (ulg)f * (bits + xbits);
9040      if (stree) gz1->static_len += (ulg)f * (stree[n].dl.len + xbits);
9041  }
9042  if (overflow == 0) return;
9043
9044  do {
9045      bits = max_length-1;
9046      while (gz1->bl_count[bits] == 0) bits--;
9047      gz1->bl_count[bits]--;      
9048      gz1->bl_count[bits+1] += 2; 
9049      gz1->bl_count[max_length]--;
9050      
9051      overflow -= 2;
9052  } while (overflow > 0);
9053
9054  for (bits = max_length; bits != 0; bits--) {
9055      n = gz1->bl_count[bits];
9056      while (n != 0) {
9057          m = gz1->heap[--h];
9058          if (m > max_code) continue;
9059          if (tree[m].dl.len != (unsigned) bits) {
9060              gz1->opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq;
9061              tree[m].dl.len = (ush)bits;
9062          }
9063          n--;
9064      }
9065   }
9066 }
9067
9068 void copy_block(
9069 PGZ1      gz1,    
9070 char     *buf,    
9071 unsigned  len,    
9072 int       header  
9073 )
9074 {
9075  #ifdef CRYPT
9076  int t;
9077  #endif
9078
9079  bi_windup( gz1 ); 
9080
9081  if ( header )
9082    {
9083     put_short((ush)len);
9084     put_short((ush)~len);
9085    }
9086
9087  while( len-- )
9088    {
9089     #ifdef CRYPT
9090         if (key) zencode(*buf, t);
9091     #endif
9092
9093     put_byte(*buf++);
9094    }
9095 }
9096
9097 int file_read( PGZ1 gz1, char *buf, unsigned size )
9098 {
9099  unsigned len = 0;
9100  unsigned bytes_to_copy = 0;
9101
9102  if ( gz1->input_ismem )
9103    {
9104     if ( gz1->input_bytesleft > 0 )
9105       {
9106        bytes_to_copy = size;
9107
9108        if ( bytes_to_copy > (unsigned) gz1->input_bytesleft )
9109          {
9110           bytes_to_copy = (unsigned) gz1->input_bytesleft;
9111          }
9112
9113        memcpy( buf, gz1->input_ptr, bytes_to_copy );
9114
9115        gz1->input_ptr       += bytes_to_copy;
9116        gz1->input_bytesleft -= bytes_to_copy;
9117
9118        len = bytes_to_copy;
9119       }
9120     else
9121       {
9122        len = 0;
9123       }
9124    }
9125  else
9126    {
9127     len = read( gz1->ifd, buf, size );
9128    }
9129
9130  if ( len == (unsigned)(-1) || len == 0 )
9131    {
9132         gz1->crc = gz1->crc ^ 0xffffffffL;
9133     /* XXX - Do we need to do something with Adler CRC's here?
9134          * I don't think so--they don't seem to need postprocessing. */
9135     return (int)len;
9136    }
9137
9138  if (gz1->compression_format != DEFLATE_FORMAT)
9139    {
9140     updcrc( gz1, (uch*)buf, len );
9141    }
9142  else
9143    {
9144         gz1->adler = adler32(gz1->adler, (uch*)buf, len);
9145    }
9146
9147  gz1->bytes_in += (ulg)len;
9148
9149  return (int)len;
9150 }
9151
9152 void bi_windup( PGZ1 gz1 )
9153 {
9154  if ( gz1->bi_valid > 8 )
9155    {
9156     put_short(gz1->bi_buf);
9157    }
9158  else if ( gz1->bi_valid > 0 )
9159    {
9160     put_byte(gz1->bi_buf);
9161    }
9162
9163  gz1->bi_buf   = 0;
9164  gz1->bi_valid = 0;
9165 }
9166
9167 void send_all_trees(
9168 PGZ1 gz1,    
9169 int  lcodes, 
9170 int  dcodes, 
9171 int  blcodes 
9172 )
9173 {
9174  int rank; 
9175
9176  send_bits(gz1,lcodes-257, 5); 
9177  send_bits(gz1,dcodes-1,   5);
9178  send_bits(gz1,blcodes-4,  4); 
9179
9180  for ( rank = 0; rank < blcodes; rank++ )
9181     {
9182      send_bits(gz1,gz1->bl_tree[bl_order[rank]].dl.len, 3 );
9183     }
9184
9185  send_tree(gz1,(ct_data *)gz1->dyn_ltree, lcodes-1); 
9186  send_tree(gz1,(ct_data *)gz1->dyn_dtree, dcodes-1); 
9187 }
9188
9189 void send_tree(
9190 PGZ1     gz1,     
9191 ct_data *tree,    
9192 int      max_code 
9193 )
9194 {
9195  int n;                        
9196  int prevlen = -1;             
9197  int curlen;                   
9198  int nextlen = tree[0].dl.len; 
9199  int count = 0;                
9200  int max_count = 7;            
9201  int min_count = 4;            
9202
9203  if (nextlen == 0) max_count = 138, min_count = 3;
9204
9205  for ( n = 0; n <= max_code; n++ )
9206     {
9207      curlen  = nextlen;
9208      nextlen = tree[n+1].dl.len;
9209
9210      if (++count < max_count && curlen == nextlen)
9211        {
9212         continue;
9213        }
9214      else if (count < min_count)
9215        {
9216         do { send_code(curlen, gz1->bl_tree); } while (--count != 0);
9217        }
9218      else if (curlen != 0)
9219        {
9220         if ( curlen != prevlen )
9221           {
9222            send_code(curlen, gz1->bl_tree); count--;
9223           }
9224
9225         send_code( REP_3_6, gz1->bl_tree ); send_bits(gz1,count-3, 2);
9226        }
9227      else if (count <= 10)
9228        {
9229         send_code(REPZ_3_10, gz1->bl_tree); send_bits(gz1,count-3, 3);
9230        }
9231      else
9232        {
9233         send_code(REPZ_11_138, gz1->bl_tree); send_bits(gz1,count-11, 7);
9234        }
9235
9236      count   = 0;
9237      prevlen = curlen;
9238
9239      if (nextlen == 0)
9240        {
9241         max_count = 138, min_count = 3;
9242        }
9243      else if (curlen == nextlen)
9244        {
9245         max_count = 6, min_count = 3;
9246        }
9247      else
9248        {
9249         max_count = 7, min_count = 4;
9250        }
9251     }
9252 }
9253
9254 void scan_tree(
9255 PGZ1     gz1,     
9256 ct_data *tree,    
9257 int      max_code 
9258 )
9259 {
9260  int n;                        
9261  int prevlen = -1;             
9262  int curlen;                   
9263  int nextlen = tree[0].dl.len; 
9264  int count = 0;                
9265  int max_count = 7;            
9266  int min_count = 4;            
9267
9268  if (nextlen == 0) max_count = 138, min_count = 3;
9269
9270  tree[max_code+1].dl.len = (ush)0xffff; 
9271
9272  for ( n = 0; n <= max_code; n++ )
9273     {
9274      curlen  = nextlen;
9275      nextlen = tree[n+1].dl.len;
9276
9277      if ( ++count < max_count && curlen == nextlen )
9278        {
9279         continue;
9280        }
9281      else if ( count < min_count )
9282        {
9283         gz1->bl_tree[curlen].fc.freq += count;
9284        }
9285      else if ( curlen != 0 )
9286        {
9287         if ( curlen != prevlen ) gz1->bl_tree[curlen].fc.freq++;
9288         gz1->bl_tree[REP_3_6].fc.freq++;
9289        }
9290      else if ( count <= 10 )
9291        {
9292         gz1->bl_tree[REPZ_3_10].fc.freq++;
9293        }
9294      else
9295        {
9296         gz1->bl_tree[REPZ_11_138].fc.freq++;
9297        }
9298
9299      count   = 0;
9300      prevlen = curlen;
9301
9302      if ( nextlen == 0 )
9303        {
9304         max_count = 138;
9305         min_count = 3;
9306        }
9307      else if (curlen == nextlen)
9308        {
9309         max_count = 6;
9310         min_count = 3;
9311        }
9312      else
9313        {
9314         max_count = 7;
9315         min_count = 4;
9316        }
9317     }
9318 }
9319
9320 void pqdownheap(
9321 PGZ1     gz1,  
9322 ct_data *tree, 
9323 int      k     
9324 )
9325 {
9326  int v = gz1->heap[k];
9327  int j = k << 1;  
9328
9329  while( j <= gz1->heap_len )
9330    {
9331     if (j < gz1->heap_len && smaller(tree, gz1->heap[j+1], gz1->heap[j])) j++;
9332
9333     if (smaller(tree, v, gz1->heap[j])) break;
9334
9335     gz1->heap[k] = gz1->heap[j];  k = j;
9336
9337     j <<= 1;
9338    }
9339
9340  gz1->heap[k] = v;
9341 }
9342
9343
9344 #define GZS_ZIP1      1
9345 #define GZS_ZIP2      2
9346 #define GZS_DEFLATE1  3
9347 #define GZS_DEFLATE2  4
9348
9349 int gzs_fsp     ( PGZ1 gz1 ); 
9350 int gzs_zip1    ( PGZ1 gz1 ); 
9351 int gzs_zip2    ( PGZ1 gz1 ); 
9352 int gzs_deflate1( PGZ1 gz1 ); 
9353 int gzs_deflate2( PGZ1 gz1 ); 
9354
9355 int gzp_main( GZP_CONTROL *gzp )
9356 {
9357  PGZ1 gz1 = 0; 
9358  int  rc  = 0;
9359  int  final_exit_code = 0;
9360  int  ofile_flags = O_RDWR | O_CREAT | O_TRUNC | O_BINARY;
9361
9362  gzp->result_code = 0; 
9363  gzp->bytes_out   = 0; 
9364
9365  gz1 = (PGZ1) gz1_init();
9366
9367  if ( gz1 == 0 )
9368    {
9369     return 0;
9370    }
9371
9372  gz1->decompress      = gzp->decompress;
9373  gz1->compression_format = gzp->compression_format;
9374
9375  strcpy( gz1->ifname, gzp->input_filename  );
9376  strcpy( gz1->ofname, gzp->output_filename );
9377
9378  gz1->input_ismem     = gzp->input_ismem;
9379  gz1->input_ptr       = gzp->input_ismem_ibuf;
9380  gz1->input_bytesleft = gzp->input_ismem_ibuflen;
9381
9382  gz1->output_ismem    = gzp->output_ismem;
9383  gz1->output_ptr      = gzp->output_ismem_obuf;
9384  gz1->output_maxlen   = gzp->output_ismem_obuflen;
9385
9386  if ( gz1->no_time < 0 ) gz1->no_time = gz1->decompress;
9387  if ( gz1->no_name < 0 ) gz1->no_name = gz1->decompress;
9388
9389  work = zip; 
9390
9391  if ( !gz1->input_ismem ) 
9392    {
9393     errno = 0;
9394
9395     rc = stat( gz1->ifname, &gz1->istat );
9396
9397     if ( rc != 0 ) 
9398       {
9399        gz1_cleanup( gz1 ); 
9400
9401        return 0; 
9402       }
9403
9404     gz1->ifile_size = gz1->istat.st_size;
9405
9406     gz1->ifd =
9407     OPEN(
9408     gz1->ifname,
9409     gz1->ascii && !gz1->decompress ? O_RDONLY : O_RDONLY | O_BINARY,
9410     RW_USER
9411     );
9412
9413     if ( gz1->ifd == -1 )
9414       {
9415        gz1_cleanup( gz1 ); 
9416
9417        return 0; 
9418       }
9419    }
9420
9421  if ( !gz1->output_ismem ) 
9422    {
9423     if ( gz1->ascii && gz1->decompress )
9424       {
9425        ofile_flags &= ~O_BINARY; 
9426       }
9427
9428     gz1->ofd = OPEN( gz1->ofname, ofile_flags, RW_USER );
9429
9430     if ( gz1->ofd == -1 )
9431       {
9432        if ( gz1->ifd ) 
9433          {
9434           close( gz1->ifd ); 
9435           gz1->ifd = 0;      
9436          }
9437
9438        gz1_cleanup( gz1 ); 
9439
9440        return 0; 
9441       }
9442    }
9443
9444  gz1->outcnt    = 0;
9445  gz1->insize    = 0;
9446  gz1->inptr     = 0;
9447  gz1->bytes_in  = 0L;
9448  gz1->bytes_out = 0L; 
9449  gz1->part_nb   = 0;
9450
9451  if ( gz1->decompress )
9452    {
9453     gz1->method = get_header( gz1, gz1->ifd );
9454
9455     if ( gz1->method < 0 )
9456       {
9457        if ( gz1->ifd ) 
9458          {
9459           close( gz1->ifd ); 
9460           gz1->ifd = 0;      
9461          }
9462
9463        if ( gz1->ofd ) 
9464          {
9465           close( gz1->ofd ); 
9466           gz1->ofd = 0;      
9467          }
9468
9469        return 0; 
9470       }
9471    }
9472
9473  gz1->save_orig_name = 0;
9474
9475  gz1->state = GZS_ZIP1;
9476
9477  for (;;) 
9478     {
9479      gzs_fsp( gz1 ); 
9480
9481      if ( gz1->done == 1 ) break; 
9482     }
9483
9484  if ( gz1->ifd ) 
9485    {
9486     close( gz1->ifd ); 
9487     gz1->ifd = 0;      
9488    }
9489
9490  if ( gz1->ofd ) 
9491    {
9492     close( gz1->ofd ); 
9493     gz1->ofd = 0;      
9494    }
9495
9496  gzp->result_code = gz1->exit_code;
9497  gzp->bytes_out   = gz1->bytes_out;
9498
9499  final_exit_code = (int) gz1->exit_code;
9500
9501  gz1_cleanup( gz1 );  
9502
9503  return final_exit_code; 
9504 }
9505
9506 int gzs_fsp( PGZ1 gz1 )
9507 {
9508  int rc=0; 
9509
9510  switch( gz1->state )
9511    {
9512     case GZS_ZIP1:
9513
9514          rc = gzs_zip1( gz1 );
9515
9516          break;
9517
9518     case GZS_ZIP2:
9519
9520          rc = gzs_zip2( gz1 );
9521
9522          break;
9523
9524     case GZS_DEFLATE1:
9525
9526          rc = gzs_deflate1( gz1 );
9527
9528          break;
9529
9530     case GZS_DEFLATE2:
9531
9532          rc = gzs_deflate2( gz1 );
9533
9534          break;
9535
9536     default: 
9537
9538          gz1->done = 1;
9539
9540          break;
9541    }
9542
9543  return( rc );
9544 }
9545
9546
9547 int gzs_zip1( PGZ1 gz1 )
9548 {
9549  uch  flags = 0;         
9550  ush  attr  = 0;         
9551  ush  deflate_flags = 0; 
9552
9553  gz1->outcnt = 0;
9554
9555  gz1->method = DEFLATED;
9556
9557  if (gz1->compression_format != DEFLATE_FORMAT)
9558    {
9559     put_byte(GZIP_MAGIC[0]); 
9560     put_byte(GZIP_MAGIC[1]);
9561     put_byte(DEFLATED);      
9562    }
9563  else
9564    {
9565         /* Yes, I know RFC 1951 doesn't mention any header at the start of
9566          * a deflated document, but zlib absolutely requires one. And since nearly
9567      * all "deflate" implementations use zlib, we need to play along with this
9568      * brain damage. */
9569     put_byte(ZLIB_HEADER[0]); 
9570     put_byte(ZLIB_HEADER[1]);
9571    }
9572
9573  if ( gz1->save_orig_name )
9574    {
9575         flags |= ORIG_NAME;
9576    }
9577
9578  if (gz1->compression_format != DEFLATE_FORMAT)
9579    {
9580     put_byte(flags);           
9581     put_long(gz1->time_stamp); 
9582
9583         gz1->crc = -1; 
9584     updcrc( gz1, NULL, 0 ); 
9585    }
9586  else
9587    {
9588         /* Deflate compression uses an Adler32 CRC, not a CRC32. */
9589         gz1->adler = 1L;
9590    }
9591
9592  gz1->state = GZS_ZIP2;
9593
9594  return 0;
9595 }
9596
9597 int gzs_zip2( PGZ1 gz1 )
9598 {
9599  uch  flags = 0;         
9600  ush  attr  = 0;         
9601  ush  deflate_flags = 0; 
9602
9603  bi_init( gz1, gz1->ofd );
9604  ct_init( gz1, &attr, &gz1->method );
9605  lm_init( gz1, gz1->level, &deflate_flags );
9606
9607  if (gz1->compression_format != DEFLATE_FORMAT)
9608    {
9609     put_byte((uch)deflate_flags); 
9610     put_byte(OS_CODE); 
9611     if ( gz1->save_orig_name )
9612       {
9613        char *p = gz1_basename( gz1, gz1->ifname );
9614
9615        do {
9616                put_char(*p);
9617
9618           } while (*p++);
9619       }
9620    }
9621
9622  gz1->header_bytes = (long)gz1->outcnt;
9623
9624  gz1->state = GZS_DEFLATE1;
9625
9626  return 0;
9627 }
9628
9629 int gzs_deflate1( PGZ1 gz1 )
9630 {
9631  if ( !gz1->deflate1_initialized )
9632    {
9633     gz1->deflate1_match_available = 0;           
9634     gz1->deflate1_match_length    = MIN_MATCH-1; 
9635     gz1->deflate1_initialized     = 1;
9636    }
9637
9638  if ( gz1->compr_level <= 3 )
9639    {
9640     gz1->done = 1; 
9641
9642     return 0;
9643    }
9644
9645  if ( gz1->lookahead == 0 )
9646    {
9647     if ( gz1->deflate1_match_available )
9648       {
9649        ct_tally( gz1, 0, gz1->window[gz1->strstart-1] );
9650       }
9651
9652     gz1->state = GZS_DEFLATE2;
9653
9654     return (int) FLUSH_BLOCK(1); 
9655    }
9656
9657  #ifdef STAY_HERE_FOR_A_CERTAIN_AMOUNT_OF_ITERATIONS
9658  
9659  while( iterations < max_iterations_per_yield )
9660    {
9661  #endif
9662
9663     gz1->ins_h =
9664     (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK;
9665
9666     prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[ gz1->ins_h ];
9667
9668     head[ gz1->ins_h ] = gz1->strstart;
9669
9670     gz1->prev_length = gz1->deflate1_match_length, gz1->deflate1_prev_match = gz1->match_start;
9671     gz1->deflate1_match_length = MIN_MATCH-1;
9672
9673     if ( gz1->deflate1_hash_head != NIL && gz1->prev_length < gz1->max_lazy_match &&
9674          gz1->strstart - gz1->deflate1_hash_head <= MAX_DIST)
9675       {
9676        gz1->deflate1_match_length = longest_match( gz1, gz1->deflate1_hash_head );
9677
9678        if ( gz1->deflate1_match_length > gz1->lookahead )
9679          {
9680           gz1->deflate1_match_length = gz1->lookahead;
9681          }
9682
9683        if (gz1->deflate1_match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR)
9684          {
9685           gz1->deflate1_match_length--;
9686          }
9687       }
9688
9689     if ( gz1->prev_length >= MIN_MATCH && gz1->deflate1_match_length <= gz1->prev_length )
9690       {
9691        gz1->deflate1_flush =
9692        ct_tally(gz1,gz1->strstart-1-gz1->deflate1_prev_match, gz1->prev_length - MIN_MATCH);
9693
9694        gz1->lookahead   -= ( gz1->prev_length - 1 );
9695        gz1->prev_length -= 2;
9696
9697        do {
9698            gz1->strstart++;
9699
9700            gz1->ins_h =
9701            (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
9702
9703            prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[gz1->ins_h];
9704
9705            head[ gz1->ins_h ] = gz1->strstart;
9706
9707           } while (--gz1->prev_length != 0);
9708
9709        gz1->deflate1_match_available = 0;
9710        gz1->deflate1_match_length    = MIN_MATCH-1;
9711
9712        gz1->strstart++;
9713
9714        if (gz1->deflate1_flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
9715       }
9716
9717     else
9718       {
9719        if ( gz1->deflate1_match_available )
9720          {
9721           if ( ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ) )
9722             {
9723              FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
9724             }
9725
9726           gz1->strstart++;
9727           gz1->lookahead--;
9728          }
9729        else 
9730          {
9731           gz1->deflate1_match_available = 1;
9732           gz1->strstart++;
9733           gz1->lookahead--;
9734          }
9735
9736        while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile )
9737          {
9738           fill_window(gz1);
9739          }
9740       }
9741
9742  return 0;
9743 }
9744
9745 int gzs_deflate2( PGZ1 gz1 )
9746 {
9747  #if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO)
9748  if (gz1->ifile_size != -1L && gz1->isize != (ulg)gz1->ifile_size)
9749    {
9750    }
9751  #endif
9752
9753  if (gz1->compression_format != DEFLATE_FORMAT)
9754    {
9755     put_long( gz1->crc );
9756     put_long( gz1->bytes_in );
9757     gz1->header_bytes += 2*sizeof(long);
9758    }
9759  else
9760    {
9761         /* Append an Adler32 CRC to our deflated data.
9762          * Yes, I know RFC 1951 doesn't mention any CRC at the end of a
9763          * deflated document, but zlib absolutely requires one. And since nearly
9764          * all "deflate" implementations use zlib, we need to play along with this
9765          * brain damage. */
9766         put_byte( (gz1->adler >> 24)        );
9767         put_byte( (gz1->adler >> 16) & 0xFF );
9768         put_byte( (gz1->adler >>  8) & 0xFF );
9769         put_byte( (gz1->adler      ) & 0xFF );
9770     gz1->header_bytes += 4*sizeof(uch);
9771    }
9772
9773  flush_outbuf( gz1 );
9774
9775  gz1->done = 1; 
9776
9777  return OK;
9778 }
9779
9780
9781 /* =========================================================================
9782    adler32 -- compute the Adler-32 checksum of a data stream
9783    Copyright (C) 1995-1998 Mark Adler
9784
9785    This software is provided 'as-is', without any express or implied
9786    warranty.  In no event will the authors be held liable for any damages
9787    arising from the use of this software.
9788
9789    Permission is granted to anyone to use this software for any purpose,
9790    including commercial applications, and to alter it and redistribute it
9791    freely, subject to the following restrictions:
9792
9793    1. The origin of this software must not be misrepresented; you must not
9794       claim that you wrote the original software. If you use this software
9795       in a product, an acknowledgment in the product documentation would be
9796       appreciated but is not required.
9797    2. Altered source versions must be plainly marked as such, and must not be
9798       misrepresented as being the original software.
9799    3. This notice may not be removed or altered from any source distribution.
9800
9801    Modified by Eric Kidd <eric.kidd@pobox.com> to play nicely with mod_gzip.
9802  */
9803
9804 #define BASE 65521L /* largest prime smaller than 65536 */
9805 #define NMAX 5552
9806 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
9807
9808 #define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
9809 #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
9810 #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
9811 #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
9812 #define DO16(buf)   DO8(buf,0); DO8(buf,8);
9813
9814 ulg adler32(ulg adler, uch *buf, unsigned len)
9815 {
9816     unsigned long s1 = adler & 0xffff;
9817     unsigned long s2 = (adler >> 16) & 0xffff;
9818     int k;
9819
9820     if (buf == NULL) return 1L;
9821
9822     while (len > 0) {
9823         k = len < NMAX ? len : NMAX;
9824         len -= k;
9825         while (k >= 16) {
9826             DO16(buf);
9827             buf += 16;
9828             k -= 16;
9829         }
9830         if (k != 0) do {
9831             s1 += *buf++;
9832             s2 += s1;
9833         } while (--k);
9834         s1 %= BASE;
9835         s2 %= BASE;
9836     }
9837     return (s2 << 16) | s1;
9838 }
9839
9840
9841 /* END OF FILE */
9842
9843