-
-static const char http_encoding_gzip_header[] = {
- (const char) 0x1f, // fixed value
- (const char) 0x8b, // fixed value
- (const char) Z_DEFLATED, // compression algorithm
- (const char) 0, // none of the possible flags defined by the GZIP "RFC"
- (const char) 0, // MTIME
- (const char) 0, // =*=
- (const char) 0, // =*=
- (const char) 0, // =*=
- (const char) 0, // two possible flag values for 9 compression levels? o_O
-#ifdef PHP_WIN32
- (const char) 0x0b // OS_CODE
-#else
- (const char) 0x03 // OS_CODE
-#endif
-};
-
-PHP_HTTP_API STATUS _http_encoding_gzencode_verify(const char *data, size_t data_len, const char **encoded, size_t *encoded_len, int error_level TSRMLS_DC)
-{
- size_t offset = sizeof(http_encoding_gzip_header);
-
- if (data_len < offset) {
- goto really_bad_gzip_header;
- }
-
- if (data[0] != (const char) 0x1F || data[1] != (const char) 0x8B) {
- http_error_ex(error_level TSRMLS_CC, HTTP_E_ENCODING, "Unrecognized GZIP header start: 0x%02X 0x%02X", (int) data[0], (int) (data[1] & 0xFF));
- return FAILURE;
- }
-
- if (data[2] != (const char) Z_DEFLATED) {
- http_error_ex(error_level TSRMLS_CC, HTTP_E_ENCODING, "Unrecognized compression format (%d)", (int) (data[2] & 0xFF));
- /* still try to decode */
- }
- if ((data[3] & 0x4) == 0x4) {
- if (data_len < offset + 2) {
- goto really_bad_gzip_header;
- }
- /* there are extra fields, the length follows the common header as 2 bytes LSB */
- offset += (unsigned) ((data[offset] & 0xFF));
- offset += 1;
- offset += (unsigned) ((data[offset] & 0xFF) << 8);
- offset += 1;
- }
- if ((data[3] & 0x8) == 0x8) {
- if (data_len <= offset) {
- goto really_bad_gzip_header;
- }
- /* there's a file name */
- offset += strlen(&data[offset]) + 1 /*NUL*/;
- }
- if ((data[3] & 0x10) == 0x10) {
- if (data_len <= offset) {
- goto really_bad_gzip_header;
- }
- /* there's a comment */
- offset += strlen(&data[offset]) + 1 /* NUL */;
- }
- if ((data[3] & 0x2) == 0x2) {
- /* there's a CRC16 of the header */
- offset += 2;
- if (data_len <= offset) {
- goto really_bad_gzip_header;
- } else {
- ulong crc, cmp;
-
- cmp = (unsigned) ((data[offset-2] & 0xFF));
- cmp += (unsigned) ((data[offset-1] & 0xFF) << 8);
-
- crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, (const Bytef *) data, sizeof(http_encoding_gzip_header));
-
- if (cmp != (crc & 0xFFFF)) {
- http_error_ex(error_level TSRMLS_CC, HTTP_E_ENCODING, "GZIP headers CRC checksums so not match (%lu, %lu)", cmp, crc & 0xFFFF);
- return FAILURE;
- }
- }
- }
-
- if (data_len < offset + 8) {
- http_error(error_level TSRMLS_CC, HTTP_E_ENCODING, "Missing or truncated GZIP footer");
- return FAILURE;
- }
-
- if (encoded) {
- *encoded = data + offset;
- }
- if (encoded_len) {
- *encoded_len = data_len - offset - 8 /* size of the assumed GZIP footer */;
- }
-
- return SUCCESS;
-
-really_bad_gzip_header:
- http_error(error_level TSRMLS_CC, HTTP_E_ENCODING, "Missing or truncated GZIP header");
- return FAILURE;
-}
-
-PHP_HTTP_API STATUS _http_encoding_gzdecode_verify(const char *data, size_t data_len, const char *decoded, size_t decoded_len, int error_level TSRMLS_DC)
-{
- STATUS status = SUCCESS;
- ulong len, cmp, crc;
-
- crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, (const Bytef *) decoded, decoded_len);
-
- cmp = (unsigned) ((data[data_len-8] & 0xFF));
- cmp += (unsigned) ((data[data_len-7] & 0xFF) << 8);
- cmp += (unsigned) ((data[data_len-6] & 0xFF) << 16);
- cmp += (unsigned) ((data[data_len-5] & 0xFF) << 24);
- len = (unsigned) ((data[data_len-4] & 0xFF));
- len += (unsigned) ((data[data_len-3] & 0xFF) << 8);
- len += (unsigned) ((data[data_len-2] & 0xFF) << 16);
- len += (unsigned) ((data[data_len-1] & 0xFF) << 24);
-
- if (cmp != crc) {
- http_error_ex(error_level TSRMLS_CC, HTTP_E_ENCODING, "Could not verify data integrity: CRC checksums do not match (%lu, %lu)", cmp, crc);
- status = FAILURE;
- }
- if (len != decoded_len) {
- http_error_ex(error_level TSRMLS_CC, HTTP_E_ENCODING, "Could not verify data integrity: data sizes do not match (%lu, %lu)", len, decoded_len);
- status = FAILURE;
- }
- return status;
-}