1 /* ====================================================================
2 * Copyright (c) 1995-2000 The Apache Group. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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
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/)."
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
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.
30 * 6. Redistributions of any form whatsoever must retain the following
32 * "This product includes software developed by the Apache Group
33 * for use in the Apache HTTP server project (http://www.apache.org/)."
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 * ====================================================================
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/>.
61 * Apache gzip compression module.
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).
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.
70 * There is NO client-side software required for using this module
71 * other than any fully HTTP 1.1 compliant user agent.
73 * Any fully HTTP 1.1 compliant user agent will be able to receive and
74 * automatically decode the compressed content.
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.
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.
83 * Sponsor: Remote Communications, Inc. http://www.RemoteCommunications.com/
84 * Authors: Konstantin Balashov, Alex Kosobrukhov and Kevin Kiley.
85 * Contact: info@RemoteCommunications.com
87 * Initial public release date: 13-Oct-2000
89 * Miscellaneous release notes:
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.
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.
104 * MOD_GZIP LOG FORMATS...
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
110 * mod_gzip uses the standard Apache NOTES interface to allow compression
111 * information to be added to the Apache Web Server log files.
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.
117 * Additional notes about logging compression information...
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.
125 * Example: This will display the compression ratio percentage along
126 * with the standard CLF ( Common Log Format ) information...
128 * Available 'mod_gzip' compression information 'notes'...
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.
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
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.
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.
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'.
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
158 * CustomLog logs/access.log common_with_mod_gzip_info2
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...
166 * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951 mod_gzip: 93pct.
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.
173 * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951
174 * mod_gzip: OK In:679188 Out:48951:93pct.
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.
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'.
190 * MOD_GZIP RUNTIME DEBUG...
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.
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.
201 * MOD_GZIP CONFIGURATION DIRECTIVES...
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.
208 * The configuration directives themselves are documented in more
209 * detail in the README and INSTALL files that accompany this module.
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.
217 # MOD_GZIP Configuration Directives
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.
225 # Add this entire section including all lines down to where
226 # it says '# End of MOD_GZIP Configuration Directives'.
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.
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.
239 # If no 'mod_gzip_temp_dir' is specified then the default location
240 # for temporary workfiles will be 'ServerRoot' directory.
242 # The special mod_gzip log formats are, of course, optional.
244 # You must, of course, load the right module name for your OS
245 # so make sure the correct 'LoadModule' command is uncommented
248 # Load Win32 module...
249 LoadModule gzip_module modules/ApacheModuleGzip.dll
251 # Load UNIX module...
252 # LoadModule gzip_module modules/mod_gzip.so
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
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.
264 CustomLog logs/access.log common_with_mod_gzip_info2
266 # Runtime control directives...
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"
278 # Item names can be any one of the following...
280 # cgi-script - A valid 'handler' name
281 # text/* - A valid MIME type name ( '*' wildcard allowed )
282 # .phtml - A valid file type extension
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/*
292 # The items listed here are the types of dynamic
293 # output that will be compressed...
295 # Dynamic items MUST have the "!" BANG character
296 # on the front of the item name.
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
305 # The items listed here are the types of static
306 # files that will be compressed...
308 # NOTE: FOR NOW ALL STATIC INCLUDES MUST
309 # COME AFTER DYNAMIC INCLUDES TO PREVENT
312 mod_gzip_item_include text/*
314 # Uncomment this line to compress graphics
315 # when graphics compression is allowed...
316 #mod_gzip_item_include image/*
319 # Exclusions... MIME types and FILE types...
321 # The items listed here will be EXCLUDED from
322 # any attempt to apply compression...
324 mod_gzip_item_exclude .js
325 mod_gzip_item_exclude .css
327 # Exclusions... HTTP support levels...
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.
333 # The item value should be in the same HTTP numeric format
334 # that Apache uses to designate HTTP version levels.
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.
342 mod_gzip_min_http 1001
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.
353 # End of MOD_GZIP Configuration Directives
355 * End of inline comments
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"
374 * Add this header for ap_server_root[ MAX_STRING_LEN ] global...
376 * #include "http_conf_globals.h"
378 * ...or just include what we need from http_conf_globals.h
379 * since that is, in fact, only 1 item at this time.
381 extern API_VAR_EXPORT char ap_server_root[ MAX_STRING_LEN ];
384 * Add this header to get 'ap_update_mtime()' prototype...
386 * #include "http_request.h"
388 * ...or just include what we need from http_request.h since
389 * that is, in fact, only 1 item at this time.
391 extern API_EXPORT(time_t)
392 ap_update_mtime(request_rec *r, time_t dependency_mtime);
395 * Version information...
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.
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 ).
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. ).
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.
420 char mod_gzip_version[] = "1.3.14.5"; /* Global version string */
423 * Declare the NAME by which this module will be known.
424 * This is the NAME that will be used in LoadModule command(s).
426 extern module MODULE_VAR_EXPORT gzip_module;
429 * Allow this module to 'read' config information from
430 * ( and interact with ) the 'real' mod_cgi module...
432 extern module cgi_module;
435 * Some compile-time code inclusion switches...
439 * Turn MOD_GZIP_ALLOWS_INTERNAL_COMMANDS switch ON to allow
440 * information requests to be sent via any standard browser.
443 #define MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
446 * Turn MOD_GZIP_USES_APACHE_LOGS switch ON to include the
447 * code that can update Apache logs with compression information.
450 #define MOD_GZIP_USES_APACHE_LOGS
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.
459 #define MOD_GZIP_USES_AP_SEND_MMAP
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.
469 #define MOD_GZIP_DEBUG1
473 * Some useful instance globals...
476 #ifndef MOD_GZIP_MAX_PATH_LEN
477 #define MOD_GZIP_MAX_PATH_LEN 512
480 char mod_gzip_temp_dir[ MOD_GZIP_MAX_PATH_LEN + 2 ];
482 long mod_gzip_iusn = 0; /* Instance Unique Sequence Number */
484 long mod_gzip_maximum_inmem_size = 60000L;
485 long mod_gzip_minimum_file_size = 300L;
488 char mod_gzip_dirsep[]="\\"; /* Dir separator is a backslash for Windows */
490 char mod_gzip_dirsep[]="/"; /* Dir separator is a forward slash for UNIX */
494 * The Compressed Object Cache control structure...
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 */
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)
506 struct mod_gzip_cache_conf {
508 const char *root; /* The location of the cache directory */
509 off_t space; /* Maximum cache size (in 1024 bytes) */
511 time_t maxexpire; /* Maximum time to keep cached files (secs) */
513 time_t defaultexpire; /* Default time to keep cached file (secs) */
514 char defaultexpire_set;
515 double lmfactor; /* Factor for estimating expires date */
517 time_t gcinterval; /* Garbage collection interval (secs) */
519 int dirlevels; /* Number of levels of subdirectories */
521 int dirlength; /* Length of subdirectory names */
526 * The Inclusion/Exclusion map item structure...
529 #define MOD_GZIP_IMAP_MAXNAMES 256
530 #define MOD_GZIP_IMAP_MAXNAMELEN 90
532 #define MOD_GZIP_IMAP_ISMIME 1
533 #define MOD_GZIP_IMAP_ISEXT 2
534 #define MOD_GZIP_IMAP_ISHANDLER 3
536 #define MOD_GZIP_IMAP_STATIC1 9001
537 #define MOD_GZIP_IMAP_DYNAMIC1 9002
538 #define MOD_GZIP_IMAP_DECLINED1 9003
542 int include; /* 1=Include 0=Exclude */
543 int type; /* _ISMIME, _ISEXT, _ISHANDLER, etc. */
544 int action; /* _STATIC1, _DYNAMIC1, etc. */
546 char name[ MOD_GZIP_IMAP_MAXNAMELEN + 2 ];
551 * The primary module configuration record...
556 struct mod_gzip_cache_conf cache; /* Compressed Object Cache control */
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 */
567 /* Inclusion/Exclusion list(s)... */
569 int imap_total_entries;
571 mod_gzip_imap imap[ MOD_GZIP_IMAP_MAXNAMES + 1 ];
576 * The GZP request control structure...
579 #define GZIP_FORMAT (0)
580 #define DEFLATE_FORMAT (1)
582 typedef struct _GZP_CONTROL {
584 int decompress; /* 0=Compress 1=Decompress */
586 int compression_format; /* GZIP_FORMAT or DEFLATE_FORMAT */
588 /* Input control... */
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 */
594 char input_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Input file name */
596 /* Output control... */
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 */
602 char output_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Output file name */
606 int result_code; /* Result code */
607 long bytes_out; /* Total number of compressed output bytes */
612 * Forward prototypes for internal routines...
615 int gzp_main( GZP_CONTROL *gzp ); /* Primary GZP API entry point */
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 );
625 FILE *mod_gzip_open_output_file(
627 char *output_filename,
631 int mod_gzip_create_unique_filename(
637 int mod_gzip_encode_and_transmit(
640 int source_is_a_file,
646 #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
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 */
654 #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */
660 #ifdef MOD_GZIP_DEBUG1
662 void mod_gzip_printf( const char *fmt, ... )
674 /* If UNIX then mod_gzip_dirsep = '/' Backward slash */
675 /* If WIN32 then mod_gzip_dirsep = '\' Forward slash */
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.
684 if ( strlen(mod_gzip_temp_dir) ) /* Use temp directory ( if specified )... */
686 sprintf( logname, "%s%smod_gzip.log", mod_gzip_temp_dir, mod_gzip_dirsep );
688 else /* Just use 'ap_server_root' Apache ServerRoot directory... */
690 sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep );
692 #endif /* FUTURE_USE */
694 /* Just use ServerRoot for now... */
695 sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep );
697 log = fopen( logname,"a" );
699 if ( !log ) /* Log file did not open... */
701 /* Just turn and burn... */
703 return; /* Void return */
706 /* Get the variable parameter list... */
710 l = vsprintf(log_line, fmt, ap);
712 /* See if we need to add LF... */
716 if ( log_line[l-1] != '\n' )
725 fprintf( log, "%s", log_line );
729 va_end(ap); /* End session */
731 return; /* Void return */
733 }/* End of log_d() */
735 void mod_gzip_hexdump( char *buffer, int buflen )
763 for ( i=0; i<buflen; i++ )
765 ch1 = (char) *buffer++;
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 /*------------------------------------------------------------*/
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 ) */
787 #define DUMPIT_ASTERISK 42
788 #define DUMPIT_LAPOSTROPHE 96
789 #define DUMPIT_RAPOSTROPHE 39
790 #define DUMPIT_PERIOD 46
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;
802 #define MASK_ALL_NON_PRINTABLE_CHARS
803 #ifdef MASK_ALL_NON_PRINTABLE_CHARS
805 /* Mask all control chars and high ends chars for UNIX or */
806 /* TTY console screws up... */
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 */
816 /* ENDIF on MASK_ALL_NON_PRINTABLE_CHARS */
821 sprintf( s, "%02X", ch1 );
823 if ( strlen(s) > 2 ) s[2]=0; /* Prevent overflow */
828 if ( strlen(l1) < (sizeof(l1) - (len1+1)) )
838 mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 );
851 }/* End 'for( i=0; i<buflen; i++ )' loop... */
853 /* Print remainder ( if anything ) */
859 mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 );
870 }/* End of mod_gzip_hexdump() */
872 #endif /* MOD_GZIP_DEBUG1 */
874 static void mod_gzip_init( server_rec *server, pool *p )
877 * The module initialization procedure...
881 char filename[ 512 ];
883 #ifdef MOD_GZIP_DEBUG1
884 char cn[]="mod_gzip_init()";
891 #ifdef MOD_GZIP_DEBUG1
892 mod_gzip_printf( "%s: Entry...\n", cn );
896 * Set some instance specific globals...
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.
903 * On most Apache installations 'ServerRoot' is automatically
904 * readable/writable by the Server while it is running.
906 * On systems where it is not there MUST be an override
907 * in the httpd.conf file.
909 * See the comments regarding the 'mod_gzip_temp_dir' directive
910 * in the httpd.conf configuration file.
913 mgc = ( mod_gzip_conf * )
914 ap_get_module_config(server->module_config, &gzip_module);
916 /* Make sure we can read/write the temp directory... */
918 sprintf( filename, "%s%smod_gzip.id", mgc->cache.root, mod_gzip_dirsep );
920 fh1 = fopen( filename, "wb" );
922 if ( !fh1 ) /* Write an ERROR to console and to log(s)... */
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");
929 /* This is a startup ERROR and has to be fixed... */
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.");
940 else /* File opened OK... just add some data and close it... */
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.
949 fprintf( fh1, "mod_gzip version %s\n", mod_gzip_version );
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 */
959 }/* End of mod_gzip_init() */
961 int mod_gzip_strnicmp( char *s1, char *s2, int len1 )
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. */
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... */
975 if ( ( s1 == 0 ) || ( s2 == 0 ) )
977 /* SAFETY! If pointer itself if NULL */
978 /* don't enter LOOP or NETSCAPE will GP... */
980 return( 1 ); /* Return '1' for NOMATCH... */
983 for ( i=0; i<len1; i++ )
985 if ( ( *s1 == 0 ) || ( *s2 == 0 ) ) return( 1 ); /* No match! */
990 if ( ch1 > 96 ) ch1 -= 32;
991 if ( ch2 > 96 ) ch2 -= 32;
993 if ( ch1 == '/' ) ch1 = '\\';
994 if ( ch2 == '/' ) ch2 = '\\';
996 if ( ch1 != ch2 ) return( 1 ); /* No match! */
1003 /* If we make it to here then everything MATCHED! */
1005 return( 0 ); /* MATCH! */
1007 }/* End mod_gzip_strnicmp() */
1009 extern API_VAR_EXPORT module *top_module;
1013 #ifdef MAKE_TABLE_PROFILE
1017 typedef struct _table _table;
1019 const char *mod_gzip_isscript( request_rec *r, _table *t, const char *key)
1022 * Get a 'handler' name for a MIME type right out of
1023 * the Apache 'Action' table(s)...
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.
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.
1039 (table_entry *) t->a.elts;
1042 char cn[]="mod_gzip_isscript()";
1048 #ifdef MOD_GZIP_DEBUG1
1049 mod_gzip_printf( "%s: Entry...\n",cn);
1050 mod_gzip_printf( "%s: key=[%s]\n",cn,key );
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);
1060 if ( r->server->loglevel == APLOG_DEBUG )
1062 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1063 "%s: Search key is NULL.",cn);
1069 for (i = 0; i < t->a.nelts; ++i)
1071 #ifdef MOD_GZIP_DEBUG1
1073 "%s: i=%4.4d Comparing [%s] with elts.key[%s].val[%s]\n",
1074 cn, i, key, elts[i].key, elts[i].val );
1077 if ( r->server->loglevel == APLOG_DEBUG )
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 );
1084 if (!strcasecmp(elts[i].key, key))
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);
1091 if ( r->server->loglevel == APLOG_DEBUG )
1093 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1094 "%s: MATCH FOUND...",cn);
1102 if ( r->server->loglevel == APLOG_DEBUG )
1104 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1105 "%s: NO MATCH FOUND...",cn);
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);
1115 }/* End of 'mod_gzip_isscript()' */
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;
1123 int mod_gzip_run_mod_action( request_rec *r )
1129 mod_actions_local_config *mod_actions_conf;
1132 const char *action=0;
1134 #ifdef MOD_GZIP_DEBUG1
1135 char cn[]="mod_gzip_run_mod_action()";
1138 #ifdef MOD_GZIP_FUTURE_USE
1139 const handler_rec *handp;
1142 /* Currently 9 possible 'event' handlers. */
1143 /* Actual content handler in a module is 'extra'. */
1144 #define MOD_GZIP_NMETHODS 9
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);
1159 for ( modp = top_module; modp; modp = modp->next )
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 /* ............... */
1170 /* 19 [http_core.c] <- Always bottom of list (last one called) */
1171 /*--------------------*/
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 );
1178 if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )
1181 /* Module information... */
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);
1188 /* Get a pointer to the module configuration data... */
1190 mod_actions_conf = (mod_actions_local_config *)
1191 ap_get_module_config(r->per_dir_config, modp );
1193 /* Get script name... */
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] */
1200 for ( pass = 0; pass < 2; pass++ )
1202 if ( pass == 0 ) /* Check r->content_type first */
1204 /* This is the first pass... */
1206 /* Set 'action' search key to 'r->content_type' */
1207 /* so we search for [application/x-httpd-php3] */
1209 action = r->content_type;
1211 else if ( pass == 1 ) /* Try r->handler */
1213 /* This is the second pass... */
1215 /* Set 'action' search key to 'r->handler' */
1216 /* so we search for [php-script] */
1218 action = r->handler;
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);
1235 (_table *) mod_actions_conf->action_types,
1236 action ? action : ap_default_type(r)
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);
1248 * If a program name was found then make it r->filename
1249 * and r->uri will become the input name for the program
1252 r->filename = ap_pstrdup(r->pool,t);
1257 }/* End 'for( pass )' loop */
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);
1264 /* If a handler was found we are DONE... */
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);
1276 #ifdef MOD_GZIP_FUTURE_USE
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 */
1291 if ( !modp->handlers )
1293 #ifdef MOD_GZIP_DEBUG1
1294 mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn);
1297 else /* There are some handlers... */
1299 for ( handp = modp->handlers; handp->content_type; ++handp )
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);
1307 }/* End 'handp' loop */
1311 #endif /* MOD_GZIP_FUTURE_USE */
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);
1320 }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */
1324 }/* End 'modp' loop... */
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);
1333 }/* End of mod_gzip_run_mod_action() */
1336 int mod_gzip_run_mod_alias( request_rec *r )
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.
1343 * 'translate_alias_redir()' is the name of routine registered
1344 * by mod_alias.c module as the 'translate' hook.
1351 #ifdef MOD_GZIP_DEBUG1
1352 char cn[]="mod_gzip_run_mod_alias()";
1355 const handler_rec *handp;
1357 /* Currently 9 possible 'event' handlers. */
1358 /* Actual content handler in a module is 'extra'. */
1359 #define MOD_GZIP_NMETHODS 9
1361 char *save_filename = 0;
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 );
1377 for ( modp = top_module; modp; modp = modp->next )
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 /* ............... */
1388 /* 19 [http_core.c] <- Always bottom of list (last one called) */
1389 /*--------------------*/
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 );
1397 There are only 3 modules that normally have
1398 'translate' handlers registered...
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 ) )
1410 /* Module information... */
1412 #ifdef MOD_GZIP_DEBUG1
1414 mod_gzip_printf( "%s: ++++++++++ MODULE FOUND!...\n",cn);
1415 mod_gzip_printf( "%s: ++++++++++ modp->module_index = %d\n",cn,(int)modp->module_index);
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);
1428 #endif /* MOD_GZIP_DEBUG1 */
1430 if ( !modp->handlers )
1432 #ifdef MOD_GZIP_DEBUG1
1433 mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn);
1436 else /* There are some handlers... */
1438 for ( handp = modp->handlers; handp->content_type; ++handp )
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);
1446 }/* End 'handp' loop */
1450 if ( modp->translate_handler )
1452 #ifdef MOD_GZIP_DEBUG1
1453 mod_gzip_printf( "%s: modp->translate_handler is VALID...\n",cn);
1457 There are only 3 modules that normally have
1458 'translate' handlers registered...
1460 mod_alias <- Will translate /php3/xxx to c:/php3017/xx
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.
1470 * 'translate_alias_redir()' is the name of routine registered
1471 * by mod_alias.c module as the 'translate' hook.
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.
1480 * We must make sure the phrase we want translated is
1481 * in r->uri and check for results in r->filename.
1485 * Calling mod_alias.c translate handler will correctly
1486 * translate 'ScriptAlias' phrases such as...
1491 * c:/php3017/php3.exe
1494 save_filename = r->filename;
1498 r->filename = nothing;
1499 r->uri = save_filename; /* Phrase to translate */
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);
1507 /* Call the actual translate routine in mod_action module... */
1509 rc = (modp->translate_handler)( (request_rec *) r );
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);
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.
1524 #ifdef MOD_GZIP_DEBUG1
1528 mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc );
1530 else if ( rc == DECLINED )
1532 mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc );
1534 else if ( rc == DONE ) /* -2 means 'totally done' */
1536 mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc );
1538 else /* Probably an HTTP ERROR value... */
1540 mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc );
1543 #endif /* MOD_GZIP_DEBUG */
1546 * Evaluate the results...
1549 if ( rc == OK ) /* There was a phrase translation... */
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 );
1556 /* Do NOT restore 'r->filename' to original value... */
1557 /* Just fall-through and continue... */
1559 else /* No phrases were replaced... */
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 );
1566 /* Restore 'r->filename' to original value... */
1568 r->filename = save_filename;
1571 /* Always 'restore' URI to original value... */
1575 /* Turn and burn... */
1577 #ifdef MOD_GZIP_DEBUG1
1578 mod_gzip_printf( "%s: Exit > return( rc=%d ) >\n",cn,rc);
1583 else /* modp->translate_handler is NULL... */
1585 #ifdef MOD_GZIP_DEBUG1
1586 mod_gzip_printf( "%s: modp->translate_handler is NOT VALID.\n",cn);
1590 }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */
1594 }/* End 'modp' loop... */
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);
1603 }/* End of mod_gzip_run_mod_alias() */
1606 static int mod_gzip_handler( request_rec *r )
1609 * The primary module request handler...
1613 char cn[]="mod_gzip_handler()";
1614 int access_status=0;
1615 int access_status2=0;
1621 if ( r->server->loglevel == APLOG_DEBUG )
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).
1628 * APLOG_MARK is what supplies __FILE__ and __LINE__ info and
1629 * it is actually defined in HTTP_LOG.H as...
1631 * define APLOG_MARK __FILE__,__LINE__
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.
1638 * The first parameter can be a custom message instead of
1639 * the __FILE__ string that would normally be substituted.
1642 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1643 "%s: Entry point...",cn);
1645 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1646 "%s: r->the_request = [%s]",cn,r->the_request);
1648 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1649 "%s: r->protocol = [%s]",cn,r->protocol);
1651 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1652 "%s: r->proto_num = %d",cn,(int)r->proto_num);
1654 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1655 "%s: r->filename = [%s]",cn,r->filename);
1657 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1658 "%s: r->uri = [%s]",cn,r->uri);
1660 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1661 "%s: r->content_type = [%s]",cn,r->content_type);
1663 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1664 "%s: r->handler = [%s]",cn,r->handler);
1666 }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */
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);
1704 #endif /* MOD_GZIP_DEBUG1 */
1707 * Call the real transaction handler....
1710 #ifdef MOD_GZIP_DEBUG1
1711 mod_gzip_printf( "%s: Call mod_gzip_request_handler()...\n", cn );
1714 rc = mod_gzip_request_handler( (request_rec *) r );
1716 #ifdef MOD_GZIP_DEBUG1
1717 mod_gzip_printf( "%s: Back mod_gzip_request_handler()... rc=%d\n",cn,rc);
1720 if ( r->server->loglevel == APLOG_DEBUG )
1723 * If LogLevel is 'debug' then show the final return code
1724 * value in the log(s)...
1729 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1730 "%s: Exit: return( rc = %d = OK )", cn, rc );
1732 else if ( rc == DECLINED )
1734 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1735 "%s: Exit: return( rc = %d = DECLINED )", cn, rc );
1737 else /* It's probably an HTTP error code... */
1739 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
1740 "%s: Exit: return( rc = %d = HTTP ERROR CODE? )", cn, rc );
1743 }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */
1745 #ifdef MOD_GZIP_DEBUG1
1749 mod_gzip_printf( "%s: rc = %d OK\n", cn, (int) rc);
1751 else if ( rc == DECLINED )
1753 mod_gzip_printf( "%s: rc = %d DECLINED\n", cn, (int) rc );
1755 else /* It's probably an HTTP error code... */
1757 mod_gzip_printf( "%s: rc = %d ( HTTP ERROR CODE? )\n", cn, (int) rc );
1760 mod_gzip_printf( "%s: Exit > return( rc = %d ) >\n",cn,rc );
1762 #endif /* MOD_GZIP_DEBUG1 */
1766 }/* End of mod_gzip_handler() */
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;
1774 extern module action_module;
1776 int mod_gzip_request_handler( request_rec *r )
1779 * Process a new request...
1786 int action_flag = 0;
1787 long compression_ratio = 0;
1789 const char* has_encoding = 0;
1790 const char* accept_encoding = 0;
1792 #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
1793 char tmp[4096]; /* Scratch buffer for HTML output */
1796 #ifdef MOD_GZIP_DEBUG1
1797 char cn[]="mod_gzip_request_handler()";
1798 const char* the_type = 0;
1801 #ifdef MOD_GZIP_USES_APACHE_LOGS
1802 char log_info[40]; /* Scratch buffer */
1805 void *modconf = r->server->module_config;
1807 mod_gzip_conf *conf = 0; /* Pointer to our own config data */
1812 * Establish a local pointer to module configuration data...
1815 conf = (mod_gzip_conf *)
1816 ap_get_module_config(modconf, &gzip_module);
1819 * Get the current Apache log level...
1822 loglevel = r->server->loglevel;
1824 #ifdef MOD_GZIP_USES_APACHE_LOGS
1827 * If the MOD_GZIP_USES_APACHE_LOGS compile-time switch is ON
1828 * then the Apache log module interface code is being included.
1830 * Reset the module 'notes' that are used by mod_gzip to
1831 * add entries to Apache standard log files...
1833 * See the note farther below about how to add mod_gzip
1834 * compression information to any standard Apache log file.
1837 /* Default for 'mod_result' message is 'DECLINED:NOP'... */
1839 ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NOP"));
1841 /* Default for in/out size is 'n/a'... 'Not available'...*/
1843 sprintf( log_info, "n/a" );
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));
1848 /* Default for compression ratio is '0' percent... */
1850 ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,"0"));
1852 #endif /* MOD_GZIP_USES_APACHE_LOGS */
1854 #ifdef MOD_GZIP_DEBUG1
1856 /* Request info... */
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);
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. */
1873 the_type = ap_table_get( r->headers_out,"Content-type" );
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 );
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. */
1883 mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler );
1885 /* Server info... */
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);
1893 /* Environment info... */
1895 mod_gzip_printf( "%s: DOCUMENT_ROOT = [%s]\n",cn,ap_document_root(r));
1897 #endif /* MOD_GZIP_DEBUG1 */
1900 * Check the 'master' request control switch and see if mod_gzip
1901 * is ON (ENABLED) or OFF (DISABLED)...
1904 if ( conf->req != 1 )
1906 /* mod_gzip is currently DISABLED so DECLINE the processing... */
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);
1914 #ifdef MOD_GZIP_USES_APACHE_LOGS
1916 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
1919 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:DISABLED"));
1921 #endif /* MOD_GZIP_USES_APACHE_LOGS */
1925 }/* End 'if( conf->req != 1 )' */
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...
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 );
1940 if ( r->proto_num < conf->min_http )
1942 /* The HTTPx/x version number does not meet the minimum requirement */
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);
1949 #ifdef MOD_GZIP_USES_APACHE_LOGS
1951 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
1953 sprintf( log_info, "DECLINED:%s:%d", r->protocol, r->proto_num );
1956 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,log_info));
1958 #endif /* MOD_GZIP_USES_APACHE_LOGS */
1962 }/* End 'if ( r->proto_num < conf->min_http )' */
1964 else /* Protocol level is OK... */
1966 #ifdef MOD_GZIP_DEBUG1
1967 mod_gzip_printf( "%s: Request HTTP level is OK...\n",cn);
1971 #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
1974 * Internal command pickups...
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.
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...
1987 if ( strstr( r->filename, "mod_gzip_command_" ) )
1989 do_command = 1; /* Process the command */
1992 #ifdef MOD_GZIP_DEBUG1
1993 mod_gzip_printf( "%s: do_command = %d\n",cn,do_command);
1998 /* Determine the exact command and respond... */
2000 if ( strstr( r->filename, "mod_gzip_command_version" ) )
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 /*------------------------------------------------------*/
2010 #ifdef MOD_GZIP_DEBUG1
2011 mod_gzip_printf( "%s: 'mod_gzip_command_version' seen...\n",cn);
2014 /* NOTE: mod_gzip command results are not sent compressed */
2016 /* Build the response buffer... */
2020 "mod_gzip is available on this Server\r\n"
2021 "mod_gzip version = %s\r\n"
2022 "</pre></body></html>",
2026 /* For all mod_gzip commands that are intercepted we */
2027 /* simply return OK. */
2029 return( mod_gzip_send_html_command_response( r, tmp, "text/html" ));
2031 else if ( strstr( r->filename, "mod_gzip_command_showstats" ) )
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 /*------------------------------------------------------*/
2041 #ifdef MOD_GZIP_DEBUG1
2042 mod_gzip_printf( "%s: 'mod_gzip_command_showstats' seen...\n",cn);
2045 /* NOTE: mod_gzip command results are not sent compressed */
2047 /* Build the response buffer... */
2049 /* NOTE: This command has been temporarily removed */
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>",
2060 /* For all mod_gzip commands that are intercepted we */
2061 /* simply return OK. */
2063 return( mod_gzip_send_html_command_response( r, tmp, "text/html" ));
2065 else if ( strstr( r->filename, "mod_gzip_command_resetstats" ) )
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 /*------------------------------------------------------*/
2074 #ifdef MOD_GZIP_DEBUG1
2075 mod_gzip_printf( "%s: 'mod_gzip_command_resetstats' seen...\n",cn);
2078 /* NOTE: mod_gzip command results are not sent compressed */
2080 /* Build the response buffer... */
2082 /* NOTE: This command has been temporarily removed */
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>",
2093 /* For all mod_gzip commands that are intercepted we */
2094 /* simply return OK. */
2096 return( mod_gzip_send_html_command_response( r, tmp, "text/html" ));
2098 else /* Unrecognized command... */
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. */
2108 }/* End 'if( do_command )' */
2110 #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */
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.
2125 if ( ( r->filename ) && ( strstr( r->filename, ".gz" ) ) )
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);
2133 #ifdef MOD_GZIP_USES_APACHE_LOGS
2135 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2138 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS.GZ"));
2140 if ( r->server->loglevel == APLOG_DEBUG )
2142 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2143 "mod_gzip: Files with .gz file extension are skipped.");
2146 #endif /* MOD_GZIP_USES_APACHE_LOGS */
2150 else /* r->filename doesn not contain '.gz' designator... */
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);
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.
2163 * WARNING: Don't submit r->content_type to strstr() it if is
2164 * NULL or the API call will GP fault. Go figure.
2167 if ( ( r->content_type ) && ( strstr( r->content_type, "image/" ) ) )
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);
2175 #ifdef MOD_GZIP_USES_APACHE_LOGS
2177 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2180 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:IMAGE"));
2182 if ( r->server->loglevel == APLOG_DEBUG )
2184 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2185 "mod_gzip: Graphics image compression option is temporarily disabled.");
2188 #endif /* MOD_GZIP_USES_APACHE_LOGS */
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.
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...
2205 has_encoding = ap_table_get( r->headers_out, "Content-encoding" );
2207 #ifdef MOD_GZIP_DEBUG1
2208 mod_gzip_printf( "%s: has_encoding = [%s]\n",cn,has_encoding);
2211 if ( has_encoding ) /* 'Content-encoding' field is present... */
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);
2218 if ( strstr( has_encoding, "gzip" ) ||
2219 strstr( has_encoding, "deflate" ) )
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);
2227 #ifdef MOD_GZIP_USES_APACHE_LOGS
2229 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2232 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS_CE:GZIP"));
2234 if ( r->server->loglevel == APLOG_DEBUG )
2236 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2237 "mod_gzip: Header already has 'Content-encoding: gzip'");
2240 #endif /* MOD_GZIP_USES_APACHE_LOGS */
2244 else /* 'gzip' designator not found... */
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);
2252 }/* End 'if( has_encoding )' */
2254 else /* Output header does NOT contain 'Content-encoding:' field... */
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);
2263 * Basic sanity checks completed and we are still here.
2265 * Now we must determine if the User-Agent is capable of receiving
2266 * compressed data...
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
2274 * Some of them are...
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.
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.
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.
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
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.
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.
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.
2337 accept_encoding = ap_table_get( r->headers_in, "Accept-Encoding" );
2339 #ifdef MOD_GZIP_DEBUG1
2341 if ( accept_encoding )
2343 mod_gzip_printf( "%s: 'Accept Encoding:' field seen.\n",cn);
2347 mod_gzip_printf( "%s: 'Accept Encoding' field NOT seen.\n",cn);
2350 #endif /* MOD_GZIP_DEBUG1 */
2352 /* If Accept-Encoding is applicable to this request...*/
2354 if ( accept_encoding )
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.
2360 if ( strstr( accept_encoding, "gzip" ) )
2362 process = 1; /* ...set the 'process' flag TRUE */
2363 ap_table_setn( r->notes,"mod_gzip_compression_format",
2364 ap_pstrdup(r->pool,"gzip"));
2367 else if ( strstr( accept_encoding, "deflate" ) )
2369 process = 1; /* ...set the 'process' flag TRUE */
2370 ap_table_setn( r->notes,"mod_gzip_compression_format",
2371 ap_pstrdup(r->pool,"deflate"));
2374 }/* End 'if( accept_encoding )' */
2376 #ifdef MOD_GZIP_DEBUG1
2377 mod_gzip_printf( "%s: 'process' flag = %d\n",cn,process);
2380 if ( !process ) /* Request does not meet criteria for processing... */
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);
2389 #ifdef MOD_GZIP_USES_APACHE_LOGS
2391 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2394 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_GZIP"));
2396 if ( r->server->loglevel == APLOG_DEBUG )
2398 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2399 "mod_gzip: The inbound request header does not have 'Accept-encoding: gzip'");
2402 #endif /* MOD_GZIP_USES_APACHE_LOGS */
2406 else /* 'gzip' designator was seen in 'Accept-Encoding:' field */
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);
2415 * Handle the transaction...
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.
2421 * We must now 'do the right thing' based on what type of
2422 * request it actually is...
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);
2432 mod_gzip_get_action_flag(
2434 (mod_gzip_conf *) conf
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);
2445 * Perform the right 'action' for this transaction...
2448 if ( action_flag == MOD_GZIP_IMAP_DECLINED1 )
2451 * If the transaction is to be DECLINED then just set the final
2452 * return code to DECLINED, fall through, and return.
2455 #ifdef MOD_GZIP_DEBUG1
2456 mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DECLINED1\n",cn);
2459 if ( r->server->loglevel == APLOG_DEBUG )
2461 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2462 "mod_gzip: action_flag = MOD_GZIP_IMAP_DECLINED1 ");
2467 else if ( action_flag == MOD_GZIP_IMAP_DYNAMIC1 )
2469 #ifdef MOD_GZIP_DEBUG1
2470 mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DYNAMIC1\n",cn);
2473 if ( r->server->loglevel == APLOG_DEBUG )
2475 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2476 "mod_gzip: action_flag = MOD_GZIP_IMAP_DYNAMIC1 ");
2480 * Check the flag that can control whether or not the
2481 * CGI dynamic output handler is ever called...
2484 if ( conf->do_cgi != 1 ) /* CGI handler is OFF for now... */
2486 if ( r->server->loglevel == APLOG_DEBUG )
2488 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2489 "mod_gzip: Calls to CGI handler currently DISABLED ");
2492 #ifdef MOD_GZIP_USES_APACHE_LOGS
2493 /* Update the result string for Apache log(s)... */
2495 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:CGI_OFF"));
2498 rc = DECLINED; /* Just set final return code and fall through */
2500 }/* End 'if( conf->do_cgi == 0 )' */
2502 else /* It's OK to call the handler... */
2504 if ( r->server->loglevel == APLOG_DEBUG )
2506 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2507 "mod_gzip: Calling cgi_handler for r->uri=[%s]",r->uri);
2510 /* Take care of some business BEFORE calling the */
2511 /* dynamic handler... */
2513 mod_gzip_prepare_for_dynamic_call( r );
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 */
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 );
2529 r->path_info = r->uri;
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 );
2536 /* Call the actual handler... */
2538 #ifdef MOD_GZIP_DEBUG1
2539 mod_gzip_printf( "%s: Call mod_gzip_cgi_handler()...\n",cn);
2542 rc = mod_gzip_cgi_handler( (request_rec *) r );
2544 #ifdef MOD_GZIP_DEBUG1
2545 mod_gzip_printf( "%s: Back mod_gzip_cgi_handler()... rc=%d\n",cn,rc);
2548 }/* End 'else' - OK to call handler */
2550 else if ( action_flag == MOD_GZIP_IMAP_STATIC1 )
2552 #ifdef MOD_GZIP_DEBUG1
2553 mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_STATIC1\n",cn);
2556 if ( r->server->loglevel == APLOG_DEBUG )
2558 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2559 "mod_gzip: action_flag = MOD_GZIP_IMAP_STATIC1 ");
2563 * Check the flag that can control whether or not the
2564 * static handler is ever called...
2567 if ( conf->do_static_files != 1 ) /* Static handler is OFF for now... */
2569 if ( r->server->loglevel == APLOG_DEBUG )
2571 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2572 "mod_gzip: Calls to static handler currently DISABLED ");
2575 #ifdef MOD_GZIP_USES_APACHE_LOGS
2576 /* Update the result string for Apache log(s)... */
2578 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:STATIC_OFF"));
2581 rc = DECLINED; /* Just set final return code and fall through */
2583 }/* End 'if( conf->do_static == 0 )' */
2585 else /* It's OK to call the handler... */
2587 if ( r->server->loglevel == APLOG_DEBUG )
2589 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2590 "mod_gzip: Calling static_handler for r->uri=[%s]",r->uri);
2593 #ifdef MOD_GZIP_DEBUG1
2594 mod_gzip_printf( "%s: Call mod_gzip_static_file_handler()...\n",cn);
2597 rc = mod_gzip_static_file_handler( (request_rec *) r );
2599 #ifdef MOD_GZIP_DEBUG1
2600 mod_gzip_printf( "%s: Back mod_gzip_static_file_handler()... rc=%d\n",cn,rc);
2603 }/* End 'else' - OK to call the handler */
2605 else /* Safety catch... No pickup for the 'action' flag... */
2607 if ( r->server->loglevel == APLOG_DEBUG )
2609 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2610 "mod_gzip: action_flag = MOD_GZIP_IMAP_????? Unknown value");
2613 if ( r->server->loglevel == APLOG_DEBUG )
2615 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
2616 "mod_gzip: No pickup for specified 'action' flag.");
2619 #ifdef MOD_GZIP_DEBUG1
2620 mod_gzip_printf( "%s: action_flag = MOD_GZIP_??? Unknown value\n",cn);
2627 * Record results to logs, if applicable, and return...
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.
2635 #ifdef MOD_GZIP_DEBUG1
2639 mod_gzip_printf( "%s: Exit > return( rc=%d OK ) >\n",cn,rc);
2641 else if ( rc == DECLINED )
2643 mod_gzip_printf( "%s: Exit > return( rc=%d DECLINED ) >\n",cn,rc);
2645 else /* HTTP ERROR VALUE... */
2647 mod_gzip_printf( "%s: Exit > return( rc=%d HTTP_ERROR ) >\n",cn,rc);
2650 #endif /* MOD_GZIP_DEBUG1 */
2652 return rc; /* Could be OK or DECLINED or HTTP_ERROR */
2654 }/* End of mod_gzip_request_handler() */
2656 int mod_gzip_prepare_for_dynamic_call( request_rec *r )
2660 #ifdef MOD_GZIP_DEBUG1
2661 char cn[]="mod_gzip_prepare_for_dynamic_call()";
2668 #ifdef MOD_GZIP_DEBUG1
2669 mod_gzip_printf( "%s: Entry...\n",cn);
2673 * mod_gzip can run other modules directly...
2677 * First run mod_action and see it there's a SCRIPT
2678 * for this mime type...
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);
2690 rc = mod_gzip_run_mod_action( (request_rec *) r );
2692 #ifdef MOD_GZIP_DEBUG1
2694 mod_gzip_printf( "%s: Back mod_gzip_run_mod_action(r)...\n",cn);
2698 mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc );
2700 else if ( rc == DECLINED )
2702 mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc );
2704 else if ( rc == DONE ) /* -2 means 'totally done' */
2706 mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc );
2708 else /* Probably an HTTP ERROR value... */
2710 mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc );
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 );
2719 #endif /* MOD_GZIP_DEBUG1 */
2722 * Now run mod_alias and get any aliases converted
2723 * to real pathnames...
2726 #ifdef MOD_GZIP_DEBUG1
2727 mod_gzip_printf( "%s: Call mod_gzip_run_mod_alias(r)...\n",cn);
2730 rc = mod_gzip_run_mod_alias( (request_rec *) r );
2732 #ifdef MOD_GZIP_DEBUG1
2733 mod_gzip_printf( "%s: Back mod_gzip_run_mod_alias(r)...\n",cn);
2737 mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc );
2739 else if ( rc == DECLINED )
2741 mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc );
2743 else if ( rc == DONE ) /* -2 means 'totally done' */
2745 mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc );
2747 else /* Probably an HTTP ERROR value... */
2749 mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc );
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 );
2758 #endif /* MOD_GZIP_DEBUG1 */
2762 }/* End of mod_gzip_prepare_for_dynamic_call() */
2765 int mod_gzip_static_file_handler( request_rec *r )
2768 long input_size = 0;
2771 #ifdef MOD_GZIP_DEBUG1
2772 char cn[]="mod_gzip_static_file_handler()";
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);
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.
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.
2797 if ( r->finfo.st_size > 0 )
2799 #ifdef MOD_GZIP_DEBUG1
2800 mod_gzip_printf( "%s: Source file length already known...\n",cn);
2803 input_size = (long) r->finfo.st_size;
2805 else /* Do our own checking... */
2808 * See if the requested source file exists...
2809 * Be SURE to open the file in BINARY mode...
2812 ifh1 = fopen( r->filename, "rb" );
2814 if ( !ifh1 ) /* The file cannot be found or opened... */
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);
2821 #ifdef MOD_GZIP_USES_APACHE_LOGS
2823 /* HTTP ERROR conditions provides a short ':WHYTAG' for logs */
2826 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HTTP_NOT_FOUND"));
2828 #endif /* MOD_GZIP_USES_APACHE_LOGS */
2830 return HTTP_NOT_FOUND;
2832 else /* The file was found and opened OK... */
2834 #ifdef MOD_GZIP_DEBUG1
2835 mod_gzip_printf( "%s: The requested source file is now OPEN...\n",cn);
2840 * Move the current file pointer to the end of the file...
2843 if ( fseek( ifh1, 0, SEEK_END ) )
2845 #ifdef MOD_GZIP_DEBUG1
2846 mod_gzip_printf( "%s: ERROR: fseek() call failed...\n",cn);
2849 fclose( ifh1 ); /* FILE is still open so CLOSE it... */
2851 /* fseek() failure could be a platform issue so log the event... */
2853 ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
2854 "mod_gzip: fseek() failed for r->filename=[%s]",r->filename );
2856 /* Return DECLINED and let default logic finish the request... */
2858 #ifdef MOD_GZIP_DEBUG1
2859 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2862 #ifdef MOD_GZIP_USES_APACHE_LOGS
2864 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2867 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FSEEK_FAIL"));
2869 #endif /* MOD_GZIP_USES_APACHE_LOGS */
2875 * Get the current SIZE of the requested file...
2878 input_size = (long) ftell( ifh1 );
2880 if ( input_size == -1l )
2882 #ifdef MOD_GZIP_DEBUG1
2883 mod_gzip_printf( "%s: ERROR: ftell() call failed...\n",cn);
2886 fclose( ifh1 ); /* FILE is still open so CLOSE it... */
2888 /* ftell() failure could be a platform issue so log the event... */
2890 ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
2891 "mod_gzip: ftell() failed for r->filename=[%s]", r->filename );
2893 /* Return DECLINED and let default logic finish the request... */
2895 #ifdef MOD_GZIP_DEBUG1
2896 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2899 #ifdef MOD_GZIP_USES_APACHE_LOGS
2901 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2904 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FTELL_FAIL"));
2906 #endif /* MOD_GZIP_USES_APACHE_LOGS */
2912 * Once we have the length just close the file...
2915 if ( fclose( ifh1 ) == EOF )
2917 #ifdef MOD_GZIP_DEBUG1
2918 mod_gzip_printf( "%s: ERROR: fclose() following ftell() call failed...\n",cn);
2921 /* fclose() failure could be a platform issue so log the event... */
2923 ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
2924 "mod_gzip: fclose() failed for r->filename=[%s]",r->filename );
2926 /* Return DECLINED and let default logic finish the request... */
2928 #ifdef MOD_GZIP_DEBUG1
2929 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
2932 #ifdef MOD_GZIP_USES_APACHE_LOGS
2934 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
2937 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FCLOSE_FAIL"));
2939 #endif /* MOD_GZIP_USES_APACHE_LOGS */
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...
2952 #ifdef MOD_GZIP_DEBUG1
2953 mod_gzip_printf( "%s: Call mod_gzip_encode_and_transmit()...\n",cn);
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 */
2965 #ifdef MOD_GZIP_DEBUG1
2966 mod_gzip_printf( "%s: Back mod_gzip_encode_and_transmit()...\n",cn);
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.
2974 * Just return the result code and finish the transaction.
2977 #ifdef MOD_GZIP_DEBUG1
2980 mod_gzip_printf( "%s: Exit > return( rc = %d OK ) >\n",cn,rc);
2982 else if ( rc == DECLINED )
2984 mod_gzip_printf( "%s: Exit > return( rc = %d DECLINED ) >\n",cn,rc);
2986 else /* HTTP ERROR */
2988 mod_gzip_printf( "%s: Exit > return( rc = %d HTTP_ERROR ) >\n",cn,rc);
2990 #endif /* MOD_GZIP_DEBUG1 */
2994 }/* End of mod_gzip_static_file_handler() */
2996 int mod_gzip_create_unique_filename(
3003 * Creates a unique work file name.
3006 long process_id = 0; /* Current Process ID */
3007 long thread_id = 0; /* Current thread ID */
3009 #ifdef MOD_GZIP_DEBUG1
3010 char cn[]="mod_gzip_create_unique_filename()";
3016 process_id = (long) GetCurrentProcessId();
3017 thread_id = (long) GetCurrentThreadId();
3019 process_id = (long) getpid();
3020 thread_id = (long) process_id; /* TODO: Add pthreads call */
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 );
3036 if ( ( !target ) || ( targetmaxlen == 0 ) )
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 );
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...
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 */
3062 mod_gzip_iusn++; /* Increment Instance Unique Sequence Number */
3064 if ( mod_gzip_iusn > 999999999L ) mod_gzip_iusn = 1; /* Wrap */
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 );
3073 }/* End of mod_gzip_create_unique_filename() */
3076 #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS
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 */
3084 /* Generic command response transmitter... */
3087 char content_length[20];
3089 #ifdef MOD_GZIP_DEBUG1
3090 char cn[]="mod_gzip_send_html_command_response()";
3095 #ifdef MOD_GZIP_DEBUG1
3096 mod_gzip_printf( "%s: Entry...\n",cn);
3097 mod_gzip_printf( "%s: ctype=[%s]\n",cn,ctype);
3100 /* Add the length of the response to the output header... */
3101 /* The third parameter to ap_table_set() MUST be a string. */
3103 tmplen = strlen( tmp );
3105 sprintf( content_length, "%d", tmplen );
3107 #ifdef MOD_GZIP_DEBUG1
3108 mod_gzip_printf( "%s: content_length = [%s]\n",cn,content_length);
3111 ap_table_set( r->headers_out, "Content-Length", content_length );
3113 /* Make sure the content type matches this response... */
3115 r->content_type = ctype; /* Actual type passed by caller */
3117 #ifdef MOD_GZIP_DEBUG1
3118 mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type);
3121 /* Start a timer... */
3123 #ifdef MOD_GZIP_DEBUG1
3124 mod_gzip_printf( "%s: Call ap_soft_timeout()...\n",cn);
3127 ap_soft_timeout( "mod_gzip_send_html_command", r );
3129 #ifdef MOD_GZIP_DEBUG1
3130 mod_gzip_printf( "%s: Back ap_soft_timeout()...\n",cn);
3133 #ifdef MOD_GZIP_COMMANDS_USE_LAST_MODIFIED
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. */
3140 #ifdef MOD_GZIP_DEBUG1
3141 mod_gzip_printf( "%s: Call ap_update_mtime(r,r-finfo.st_mtime)...\n",cn);
3144 ap_update_mtime( r, r->finfo.st_mtime );
3146 #ifdef MOD_GZIP_DEBUG1
3147 mod_gzip_printf( "%s: Back ap_update_mtime(r,r-finfo.st_mtime)...\n",cn);
3150 /* Update the 'Last modified' stamp in output header... */
3152 #ifdef MOD_GZIP_DEBUG1
3153 mod_gzip_printf( "%s: Call ap_set_last_modified()...\n",cn);
3156 ap_set_last_modified(r);
3158 /* TODO: Add 'no-cache' option(s) to mod_gzip command responses */
3159 /* so user doesn't have hit reload to get fresh data. */
3161 #ifdef MOD_GZIP_DEBUG1
3162 mod_gzip_printf( "%s: Back ap_set_last_modified()...\n",cn);
3165 #endif /* MOD_GZIP_COMMANDS_USE_LAST_MODIFIED */
3167 /* Send the HTTP response header... */
3169 #ifdef MOD_GZIP_DEBUG1
3170 mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn);
3173 ap_send_http_header(r);
3175 #ifdef MOD_GZIP_DEBUG1
3176 mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn);
3179 /* Send the response BODY... */
3181 #ifdef MOD_GZIP_DEBUG1
3182 mod_gzip_printf( "%s: Sending response...\n%s\n",cn,tmp);
3185 #ifdef MOD_GZIP_USES_AP_SEND_MMAP
3187 /* Use ap_send_mmap() call to send the data... */
3189 ap_send_mmap( tmp, r, 0, tmplen );
3191 #else /* !MOD_GZIP_USES_AP_SEND_MMAP */
3193 /* Use ap_rwrite() call to send the data... */
3195 ap_rwrite( tmp, tmplen, r );
3197 #endif /* MOD_GZIP_USES_AP_SEND_MMAP */
3199 /* Clean up and exit... */
3201 #ifdef MOD_GZIP_DEBUG1
3202 mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn);
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);
3214 }/* End of mod_gzip_send_html_command_response() */
3216 #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */
3219 mod_gzip_create_config( pool *p, server_rec *s )
3223 mod_gzip_conf *ps = 0;
3225 #ifdef MOD_GZIP_DEBUG1
3226 char cn[]="mod_gzip_create_config()";
3230 * Set all the configuration default values...
3233 #ifdef MOD_GZIP_DEBUG1
3234 mod_gzip_printf( "%s: Entry\n", cn );
3238 * Allocate a new config structure...
3241 ps = ( mod_gzip_conf * ) ap_pcalloc( p, sizeof( mod_gzip_conf ) );
3244 * Set all default values...
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 */
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 */
3259 /* Compressed object cache control variables... */
3261 /* Using these default values the compressed object cache
3262 /* can have 2^18 directories (256,000) */
3264 ps->cache.root = ap_server_root; /* Default DIR is ServerRoot */
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;
3281 /* Initialize the include/exclude item map list... */
3283 /* For now all init values are ZERO but don't use */
3284 /* memset() since this may not always be the case. */
3286 ps->imap_total_entries = 0;
3288 for ( i=0; i<MOD_GZIP_IMAP_MAXNAMES; i++ )
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;
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 );
3304 }/* End of mod_gzip_create_config() */
3307 mod_gzip_merge_config( pool *p, void *basev, void *overridesv )
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;
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;
3325 }/* End of mod_gzip_merge_config() */
3328 * Module configuration directive handlers...
3332 mod_gzip_set_on(cmd_parms *parms, void *dummy, char *arg)
3336 #ifdef MOD_GZIP_DEBUG1
3337 char cn[]="mod_gzip_set_on()";
3342 #ifdef MOD_GZIP_DEBUG1
3343 mod_gzip_printf( "%s: Entry\n", cn );
3344 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3347 mgc = ( mod_gzip_conf * )
3348 ap_get_module_config(parms->server->module_config, &gzip_module);
3350 if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3352 /* Set the master 'request control' switches ON... */
3354 mgc->req = 1; /* Yes */
3355 mgc->req_set = 1; /* Yes */
3357 else /* Set the master 'request control' switches OFF... */
3359 mgc->req = 0; /* No */
3360 mgc->req_set = 0; /* No */
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 );
3372 mod_gzip_set_keep_workfiles(cmd_parms *parms, void *dummy, char *arg)
3376 #ifdef MOD_GZIP_DEBUG1
3377 char cn[]="mod_gzip_set_keep_workfiles()";
3382 #ifdef MOD_GZIP_DEBUG1
3383 mod_gzip_printf( "%s: Entry\n", cn );
3384 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3387 mgc = ( mod_gzip_conf * )
3388 ap_get_module_config(parms->server->module_config, &gzip_module);
3390 if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3392 mgc->keep_workfiles = 1; /* Yes */
3396 mgc->keep_workfiles = 0; /* No */
3399 #ifdef MOD_GZIP_DEBUG1
3400 mod_gzip_printf( "%s: mgc->keep_workfiles = %ld\n", cn,
3401 (long) mgc->keep_workfiles );
3408 mod_gzip_set_min_http(cmd_parms *parms, void *dummy, char *arg)
3412 #ifdef MOD_GZIP_DEBUG1
3413 char cn[]="mod_gzip_set_min_http()";
3418 #ifdef MOD_GZIP_DEBUG1
3419 mod_gzip_printf( "%s: Entry\n", cn );
3420 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3423 mgc = ( mod_gzip_conf * )
3424 ap_get_module_config(parms->server->module_config, &gzip_module);
3426 mgc->min_http = (int) atoi( arg );
3428 #ifdef MOD_GZIP_DEBUG1
3429 mod_gzip_printf( "%s: mgc->min_http = %ld\n", cn,
3430 (long) mgc->min_http );
3438 mod_gzip_imap_add_item( mod_gzip_conf *mgc, char *arg, int flag1 )
3445 int this_include=flag1;
3447 #ifdef MOD_GZIP_DEBUG1
3448 char cn[]="mod_gzip_imap_add_item()";
3453 #ifdef MOD_GZIP_DEBUG1
3455 mod_gzip_printf( "%s: Entry\n", cn );
3456 mod_gzip_printf( "%s: 1 arg=[%s]\n", cn, arg );
3460 mod_gzip_printf( "%s: flag1 = %d = INCLUDE\n", cn, flag1 );
3462 else if ( flag1 == 0 )
3464 mod_gzip_printf( "%s: flag1 = %d = EXCLUDE\n", cn, flag1 );
3468 mod_gzip_printf( "%s: flag1 = %d = ??? Unknown value\n", cn, flag1 );
3471 mod_gzip_printf( "%s: MOD-GZIP_IMAP_MAXNAMES = %d\n",
3472 cn, MOD_GZIP_IMAP_MAXNAMES );
3474 mod_gzip_printf( "%s: mgc->imap_total_entries = %d\n",
3475 cn, mgc->imap_total_entries );
3477 #endif /* MOD_GZIP_DEBUG1 */
3480 * Parse the config line...
3484 while((*p1!=0)&&(*p1<33)) p1++;
3487 this_type = MOD_GZIP_IMAP_ISHANDLER;
3488 this_action = MOD_GZIP_IMAP_DYNAMIC1;
3494 while((*p1!=0)&&(*p1<33)) p1++;
3499 this_action = MOD_GZIP_IMAP_STATIC1;
3504 this_type = MOD_GZIP_IMAP_ISEXT;
3513 this_type = MOD_GZIP_IMAP_ISMIME;
3523 if ( ( this_type != MOD_GZIP_IMAP_ISMIME ) &&
3524 ( this_type != MOD_GZIP_IMAP_ISEXT ) &&
3525 ( this_type != MOD_GZIP_IMAP_ISHANDLER ) )
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);
3532 return( "mod_gzip: ERROR: Unrecognized item 'type'" );
3535 if ( ( this_action != MOD_GZIP_IMAP_DYNAMIC1 ) &&
3536 ( this_action != MOD_GZIP_IMAP_STATIC1 ) )
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);
3543 return( "mod_gzip: ERROR: Unrecognized item 'action'" );
3550 if ( this_type != MOD_GZIP_IMAP_ISMIME )
3553 * Wildcards are only allowed in MIME strings such as 'image/*'
3561 return( "mod_gzip: ERROR: Wildcards are only allowed in MIME strings." );
3568 * If there is room for a new record then add it...
3571 if ( mgc->imap_total_entries < MOD_GZIP_IMAP_MAXNAMES )
3573 if ( strlen( arg ) < MOD_GZIP_IMAP_MAXNAMELEN )
3575 x = mgc->imap_total_entries;
3578 while((*p1!=0)&&(*p1<33)) p1++;
3580 strcpy( mgc->imap[x].name, p1 );
3582 mgc->imap[x].include = this_include;
3583 mgc->imap[x].type = this_type;
3584 mgc->imap[x].action = this_action;
3586 mgc->imap_total_entries++; /* Increase onboard items */
3588 else /* ERROR: Name is too long */
3590 #ifdef MOD_GZIP_DEBUG1
3591 mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item name is too long\n",cn);
3594 return( "mod_gzip: ERROR: Item name is too long" );
3597 else /* ERROR: INDEX is FULL */
3599 #ifdef MOD_GZIP_DEBUG1
3600 mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item index is full\n",cn);
3603 return( "mod_gzip: ERROR: Item index is full" );
3606 #ifdef MOD_GZIP_DEBUG1
3607 mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn);
3612 }/* End of mod_gzip_imap_add_item() */
3614 #ifdef MOD_GZIP_DEBUG1
3616 int mod_gzip_imap_show_items( mod_gzip_conf *mgc )
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.
3626 char cn[]="mod_gzip_imap_show_items()";
3630 mod_gzip_printf( "\n");
3631 mod_gzip_printf( "%s: Entry\n", cn );
3633 mod_gzip_printf( "%s: mgc->imap_total_entries= %d\n", cn,
3634 (long) mgc->imap_total_entries );
3636 for ( i=0; i<mgc->imap_total_entries; i++ )
3638 x = i; /* Work variable */
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);
3644 if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME )
3646 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISMIME\n",cn,x);
3648 else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT )
3650 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISEXT\n",cn,x);
3652 else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER )
3654 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISHANDLER\n",cn,x);
3656 else /* Unrecognized item type... */
3658 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x);
3661 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = %d\n", cn,x,mgc->imap[x].action);
3663 if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 )
3665 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x);
3667 else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 )
3669 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_STATIC1\n",cn,x);
3671 else /* Unrecognized action type... */
3673 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_??? Unknown action\n",cn,x);
3676 mod_gzip_printf( "%s: mgc->imap[%3.3d].name = [%s]\n",cn,x,mgc->imap[x].name);
3680 mod_gzip_printf( "\n");
3684 }/* End of mod_gzip_imap_show_items() */
3686 #endif /* MOD_GZIP_DEBUG1 */
3689 mod_gzip_set_item_include(cmd_parms *parms, void *dummy, char *arg)
3693 #ifdef MOD_GZIP_DEBUG1
3694 char cn[]="mod_gzip_set_item_include()";
3699 #ifdef MOD_GZIP_DEBUG1
3700 mod_gzip_printf( "%s: Entry\n", cn );
3701 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3704 mgc = ( mod_gzip_conf * )
3705 ap_get_module_config(parms->server->module_config, &gzip_module);
3707 /* Pass pre-determined pointer to config structure... */
3708 /* Pass '1' for parm 3 to INCLUDE this item... */
3710 return( mod_gzip_imap_add_item( mgc, arg, 1 ) );
3714 mod_gzip_set_item_exclude(cmd_parms *parms, void *dummy, char *arg)
3718 #ifdef MOD_GZIP_DEBUG1
3719 char cn[]="mod_gzip_set_item_exclude()";
3724 #ifdef MOD_GZIP_DEBUG1
3725 mod_gzip_printf( "%s: Entry\n", cn );
3726 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3729 mgc = ( mod_gzip_conf * )
3730 ap_get_module_config(parms->server->module_config, &gzip_module);
3732 /* Pass pre-determined pointer to config structure... */
3733 /* Pass '0' for parm 3 to EXCLUDE this item... */
3735 return( mod_gzip_imap_add_item( mgc, arg, 0 ) );
3739 mod_gzip_set_temp_dir(cmd_parms *parms, void *dummy, char *arg)
3743 char cn[]="mod_gzip_set_temp_dir()";
3747 #ifdef MOD_GZIP_DEBUG1
3748 mod_gzip_printf( "%s: Entry\n", cn );
3749 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3752 mgc = ( mod_gzip_conf * )
3753 ap_get_module_config(parms->server->module_config, &gzip_module);
3755 mgc->cache.root = arg; /* For now temp dir is used as cache root */
3757 strcpy( mod_gzip_temp_dir, arg );
3758 mgc->cache.root = mod_gzip_temp_dir;
3760 #ifdef MOD_GZIP_DEBUG1
3761 mod_gzip_printf( "%s: mgc->cache.root=[%s]\n", cn, mgc->cache.root );
3768 mod_gzip_set_minimum_file_size(cmd_parms *parms, void *dummy, char *arg)
3773 #ifdef MOD_GZIP_DEBUG1
3774 char cn[]="mod_gzip_set_minimum_file_size()";
3779 #ifdef MOD_GZIP_DEBUG1
3780 mod_gzip_printf( "%s: Entry\n", cn );
3781 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3784 mgc = ( mod_gzip_conf * )
3785 ap_get_module_config(parms->server->module_config, &gzip_module);
3787 lval = (long) atol(arg);
3789 /* 300 bytes is the minimum at all times */
3790 if ( lval < 300L ) lval = 300L;
3792 mgc->minimum_file_size = (long) lval; /* Set config */
3793 mod_gzip_minimum_file_size = (long) lval; /* Set global */
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 );
3806 mod_gzip_set_maximum_inmem_size(cmd_parms *parms, void *dummy, char *arg)
3811 #ifdef MOD_GZIP_DEBUG1
3812 char cn[]="mod_gzip_set_maximum_inmem_size()";
3817 #ifdef MOD_GZIP_DEBUG1
3818 mod_gzip_printf( "%s: Entry\n", cn );
3819 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3822 mgc = ( mod_gzip_conf * )
3823 ap_get_module_config(parms->server->module_config, &gzip_module);
3825 lval = (long) atol(arg);
3827 /* 60000 bytes is the current maximum since a malloc() call is used */
3828 if ( lval > 60000L ) lval = 60000L;
3830 mgc->maximum_inmem_size = (long) lval; /* Set config */
3831 mod_gzip_maximum_inmem_size = (long) lval; /* Set global */
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 );
3844 mod_gzip_set_do_static_files(cmd_parms *parms, void *dummy, char *arg)
3848 #ifdef MOD_GZIP_DEBUG1
3849 char cn[]="mod_gzip_set_do_static_files()";
3854 #ifdef MOD_GZIP_DEBUG1
3855 mod_gzip_printf( "%s: Entry\n", cn );
3856 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3859 mgc = ( mod_gzip_conf * )
3860 ap_get_module_config(parms->server->module_config, &gzip_module);
3862 if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3864 mgc->do_static_files = 1; /* Yes */
3868 mgc->do_static_files = 0; /* No */
3871 #ifdef MOD_GZIP_DEBUG1
3872 mod_gzip_printf( "%s: mgc->do_static_files = %ld\n", cn,
3873 (long) mgc->do_static_files );
3880 mod_gzip_set_do_cgi(cmd_parms *parms, void *dummy, char *arg)
3884 #ifdef MOD_GZIP_DEBUG1
3885 char cn[]="mod_gzip_set_do_cgi()";
3890 #ifdef MOD_GZIP_DEBUG1
3891 mod_gzip_printf( "%s: Entry\n", cn );
3892 mod_gzip_printf( "%s: arg=[%s]\n", cn, arg );
3895 mgc = ( mod_gzip_conf * )
3896 ap_get_module_config(parms->server->module_config, &gzip_module);
3898 if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) )
3900 mgc->do_cgi = 1; /* Yes */
3904 mgc->do_cgi = 0; /* No */
3907 #ifdef MOD_GZIP_DEBUG1
3908 mod_gzip_printf( "%s: mgc->do_cgi = %ld\n", cn,
3909 (long) mgc->do_cgi );
3915 static const handler_rec mod_gzip_handlers[] =
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...
3924 /* Add a 'name' and some types to our handler... */
3926 {"mod_gzip_handler", mod_gzip_handler},
3927 {CGI_MAGIC_TYPE, mod_gzip_handler},
3928 {"cgi-script", mod_gzip_handler},
3929 {"*", mod_gzip_handler},
3934 static const command_rec mod_gzip_cmds[] =
3937 * Define our httpd.conf configuration diectives and
3938 * the local routines that are responsible for processing
3939 * those directives when the time comes...
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"},
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."},
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."},
3951 {"mod_gzip_keep_workfiles", mod_gzip_set_keep_workfiles, NULL, RSRC_CONF, TAKE1,
3952 "On=Keep work files Off=No"},
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"},
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"},
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."},
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"},
3966 {"mod_gzip_item_include", mod_gzip_set_item_include, NULL, RSRC_CONF, TAKE1,
3967 "Add the item the inclusion list"},
3969 {"mod_gzip_item_exclude", mod_gzip_set_item_exclude, NULL, RSRC_CONF, TAKE1,
3970 "Add the item the exclusion list"},
3976 * The actual module 'jump' table...
3978 * If one of the fixed 'call' points has a valid function
3979 * address then Apache will 'call' into it at the appropriate time.
3981 * When the compressed object cache is engaged we will need to
3982 * simply add some handlers for the URI detection and translation
3986 module MODULE_VAR_EXPORT gzip_module =
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 */
4003 NULL, /* header parser */
4004 NULL, /* child_init */
4005 NULL, /* child_exit */
4006 NULL /* post read-request */
4010 int main(int argc, char *argv[])
4012 ExitThread(TSR_THREAD, 0);
4016 FILE *mod_gzip_open_output_file(
4018 char *output_filename,
4024 #ifdef MOD_GZIP_DEBUG1
4025 char cn[]="mod_gzip_open_output_file():::";
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);
4037 ifh = fopen( output_filename, "rb" ); /* Open in BINARY mode */
4039 if ( !ifh ) /* The file failed to open... */
4041 #ifdef MOD_GZIP_DEBUG1
4042 mod_gzip_printf( "%s: ERROR: Cannot open file [%s]\n",
4043 cn,output_filename);
4047 * The workfile was created OK but now will not re-open.
4048 * This is worth a strike in the ERROR log.
4051 ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server,
4052 "mod_gzip: Cannot re-open output_filename=[%s]",
4055 /* Return DECLINED and let default logic finish the request... */
4057 #ifdef MOD_GZIP_DEBUG1
4058 mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn);
4061 #ifdef MOD_GZIP_USES_APACHE_LOGS
4063 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4066 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:WORK_OPENFAIL"));
4068 #endif /* MOD_GZIP_USES_APACHE_LOGS */
4070 *rc = DECLINED; /* Update caller's result code... */
4074 }/* End 'if ( !ifh )' */
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);
4081 *rc = OK; /* Update caller's result code */
4083 return ifh; /* Return the file handle */
4085 }/* End of mod_gzip_open_output_file() */
4087 int mod_gzip_encode_and_transmit(
4090 int source_is_a_file,
4096 GZP_CONTROL* gzp = &gzc;
4101 long output_size = 0;
4102 long compression_ratio = 0;
4103 char* gz1_ismem_obuf = 0;
4104 int finalize_stats = 1;
4106 int gz1_ismem_obuf_was_allocated = 0;
4108 char content_length[20]; /* For Content-length updates */
4110 #define MOD_GZIP_LARGE_BUFFER_SIZE 8192
4112 char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */
4114 char *actual_content_encoding_name = "gzip"; /* Adjustable */
4115 const char *compression_format;
4117 #ifdef MOD_GZIP_DEBUG1
4118 char cn[]="mod_gzip_encode_and_transmit()";
4121 void *modconf = r->server->module_config;
4123 #ifdef MOD_GZIP_USES_APACHE_LOGS
4124 char log_info[40]; /* Scratch buffer */
4130 * Establish a local pointer to module configuration data...
4133 mod_gzip_conf *conf =
4134 (mod_gzip_conf *) ap_get_module_config( modconf, &gzip_module );
4136 #ifdef MOD_GZIP_DEBUG1
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);
4142 if ( source_is_a_file ) /* Show the filename... */
4144 mod_gzip_printf( "%s: source = [%s]\n", cn, source);
4146 else /* Don't try to print the memory buffer... */
4148 mod_gzip_printf( "%s: source = MEMORY BUFFER\n", cn );
4151 mod_gzip_printf( "%s: input_size = %ld\n", cn,(long)input_size);
4153 #endif /* MOD_GZIP_DEBUG1 */
4156 #ifdef MOD_GZIP_USES_APACHE_LOGS
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. */
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. */
4168 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK"));
4170 /* We can also update the 'input' size right away since it is known */
4172 sprintf( log_info,"%d", (int) input_size );
4173 ap_table_setn( r->notes,"mod_gzip_input_size",ap_pstrdup(r->pool,log_info));
4175 #endif /* MOD_GZIP_USES_APACHE_LOGS */
4178 * If the source has no length then DECLINE the processing...
4181 if ( input_size < 1 )
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);
4188 /* An existing request object with no length is worth a warning... */
4190 ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_WARNING, r->server,
4191 "mod_gzip: r->filename=[%s] has no length",r->filename );
4193 #ifdef MOD_GZIP_DEBUG1
4194 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
4197 #ifdef MOD_GZIP_USES_APACHE_LOGS
4199 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4202 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_I_LEN"));
4204 #endif /* MOD_GZIP_USES_APACHE_LOGS */
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'...
4215 if ( r->header_only )
4217 #ifdef MOD_GZIP_DEBUG1
4218 mod_gzip_printf( "%s: HEAD request only... ignore body data...\n",cn);
4222 * Set outbound response header fields...
4224 * NOTE: If this is just a HEAD request then
4225 * there is no need to make the API call...
4227 * ap_update_mtime( r, r->finfo.st_mtime );
4229 * ...and update the actual time. Use the time
4230 * that's currently associated with the object.
4233 ap_set_last_modified(r);
4235 ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
4237 /* Start a timer for this transaction... */
4239 ap_soft_timeout( "mod_gzip: HEAD request handler", r );
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);
4246 ap_send_http_header(r);
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);
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);
4260 #ifdef MOD_GZIP_USES_APACHE_LOGS
4262 /* Return OK but distinguish it from a 'GET' request in logs... */
4265 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK:HEAD_ONLY"));
4267 #endif /* MOD_GZIP_USES_APACHE_LOGS */
4271 }/* End 'if( r->header_only )' */
4274 * See if the source meets the MINUMUM SIZE requirement...
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
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.
4286 #ifdef MOD_GZIP_DEBUG1
4287 mod_gzip_printf( "%s: conf->minimum_file_size = %ld\n",
4288 cn, (long) conf->minimum_file_size );
4291 if ( input_size < (long) conf->minimum_file_size )
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);
4298 /* Set the 'mod_gzip_result' note value to something */
4299 /* that indicates this was too small... */
4301 #ifdef MOD_GZIP_USES_APACHE_LOGS
4303 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4306 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:TOO_SMALL"));
4308 #endif /* MOD_GZIP_USES_APACHE_LOGS */
4310 /* Is it OK to DECLINE?... */
4312 if ( nodecline ) /* We have been told NOT to DECLINE */
4314 #ifdef MOD_GZIP_DEBUG1
4315 mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn);
4318 /* Skip the compression phase and just set the output */
4319 /* control skid up to send the real input data... */
4321 output_size = input_size;
4323 if ( source_is_a_file ) /* Source is a workfile... */
4325 #ifdef MOD_GZIP_DEBUG1
4326 mod_gzip_printf( "%s: Force send - source = FILE[%s]\n",
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 */
4336 ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4338 if ( !ifh ) /* The file failed to open... */
4340 /* We really MUST decline... */
4341 /* Logs have already been updated... */
4346 else /* Source is just a memory buffer... */
4348 #ifdef MOD_GZIP_DEBUG1
4349 mod_gzip_printf( "%s: Force send - source = MEMORY BUFFER\n",cn);
4352 gzp->output_ismem = 1;
4353 gz1_ismem_obuf = source;
4355 gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */
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);
4363 goto mod_gzip_encode_and_transmit_send_start; /* Jump */
4365 else /* It's OK to DECLINE the processing... */
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);
4375 else /* The source is larger than the minimum size requirement... */
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);
4384 * We must now encode the requested object...
4386 * Statistically speaking, most 'text/*' pages are
4387 * less than 60k. XML documents are an exception.
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.
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 ).
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.
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),
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.
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'.
4436 * See if the object size exceeds the current MAXIMUM size
4437 * to use for in-memory compression...
4439 * See notes above about a range of 60k or so being the best
4440 * value for heavy load conditions.
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.
4449 #ifdef MOD_GZIP_DEBUG1
4450 mod_gzip_printf( "%s: conf->maximum_inmem_size = %ld\n",
4451 cn, (long) conf->maximum_inmem_size );
4455 * Set up the INPUT target...
4458 /* The size and type of the input source is always known */
4459 /* and was passed by the caller... */
4461 if ( source_is_a_file )
4463 #ifdef MOD_GZIP_DEBUG1
4464 mod_gzip_printf( "%s: Input source is file[%s]\n",cn,source);
4467 strcpy( gzp->input_filename, source );
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 */
4475 #ifdef MOD_GZIP_DEBUG1
4476 mod_gzip_printf( "%s: Input source is a MEMORY BUFFER\n",cn);
4479 *gzp->input_filename = 0; /* Not used */
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 */
4487 * Set up the OUTPUT target...
4490 gzp->decompress = 0; /* Perform encoding */
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)
4496 actual_content_encoding_name = "deflate";
4497 gzp->compression_format = DEFLATE_FORMAT;
4501 gzp->compression_format = GZIP_FORMAT;
4504 if ( input_size <= (long) conf->maximum_inmem_size )
4506 /* The input source is small enough to compress directly */
4507 /* to an in-memory output buffer... */
4509 #ifdef MOD_GZIP_DEBUG1
4510 mod_gzip_printf( "%s: Input source is small enough for in-memory compression.\n",cn);
4513 *gzp->output_filename = 0; /* Not used */
4514 gzp->output_ismem = 1; /* Output is a memory buffer */
4517 * Allocate a memory buffer to hold compressed output.
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.
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 )
4530 gz1_ismem_obuf = (char *) malloc( input_size + 1000 );
4532 if ( !gz1_ismem_obuf )
4535 * There wasn't enough memory left for another
4536 * in-memory compression buffer so default to using
4537 * an output disk file instead...
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);
4545 gzp->output_ismem = 0; /* Switch to using a disk file */
4548 else /* We got the memory we need for in-memory compression... */
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... */
4555 gz1_ismem_obuf_was_allocated = 1; /* 'free' is required */
4557 /* Compression codecs require a 'clean' buffer so */
4558 /* we need to spend the cycles for a memset() call. */
4560 memset( gz1_ismem_obuf, 0, ( input_size + 1000 ) );
4562 /* Set OUTPUT buffer control variables... */
4564 gzp->output_ismem_obuf = gz1_ismem_obuf;
4565 gzp->output_ismem_obuflen = input_size + 1000;
4568 }/* End 'if ( input_size <= conf->maximum_inmem_size )' */
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.
4576 if ( gzp->output_ismem != 1 )
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...
4584 #ifdef MOD_GZIP_DEBUG1
4585 mod_gzip_printf( "%s: Input source too big for in-memory compression.\n",cn);
4589 * Create the GZP output target name...
4592 mod_gzip_create_unique_filename(
4593 (mod_gzip_conf *) conf,
4594 (char *) gzp->output_filename,
4595 MOD_GZIP_MAX_PATH_LEN
4599 * COMPRESSION OBJECT CACHE
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.
4612 gzp->output_ismem = 0; /* Output is a disk file */
4614 gz1_ismem_obuf = 0; /* Make sure this is NULL */
4616 /* Set OUTPUT buffer control variables... */
4618 gzp->output_ismem_obuf = 0; /* Not used for this method */
4619 gzp->output_ismem_obuflen = 0; /* Not used for this method */
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);
4633 rc = gzp_main( gzp ); /* Perform the compression... */
4635 output_size = (long) gzp->bytes_out;
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 );
4646 /* Compute the compresion ratio for access.log and */
4647 /* internal statistics update... */
4649 compression_ratio = 0; /* Reset */
4651 /* Prevent 'Divide by zero' error... */
4653 if ( ( input_size > 0 ) &&
4654 ( output_size > 0 ) )
4656 compression_ratio = 100 - (int)
4657 ( output_size * 100L / input_size );
4660 #ifdef MOD_GZIP_DEBUG1
4661 mod_gzip_printf( "%s: Compression ratio = %ld percent\n",cn,
4662 (long) compression_ratio );
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.
4672 #ifdef MOD_GZIP_USES_APACHE_LOGS
4674 sprintf( log_info,"%d", (int) output_size );
4675 ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info));
4677 sprintf( log_info,"%d", (int) compression_ratio );
4678 ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info));
4680 #endif /* MOD_GZIP_USES_APACHE_LOGS */
4683 * Evaluate the compression result(s)...
4685 * If the compression pass failed then the output length
4686 * will be ZERO bytes...
4689 if ( output_size < 1 )
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);
4696 finalize_stats = 0; /* Don't update stats again */
4698 if ( r->server->loglevel == APLOG_DEBUG )
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);
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.
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.
4718 #ifdef MOD_GZIP_USES_APACHE_LOGS
4720 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4723 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_O_LEN"));
4725 #endif /* MOD_GZIP_USES_APACHE_LOGS */
4727 /* Is it OK to DECLINE?... */
4729 if ( nodecline ) /* We have been told NOT to DECLINE... */
4731 #ifdef MOD_GZIP_DEBUG1
4732 mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn);
4735 /* Just set the output control skid */
4736 /* to send the real input data... */
4738 output_size = input_size;
4740 if ( source_is_a_file ) /* Source is a workfile... */
4742 strcpy( gzp->output_filename, source );
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 */
4749 ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4751 if ( !ifh ) /* We really must DECLINE... */
4756 else /* Source is just a memory buffer... */
4758 gzp->output_ismem = 1;
4759 gz1_ismem_obuf = source;
4762 #ifdef MOD_GZIP_DEBUG1
4763 mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn);
4766 goto mod_gzip_encode_and_transmit_send_start; /* Jump */
4768 else /* It's OK to DECLINE the processing... */
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);
4775 /* Free the local memory buffer allocation ( if necessary )... */
4777 if ( gz1_ismem_obuf )
4779 /* The pointer may have been 'borrowed' and was */
4780 /* not actually 'allocated' so check the flag... */
4782 if ( gz1_ismem_obuf_was_allocated )
4784 free( gz1_ismem_obuf );
4787 gz1_ismem_obuf_was_allocated = 0;
4789 }/* End 'if( gz1_ismem_obuf_was_allocated )' */
4791 }/* End 'if( gz1_ismem_obuf )' */
4798 }/* End 'if( output_size < 1 )' */
4801 * If we reach this point then the compressed version has
4802 * a valid length. Time to see if it it's worth sending.
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...
4809 if ( output_size > input_size )
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);
4816 finalize_stats = 0; /* Don't update stats again */
4818 #ifdef MOD_GZIP_USES_APACHE_LOGS
4820 /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */
4823 r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:ORIGINAL_SMALLER"));
4825 #endif /* MOD_GZIP_USES_APACHE_LOGS */
4827 /* Is it OK to DECLINE?... */
4829 if ( nodecline ) /* We have been told NOT to DECLINE... */
4831 #ifdef MOD_GZIP_DEBUG1
4832 mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn);
4835 /* Just set the output control skid */
4836 /* to send the real input data... */
4838 output_size = input_size;
4840 if ( source_is_a_file ) /* Source is a workfile... */
4842 strcpy( gzp->output_filename, source );
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 */
4849 ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4851 if ( !ifh ) /* We really must DECLINE... */
4856 else /* Source is just a memory buffer... */
4858 gzp->output_ismem = 1;
4859 gz1_ismem_obuf = source;
4861 gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */
4864 #ifdef MOD_GZIP_DEBUG1
4865 mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn);
4868 goto mod_gzip_encode_and_transmit_send_start; /* Jump */
4870 else /* It's OK to DECLINE the processing... */
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);
4877 /* Free the local memory buffer allocation ( if necessary )... */
4879 if ( gz1_ismem_obuf )
4881 /* The pointer may have been 'borrowed' and was */
4882 /* not actually 'allocated' so check the flag... */
4884 if ( gz1_ismem_obuf_was_allocated )
4886 free( gz1_ismem_obuf );
4889 gz1_ismem_obuf_was_allocated = 0;
4891 }/* End 'if( gz1_ismem_obuf_was_allocated )' */
4893 }/* End 'if( gz1_ismem_obuf )' */
4900 else /* Compressed version is smaller than original... */
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);
4909 * If an output workfile was used then make SURE it is going
4910 * to reopen before beginning the transmit phase.
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.
4917 * This only matters for 'static' files or times when the
4918 * 'nodecline' flag is FALSE and it is actually OK to DECLINE.
4921 if ( !gzp->output_ismem ) /* Workfile was used... */
4923 #ifdef MOD_GZIP_DEBUG1
4924 mod_gzip_printf( "%s: Opening compressed output file [%s]...\n",
4925 cn, gzp->output_filename );
4928 ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc );
4930 if ( !ifh ) /* The file failed to open... */
4932 #ifdef MOD_GZIP_DEBUG1
4933 mod_gzip_printf( "%s: ERROR: Cannot re-open file [%s]\n",
4934 cn,gzp->output_filename);
4937 /* We really must DECLINE... */
4938 /* Logs have already been updated... */
4940 #ifdef MOD_GZIP_DEBUG1
4941 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
4946 }/* End 'if ( !ifh )' */
4948 #ifdef MOD_GZIP_DEBUG1
4949 mod_gzip_printf( "%s: Workile re-opened OK...\n",cn);
4952 }/* End 'if ( !gzp->output_ismem )' */
4957 * If we have made it to here then all is well and only
4958 * now can we set the encoding for this response...
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.
4965 r->content_encoding = actual_content_encoding_name;
4967 #ifdef MOD_GZIP_DEBUG1
4968 mod_gzip_printf( "%s: r->content_encoding is now [%s]\n",
4969 cn, r->content_encoding );
4973 * Begin the transmission phase...
4975 * Even if the 'nodecline' flag is TRUE if we encounter
4976 * any fatal errors at this point we must 'DECLINE'.
4979 mod_gzip_encode_and_transmit_send_start: ; /* <<-- Jump point */
4981 #ifdef MOD_GZIP_DEBUG1
4982 mod_gzip_printf( "%s: Starting transmit phase...\n",cn);
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.
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
5004 * Set relevant outbound response header fields...
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.
5011 ap_update_mtime( r, r->finfo.st_mtime );
5012 ap_set_last_modified(r);
5014 ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
5017 * Start a timer for this transaction...
5020 ap_soft_timeout( "mod_gzip: Encoded data transmit", r );
5023 * Return the length of the compressed output in
5024 * the response header.
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.
5031 sprintf( content_length, "%ld", output_size );
5032 ap_table_set (r->headers_out, "Content-Length", content_length );
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);
5040 ap_send_http_header(r);
5042 #ifdef MOD_GZIP_DEBUG1
5043 mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn);
5047 * Send the response...
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...
5056 if ( gzp->output_ismem )
5058 /* Send the in-memory output buffer... */
5060 #ifdef MOD_GZIP_DEBUG1
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);
5065 /* Turn this 'on' for VERY verbose diagnostics...
5066 #define MOD_GZIP_DUMP_JUST_BEFORE_SENDING
5068 #ifdef MOD_GZIP_DUMP_JUST_BEFORE_SENDING
5069 mod_gzip_hexdump( gz1_ismem_obuf, output_size );
5072 #endif /* MOD_GZIP_DEBUG1 */
5074 /* This module can use either ap_send_mmap() or ap_rwrite()... */
5076 #ifdef MOD_GZIP_USES_AP_SEND_MMAP
5078 /* Use ap_send_mmap() call to send the data... */
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 );
5085 ap_send_mmap( gz1_ismem_obuf, r, 0, output_size );
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 );
5092 #else /* !MOD_GZIP_USES_AP_SEND_MMAP */
5094 /* Use ap_rwrite() call to send the data... */
5096 #ifdef MOD_GZIP_DEBUG1
5097 mod_gzip_printf( "%s: Call ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n",
5098 cn, (long)output_size );
5101 ap_rwrite( gz1_ismem_obuf, output_size, r );
5103 #ifdef MOD_GZIP_DEBUG1
5104 mod_gzip_printf( "%s: Back ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n",
5105 cn, (long)output_size );
5108 #endif /* MOD_GZIP_USES_AP_SEND_MMAP */
5110 /* Stop the timer... */
5112 #ifdef MOD_GZIP_DEBUG1
5113 mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn);
5118 #ifdef MOD_GZIP_DEBUG1
5119 mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn);
5122 /* Free the local memory buffer allocation ( if necessary )... */
5124 if ( gz1_ismem_obuf )
5126 /* The pointer may have been 'borrowed' and was */
5127 /* not actually 'allocated' so check the flag... */
5129 if ( gz1_ismem_obuf_was_allocated )
5131 free( gz1_ismem_obuf );
5134 gz1_ismem_obuf_was_allocated = 0;
5136 }/* End 'if( gz1_ismem_obuf_was_allocated )' */
5138 }/* End 'if( gz1_ismem_obuf )' */
5140 else /* Output workfile was used so send the contents... */
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.
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);
5157 bytesread = fread( tmp, 1, sizeof( tmp ), ifh );
5159 #ifdef MOD_GZIP_DEBUG1
5160 mod_gzip_printf( "%s: Back fread(): bytesread=%d\n",cn,bytesread);
5163 if ( bytesread < 1 ) break; /* File is exhausted... We are done...*/
5165 /* This module can use either ap_send_mmap() or ap_rwrite()... */
5167 #ifdef MOD_GZIP_USES_AP_SEND_MMAP
5169 /* Use ap_send_mmap() call to send the data... */
5171 ap_send_mmap( tmp, r, 0, bytesread );
5173 #else /* !MOD_GZIP_USES_AP_SEND_MMAP */
5175 /* Use ap_rwrite() call to send the data... */
5177 ap_rwrite( tmp, bytesread, r );
5179 #endif /* MOD_GZIP_USES_AP_SEND_MMAP */
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 );
5188 fclose( ifh ); /* Close the input file */
5190 /* Stop the timer before attempting to delete the workfile... */
5192 #ifdef MOD_GZIP_DEBUG1
5193 mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn);
5198 #ifdef MOD_GZIP_DEBUG1
5199 mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn);
5202 /* Delete the workfile if 'keep' flag is OFF... */
5204 #ifdef MOD_GZIP_DEBUG1
5205 mod_gzip_printf( "%s: conf->keep_workfiles = %d\n",
5206 cn, conf->keep_workfiles );
5209 if ( !conf->keep_workfiles ) /* Default is OFF */
5211 #ifdef MOD_GZIP_DEBUG1
5212 mod_gzip_printf( "%s: Deleting workfile [%s]...\n",
5213 cn, gzp->output_filename );
5217 DeleteFile( gzp->output_filename );
5219 unlink( gzp->output_filename );
5222 else /* Keep all work files... */
5224 #ifdef MOD_GZIP_DEBUG1
5225 mod_gzip_printf( "%s: Keeping workfile [%s]...\n",
5226 cn, gzp->output_filename );
5230 }/* End 'else' that sends compressed workfile */
5233 * The compressed object has been sent...
5236 #ifdef MOD_GZIP_USES_APACHE_LOGS
5238 if ( finalize_stats )
5240 sprintf( log_info,"%d", (int) output_size );
5241 ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info));
5243 sprintf( log_info,"%d", (int) compression_ratio );
5244 ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info));
5247 #endif /* MOD_GZIP_USES_APACHE_LOGS */
5249 if ( r->server->loglevel == APLOG_DEBUG )
5252 * If LogLevel is 'debug' then show the compression results
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.",
5261 (long) compression_ratio
5264 }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */
5267 * Return OK to the Server to indicate SUCCESS...
5270 #ifdef MOD_GZIP_DEBUG1
5271 mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn);
5276 }/* End of mod_gzip_encode_and_transmit() */
5278 int mod_gzip_ismatch( char *s1, char *s2, int len1, int haswilds )
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. */
5285 /* Unlike strncmp() this routine returns TRUE (1) if the */
5286 /* strings match and FALSE (0) if they do not... */
5295 /* WARNING! We MUST have a check for 'NULL' on the pointer(s) */
5296 /* themselves or we might GP */
5298 if ( ( s1 == 0 ) || ( s2 == 0 ) )
5300 /* SAFETY! If pointer itself if NULL */
5301 /* don't enter LOOP... */
5303 return( 0 ); /* Return FALSE for NOMATCH... */
5306 distance = len1; /* Default to value passed... */
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. */
5317 /* If either string had a valid pointer but is EMPTY */
5318 /* then this is an automatic 'no match'... */
5320 if ((l1==0)||(l2==0))
5322 return( 0 ); /* Return FALSE for NOMATCH... */
5327 if ( haswilds == 0 )
5329 return( 0 ); /* Return FALSE for NOMATCH... */
5333 /* If the lengths ARE equal then this is a possible */
5334 /* match. Use the smaller of the 2 values for scan...*/
5336 if ( l1 < l2 ) distance = l1;
5340 /* Final check... if distance is still 0 then this */
5341 /* is an automatic 'no match'... */
5343 if ( distance == 0 )
5345 return( 0 ); /* Return FALSE for NOMATCH... */
5348 /* Do the deed... */
5350 for ( i=0; i<distance; i++ )
5352 /* If we encounter a null in either string before we */
5353 /* have 'gone the distance' then the strings don't match... */
5355 if ( ( *s1 == 0 ) || ( *s2 == 0 ) ) return( 0 ); /* No match! */
5360 if ( ( ch1 == '*' ) || ( ch2 == '*' ) )
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... */
5368 return( 1 ); /* Wildcard match was OK this time... */
5372 if ( ch1 == '/' ) ch1 = '\\';
5373 if ( ch2 == '/' ) ch2 = '\\';
5375 if ( ch1 != ch2 ) return( 0 ); /* No match! */
5382 /* If we make it to here then everything MATCHED! */
5384 return( 1 ); /* MATCH! */
5386 }/* End mod_gzip_ismatch() */
5388 int mod_gzip_get_action_flag( request_rec *r, mod_gzip_conf *mgc )
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;
5402 int this_action = 0;
5403 char *this_name = 0;
5404 char *file_extension = 0;
5405 int file_extension_len = 0;
5408 #ifdef MOD_GZIP_DEBUG1
5409 char cn[]="mod_gzip_get_action_flag()";
5416 if ( r->content_type ) clen = strlen( r->content_type );
5417 if ( r->handler ) hlen = strlen( r->handler );
5421 flen = strlen( r->filename );
5423 while(*p1!=0){if (*p1=='.') file_extension=p1; p1++;}
5424 if ( file_extension ) file_extension_len = strlen( file_extension );
5427 #ifdef MOD_GZIP_DEBUG1
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);
5439 #endif /* MOD_GZIP_DEBUG1 */
5445 if ( ( hlen == 0 ) && ( clen == 0 ) )
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.
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.
5457 * Both the r->content_type field and the r->handler
5458 * field are empty. Ignore this one...
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);
5466 if ( r->server->loglevel == APLOG_DEBUG )
5468 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5469 "mod_gzip: There is no valid r->handler or r->content_length ");
5472 return( MOD_GZIP_IMAP_DECLINED1 );
5476 * Perform 2 passes at the Include/Exclude list...
5478 * The first pass is the higher-priority EXCLUSION check.
5479 * The second pass is the lower-priority INCLUSION check.
5482 for ( pass=0; pass<2; pass++ )
5485 pass_result = 0; /* Reset result */
5487 if ( pass == 0 ) /* EXCLUSION CHECK */
5491 #ifdef MOD_GZIP_DEBUG1
5492 mod_gzip_printf( "%s: EXCLUSION CHECK...\n",cn);
5495 else if ( pass == 1 ) /* INCLUSION CHECK */
5499 #ifdef MOD_GZIP_DEBUG1
5500 mod_gzip_printf( "%s: INCLUSION CHECK...\n",cn);
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 );
5511 for ( x=0; x<mgc->imap_total_entries; x++ )
5513 if ( r->server->loglevel == APLOG_DEBUG )
5515 /* Show the lookups in the Apache ERROR log if DEBUG is on */
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]",
5520 mgc->imap[x].include,
5522 mgc->imap[x].action,
5527 #ifdef MOD_GZIP_DEBUG1
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);
5537 if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME )
5539 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISMIME\n",cn,x);
5541 else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT )
5543 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISEXT\n",cn,x);
5545 else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER )
5547 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISHANDLER\n",cn,x);
5549 else /* Unrecognized item type... */
5551 mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x);
5554 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = %d\n", cn,x,mgc->imap[x].action);
5556 if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 )
5558 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x);
5560 else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 )
5562 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_STATIC1\n",cn,x);
5564 else /* Unrecognized action type... */
5566 mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_??? Unknown action\n",cn,x);
5569 mod_gzip_printf( "%s: mgc->imap[%3.3d].name = [%s]\n",cn,x,mgc->imap[x].name);
5571 #endif /* MOD_GZIP_DEBUG1 */
5573 /* 'filter_value' mirrors 'pass' value for now but this might */
5574 /* not always be true. First pass is EXCLUDE and second is INCLUDE */
5576 if ( mgc->imap[x].include == filter_value )
5578 #ifdef MOD_GZIP_DEBUG1
5579 mod_gzip_printf( "%s: This record matches filter_value %d\n",
5581 mod_gzip_printf( "%s: The record will be checked...\n",cn);
5585 * Set work values for this record...
5588 this_type = mgc->imap[x].type;
5589 this_action = mgc->imap[x].action;
5590 this_name = mgc->imap[x].name;
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".
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.
5602 if ( hlen > 0 ) /* r->handler field has a value... */
5604 #ifdef MOD_GZIP_DEBUG1
5605 mod_gzip_printf( "%s: hlen has value...\n",cn);
5608 if ( this_type == MOD_GZIP_IMAP_ISHANDLER )
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 );
5616 /* mod_gzip_ismatch()... */
5618 /* The 2 strings must match exactly so */
5619 /* pass '0' for parm 3... */
5621 /* Wildcard matches are not allowed for */
5622 /* handler strings like 'cgi-script' so */
5623 /* Fourth parm should be 0.. */
5625 if ( mod_gzip_ismatch(
5626 this_name, (char *)r->handler,0,0) )
5628 pass_result = 1; /* We found a match */
5629 action_flag = this_action; /* What to do */
5630 break; /* Stop now */
5633 }/* End 'if ( this_type == MOD_GZIP_IMAP_ISHANDLER )' */
5635 }/* End 'if( hlen > 0 )' */
5637 if ( clen > 0 ) /* r->content_type field has a value... */
5639 #ifdef MOD_GZIP_DEBUG1
5640 mod_gzip_printf( "%s: clen has value...\n",cn);
5643 if ( this_type == MOD_GZIP_IMAP_ISMIME )
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 );
5652 /* mod_gzip_ismatch()... */
5654 /* Wildcard matches are ALLOWED for */
5655 /* MIME type strings like 'cgi-script' */
5656 /* so fourth parm should be 1... */
5658 if ( mod_gzip_ismatch(
5659 this_name, (char *)r->content_type, 0, 1 ) )
5661 pass_result = 1; /* We found a match */
5662 action_flag = this_action; /* What to do */
5663 break; /* Stop now */
5666 }/* End 'if ( this_type == MOD_GZIP_IMAP_ISMIME )' */
5668 }/* End 'if( clen > 0 )' */
5670 if ( flen > 0 ) /* r->filename field has a value... */
5672 #ifdef MOD_GZIP_DEBUG1
5673 mod_gzip_printf( "%s: flen has value...\n",cn);
5676 if ( this_type == MOD_GZIP_IMAP_ISEXT )
5678 #ifdef MOD_GZIP_DEBUG1
5679 mod_gzip_printf( "%s: this_type = ISEXT\n",cn);
5682 if ( file_extension_len > 0 ) /* There is a file extension */
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 );
5690 /* mod_gzip_ismatch()... */
5692 /* The 2 strings must match exactly so */
5693 /* pass '0' for parm 3... */
5695 /* Wildcard matches are not allowed for */
5696 /* file extensions like '.html' so */
5697 /* Fourth parm should be 0.. */
5699 if ( mod_gzip_ismatch(
5700 this_name, file_extension, 0, 0 ) )
5702 pass_result = 1; /* We found a match */
5703 action_flag = this_action; /* What to do */
5704 break; /* Stop now */
5707 }/* End 'if( file_extension_len > 0 )' */
5709 }/* End 'if( this_type == MOD_GZIP)IMAP_ISEXT )' */
5711 }/* End 'if( flen > 0 )' */
5713 }/* End 'if ( mgc->imap[x].include == filter )' */
5715 else /* The record did not match the current 'filter' value... */
5717 #ifdef MOD_GZIP_DEBUG1
5718 mod_gzip_printf( "%s: This record does NOT match filter_value %d\n",
5720 mod_gzip_printf( "%s: The record has been SKIPPED...\n",cn);
5724 }/* End 'x' loop that looks at 'filtered' records... */
5726 #ifdef MOD_GZIP_DEBUG1
5727 mod_gzip_printf( "%s: --------------------------------------------\n",cn);
5728 mod_gzip_printf( "%s: pass_result = %d\n",cn,pass_result);
5731 if ( pass_result ) /* We are done... */
5733 if ( pass == 0 ) item_is_excluded = 1;
5734 else item_is_included = 1;
5736 break; /* Break out of 'pass' loop now... */
5739 }/* End 'pass' loop */
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);
5747 if ( item_is_excluded )
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);
5754 if ( r->server->loglevel == APLOG_DEBUG )
5756 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5757 "mod_gzip: This item is EXCLUDED as per httpd.conf");
5760 return( MOD_GZIP_IMAP_DECLINED1 );
5763 else if ( item_is_included )
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);
5770 if ( r->server->loglevel == APLOG_DEBUG )
5772 ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server,
5773 "mod_gzip: This item is INCLUDED as per httpd.conf");
5776 return( action_flag ); /* STATIC1 or DYNAMIC1 */
5780 * Default action is to DECLINE processing...
5783 #ifdef MOD_GZIP_DEBUG1
5784 mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn);
5787 if ( r->server->loglevel == APLOG_DEBUG )
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.");
5795 return( MOD_GZIP_IMAP_DECLINED1 );
5797 }/* End of mod_gzip_get_action_flag() */
5799 /*--------------------------------------------------------------------------*/
5800 /* ALL SOURCE CODE BELOW THIS POINT IS COMPRESSION SPECIFIC... */
5801 /*--------------------------------------------------------------------------*/
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(
5810 int *final_return_code
5812 long mod_gzip_ap_send_fb_length(
5816 int *final_return_code
5818 #define DEFAULT_LOGBYTES 10385760
5819 #define DEFAULT_BUFBYTES 1024
5820 static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo);
5826 struct mod_gzip_cgi_child_stuff {
5835 static int is_scriptaliased( request_rec *r )
5837 const char *t = ap_table_get(r->notes, "alias-forced-type");
5838 return t && (!strcasecmp(t, "cgi-script"));
5840 static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret,
5841 int show_errno, char *error)
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),
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);
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)
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];
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),
5875 while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0)
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,
5883 while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0)
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) {
5895 fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
5897 if ((r->method_number == M_POST || r->method_number == M_PUT)
5899 fprintf(f, "\n%s\n", dbuf);
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) {
5907 fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
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);
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);
5925 ap_bclose( script_in );
5926 ap_bclose( script_err );
5927 ap_pfclose(r->pool, f);
5930 int mod_gzip_cgi_handler( request_rec *r )
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[]="";
5946 cgi_server_conf *conf =
5947 (cgi_server_conf *) ap_get_module_config(sconf, &cgi_module);
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;
5956 if ( r->method_number == M_OPTIONS )
5958 r->allowed |= (1 << M_GET);
5959 r->allowed |= (1 << M_POST);
5962 if ((argv0 = strrchr(r->filename, '/')) != NULL)
5968 argv0 = r->filename;
5970 nph = !(strncmp(argv0, "nph-", 4));
5971 if ( !(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r) )
5973 return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
5974 "Options ExecCGI is off in this directory");
5976 if ( nph && is_included )
5978 return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
5979 "attempt to include NPH CGI script");
5981 #if defined(OS2) || defined(WIN32)
5982 if ( r->finfo.st_mode == 0 )
5984 struct stat statbuf;
5986 newfile = ap_pstrcat(r->pool, r->filename, ".EXE", NULL);
5987 if ((stat(newfile, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
5989 return log_scripterror(r, conf, NOT_FOUND, 0,
5990 "script not found or unable to stat");
5994 r->filename = newfile;
5998 if ( r->finfo.st_mode == 0 )
6000 return log_scripterror(r, conf, NOT_FOUND, APLOG_NOERRNO,
6001 "script not found or unable to stat");
6004 if ( S_ISDIR( r->finfo.st_mode ) )
6006 return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
6007 "attempt to invoke directory as script");
6009 if ( !ap_suexec_enabled )
6011 if ( !ap_can_exec( &r->finfo ) )
6013 return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO,
6014 "file permissions deny server execution");
6017 if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
6021 ap_add_common_vars(r);
6025 cld.debug = conf->logname ? 1 : 0;
6027 cld.t.filename = r->filename;
6028 cld.t.subprocess_env = r->subprocess_env;
6029 cld.t.prog_type = FORK_FILE;
6031 #ifdef CHARSET_EBCDIC
6032 ap_bsetflag( r->connection->client, B_EBCDIC2ASCII, 1 );
6034 if ( !ap_bspawn_child(
6035 r->main ? r->main->pool : r->pool,
6045 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
6046 "couldn't spawn child process: %s", r->filename);
6047 return HTTP_INTERNAL_SERVER_ERROR;
6052 if ( ap_should_client_block(r) )
6054 int dbsize, len_read;
6055 if ( conf->logname )
6057 dbuf = ap_pcalloc( r->pool, conf->bufbytes + 1 );
6060 ap_hard_timeout("copy script args", r);
6064 ap_get_client_block( r, argsbuffer, HUGE_STRING_LEN );
6071 if ((dbpos + len_read) > conf->bufbytes)
6073 dbsize = conf->bufbytes - dbpos;
6079 memcpy(dbuf + dbpos, argsbuffer, dbsize);
6082 ap_reset_timeout(r);
6083 if ( ap_bwrite(script_out, argsbuffer, len_read) < len_read )
6086 ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0)
6095 ap_bflush( script_out );
6101 ap_bclose( script_out );
6102 if ( script_in && !nph )
6104 char sbuf[MAX_STRING_LEN];
6106 if ((ret = ap_scan_script_header_err_buff(r, script_in, sbuf)))
6108 return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err);
6110 #ifdef CHARSET_EBCDIC
6113 location = ap_table_get( r->headers_out, "Location" );
6114 if ( location && location[0] == '/' && r->status == 200 )
6116 ap_hard_timeout("read from script", r);
6117 while ( ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0 )
6121 while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0)
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 );
6132 else if ( location && r->status == 200 )
6137 if ( r->header_only )
6139 ap_send_http_header(r);
6144 #else /* !USE_GATHER */
6145 ap_send_http_header(r);
6146 #endif /* USE_GATHER */
6147 if (!r->header_only)
6149 mod_gzip_ap_send_fb( script_in, r, &final_result );
6151 ap_bclose( script_in );
6152 ap_soft_timeout("soaking script stderr", r);
6155 bytesread = ap_bgets( argsbuffer, HUGE_STRING_LEN, script_err );
6156 if ( bytesread < 1 )
6162 ap_bclose( script_err );
6167 if ( script_in && nph )
6169 #ifdef RUSSIAN_APACHE
6170 if (ra_charset_active(r))
6175 mod_gzip_ap_send_fb( script_in, r, &final_result );
6183 return final_result;
6185 static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo)
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;
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. */
6202 FILE *dbg = fopen("con", "w");
6205 FILE *dbg = fopen("c:\\script.dbg", "a" );
6207 FILE *dbg = fopen("/dev/tty", "w");
6213 RAISE_SIGSTOP(CGI_CHILD);
6215 fprintf(dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n",
6216 r->filename, cld->nph ? "NPH " : "", argv0);
6219 env = ap_create_environment(r->pool, r->subprocess_env);
6221 fprintf(dbg, "Environment: \n");
6222 for (i = 0; env[i]; ++i)
6223 fprintf(dbg, "'%s'\n", env[i]);
6227 fprintf(dbg, "Call ap_chdir_file(r->filename=[%s]\n",r->filename);
6229 ap_chdir_file(r->filename);
6231 fprintf(dbg, "Back ap_chdir_file(r->filename=[%s]\n",r->filename);
6235 ap_error_log2stderr(r->server);
6239 fprintf(dbg, "TPF defined... return( 0 ) now...\n");
6240 if ( dbg ) { fclose(dbg); dbg=0; }
6246 fprintf(dbg, "Call ap_cleanup_for_exec()...\n");
6248 ap_cleanup_for_exec();
6250 fprintf(dbg, "Back ap_cleanup_for_exec()...\n");
6251 fprintf(dbg, "Call ap_call_exec()...\n");
6253 child_pid = ap_call_exec(r, pinfo, argv0, env, 0);
6255 fprintf(dbg, "Back ap_call_exec()...\n");
6257 #if defined(WIN32) || defined(OS2)
6260 fprintf(dbg, "WIN32 or OS2 defined... return( child_pid ) now...\n");
6261 if ( dbg ) { fclose(dbg); dbg=0; }
6266 ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename);
6270 if ( dbg ) { fclose(dbg); dbg=0; }
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); \
6281 long mod_gzip_ap_send_fb( BUFF *fb, request_rec *r, int *final_return_code )
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;
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))
6296 #define mod_gzip_ap_select(_a, _b, _c, _d, _e) \
6297 select(_a, _b, _c, _d, _e)
6299 long mod_gzip_ap_send_fb_length(
6303 int *final_return_code
6306 char cn[]="mod_gzip_ab_send_fb_length()";
6307 char buf[IOBUFSIZE];
6308 long total_bytes_sent = 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 ];
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 );
6341 ap_bsetflag( fb, B_RD, 0 );
6343 ap_bnonblock( fb, B_RD );
6345 fd = ap_bfileno( fb, B_RD );
6346 #ifdef CHECK_FD_SETSIZE
6347 if ( fd >= FD_SETSIZE )
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);
6360 ap_soft_timeout("send body", r);
6364 if ( (long) conf->maximum_inmem_size < (long) gather_bufmaxlen )
6366 gather_maxlen = (int) conf->maximum_inmem_size;
6370 gather_maxlen = (int) gather_bufmaxlen;
6372 gather_bufstart = malloc( (int)(gather_maxlen + 2) );
6373 if ( gather_bufstart )
6376 gather_buf = gather_bufstart;
6377 gather_source = gather_bufstart;
6384 while( !r->connection->aborted )
6386 #ifdef NDELAY_PIPE_RETURNS_ZERO
6387 int afterselect = 0;
6389 if ( (length > 0) && (total_bytes_sent + IOBUFSIZE) > length )
6391 len = length - total_bytes_sent;
6398 n = ap_bread( fb, buf, len );
6399 #ifdef NDELAY_PIPE_RETURNS_ZERO
6400 if ((n > 0) || (n == 0 && afterselect))
6410 if ( r->connection->aborted )
6414 if ( n < 0 && errno != EAGAIN )
6418 if ( ap_bflush( r->connection->client ) < 0 )
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;
6427 FD_SET( (unsigned) fd, &fds );
6432 mod_gzip_ap_select(fd + 1, &fds, NULL, NULL, NULL);
6434 #ifdef NDELAY_PIPE_RETURNS_ZERO
6437 } while ( !r->connection->aborted );
6438 if ( n < 1 || r->connection->aborted )
6445 if ( ( gather_length + n ) >= gather_maxlen )
6449 mod_gzip_create_unique_filename(
6450 (mod_gzip_conf *) conf,
6451 (char *) gather_filename,
6452 sizeof( gather_filename )
6454 gather_fh1 = fopen( gather_filename, "wb" );
6457 gather_source = gather_filename;
6465 if ( ( gather_fh1 ) && ( gather_length > 0 ) )
6467 gather_byteswritten =
6468 fwrite( gather_bufstart, 1, gather_length, gather_fh1 );
6469 if ( gather_byteswritten != gather_length )
6474 if ( ( gather_fh1 ) && ( n > 0 ) )
6476 gather_byteswritten =
6477 fwrite( buf, 1, n, gather_fh1 );
6478 if ( gather_byteswritten != n )
6483 gather_buf = gather_bufstart;
6490 memcpy( gather_buf, buf, n );
6500 while ( n && !r->connection->aborted )
6502 #ifdef RUSSIAN_APACHE
6503 unsigned char *newbuf,*p;
6505 if ( ra_charset_active(r) )
6507 if ( ra_flag( r, RA_WIDE_CHARS_SC ) )
6509 ra_data_server2client(r,&buf[o],n,&newbuf,&newlen);
6513 w = ap_bwrite( r->connection->client, p, newlen );
6514 if(w<=0) goto RECODE_DONE;
6522 unsigned char *t = r->ra_codep->cp_otabl_p;
6523 unsigned char *b = (unsigned char *)&buf[o];
6524 unsigned char *end = b+n;
6530 w = ap_bwrite( r->connection->client, &buf[o], n );
6535 w = ap_bwrite( r->connection->client, &buf[o], n );
6539 w = ap_bwrite( r->connection->client, &buf[o], n );
6543 ap_reset_timeout(r);
6544 total_bytes_sent += w;
6550 if ( !r->connection->aborted )
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;
6563 MOD_GZIP_SET_BYTES_SENT(r);
6567 if ( gather_length > 0 )
6569 gather_byteswritten =
6570 fwrite( gather_bufstart, 1, gather_length, gather_fh1 );
6571 if ( gather_byteswritten != gather_length )
6576 fclose( gather_fh1 );
6579 if ( gather_totlen > 0 )
6582 mod_gzip_encode_and_transmit(
6584 (char *) gather_source,
6585 (int ) gather_origin,
6586 (long ) gather_totlen,
6589 *final_return_code = rc;
6591 if ( gather_bufstart )
6593 free( gather_bufstart );
6594 gather_bufstart = 0;
6598 return total_bytes_sent;
6601 /*--------------------------------------------------------------------------*/
6602 /* COMPRESSION SUPPORT ROUTINES */
6603 /*--------------------------------------------------------------------------*/
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;
6615 typedef void *voidp;
6617 typedef char *voidp;
6620 #if defined(__MSDOS__) && !defined(MSDOS)
6624 #if defined(__OS2__) && !defined(OS2)
6628 #if defined(OS2) && defined(MSDOS)
6639 # ifdef __BORLANDC__
6645 # define HAVE_SYS_UTIME_H
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"
6657 # define STDC_HEADERS
6658 # define NO_SIZE_CHECK
6659 # define casemap(c) tolow(c)
6662 # define OS_CODE 0x00
6663 # define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
6664 # if !defined(NO_ASM) && !defined(ASMV)
6672 # define PATH_SEP2 '\\'
6673 # define PATH_SEP3 ':'
6674 # define MAX_PATH_LEN 260
6676 # define NO_MULTIPLE_DOTS
6677 # define MAX_EXT_CHARS 3
6678 # define Z_SUFFIX "z"
6679 # define casemap(c) tolow(c)
6683 # define STDC_HEADERS
6686 # define OS_CODE 0x06
6687 # define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
6689 # define HAVE_SYS_UTIME_H
6696 # define HAVE_SYS_UTIME_H
6699 # define EXPAND(argc,argv) \
6700 {_response(&argc, &argv); _wildcard(&argc, &argv);}
6702 # ifdef __BORLANDC__
6709 # define EXPAND(argc,argv) \
6710 {response_expand(&argc, &argv);}
6715 # define HAVE_SYS_UTIME_H
6717 # define PATH_SEP2 '\\'
6718 # define PATH_SEP3 ':'
6719 # undef MAX_PATH_LEN
6720 # define MAX_PATH_LEN 260
6723 # define STDC_HEADERS
6724 # define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
6727 # define NO_MULTIPLE_DOTS
6728 # define MAX_EXT_CHARS 3
6729 # define Z_SUFFIX "z"
6730 # define casemap(c) tolow(c)
6734 # define OS_CODE 0x00
6742 void * fcalloc (unsigned items, unsigned size);
6743 void fcfree (void *ptr);
6745 # define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
6746 # define fcfree(ptr) hfree(ptr)
6750 # define fcalloc(items,size) calloc((items),(size))
6752 # define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
6754 # define fcfree(ptr) free(ptr)
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)
6766 # define OS_CODE 0x02
6767 # define OPTIONS_VAR "GZIP_OPT"
6768 # define STDC_HEADERS
6770 # define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
6772 # define unlink delete
6775 # include <unixio.h>
6780 # define PATH_SEP2 ':'
6781 # define STDC_HEADERS
6783 # define OS_CODE 0x01
6787 # define HAVE_UNISTD_H
6789 # define NO_STDIN_FSTAT
6795 # define direct dirent
6796 extern void _expand_args(int *argc, char ***argv);
6797 # define EXPAND(argc,argv) _expand_args(&argc,&argv);
6802 #if defined(ATARI) || defined(atarist)
6803 # ifndef STDC_HEADERS
6804 # define STDC_HEADERS
6805 # define HAVE_UNISTD_H
6810 # define OS_CODE 0x05
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"
6819 # define casemap(c) tolow(c)
6825 # define PATH_SEP ':'
6828 # define NO_STDIN_FSTAT
6831 # define chmod(file, mode) (0)
6832 # define OPEN(name, flags, mode) open(name, flags)
6834 # define OS_CODE 0x07
6836 # define isatty(fd) ((fd) <= 2)
6841 # define PATH_SEP '>'
6842 # define STDC_HEADERS
6843 # define NO_MEMORY_H
6847 # define NO_STDIN_FSTAT
6848 # define NO_SIZE_CHECK
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())
6855 # define OS_CODE 0x0F
6861 #if defined(pyr) && !defined(NOMEMCPY)
6867 # define OS_CODE 0x0a
6876 # define OS_CODE 0x03
6880 # define PATH_SEP '/'
6884 # define casemap(c) (c)
6888 # define OPTIONS_VAR "GZIP"
6892 # define Z_SUFFIX ".gz"
6895 #ifdef MAX_EXT_CHARS
6896 # define MAX_SUFFIX MAX_EXT_CHARS
6898 # define MAX_SUFFIX 30
6906 # define EXPAND(argc,argv)
6910 # define RECORD_IO 0
6913 #ifndef SET_BINARY_MODE
6914 # define SET_BINARY_MODE(fd)
6918 # define OPEN(name, flags, mode) open(name, flags, mode)
6922 # define get_char() get_byte()
6926 # define put_char(c) put_byte(c)
6937 #define COMPRESSED 1
6941 #define MAX_METHODS 9
6944 #include <sys/file.h>
6946 #define O_CREAT FCREAT
6949 #define O_EXCL FEXCL
6954 #define S_IRUSR 0400
6957 #define S_IWUSR 0200
6959 #define RW_USER (S_IRUSR | S_IWUSR)
6961 #ifndef MAX_PATH_LEN
6962 #define MAX_PATH_LEN 256
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
6986 #define WSIZE 0x8000
6991 #define INBUFSIZ 0x2000
6993 #define INBUFSIZ 0x8000
6996 #define INBUF_EXTRA 64
7000 #define OUTBUFSIZ 8192
7002 #define OUTBUFSIZ 0x4000
7005 #define OUTBUF_EXTRA 2048
7007 #ifndef DIST_BUFSIZE
7009 #define DIST_BUFSIZE 0x2000
7011 #define DIST_BUFSIZE 0x8000
7019 #define LZW_MAGIC "\037\235"
7022 #define MAX_MATCH 258
7024 #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
7025 #define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
7028 #define HASH_BITS 13
7031 #define HASH_BITS 14
7034 #define HASH_BITS 15
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)
7043 #define TOO_FAR 4096
7050 #define REPZ_3_10 17
7051 #define REPZ_11_138 18
7053 #define MAX_BL_BITS 7
7057 #define LENGTH_CODES 29
7058 #define LITERALS 256
7059 #define END_BLOCK 256
7060 #define L_CODES (LITERALS+1+LENGTH_CODES)
7064 #define LIT_BUFSIZE 0x2000
7067 #define LIT_BUFSIZE 0x4000
7069 #define LIT_BUFSIZE 0x8000
7074 #define HEAP_SIZE (2*L_CODES+1)
7075 #define STORED_BLOCK 0
7076 #define STATIC_TREES 1
7078 #define NO_FILE (-1)
7083 #define LOCSIG 0x04034b50L
7096 #define RAND_HEAD_LEN 12
7097 #define BUFSIZE (8 * 2*sizeof(char))
7099 #define translate_eol 0
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))
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"); \
7110 # define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
7112 # define ALLOC(type, array, size)
7113 # define FREE(array)
7116 #define GZ1_MAX(a,b) (a >= b ? a : b)
7118 #define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c))
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]))
7124 #define send_code(c, tree) send_bits(gz1,tree[c].fc.code, tree[c].dl.len)
7126 #define put_byte(c) {gz1->outbuf[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==OUTBUFSIZ)\
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); \
7134 put_byte((uch)((w) & 0xff)); \
7135 put_byte((uch)((ush)(w) >> 8)); \
7139 #define put_long(n) { \
7140 put_short((n) & 0xffff); \
7141 put_short(((ulg)(n)) >> 16); \
7146 # define NEXTBYTE() \
7147 (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
7149 # define NEXTBYTE() (uch)get_byte()
7152 #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
7153 #define DUMPBITS(n) {b>>=(n);k-=(n);}
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))
7158 #define put_ubyte(c) {gz1->window[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==WSIZE)\
7161 #define WARN(msg) { if (gz1->exit_code == OK) gz1->exit_code = WARNING; }
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))
7166 #define d_code(dist) \
7167 ((dist) < 256 ? gz1->dist_code[dist] : gz1->dist_code[256+((dist)>>7)])
7169 typedef struct config {
7176 config configuration_table[10] = {
7186 {32, 128, 258, 1024},
7187 {32, 258, 258, 4096}};
7189 typedef struct ct_data {
7202 typedef struct tree_desc {
7204 ct_data *static_tree;
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};
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};
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};
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};
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,
7288 typedef struct _GZ1 {
7289 long compression_format;
7294 int deflate1_initialized;
7295 unsigned deflate1_hash_head;
7296 unsigned deflate1_prev_match;
7298 int deflate1_match_available;
7299 unsigned deflate1_match_length;
7301 char ifname[MAX_PATH_LEN];
7302 char ofname[MAX_PATH_LEN];
7309 long input_bytesleft;
7334 uns max_chain_length;
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)];
7397 uch inbuf [INBUFSIZ +INBUF_EXTRA];
7398 uch outbuf[OUTBUFSIZ+OUTBUF_EXTRA];
7399 ush d_buf [DIST_BUFSIZE];
7400 uch window[2L*WSIZE];
7404 #define nice_match MAX_MATCH
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];
7425 ush prev2[1L<<BITS];
7427 #define prev gz1->prev2
7428 #define head (gz1->prev2+WSIZE)
7435 #define prev gz1->prev2
7436 #define head gz1->tab_prefix1
7442 int gz1_size = sizeof( GZ1 );
7444 /* Declare some local function protypes... */
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. */
7453 PGZ1 gz1_init ( void );
7454 int gz1_cleanup ( PGZ1 gz1 );
7455 ulg gz1_deflate ( PGZ1 gz1 );
7456 ulg gz1_deflate_fast( PGZ1 gz1 );
7458 /* The rest of the routines should not need the 'gz1_' prefix. */
7459 /* No conflicts reported at this time. */
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 );
7483 void error( char *msg );
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.
7490 #define ZLIB_HEADER "\170
\9c"
7492 ulg adler32(ulg adler, uch *buf, unsigned len);
7532 void send_all_trees(
7556 void compress_block(
7610 unsigned bi_reverse(
7625 gz1 = (PGZ1) malloc( gz1_size );
7632 memset( gz1, 0, gz1_size );
7634 ALLOC(uch, gz1->inbuf, INBUFSIZ +INBUF_EXTRA);
7642 ALLOC(uch, gz1->outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
7651 ALLOC(ush, gz1->d_buf, DIST_BUFSIZE);
7655 FREE( gz1->outbuf );
7661 ALLOC(uch, gz1->window, 2L*WSIZE);
7666 FREE( gz1->outbuf );
7676 ALLOC(ush, gz1->prev2, 1L<<(BITS-1) );
7680 FREE( gz1->window );
7682 FREE( gz1->outbuf );
7688 ALLOC(ush, gz1->tab_prefix1, 1L<<(BITS-1) );
7690 if ( !gz1->tab_prefix1 )
7693 FREE( gz1->window );
7695 FREE( gz1->outbuf );
7703 gz1->method = DEFLATED;
7707 gz1->exit_code = OK;
7711 gz1->window_size = (ulg)2*WSIZE;
7712 gz1->crc = (ulg)0xffffffffL;
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;
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;
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;
7742 int gz1_cleanup( PGZ1 gz1 )
7749 FREE( gz1->tab_prefix1 );
7753 FREE( gz1->window );
7755 FREE( gz1->outbuf );
7764 int (*read_buf)(PGZ1 gz1, char *buf, unsigned size);
7766 void error( char *msg )
7771 int (*work)( PGZ1 gz1, int infile, int outfile ) = 0;
7777 int get_header( PGZ1 gz1, int in )
7785 if ( gz1->force && gz1->to_stdout )
7787 magic[0] = (char)try_byte();
7788 magic[1] = (char)try_byte();
7792 magic[0] = (char)get_byte();
7793 magic[1] = (char)get_byte();
7797 gz1->header_bytes = 0;
7798 gz1->last_member = RECORD_IO;
7801 if ( memcmp(magic, GZIP_MAGIC, 2 ) == 0 ||
7802 memcmp(magic, OLD_GZIP_MAGIC, 2 ) == 0 )
7804 gz1->method = (int)get_byte();
7806 if ( gz1->method != DEFLATED )
7808 gz1->exit_code = LZ1_ERROR;
7815 if ((flags & ENCRYPTED) != 0)
7817 gz1->exit_code = LZ1_ERROR;
7821 if ((flags & CONTINUATION) != 0)
7823 gz1->exit_code = LZ1_ERROR;
7824 if ( gz1->force <= 1) return -1;
7827 if ((flags & RESERVED) != 0)
7829 gz1->exit_code = LZ1_ERROR;
7830 if ( gz1->force <= 1)
7834 stamp = (ulg)get_byte();
7835 stamp |= ((ulg)get_byte()) << 8;
7836 stamp |= ((ulg)get_byte()) << 16;
7837 stamp |= ((ulg)get_byte()) << 24;
7839 if ( stamp != 0 && !gz1->no_time )
7841 gz1->time_stamp = stamp;
7847 if ((flags & CONTINUATION) != 0)
7849 part = (unsigned) get_byte();
7850 part |= ((unsigned) get_byte())<<8;
7853 if ((flags & EXTRA_FIELD) != 0)
7855 len = (unsigned) get_byte();
7856 len |= ((unsigned) get_byte())<<8;
7858 while (len--) (void)get_byte();
7861 if ((flags & COMMENT) != 0)
7863 while (get_char() != 0) ;
7866 if ( gz1->part_nb == 1 )
7868 gz1->header_bytes = gz1->inptr + 2*sizeof(long);
7875 int fill_inbuf( PGZ1 gz1, int eof_ok )
7884 if ( gz1->input_ismem )
7886 if ( gz1->input_bytesleft > 0 )
7888 bytes_to_copy = INBUFSIZ - gz1->insize;
7890 if ( bytes_to_copy > gz1->input_bytesleft )
7892 bytes_to_copy = gz1->input_bytesleft;
7896 (char*)gz1->inbuf+gz1->insize,
7901 gz1->input_ptr += bytes_to_copy;
7902 gz1->input_bytesleft -= bytes_to_copy;
7904 len = bytes_to_copy;
7916 (char*)gz1->inbuf+gz1->insize,
7917 INBUFSIZ-gz1->insize
7921 if (len == 0 || len == EOF) break;
7925 } while( gz1->insize < INBUFSIZ );
7927 if ( gz1->insize == 0 )
7929 if( eof_ok ) return EOF;
7933 gz1->bytes_in += (ulg) gz1->insize;
7936 return gz1->inbuf[0];
7958 c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
7966 return( c ^ 0xffffffffL );
7969 void read_error( PGZ1 gz1 )
7974 void mod_gzip_strlwr( char *s )
7978 if ( s == 0 ) return;
7982 if ( *p1 > 96 ) *p1 = *p1 - 32;
7991 char *gz1_basename( PGZ1 gz1, char *fname )
7995 if ((p = strrchr(fname, PATH_SEP)) != NULL) fname = p+1;
7998 if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
8002 if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
8006 if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
8009 if (casemap('A') == 'a') mod_gzip_strlwr(fname);
8014 void write_buf( PGZ1 gz1, int fd, voidp buf, unsigned cnt )
8018 if ( gz1->output_ismem )
8020 if ( ( gz1->bytes_out + cnt ) < gz1->output_maxlen )
8022 memcpy( gz1->output_ptr, buf, cnt );
8023 gz1->output_ptr += cnt;
8032 while ((n = write(fd, buf, cnt)) != cnt)
8034 if (n == (unsigned)(-1))
8039 buf = (voidp)((char*)buf+n);
8044 void write_error( PGZ1 gz1 )
8052 static ush ptr_offset = 0;
8059 void * buf = farmalloc((ulg)items*size + 16L);
8061 if (buf == NULL) return NULL;
8063 if (ptr_offset == 0)
8065 ptr_offset = (ush)((uch*)buf-0);
8067 else if (ptr_offset != (ush)((uch*)buf-0))
8069 error("inconsistent ptr_offset");
8072 *((ush*)&buf+1) += (ptr_offset + 15) >> 4;
8078 void fcfree( void *ptr )
8080 *((ush*)&ptr+1) -= (ptr_offset + 15) >> 4;
8081 *(ush*)&ptr = ptr_offset;
8097 ush deflate_flags = 0;
8103 gz1->method = DEFLATED;
8105 put_byte(GZIP_MAGIC[0]);
8106 put_byte(GZIP_MAGIC[1]);
8109 if ( gz1->save_orig_name )
8115 put_long(gz1->time_stamp);
8119 updcrc( gz1, NULL, 0 );
8121 bi_init( gz1, out );
8122 ct_init( gz1, &attr, &gz1->method );
8123 lm_init( gz1, gz1->level, &deflate_flags );
8125 put_byte((uch)deflate_flags);
8129 if ( gz1->save_orig_name )
8131 char *p = gz1_basename( gz1, gz1->ifname );
8139 gz1->header_bytes = (long)gz1->outcnt;
8141 (void) gz1_deflate( gz1 );
8143 put_long( gz1->crc );
8144 put_long( gz1->bytes_in );
8146 gz1->header_bytes += 2*sizeof(long);
8148 flush_outbuf( gz1 );
8153 ulg gz1_deflate( PGZ1 gz1 )
8156 unsigned prev_match;
8158 int match_available = 0;
8159 register unsigned match_length = MIN_MATCH-1;
8164 if (gz1->compr_level <= 3)
8166 return gz1_deflate_fast(gz1);
8169 while (gz1->lookahead != 0)
8172 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK;
8174 prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ];
8176 head[ gz1->ins_h ] = gz1->strstart;
8178 gz1->prev_length = match_length, prev_match = gz1->match_start;
8179 match_length = MIN_MATCH-1;
8181 if (hash_head != NIL && gz1->prev_length < gz1->max_lazy_match &&
8182 gz1->strstart - hash_head <= MAX_DIST) {
8184 match_length = longest_match( gz1, hash_head );
8186 if (match_length > gz1->lookahead) match_length = gz1->lookahead;
8188 if (match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR){
8194 if (gz1->prev_length >= MIN_MATCH && match_length <= gz1->prev_length) {
8196 flush = ct_tally(gz1,gz1->strstart-1-prev_match, gz1->prev_length - MIN_MATCH);
8198 gz1->lookahead -= ( gz1->prev_length - 1 );
8199 gz1->prev_length -= 2;
8205 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
8207 prev[ gz1->strstart & WMASK ] = hash_head = head[gz1->ins_h];
8209 head[ gz1->ins_h ] = gz1->strstart;
8211 } while (--gz1->prev_length != 0);
8212 match_available = 0;
8213 match_length = MIN_MATCH-1;
8215 if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
8217 } else if (match_available) {
8219 if (ct_tally( gz1, 0, gz1->window[gz1->strstart-1] )) {
8220 FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
8226 match_available = 1;
8231 while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1);
8233 if (match_available) ct_tally( gz1, 0, gz1->window[gz1->strstart-1] );
8235 return FLUSH_BLOCK(1);
8240 void flush_outbuf( PGZ1 gz1 )
8242 if ( gz1->outcnt == 0 )
8247 write_buf( gz1, gz1->ofd, (char *)gz1->outbuf, gz1->outcnt );
8249 gz1->bytes_out += (ulg)gz1->outcnt;
8259 register unsigned j;
8261 if ( pack_level < 1 || pack_level > 9 )
8263 error("bad pack level");
8266 gz1->compr_level = pack_level;
8268 #if defined(MAXSEG_64K) && HASH_BITS == 15
8269 for (j = 0; j < HASH_SIZE; j++) head[j] = NIL;
8271 memset( (char*)head, 0, (HASH_SIZE*sizeof(*head)) );
8274 gz1->max_lazy_match = configuration_table[pack_level].max_lazy;
8275 gz1->good_match = configuration_table[pack_level].good_length;
8277 gz1->nice_match = configuration_table[pack_level].nice_length;
8279 gz1->max_chain_length = configuration_table[pack_level].max_chain;
8281 if ( pack_level == 1 )
8285 else if ( pack_level == 9 )
8291 gz1->block_start = 0L;
8296 gz1->lookahead = read_buf(gz1,(char*)gz1->window,
8297 sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE);
8299 if (gz1->lookahead == 0 || gz1->lookahead == (unsigned)EOF)
8301 gz1->eofile = 1, gz1->lookahead = 0;
8307 while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile)
8314 for ( j=0; j<MIN_MATCH-1; j++ )
8317 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[j])) & HASH_MASK;
8321 void fill_window( PGZ1 gz1 )
8323 register unsigned n, m;
8326 (unsigned)( gz1->window_size - (ulg)gz1->lookahead - (ulg)gz1->strstart );
8328 if ( more == (unsigned)EOF)
8332 else if ( gz1->strstart >= WSIZE+MAX_DIST )
8334 memcpy((char*)gz1->window, (char*)gz1->window+WSIZE, (unsigned)WSIZE);
8336 gz1->match_start -= WSIZE;
8337 gz1->strstart -= WSIZE;
8339 gz1->block_start -= (long) WSIZE;
8341 for ( n = 0; n < HASH_SIZE; n++ )
8344 head[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL);
8347 for ( n = 0; n < WSIZE; n++ )
8351 prev[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL);
8359 n = read_buf(gz1,(char*)gz1->window+gz1->strstart+gz1->lookahead, more);
8361 if ( n == 0 || n == (unsigned)EOF )
8367 gz1->lookahead += n;
8372 ulg gz1_deflate_fast( PGZ1 gz1 )
8376 unsigned match_length = 0;
8378 gz1->prev_length = MIN_MATCH-1;
8380 while (gz1->lookahead != 0)
8383 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
8385 prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ];
8387 head[ gz1->ins_h ] = gz1->strstart;
8389 if (hash_head != NIL && gz1->strstart - hash_head <= MAX_DIST) {
8391 match_length = longest_match( gz1, hash_head );
8393 if (match_length > gz1->lookahead) match_length = gz1->lookahead;
8395 if (match_length >= MIN_MATCH) {
8397 flush = ct_tally(gz1,gz1->strstart-gz1->match_start, match_length - MIN_MATCH);
8399 gz1->lookahead -= match_length;
8401 if (match_length <= gz1->max_lazy_match )
8409 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
8411 prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ];
8413 head[ gz1->ins_h ] = gz1->strstart;
8415 } while (--match_length != 0);
8418 gz1->strstart += match_length;
8420 gz1->ins_h = gz1->window[gz1->strstart];
8423 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[gz1->strstart+1])) & HASH_MASK;
8426 Call UPDATE_HASH() MIN_MATCH-3 more times
8431 flush = ct_tally(gz1, 0, gz1->window[gz1->strstart]);
8435 if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
8437 while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1);
8440 return FLUSH_BLOCK(1);
8459 gz1->file_type = attr;
8460 gz1->file_method = methodp;
8461 gz1->compressed_len = gz1->input_len = 0L;
8463 if ( gz1->static_dtree[0].dl.len != 0 )
8470 for ( code = 0; code < LENGTH_CODES-1; code++ )
8472 gz1->base_length[code] = length;
8474 for ( n = 0; n < (1<<extra_lbits[code]); n++ )
8476 gz1->length_code[length++] = (uch)code;
8480 gz1->length_code[length-1] = (uch)code;
8484 for ( code = 0 ; code < 16; code++ )
8486 gz1->base_dist[code] = dist;
8488 for ( n = 0; n < (1<<extra_dbits[code]); n++ )
8490 gz1->dist_code[dist++] = (uch)code;
8496 for ( ; code < D_CODES; code++ )
8498 gz1->base_dist[code] = dist << 7;
8500 for ( n = 0; n < (1<<(extra_dbits[code]-7)); n++ )
8502 gz1->dist_code[256 + dist++] = (uch)code;
8506 for ( bits = 0; bits <= MAX_BITS; bits++ )
8508 gz1->bl_count[bits] = 0;
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]++;
8518 gen_codes(gz1,(ct_data *)gz1->static_ltree, L_CODES+1);
8520 for ( n = 0; n < D_CODES; n++ )
8522 gz1->static_dtree[n].dl.len = 5;
8523 gz1->static_dtree[n].fc.code = bi_reverse( gz1, n, 5 );
8540 gz1->flag_buf[gz1->last_flags] = gz1->flags;
8542 if (*gz1->file_type == (ush)UNKNOWN) set_file_type(gz1);
8544 build_tree( gz1, (tree_desc *)(&gz1->l_desc) );
8545 build_tree( gz1, (tree_desc *)(&gz1->d_desc) );
8547 max_blindex = build_bl_tree( gz1 );
8549 opt_lenb = (gz1->opt_len+3+7)>>3;
8550 static_lenb = (gz1->static_len+3+7)>>3;
8551 gz1->input_len += stored_len;
8553 if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
8557 if ( level == 1 && eof && gz1->compressed_len == 0L )
8559 if (stored_len <= opt_lenb && eof && gz1->compressed_len == 0L && 0 )
8562 if (buf == (char*)0) error ("block vanished");
8564 copy_block( gz1, buf, (unsigned)stored_len, 0 );
8566 gz1->compressed_len = stored_len << 3;
8567 *gz1->file_method = STORED;
8570 } else if (level == 2 && buf != (char*)0) {
8572 } else if (stored_len+4 <= opt_lenb && buf != (char*)0) {
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;
8580 copy_block(gz1, buf, (unsigned)stored_len, 1);
8583 } else if (level == 3) {
8585 } else if (static_lenb == opt_lenb) {
8587 send_bits(gz1,(STATIC_TREES<<1)+eof, 3);
8591 (ct_data *)gz1->static_ltree,
8592 (ct_data *)gz1->static_dtree
8595 gz1->compressed_len += 3 + gz1->static_len;
8599 send_bits(gz1,(DYN_TREES<<1)+eof, 3);
8603 gz1->l_desc.max_code+1,
8604 gz1->d_desc.max_code+1,
8610 (ct_data *)gz1->dyn_ltree,
8611 (ct_data *)gz1->dyn_dtree
8614 gz1->compressed_len += 3 + gz1->opt_len;
8623 gz1->compressed_len += 7;
8626 return gz1->compressed_len >> 3;
8633 unsigned bi_reverse(
8639 register unsigned res = 0;
8643 code >>= 1, res <<= 1;
8645 } while (--len > 0);
8650 void set_file_type( PGZ1 gz1 )
8653 unsigned ascii_freq = 0;
8654 unsigned bin_freq = 0;
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;
8660 *gz1->file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
8663 void init_block( PGZ1 gz1 )
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;
8671 gz1->dyn_ltree[END_BLOCK].fc.freq = 1;
8674 gz1->static_len = 0L;
8677 gz1->last_flags = 0;
8682 void bi_init( PGZ1 gz1, gz1_file_t zipfile )
8684 gz1->zfile = zipfile;
8688 if ( gz1->zfile != NO_FILE )
8690 read_buf = file_read;
8702 gz1->inbuf[gz1->last_lit++] = (uch)lc;
8706 gz1->dyn_ltree[lc].fc.freq++;
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;
8718 gz1->flag_bit <<= 1;
8720 if ( (gz1->last_lit & 7) == 0 )
8722 gz1->flag_buf[gz1->last_flags++] = gz1->flags;
8723 gz1->flags = 0, gz1->flag_bit = 1;
8726 if ( gz1->level > 2 && (gz1->last_lit & 0xfff) == 0)
8728 ulg out_length = (ulg) ( gz1->last_lit * 8L );
8729 ulg in_length = (ulg) ( gz1->strstart - gz1->block_start );
8731 for ( dcode = 0; dcode < D_CODES; dcode++ )
8733 out_length += (ulg) ((gz1->dyn_dtree[dcode].fc.freq)*(5L+extra_dbits[dcode]));
8738 if ( gz1->last_dist < gz1->last_lit/2 && out_length < in_length/2 )
8744 return( gz1->last_lit == LIT_BUFSIZE-1 || gz1->last_dist == DIST_BUFSIZE );
8747 void compress_block(
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);
8769 code = gz1->length_code[lc];
8770 send_code(code+LITERALS+1, ltree);
8771 extra = extra_lbits[code];
8773 lc -= gz1->base_length[code];
8774 send_bits(gz1,lc, extra);
8776 dist = gz1->d_buf[dx++];
8778 code = d_code(dist);
8780 send_code(code, dtree);
8781 extra = extra_dbits[code];
8783 dist -= gz1->base_dist[code];
8784 send_bits(gz1,dist, extra);
8788 } while (lx < gz1->last_lit);
8790 send_code(END_BLOCK, ltree);
8795 int longest_match( PGZ1 gz1, unsigned cur_match )
8797 unsigned chain_length = gz1->max_chain_length;
8798 register uch *scan = gz1->window + gz1->strstart;
8799 register uch *match;
8801 int best_len = gz1->prev_length;
8802 unsigned limit = gz1->strstart > (unsigned)MAX_DIST ? gz1->strstart - (unsigned)MAX_DIST : NIL;
8804 #if HASH_BITS < 8 || MAX_MATCH != 258
8805 error: Code too clever
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);
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];
8819 if (gz1->prev_length >= gz1->good_match) {
8824 match = gz1->window + cur_match;
8826 #if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
8828 if (*(ush*)(match+best_len-1) != scan_end ||
8829 *(ush*)match != scan_start) continue;
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) &&
8839 if (*scan == *match) scan++;
8841 len = (MAX_MATCH - 1) - (int)(strend-scan);
8842 scan = strend - (MAX_MATCH-1);
8844 if (match[best_len] != scan_end ||
8845 match[best_len-1] != scan_end1 ||
8847 *++match != scan[1]) continue;
8852 } while (*++scan == *++match && *++scan == *++match &&
8853 *++scan == *++match && *++scan == *++match &&
8854 *++scan == *++match && *++scan == *++match &&
8855 *++scan == *++match && *++scan == *++match &&
8858 len = MAX_MATCH - (int)(strend - scan);
8859 scan = strend - MAX_MATCH;
8861 if (len > best_len) {
8862 gz1->match_start = cur_match;
8864 if (len >= gz1->nice_match) break;
8866 scan_end = *(ush*)(scan+best_len-1);
8868 scan_end1 = scan[best_len-1];
8869 scan_end = scan[best_len];
8872 } while ((cur_match = prev[cur_match & WMASK]) > limit
8873 && --chain_length != 0);
8885 if ( gz1->bi_valid > (int) BUFSIZE - length )
8887 gz1->bi_buf |= (value << gz1->bi_valid);
8889 put_short(gz1->bi_buf);
8891 gz1->bi_buf = (ush)value >> (BUFSIZE - gz1->bi_valid);
8892 gz1->bi_valid += length - BUFSIZE;
8896 gz1->bi_buf |= value << gz1->bi_valid;
8897 gz1->bi_valid += length;
8906 int elems = desc->elems;
8907 ct_data *tree = desc->dyn_tree;
8908 ct_data *stree = desc->static_tree;
8916 gz1->heap_len = 0, gz1->heap_max = HEAP_SIZE;
8918 for (n = 0; n < elems; n++) {
8919 if (tree[n].fc.freq != 0) {
8920 gz1->heap[++gz1->heap_len] = max_code = n;
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;
8933 desc->max_code = max_code;
8935 for (n = gz1->heap_len/2; n >= 1; n--) pqdownheap(gz1, tree, n);
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);
8950 } while (gz1->heap_len >= 2);
8952 gz1->heap[--gz1->heap_max] = gz1->heap[SMALLEST];
8954 gen_bitlen(gz1,(tree_desc *)desc);
8956 gen_codes(gz1,(ct_data *)tree, max_code);
8959 int build_bl_tree( PGZ1 gz1 )
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 );
8966 build_tree( gz1, (tree_desc *)(&gz1->bl_desc) );
8968 for ( max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex-- )
8970 if (gz1->bl_tree[bl_order[max_blindex]].dl.len != 0) break;
8973 gz1->opt_len += 3*(max_blindex+1) + 5+5+4;
8984 ush next_code[MAX_BITS+1];
8989 for ( bits = 1; bits <= MAX_BITS; bits++ )
8991 next_code[bits] = code = (code + gz1->bl_count[bits-1]) << 1;
8994 for ( n = 0; n <= max_code; n++ )
8996 int len = tree[n].dl.len;
8997 if (len == 0) continue;
8999 tree[n].fc.code = bi_reverse( gz1, next_code[len]++, len );
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;
9023 for (bits = 0; bits <= MAX_BITS; bits++) gz1->bl_count[bits] = 0;
9025 tree[gz1->heap[gz1->heap_max]].dl.len = 0;
9027 for (h = gz1->heap_max+1; h < HEAP_SIZE; 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;
9033 if (n > max_code) continue;
9035 gz1->bl_count[bits]++;
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);
9042 if (overflow == 0) return;
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]--;
9052 } while (overflow > 0);
9054 for (bits = max_length; bits != 0; bits--) {
9055 n = gz1->bl_count[bits];
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;
9083 put_short((ush)len);
9084 put_short((ush)~len);
9090 if (key) zencode(*buf, t);
9097 int file_read( PGZ1 gz1, char *buf, unsigned size )
9100 unsigned bytes_to_copy = 0;
9102 if ( gz1->input_ismem )
9104 if ( gz1->input_bytesleft > 0 )
9106 bytes_to_copy = size;
9108 if ( bytes_to_copy > (unsigned) gz1->input_bytesleft )
9110 bytes_to_copy = (unsigned) gz1->input_bytesleft;
9113 memcpy( buf, gz1->input_ptr, bytes_to_copy );
9115 gz1->input_ptr += bytes_to_copy;
9116 gz1->input_bytesleft -= bytes_to_copy;
9118 len = bytes_to_copy;
9127 len = read( gz1->ifd, buf, size );
9130 if ( len == (unsigned)(-1) || len == 0 )
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. */
9138 if (gz1->compression_format != DEFLATE_FORMAT)
9140 updcrc( gz1, (uch*)buf, len );
9144 gz1->adler = adler32(gz1->adler, (uch*)buf, len);
9147 gz1->bytes_in += (ulg)len;
9152 void bi_windup( PGZ1 gz1 )
9154 if ( gz1->bi_valid > 8 )
9156 put_short(gz1->bi_buf);
9158 else if ( gz1->bi_valid > 0 )
9160 put_byte(gz1->bi_buf);
9167 void send_all_trees(
9176 send_bits(gz1,lcodes-257, 5);
9177 send_bits(gz1,dcodes-1, 5);
9178 send_bits(gz1,blcodes-4, 4);
9180 for ( rank = 0; rank < blcodes; rank++ )
9182 send_bits(gz1,gz1->bl_tree[bl_order[rank]].dl.len, 3 );
9185 send_tree(gz1,(ct_data *)gz1->dyn_ltree, lcodes-1);
9186 send_tree(gz1,(ct_data *)gz1->dyn_dtree, dcodes-1);
9198 int nextlen = tree[0].dl.len;
9203 if (nextlen == 0) max_count = 138, min_count = 3;
9205 for ( n = 0; n <= max_code; n++ )
9208 nextlen = tree[n+1].dl.len;
9210 if (++count < max_count && curlen == nextlen)
9214 else if (count < min_count)
9216 do { send_code(curlen, gz1->bl_tree); } while (--count != 0);
9218 else if (curlen != 0)
9220 if ( curlen != prevlen )
9222 send_code(curlen, gz1->bl_tree); count--;
9225 send_code( REP_3_6, gz1->bl_tree ); send_bits(gz1,count-3, 2);
9227 else if (count <= 10)
9229 send_code(REPZ_3_10, gz1->bl_tree); send_bits(gz1,count-3, 3);
9233 send_code(REPZ_11_138, gz1->bl_tree); send_bits(gz1,count-11, 7);
9241 max_count = 138, min_count = 3;
9243 else if (curlen == nextlen)
9245 max_count = 6, min_count = 3;
9249 max_count = 7, min_count = 4;
9263 int nextlen = tree[0].dl.len;
9268 if (nextlen == 0) max_count = 138, min_count = 3;
9270 tree[max_code+1].dl.len = (ush)0xffff;
9272 for ( n = 0; n <= max_code; n++ )
9275 nextlen = tree[n+1].dl.len;
9277 if ( ++count < max_count && curlen == nextlen )
9281 else if ( count < min_count )
9283 gz1->bl_tree[curlen].fc.freq += count;
9285 else if ( curlen != 0 )
9287 if ( curlen != prevlen ) gz1->bl_tree[curlen].fc.freq++;
9288 gz1->bl_tree[REP_3_6].fc.freq++;
9290 else if ( count <= 10 )
9292 gz1->bl_tree[REPZ_3_10].fc.freq++;
9296 gz1->bl_tree[REPZ_11_138].fc.freq++;
9307 else if (curlen == nextlen)
9326 int v = gz1->heap[k];
9329 while( j <= gz1->heap_len )
9331 if (j < gz1->heap_len && smaller(tree, gz1->heap[j+1], gz1->heap[j])) j++;
9333 if (smaller(tree, v, gz1->heap[j])) break;
9335 gz1->heap[k] = gz1->heap[j]; k = j;
9346 #define GZS_DEFLATE1 3
9347 #define GZS_DEFLATE2 4
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 );
9355 int gzp_main( GZP_CONTROL *gzp )
9359 int final_exit_code = 0;
9360 int ofile_flags = O_RDWR | O_CREAT | O_TRUNC | O_BINARY;
9362 gzp->result_code = 0;
9365 gz1 = (PGZ1) gz1_init();
9372 gz1->decompress = gzp->decompress;
9373 gz1->compression_format = gzp->compression_format;
9375 strcpy( gz1->ifname, gzp->input_filename );
9376 strcpy( gz1->ofname, gzp->output_filename );
9378 gz1->input_ismem = gzp->input_ismem;
9379 gz1->input_ptr = gzp->input_ismem_ibuf;
9380 gz1->input_bytesleft = gzp->input_ismem_ibuflen;
9382 gz1->output_ismem = gzp->output_ismem;
9383 gz1->output_ptr = gzp->output_ismem_obuf;
9384 gz1->output_maxlen = gzp->output_ismem_obuflen;
9386 if ( gz1->no_time < 0 ) gz1->no_time = gz1->decompress;
9387 if ( gz1->no_name < 0 ) gz1->no_name = gz1->decompress;
9391 if ( !gz1->input_ismem )
9395 rc = stat( gz1->ifname, &gz1->istat );
9404 gz1->ifile_size = gz1->istat.st_size;
9409 gz1->ascii && !gz1->decompress ? O_RDONLY : O_RDONLY | O_BINARY,
9413 if ( gz1->ifd == -1 )
9421 if ( !gz1->output_ismem )
9423 if ( gz1->ascii && gz1->decompress )
9425 ofile_flags &= ~O_BINARY;
9428 gz1->ofd = OPEN( gz1->ofname, ofile_flags, RW_USER );
9430 if ( gz1->ofd == -1 )
9448 gz1->bytes_out = 0L;
9451 if ( gz1->decompress )
9453 gz1->method = get_header( gz1, gz1->ifd );
9455 if ( gz1->method < 0 )
9473 gz1->save_orig_name = 0;
9475 gz1->state = GZS_ZIP1;
9481 if ( gz1->done == 1 ) break;
9496 gzp->result_code = gz1->exit_code;
9497 gzp->bytes_out = gz1->bytes_out;
9499 final_exit_code = (int) gz1->exit_code;
9503 return final_exit_code;
9506 int gzs_fsp( PGZ1 gz1 )
9510 switch( gz1->state )
9514 rc = gzs_zip1( gz1 );
9520 rc = gzs_zip2( gz1 );
9526 rc = gzs_deflate1( gz1 );
9532 rc = gzs_deflate2( gz1 );
9547 int gzs_zip1( PGZ1 gz1 )
9551 ush deflate_flags = 0;
9555 gz1->method = DEFLATED;
9557 if (gz1->compression_format != DEFLATE_FORMAT)
9559 put_byte(GZIP_MAGIC[0]);
9560 put_byte(GZIP_MAGIC[1]);
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
9569 put_byte(ZLIB_HEADER[0]);
9570 put_byte(ZLIB_HEADER[1]);
9573 if ( gz1->save_orig_name )
9578 if (gz1->compression_format != DEFLATE_FORMAT)
9581 put_long(gz1->time_stamp);
9584 updcrc( gz1, NULL, 0 );
9588 /* Deflate compression uses an Adler32 CRC, not a CRC32. */
9592 gz1->state = GZS_ZIP2;
9597 int gzs_zip2( PGZ1 gz1 )
9601 ush deflate_flags = 0;
9603 bi_init( gz1, gz1->ofd );
9604 ct_init( gz1, &attr, &gz1->method );
9605 lm_init( gz1, gz1->level, &deflate_flags );
9607 if (gz1->compression_format != DEFLATE_FORMAT)
9609 put_byte((uch)deflate_flags);
9611 if ( gz1->save_orig_name )
9613 char *p = gz1_basename( gz1, gz1->ifname );
9622 gz1->header_bytes = (long)gz1->outcnt;
9624 gz1->state = GZS_DEFLATE1;
9629 int gzs_deflate1( PGZ1 gz1 )
9631 if ( !gz1->deflate1_initialized )
9633 gz1->deflate1_match_available = 0;
9634 gz1->deflate1_match_length = MIN_MATCH-1;
9635 gz1->deflate1_initialized = 1;
9638 if ( gz1->compr_level <= 3 )
9645 if ( gz1->lookahead == 0 )
9647 if ( gz1->deflate1_match_available )
9649 ct_tally( gz1, 0, gz1->window[gz1->strstart-1] );
9652 gz1->state = GZS_DEFLATE2;
9654 return (int) FLUSH_BLOCK(1);
9657 #ifdef STAY_HERE_FOR_A_CERTAIN_AMOUNT_OF_ITERATIONS
9659 while( iterations < max_iterations_per_yield )
9664 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK;
9666 prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[ gz1->ins_h ];
9668 head[ gz1->ins_h ] = gz1->strstart;
9670 gz1->prev_length = gz1->deflate1_match_length, gz1->deflate1_prev_match = gz1->match_start;
9671 gz1->deflate1_match_length = MIN_MATCH-1;
9673 if ( gz1->deflate1_hash_head != NIL && gz1->prev_length < gz1->max_lazy_match &&
9674 gz1->strstart - gz1->deflate1_hash_head <= MAX_DIST)
9676 gz1->deflate1_match_length = longest_match( gz1, gz1->deflate1_hash_head );
9678 if ( gz1->deflate1_match_length > gz1->lookahead )
9680 gz1->deflate1_match_length = gz1->lookahead;
9683 if (gz1->deflate1_match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR)
9685 gz1->deflate1_match_length--;
9689 if ( gz1->prev_length >= MIN_MATCH && gz1->deflate1_match_length <= gz1->prev_length )
9691 gz1->deflate1_flush =
9692 ct_tally(gz1,gz1->strstart-1-gz1->deflate1_prev_match, gz1->prev_length - MIN_MATCH);
9694 gz1->lookahead -= ( gz1->prev_length - 1 );
9695 gz1->prev_length -= 2;
9701 (((gz1->ins_h)<<H_SHIFT) ^ (gz1->window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK;
9703 prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[gz1->ins_h];
9705 head[ gz1->ins_h ] = gz1->strstart;
9707 } while (--gz1->prev_length != 0);
9709 gz1->deflate1_match_available = 0;
9710 gz1->deflate1_match_length = MIN_MATCH-1;
9714 if (gz1->deflate1_flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
9719 if ( gz1->deflate1_match_available )
9721 if ( ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ) )
9723 FLUSH_BLOCK(0), gz1->block_start = gz1->strstart;
9731 gz1->deflate1_match_available = 1;
9736 while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile )
9745 int gzs_deflate2( PGZ1 gz1 )
9747 #if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO)
9748 if (gz1->ifile_size != -1L && gz1->isize != (ulg)gz1->ifile_size)
9753 if (gz1->compression_format != DEFLATE_FORMAT)
9755 put_long( gz1->crc );
9756 put_long( gz1->bytes_in );
9757 gz1->header_bytes += 2*sizeof(long);
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
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);
9773 flush_outbuf( gz1 );
9781 /* =========================================================================
9782 adler32 -- compute the Adler-32 checksum of a data stream
9783 Copyright (C) 1995-1998 Mark Adler
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.
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:
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.
9801 Modified by Eric Kidd <eric.kidd@pobox.com> to play nicely with mod_gzip.
9804 #define BASE 65521L /* largest prime smaller than 65536 */
9806 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
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);
9814 ulg adler32(ulg adler, uch *buf, unsigned len)
9816 unsigned long s1 = adler & 0xffff;
9817 unsigned long s2 = (adler >> 16) & 0xffff;
9820 if (buf == NULL) return 1L;
9823 k = len < NMAX ? len : NMAX;
9837 return (s2 << 16) | s1;