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 
mod_gzip_printf(const char * fmt,...)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 
mod_gzip_hexdump(char * buffer,int buflen)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 
mod_gzip_init(server_rec * server,pool * p)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 
mod_gzip_strnicmp(char * s1,char * s2,int len1)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 
mod_gzip_isscript(request_rec * r,_table * t,const char * key)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 
mod_gzip_run_mod_action(request_rec * r)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 
mod_gzip_run_mod_alias(request_rec * r)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 
mod_gzip_handler(request_rec * r)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 
mod_gzip_request_handler(request_rec * r)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 
mod_gzip_prepare_for_dynamic_call(request_rec * r)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 
mod_gzip_static_file_handler(request_rec * r)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 
mod_gzip_create_unique_filename(mod_gzip_conf * mgc,char * target,int targetmaxlen)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 
mod_gzip_send_html_command_response(request_rec * r,char * tmp,char * ctype)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 *
mod_gzip_create_config(pool * p,server_rec * s)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 *
mod_gzip_merge_config(pool * p,void * basev,void * overridesv)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 *
mod_gzip_set_on(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_keep_workfiles(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_min_http(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_imap_add_item(mod_gzip_conf * mgc,char * arg,int flag1)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 
mod_gzip_imap_show_items(mod_gzip_conf * mgc)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 *
mod_gzip_set_item_include(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_item_exclude(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_temp_dir(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_minimum_file_size(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_maximum_inmem_size(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_do_static_files(cmd_parms * parms,void * dummy,char * arg)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 *
mod_gzip_set_do_cgi(cmd_parms * parms,void * dummy,char * arg)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
main(int argc,char * argv[])4010 int main(int argc, char *argv[])
4011 {
4012     ExitThread(TSR_THREAD, 0);
4013 }
4014 #endif
4015 
mod_gzip_open_output_file(request_rec * r,char * output_filename,int * rc)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 
mod_gzip_encode_and_transmit(request_rec * r,char * source,int source_is_a_file,long input_size,int nodecline)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 
mod_gzip_ismatch(char * s1,char * s2,int len1,int haswilds)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 
mod_gzip_get_action_flag(request_rec * r,mod_gzip_conf * mgc)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 };
is_scriptaliased(request_rec * r)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 }
log_scripterror(request_rec * r,cgi_server_conf * conf,int ret,int show_errno,char * error)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 }
log_script(request_rec * r,cgi_server_conf * conf,int ret,char * dbuf,const char * sbuf,BUFF * script_in,BUFF * script_err)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 }
mod_gzip_cgi_handler(request_rec * r)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 }
mod_gzip_cgi_child(void * child_stuff,child_info * pinfo)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)
mod_gzip_ap_send_fb(BUFF * fb,request_rec * r,int * final_return_code)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
mod_gzip_ap_send_fb_length(BUFF * fb,request_rec * r,long length,int * final_return_code)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�"
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 
gz1_init()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 
gz1_cleanup(PGZ1 gz1)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 
error(char * msg)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 
get_header(PGZ1 gz1,int in)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 
fill_inbuf(PGZ1 gz1,int eof_ok)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 
updcrc(PGZ1 gz1,uch * s,unsigned n)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 
read_error(PGZ1 gz1)7969 void read_error( PGZ1 gz1 )
7970 {
7971  gz1->abortflag = 1;
7972 }
7973 
mod_gzip_strlwr(char * s)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 
gz1_basename(PGZ1 gz1,char * fname)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 
write_buf(PGZ1 gz1,int fd,voidp buf,unsigned cnt)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 
write_error(PGZ1 gz1)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 
fcalloc(unsigned items,unsigned size)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 
fcfree(void * ptr)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 
zip(PGZ1 gz1,int in,int out)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 
gz1_deflate(PGZ1 gz1)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 
flush_outbuf(PGZ1 gz1)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 
lm_init(PGZ1 gz1,int pack_level,ush * flags)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 
fill_window(PGZ1 gz1)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 
gz1_deflate_fast(PGZ1 gz1)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 
ct_init(PGZ1 gz1,ush * attr,int * methodp)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 
flush_block(PGZ1 gz1,char * buf,ulg stored_len,int eof)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 
bi_reverse(PGZ1 gz1,unsigned code,int len)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 
set_file_type(PGZ1 gz1)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 
init_block(PGZ1 gz1)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 
bi_init(PGZ1 gz1,gz1_file_t zipfile)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 
ct_tally(PGZ1 gz1,int dist,int lc)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 
compress_block(PGZ1 gz1,ct_data * ltree,ct_data * dtree)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 
longest_match(PGZ1 gz1,unsigned cur_match)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 
send_bits(PGZ1 gz1,int value,int length)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 
build_tree(PGZ1 gz1,tree_desc * desc)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 
build_bl_tree(PGZ1 gz1)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 
gen_codes(PGZ1 gz1,ct_data * tree,int max_code)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 
gen_bitlen(PGZ1 gz1,tree_desc * desc)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 
copy_block(PGZ1 gz1,char * buf,unsigned len,int header)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 
file_read(PGZ1 gz1,char * buf,unsigned size)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 
bi_windup(PGZ1 gz1)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 
send_all_trees(PGZ1 gz1,int lcodes,int dcodes,int blcodes)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 
send_tree(PGZ1 gz1,ct_data * tree,int max_code)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 
scan_tree(PGZ1 gz1,ct_data * tree,int max_code)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 
pqdownheap(PGZ1 gz1,ct_data * tree,int k)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 
gzp_main(GZP_CONTROL * gzp)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 
gzs_fsp(PGZ1 gz1)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 
gzs_zip1(PGZ1 gz1)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 
gzs_zip2(PGZ1 gz1)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 
gzs_deflate1(PGZ1 gz1)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 
9844