2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
23 #include "php_http_encoding_api.h"
25 #include "php_http_api.h"
30 #define HTTP_GZMAXTRY 10
31 #define HTTP_GZBUFLEN(l) (l + (l / 1000) + 16 + 1)
33 ZEND_EXTERN_MODULE_GLOBALS(http
);
35 static const char http_gzencode_header
[] = {
38 (const char) Z_DEFLATED
,
43 inline void http_init_gzencode_buffer(z_stream
*Z
, const char *data
, size_t data_len
, char **buf_ptr
)
49 Z
->next_in
= (Bytef
*) data
;
50 Z
->avail_in
= data_len
;
51 Z
->avail_out
= HTTP_GZBUFLEN(data_len
) - 1;
53 *buf_ptr
= emalloc(Z
->avail_out
+ sizeof(http_gzencode_header
));
54 memcpy(*buf_ptr
, http_gzencode_header
, sizeof(http_gzencode_header
));
56 Z
->next_out
= *buf_ptr
+ sizeof(http_gzencode_header
);
59 inline void http_init_deflate_buffer(z_stream
*Z
, const char *data
, size_t data_len
, char **buf_ptr
)
65 Z
->data_type
= Z_ASCII
;
66 Z
->next_in
= (Bytef
*) data
;
67 Z
->avail_in
= data_len
;
68 Z
->avail_out
= HTTP_GZBUFLEN(data_len
) - 1;
69 Z
->next_out
= emalloc(Z
->avail_out
);
71 *buf_ptr
= Z
->next_out
;
74 inline void http_init_inflate_buffer(z_stream
*Z
, const char *data
, size_t data_len
, char **buf_ptr
, size_t *buf_len
, int iteration
)
80 *buf_len
= data_len
* 2;
81 *buf_ptr
= emalloc(*buf_len
+ 1);
84 *buf_ptr
= erealloc(*buf_ptr
, *buf_len
+ 1);
87 Z
->next_in
= (Bytef
*) data
;
88 Z
->avail_in
= data_len
;
89 Z
->avail_out
= *buf_len
;
90 Z
->next_out
= *buf_ptr
;
93 inline size_t http_finish_buffer(size_t buf_len
, char **buf_ptr
)
95 (*buf_ptr
)[buf_len
] = '\0';
99 inline size_t http_finish_gzencode_buffer(z_stream
*Z
, const char *data
, size_t data_len
, char **buf_ptr
)
104 crc
= crc32(0L, Z_NULL
, 0);
105 crc
= crc32(crc
, (const Bytef
*) data
, data_len
);
107 trailer
= *buf_ptr
+ sizeof(http_gzencode_header
) + Z
->total_out
;
109 /* write crc & stream.total_in in LSB order */
110 trailer
[0] = (char) crc
& 0xFF;
111 trailer
[1] = (char) (crc
>> 8) & 0xFF;
112 trailer
[2] = (char) (crc
>> 16) & 0xFF;
113 trailer
[3] = (char) (crc
>> 24) & 0xFF;
114 trailer
[4] = (char) (Z
->total_in
) & 0xFF;
115 trailer
[5] = (char) (Z
->total_in
>> 8) & 0xFF;
116 trailer
[6] = (char) (Z
->total_in
>> 16) & 0xFF;
117 trailer
[7] = (char) (Z
->total_in
>> 24) & 0xFF;
119 return http_finish_buffer(Z
->total_out
+ sizeof(http_gzencode_header
) + 8, buf_ptr
);
123 PHP_HTTP_API STATUS
_http_encoding_gzencode(int level
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
126 STATUS status
= Z_OK
;
128 http_init_gzencode_buffer(&Z
, data
, data_len
, encoded
);
130 if ( (Z_OK
== (status
= deflateInit2(&Z
, level
, Z_DEFLATED
, -MAX_WBITS
, MAX_MEM_LEVEL
, Z_DEFAULT_STRATEGY
))) &&
131 (Z_STREAM_END
== (status
= deflate(&Z
, Z_FINISH
))) &&
132 (Z_OK
== (status
= deflateEnd(&Z
)))) {
133 *encoded_len
= http_finish_gzencode_buffer(&Z
, data
, data_len
, encoded
);
138 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not gzencode data: %s", zError(status
));
142 PHP_HTTP_API STATUS
_http_encoding_deflate(int level
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
145 STATUS status
= Z_OK
;
147 http_init_deflate_buffer(&Z
, data
, data_len
, encoded
);
149 if ( (Z_OK
== (status
= deflateInit2(&Z
, level
, Z_DEFLATED
, -MAX_WBITS
, MAX_MEM_LEVEL
, Z_DEFAULT_STRATEGY
))) &&
150 (Z_STREAM_END
== (status
= deflate(&Z
, Z_FINISH
))) &&
151 (Z_OK
== (status
= deflateEnd(&Z
)))) {
152 *encoded_len
= http_finish_buffer(Z
.total_out
, encoded
);
157 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not deflate data: %s", zError(status
));
161 PHP_HTTP_API STATUS
_http_encoding_compress(int level
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
165 *encoded
= emalloc(*encoded_len
= HTTP_GZBUFLEN(data_len
));
167 if (Z_OK
== (status
= compress2(*encoded
, encoded_len
, data
, data_len
, level
))) {
168 http_finish_buffer(*encoded_len
, encoded
);
173 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not compress data: %s", zError(status
));
177 PHP_HTTP_API STATUS
_http_encoding_gzdecode(const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
179 const char *encoded
= data
+ sizeof(http_gzencode_header
);
182 if (data_len
<= sizeof(http_gzencode_header
) + 8) {
183 http_error(HE_WARNING
, HTTP_E_ENCODING
, "Could not gzdecode data: too short data length");
185 encoded_len
= data_len
- sizeof(http_gzencode_header
) - 8;
187 if (SUCCESS
== http_encoding_inflate(encoded
, encoded_len
, decoded
, decoded_len
)) {
188 unsigned long len
= 0, cmp
= 0, crc
= crc32(0L, Z_NULL
, 0);
190 crc
= crc32(crc
, *decoded
, *decoded_len
);
192 cmp
= (unsigned) (data
[data_len
-8]);
193 cmp
+= (unsigned) (data
[data_len
-7] << 8);
194 cmp
+= (unsigned) (data
[data_len
-6] << 16);
195 cmp
+= (unsigned) (data
[data_len
-5] << 24);
196 len
= (unsigned) (data
[data_len
-4]);
197 len
+= (unsigned) (data
[data_len
-4] << 8);
198 len
+= (unsigned) (data
[data_len
-4] << 16);
199 len
+= (unsigned) (data
[data_len
-4] << 24);
202 http_error(HE_NOTICE
, HTTP_E_ENCODING
, "Could not verify data integrity: CRC check failed");
204 if (len
!= *decoded_len
) {
205 http_error(HE_NOTICE
, HTTP_E_ENCODING
, "Could not verify data integrity: data length check failed");
214 PHP_HTTP_API STATUS
_http_encoding_inflate(const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
221 http_init_inflate_buffer(&Z
, data
, data_len
, decoded
, decoded_len
, max
++);
222 if (Z_OK
== (status
= inflateInit2(&Z
, -MAX_WBITS
))) {
223 if (Z_STREAM_END
== (status
= inflate(&Z
, Z_FINISH
))) {
224 if (Z_OK
== (status
= inflateEnd(&Z
))) {
225 *decoded_len
= http_finish_buffer(Z
.total_out
, decoded
);
230 } while (max
< HTTP_GZMAXTRY
);
232 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not inflate data: %s", zError(status
));
236 PHP_HTTP_API STATUS
_http_encoding_uncompress(const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
240 size_t want
= data_len
* 2;
242 *decoded
= emalloc(want
+ 1);
243 if (Z_BUF_ERROR
== (status
= uncompress(*decoded
, &want
, data
, data_len
))) do {
244 /* this is a lot faster with large data than gzuncompress(),
245 but could be a problem with a low memory limit */
247 *decoded
= erealloc(*decoded
, want
+ 1);
248 status
= uncompress(*decoded
, &want
, data
, data_len
);
249 } while (++max
< HTTP_GZMAXTRY
&& status
== Z_BUF_ERROR
);
251 if (Z_OK
== status
) {
252 *decoded_len
= http_finish_buffer(want
, decoded
);
257 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not uncompress data: %s", zError(status
));
261 #endif /* HTTP_HAVE_ZLIB */
268 * vim600: noet sw=4 ts=4 fdm=marker
269 * vim<600: noet sw=4 ts=4