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