LTP GCOV extension - code coverage report
Current view: directory - ext/http - http_encoding_api.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 378
Code covered: 75.4 % Executed lines: 285
Legend: not executed executed

       1                 : /*
       2                 :     +--------------------------------------------------------------------+
       3                 :     | PECL :: http                                                       |
       4                 :     +--------------------------------------------------------------------+
       5                 :     | Redistribution and use in source and binary forms, with or without |
       6                 :     | modification, are permitted provided that the conditions mentioned |
       7                 :     | in the accompanying LICENSE file are met.                          |
       8                 :     +--------------------------------------------------------------------+
       9                 :     | Copyright (c) 2004-2007, Michael Wallner <mike@php.net>            |
      10                 :     +--------------------------------------------------------------------+
      11                 : */
      12                 : 
      13                 : /* $Id: http_encoding_api.c,v 1.62 2007/02/07 11:50:26 mike Exp $ */
      14                 : 
      15                 : #define HTTP_WANT_ZLIB
      16                 : #include "php_http.h"
      17                 : 
      18                 : #include "php_http_api.h"
      19                 : #include "php_http_encoding_api.h"
      20                 : #include "php_http_send_api.h"
      21                 : #include "php_http_headers_api.h"
      22                 : 
      23                 : /* {{{ */
      24                 : #ifdef HTTP_HAVE_ZLIB
      25                 : PHP_MINIT_FUNCTION(http_encoding)
      26             220 : {
      27             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_DEF", HTTP_DEFLATE_LEVEL_DEF);
      28             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MIN", HTTP_DEFLATE_LEVEL_MIN);
      29             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MAX", HTTP_DEFLATE_LEVEL_MAX);
      30             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_ZLIB", HTTP_DEFLATE_TYPE_ZLIB);
      31             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_GZIP", HTTP_DEFLATE_TYPE_GZIP);
      32             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_RAW", HTTP_DEFLATE_TYPE_RAW);
      33             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_DEF", HTTP_DEFLATE_STRATEGY_DEF);
      34             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FILT", HTTP_DEFLATE_STRATEGY_FILT);
      35             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_HUFF", HTTP_DEFLATE_STRATEGY_HUFF);
      36             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_RLE", HTTP_DEFLATE_STRATEGY_RLE);
      37             220 :         HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FIXED", HTTP_DEFLATE_STRATEGY_FIXED);
      38                 :         
      39             220 :         HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_NONE", HTTP_ENCODING_STREAM_FLUSH_NONE);
      40             220 :         HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_SYNC", HTTP_ENCODING_STREAM_FLUSH_SYNC);
      41             220 :         HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_FULL", HTTP_ENCODING_STREAM_FLUSH_FULL);
      42                 :         
      43             220 :         return SUCCESS;
      44                 : }
      45                 : 
      46                 : PHP_RINIT_FUNCTION(http_encoding)
      47             219 : {
      48             219 :         if (HTTP_G->send.inflate.start_auto) {
      49               0 :                 php_ob_set_internal_handler(_http_ob_inflatehandler, HTTP_INFLATE_BUFFER_SIZE, "http inflate", 0 TSRMLS_CC);
      50                 :         }
      51             219 :         if (HTTP_G->send.deflate.start_auto) {
      52               0 :                 php_ob_set_internal_handler(_http_ob_deflatehandler, HTTP_DEFLATE_BUFFER_SIZE, "http deflate", 0 TSRMLS_CC);
      53                 :         }
      54             219 :         return SUCCESS;
      55                 : }
      56                 : 
      57                 : PHP_RSHUTDOWN_FUNCTION(http_encoding)
      58             219 : {
      59             219 :         if (HTTP_G->send.deflate.stream) {
      60               0 :                 http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream);
      61                 :         }
      62             219 :         if (HTTP_G->send.inflate.stream) {
      63               0 :                 http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream);
      64                 :         }
      65             219 :         return SUCCESS;
      66                 : }
      67                 : #endif
      68                 : /* }}} */
      69                 : 
      70                 : /* {{{ eol_match(char **, int *) */
      71                 : static inline int eol_match(char **line, int *eol_len)
      72             656 : {
      73             656 :         char *ptr = *line;
      74                 :         
      75             656 :         while (' ' == *ptr) ++ptr;
      76                 : 
      77             656 :         if (ptr == http_locate_eol(*line, eol_len)) {
      78             656 :                 *line = ptr;
      79             656 :                 return 1;
      80                 :         } else {
      81               0 :                 return 0;
      82                 :         }
      83                 : }
      84                 : /* }}} */
      85                 :                         
      86                 : /* {{{ char *http_encoding_dechunk(char *, size_t, char **, size_t *) */
      87                 : PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC)
      88              30 : {
      89              30 :         int eol_len = 0;
      90              30 :         char *n_ptr = NULL;
      91              30 :         const char *e_ptr = encoded;
      92                 :         
      93              30 :         *decoded_len = 0;
      94              30 :         *decoded = ecalloc(1, encoded_len);
      95                 : 
      96             714 :         while ((encoded + encoded_len - e_ptr) > 0) {
      97             684 :                 ulong chunk_len = 0, rest;
      98                 : 
      99             684 :                 chunk_len = strtoul(e_ptr, &n_ptr, 16);
     100                 : 
     101                 :                 /* we could not read in chunk size */
     102             684 :                 if (n_ptr == e_ptr) {
     103                 :                         /*
     104                 :                          * if this is the first turn and there doesn't seem to be a chunk
     105                 :                          * size at the begining of the body, do not fail on apparently
     106                 :                          * not encoded data and return a copy
     107                 :                          */
     108               0 :                         if (e_ptr == encoded) {
     109               0 :                                 http_error(HE_NOTICE, HTTP_E_ENCODING, "Data does not seem to be chunked encoded");
     110               0 :                                 memcpy(*decoded, encoded, encoded_len);
     111               0 :                                 *decoded_len = encoded_len;
     112               0 :                                 return encoded + encoded_len;
     113                 :                         } else {
     114               0 :                                 efree(*decoded);
     115               0 :                                 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len);
     116               0 :                                 return NULL;
     117                 :                         }
     118                 :                 }
     119                 :                 
     120                 :                 /* reached the end */
     121             684 :                 if (!chunk_len) {
     122                 :                         /* move over '0' chunked encoding terminator */
     123              28 :                         while (*e_ptr == '0') ++e_ptr;
     124              28 :                         break;
     125                 :                 }
     126                 : 
     127                 :                 /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
     128             656 :                 if (*n_ptr && !eol_match(&n_ptr, &eol_len)) {
     129               0 :                         if (eol_len == 2) {
     130               0 :                                 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr - encoded, encoded_len, *n_ptr, *(n_ptr + 1));
     131                 :                         } else {
     132               0 :                                 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr);
     133                 :                         }
     134                 :                 }
     135             656 :                 n_ptr += eol_len;
     136                 :                 
     137                 :                 /* chunk size pretends more data than we actually got, so it's probably a truncated message */
     138             656 :                 if (chunk_len > (rest = encoded + encoded_len - n_ptr)) {
     139               1 :                         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len, rest, n_ptr - encoded, encoded_len);
     140               1 :                         chunk_len = rest;
     141                 :                 }
     142                 : 
     143                 :                 /* copy the chunk */
     144             656 :                 memcpy(*decoded + *decoded_len, n_ptr, chunk_len);
     145             656 :                 *decoded_len += chunk_len;
     146                 :                 
     147             656 :                 if (chunk_len == rest) {
     148               2 :                         e_ptr = n_ptr + chunk_len;
     149               2 :                         break;
     150                 :                 } else {
     151                 :                         /* advance to next chunk */
     152             654 :                         e_ptr = n_ptr + chunk_len + eol_len;
     153                 :                 }
     154                 :         }
     155                 : 
     156              30 :         return e_ptr;
     157                 : }
     158                 : /* }}} */
     159                 : 
     160                 : /* {{{ int http_encoding_response_start(size_t) */
     161                 : PHP_HTTP_API int _http_encoding_response_start(size_t content_length, zend_bool ignore_http_ohandler TSRMLS_DC)
     162              27 : {
     163              27 :         int response = HTTP_G->send.deflate.response;
     164              27 :         int ohandler = php_ob_handler_used("ob_gzhandler" TSRMLS_CC) || php_ob_handler_used("zlib output compression" TSRMLS_CC);
     165                 :         
     166              27 :         if (!ohandler && !ignore_http_ohandler) {
     167              26 :                 ohandler = php_ob_handler_used("ob_deflatehandler" TSRMLS_CC) || php_ob_handler_used("http deflate" TSRMLS_CC);
     168                 :         }
     169                 :         
     170              30 :         if (response && !ohandler) {
     171                 : #ifdef HTTP_HAVE_ZLIB
     172                 :                 HashTable *selected;
     173                 :                 zval zsupported;
     174                 :                 
     175               3 :                 HTTP_G->send.deflate.encoding = 0;
     176                 :                 
     177               3 :                 INIT_PZVAL(&zsupported);
     178               3 :                 array_init(&zsupported);
     179               3 :                 add_next_index_stringl(&zsupported, "gzip", lenof("gzip"), 1);
     180               3 :                 add_next_index_stringl(&zsupported, "x-gzip", lenof("x-gzip"), 1);
     181               3 :                 add_next_index_stringl(&zsupported, "deflate", lenof("deflate"), 1);
     182                 :                 
     183               3 :                 if ((selected = http_negotiate_encoding(&zsupported))) {
     184               3 :                         STATUS hs = FAILURE;
     185               3 :                         char *encoding = NULL;
     186                 :                         ulong idx;
     187                 :                         
     188               3 :                         if (HASH_KEY_IS_STRING == zend_hash_get_current_key(selected, &encoding, &idx, 0) && encoding) {
     189               6 :                                 if (!strcmp(encoding, "gzip") || !strcmp(encoding, "x-gzip")) {
     190               3 :                                         if (SUCCESS == (hs = http_send_header_string("Content-Encoding: gzip"))) {
     191               3 :                                                 HTTP_G->send.deflate.encoding = HTTP_ENCODING_GZIP;
     192                 :                                         }
     193               0 :                                 } else if (!strcmp(encoding, "deflate")) {
     194               0 :                                         if (SUCCESS == (hs = http_send_header_string("Content-Encoding: deflate"))) {
     195               0 :                                                 HTTP_G->send.deflate.encoding = HTTP_ENCODING_DEFLATE;
     196                 :                                         }
     197                 :                                 }
     198               3 :                                 if (SUCCESS == hs) {
     199               3 :                                         http_send_header_string("Vary: Accept-Encoding");
     200                 :                                 }
     201                 :                         }
     202                 :                         
     203               3 :                         zend_hash_destroy(selected);
     204               3 :                         FREE_HASHTABLE(selected);
     205                 :                 }
     206                 :                 
     207               3 :                 zval_dtor(&zsupported);
     208                 : #else
     209                 :                 HTTP_G->send.deflate.encoding = 0;
     210                 :                 php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC);
     211                 : #endif /* HTTP_HAVE_ZLIB */
     212              44 :         } else if (content_length && !ohandler) {
     213                 :                 /* emit a content-length header */
     214                 :                 char cl_header_str[128];
     215                 :                 size_t cl_header_len;
     216              20 :                 cl_header_len = snprintf(cl_header_str, sizeof(cl_header_str), "Content-Length: %zu", content_length);
     217              20 :                 http_send_header_string_ex(cl_header_str, cl_header_len, 1);
     218                 :         } else {
     219               4 :                 HTTP_G->send.deflate.encoding = 0;
     220                 :         }
     221                 :         
     222              27 :         return HTTP_G->send.deflate.encoding;
     223                 : }
     224                 : /* }}} */
     225                 : 
     226                 : #ifdef HTTP_HAVE_ZLIB
     227                 : 
     228                 : /* {{{ inline int http_inflate_rounds */
     229                 : static inline int http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
     230              29 : {
     231              29 :         int status = 0, round = 0;
     232                 :         phpstr buffer;
     233                 :         
     234              29 :         *buf = NULL;
     235              29 :         *len = 0;
     236                 :         
     237              29 :         phpstr_init_ex(&buffer, Z->avail_in, PHPSTR_INIT_PREALLOC);
     238                 :         
     239                 :         do {
     240              69 :                 if (PHPSTR_NOMEM == phpstr_resize_ex(&buffer, buffer.size, 0, 1)) {
     241               0 :                         status = Z_MEM_ERROR;
     242                 :                 } else {
     243              69 :                         Z->avail_out = buffer.free;
     244              69 :                         Z->next_out = (Bytef *) buffer.data + buffer.used;
     245                 : #if 0
     246                 :                         fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
     247                 : #endif
     248              69 :                         status = inflate(Z, flush);
     249                 :                         
     250              69 :                         buffer.used += buffer.free - Z->avail_out;
     251              69 :                         buffer.free = Z->avail_out;
     252                 : #if 0
     253                 :                         fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
     254                 : #endif
     255              69 :                         HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
     256                 :                 }
     257              69 :         } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < HTTP_INFLATE_ROUNDS);
     258                 :         
     259              56 :         if (status == Z_OK || status == Z_STREAM_END) {
     260              27 :                 phpstr_shrink(&buffer);
     261              27 :                 phpstr_fix(&buffer);
     262              27 :                 *buf = buffer.data;
     263              27 :                 *len = buffer.used;
     264                 :         } else {
     265               2 :                 phpstr_dtor(&buffer);
     266                 :         }
     267                 :         
     268              29 :         return status;
     269                 : }
     270                 : /* }}} */
     271                 : 
     272                 : /* {{{ STATUS http_encoding_deflate(int, char *, size_t, char **, size_t *) */
     273                 : PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     274               4 : {
     275                 :         int status, level, wbits, strategy;
     276                 :         z_stream Z;
     277                 :         
     278               4 :         HTTP_DEFLATE_LEVEL_SET(flags, level);
     279               4 :         HTTP_DEFLATE_WBITS_SET(flags, wbits);
     280               4 :         HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
     281                 :         
     282               4 :         memset(&Z, 0, sizeof(z_stream));
     283               4 :         *encoded = NULL;
     284               4 :         *encoded_len = 0;
     285                 :         
     286               4 :         status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy);
     287               4 :         if (Z_OK == status) {
     288               4 :                 *encoded_len = HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
     289               4 :                 *encoded = emalloc_rel(*encoded_len);
     290                 :                 
     291               4 :                 Z.next_in = (Bytef *) data;
     292               4 :                 Z.next_out = (Bytef *) *encoded;
     293               4 :                 Z.avail_in = data_len;
     294               4 :                 Z.avail_out = *encoded_len;
     295                 :                 
     296               4 :                 status = deflate(&Z, Z_FINISH);
     297               4 :                 deflateEnd(&Z);
     298                 :                 
     299               4 :                 if (Z_STREAM_END == status) {
     300                 :                         /* size buffer down to actual length */
     301               4 :                         *encoded = erealloc_rel(*encoded, Z.total_out + 1);
     302               4 :                         (*encoded)[*encoded_len = Z.total_out] = '\0';
     303               4 :                         return SUCCESS;
     304                 :                 } else {
     305               0 :                         STR_SET(*encoded, NULL);
     306               0 :                         *encoded_len = 0;
     307                 :                 }
     308                 :         }
     309                 :         
     310               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not deflate data: %s", zError(status));
     311               0 :         return FAILURE;
     312                 : }
     313                 : /* }}} */
     314                 : 
     315                 : /* {{{ STATUS http_encoding_inflate(char *, size_t, char **, size_t) */
     316                 : PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     317              17 : {
     318                 :         z_stream Z;
     319              17 :         int status, wbits = HTTP_WINDOW_BITS_ANY;
     320                 :         
     321              17 :         memset(&Z, 0, sizeof(z_stream));
     322                 :         
     323              19 : retry_raw_inflate:
     324              19 :         status = inflateInit2(&Z, wbits);
     325              19 :         if (Z_OK == status) {
     326              19 :                 Z.next_in = (Bytef *) data;
     327              19 :                 Z.avail_in = data_len;
     328                 :                 
     329              19 :                 switch (status = http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) {
     330                 :                         case Z_OK:
     331                 :                         case Z_STREAM_END:
     332              17 :                                 inflateEnd(&Z);
     333              17 :                                 return SUCCESS;
     334                 :                         
     335                 :                         case Z_DATA_ERROR:
     336                 :                                 /* raw deflated data? */
     337               2 :                                 if (HTTP_WINDOW_BITS_ANY == wbits) {
     338               2 :                                         inflateEnd(&Z);
     339               2 :                                         wbits = HTTP_WINDOW_BITS_RAW;
     340               2 :                                         goto retry_raw_inflate;
     341                 :                                 }
     342                 :                 }
     343               0 :                 inflateEnd(&Z);
     344                 :         }
     345                 :         
     346               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not inflate data: %s", zError(status));
     347               0 :         return FAILURE;
     348                 : }
     349                 : /* }}} */
     350                 : 
     351                 : /* {{{ http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *, int) */
     352                 : PHP_HTTP_API http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     353              12 : {
     354                 :         int status, level, wbits, strategy, free_stream;
     355                 :         
     356              12 :         if ((free_stream = !s)) {
     357               9 :                 s = pemalloc_rel(sizeof(http_encoding_stream), (flags & HTTP_ENCODING_STREAM_PERSISTENT));
     358                 :         }
     359              12 :         memset(s, 0, sizeof(http_encoding_stream));
     360              12 :         s->flags = flags;
     361                 :         
     362              12 :         HTTP_DEFLATE_LEVEL_SET(flags, level);
     363              12 :         HTTP_DEFLATE_WBITS_SET(flags, wbits);
     364              12 :         HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
     365                 :         
     366              12 :         if (Z_OK == (status = deflateInit2(&s->stream, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) {
     367              12 :                 int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0;
     368                 :                 
     369              12 :                 if ((s->stream.opaque = phpstr_init_ex(NULL, HTTP_DEFLATE_BUFFER_SIZE, p))) {
     370              12 :                         return s;
     371                 :                 }
     372               0 :                 deflateEnd(&s->stream);
     373               0 :                 status = Z_MEM_ERROR;
     374                 :         }
     375                 :         
     376               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize deflate encoding stream: %s", zError(status));
     377               0 :         if (free_stream) {
     378               0 :                 efree(s);
     379                 :         }
     380               0 :         return NULL;
     381                 : }
     382                 : /* }}} */
     383                 : 
     384                 : /* {{{ http_encoding_stream *http_encoding_inflate_stream_init(http_encoding_stream *, int) */
     385                 : PHP_HTTP_API http_encoding_stream *_http_encoding_inflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     386               7 : {
     387                 :         int status, wbits, free_stream;
     388                 :         
     389               7 :         if ((free_stream = !s)) {
     390               4 :                 s = pemalloc_rel(sizeof(http_encoding_stream), (flags & HTTP_ENCODING_STREAM_PERSISTENT));
     391                 :         }
     392               7 :         memset(s, 0, sizeof(http_encoding_stream));
     393               7 :         s->flags = flags;
     394                 :         
     395               7 :         HTTP_INFLATE_WBITS_SET(flags, wbits);
     396                 :         
     397               7 :         if (Z_OK == (status = inflateInit2(&s->stream, wbits))) {
     398               7 :                 int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0;
     399                 :                 
     400               7 :                 if ((s->stream.opaque = phpstr_init_ex(NULL, HTTP_DEFLATE_BUFFER_SIZE, p))) {
     401               7 :                         return s;
     402                 :                 }
     403               0 :                 inflateEnd(&s->stream);
     404               0 :                 status = Z_MEM_ERROR;
     405                 :         }
     406                 :         
     407               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize inflate stream: %s", zError(status));
     408               0 :         if (free_stream) {
     409               0 :                 efree(s);
     410                 :         }
     411               0 :         return NULL;
     412                 : }
     413                 : /* }}} */
     414                 : 
     415                 : /* {{{ STATUS http_encoding_deflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */
     416                 : PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     417             159 : {
     418                 :         int status;
     419                 :         
     420                 :         /* append input to our buffer */
     421             159 :         phpstr_append(PHPSTR(s->stream.opaque), data, data_len);
     422                 :         
     423             159 :         s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
     424             159 :         s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
     425                 :         
     426                 :         /* deflate */
     427             159 :         *encoded_len = HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
     428             159 :         *encoded = emalloc_rel(*encoded_len);
     429             159 :         s->stream.avail_out = *encoded_len;
     430             159 :         s->stream.next_out = (Bytef *) *encoded;
     431                 :         
     432             159 :         switch (status = deflate(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) {
     433                 :                 case Z_OK:
     434                 :                 case Z_STREAM_END:
     435                 :                         /* cut processed chunk off the buffer */
     436             159 :                         if (s->stream.avail_in) {
     437               0 :                                 phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
     438                 :                         } else {
     439             159 :                                 phpstr_reset(PHPSTR(s->stream.opaque));
     440                 :                         }
     441                 :                         
     442                 :                         /* size buffer down to actual size */
     443             159 :                         *encoded_len -= s->stream.avail_out;
     444             159 :                         *encoded = erealloc_rel(*encoded, *encoded_len + 1);
     445             159 :                         (*encoded)[*encoded_len] = '\0';
     446             159 :                         return SUCCESS;
     447                 :         }
     448                 :         
     449               0 :         STR_SET(*encoded, NULL);
     450               0 :         *encoded_len = 0;
     451               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update deflate stream: %s", zError(status));
     452               0 :         return FAILURE;
     453                 : }
     454                 : /* }}} */
     455                 : 
     456                 : /* {{{ STATUS http_encoding_inflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */
     457                 : PHP_HTTP_API STATUS _http_encoding_inflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     458              10 : {
     459                 :         int status;
     460                 :         
     461                 :         /* append input to buffer */
     462              10 :         phpstr_append(PHPSTR(s->stream.opaque), data, data_len);
     463                 :         
     464              10 : retry_raw_inflate:
     465              10 :         s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
     466              10 :         s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
     467                 :         
     468              10 :         switch (status = http_inflate_rounds(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) {
     469                 :                 case Z_OK:
     470                 :                 case Z_STREAM_END:
     471                 :                         /* cut off */
     472              10 :                         if (s->stream.avail_in) {
     473               0 :                                 phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
     474                 :                         } else {
     475              10 :                                 phpstr_reset(PHPSTR(s->stream.opaque));
     476                 :                         }
     477              10 :                         return SUCCESS;
     478                 :                 
     479                 :                 case Z_DATA_ERROR:
     480                 :                         /* raw deflated data ? */
     481               0 :                         if (!(s->flags & HTTP_INFLATE_TYPE_RAW) && !s->stream.total_out) {
     482               0 :                                 inflateEnd(&s->stream);
     483               0 :                                 s->flags |= HTTP_INFLATE_TYPE_RAW;
     484               0 :                                 inflateInit2(&s->stream, HTTP_WINDOW_BITS_RAW);
     485               0 :                                 goto retry_raw_inflate;
     486                 :                         }
     487                 :         }
     488                 :         
     489               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update inflate stream: %s", zError(status));
     490               0 :         return FAILURE;
     491                 : }
     492                 : /* }}} */
     493                 : 
     494                 : /* {{{ STATUS http_encoding_deflate_stream_flush(http_encoding_stream *, char **, size_t *) */
     495                 : PHP_HTTP_API STATUS _http_encoding_deflate_stream_flush(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     496               4 : {
     497                 :         int status;
     498                 :         
     499               4 :         *encoded_len = HTTP_DEFLATE_BUFFER_SIZE;
     500               4 :         *encoded = emalloc_rel(*encoded_len);
     501                 :         
     502               4 :         s->stream.avail_in = 0;
     503               4 :         s->stream.next_in = NULL;
     504               4 :         s->stream.avail_out = *encoded_len;
     505               4 :         s->stream.next_out = (Bytef *) *encoded;
     506                 :         
     507               4 :         switch (status = deflate(&s->stream, Z_FULL_FLUSH)) {
     508                 :                 case Z_OK:
     509                 :                 case Z_STREAM_END:
     510               4 :                         *encoded_len = HTTP_DEFLATE_BUFFER_SIZE - s->stream.avail_out;
     511               4 :                         *encoded = erealloc_rel(*encoded, *encoded_len + 1);
     512               4 :                         (*encoded)[*encoded_len] = '\0';
     513               4 :                         return SUCCESS;
     514                 :         }
     515                 :         
     516               0 :         STR_SET(*encoded, NULL);
     517               0 :         *encoded_len = 0;
     518               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to flush deflate stream: %s", zError(status));
     519               0 :         return FAILURE;
     520                 : }
     521                 : /* }}} */
     522                 : 
     523                 : /* {{{ STATUS http_encoding_inflate_straem_flush(http_encoding_stream *, char **, size_t *) */
     524                 : PHP_HTTP_API STATUS _http_encoding_inflate_stream_flush(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     525               0 : {
     526                 :         /* noop */
     527               0 :         *decoded = estrndup("", *decoded_len = 0);
     528               0 :         return SUCCESS;
     529                 : }
     530                 : /* }}} */
     531                 : 
     532                 : /* {{{ STATUS http_encoding_deflate_stream_finish(http_encoding_stream *, char **, size_t *) */
     533                 : PHP_HTTP_API STATUS _http_encoding_deflate_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     534              11 : {
     535                 :         int status;
     536                 :         
     537              11 :         *encoded_len = HTTP_DEFLATE_BUFFER_SIZE;
     538              11 :         *encoded = emalloc_rel(*encoded_len);
     539                 :         
     540                 :         /* deflate remaining input */
     541              11 :         s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
     542              11 :         s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
     543                 :         
     544              11 :         s->stream.avail_out = *encoded_len;
     545              11 :         s->stream.next_out = (Bytef *) *encoded;
     546                 :         
     547                 :         do {
     548              11 :                 status = deflate(&s->stream, Z_FINISH);
     549              11 :         } while (Z_OK == status);
     550                 :         
     551              11 :         if (Z_STREAM_END == status) {
     552                 :                 /* cut processed intp off */
     553              11 :                 phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
     554                 :                 
     555                 :                 /* size down */
     556              11 :                 *encoded_len -= s->stream.avail_out;
     557              11 :                 *encoded = erealloc_rel(*encoded, *encoded_len + 1);
     558              11 :                 (*encoded)[*encoded_len] = '\0';
     559              11 :                 return SUCCESS;
     560                 :         }
     561                 :         
     562               0 :         STR_SET(*encoded, NULL);
     563               0 :         *encoded_len = 0;
     564               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish deflate stream: %s", zError(status));
     565               0 :         return FAILURE;
     566                 : }
     567                 : /* }}} */
     568                 : 
     569                 : /* {{{ STATUS http_encoding_inflate_stream_finish(http_encoding_stream *, char **, size_t *) */
     570                 : PHP_HTTP_API STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     571               6 : {
     572                 :         int status;
     573                 :         
     574               6 :         if (!PHPSTR_LEN(s->stream.opaque)) {
     575               6 :                 *decoded = NULL;
     576               6 :                 *decoded_len = 0;
     577               6 :                 return SUCCESS;
     578                 :         }
     579                 :         
     580               0 :         *decoded_len = (PHPSTR_LEN(s->stream.opaque) + 1) * HTTP_INFLATE_ROUNDS;
     581               0 :         *decoded = emalloc_rel(*decoded_len);
     582                 :         
     583                 :         /* inflate remaining input */
     584               0 :         s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
     585               0 :         s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
     586                 :         
     587               0 :         s->stream.avail_out = *decoded_len;
     588               0 :         s->stream.next_out = (Bytef *) *decoded;
     589                 :         
     590               0 :         if (Z_STREAM_END == (status = inflate(&s->stream, Z_FINISH))) {
     591                 :                 /* cut processed input off */
     592               0 :                 phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
     593                 :                 
     594                 :                 /* size down */
     595               0 :                 *decoded_len -= s->stream.avail_out;
     596               0 :                 *decoded = erealloc_rel(*decoded, *decoded_len + 1);
     597               0 :                 (*decoded)[*decoded_len] = '\0';
     598               0 :                 return SUCCESS;
     599                 :         }
     600                 :         
     601               0 :         STR_SET(*decoded, NULL);
     602               0 :         *decoded_len = 0;
     603               0 :         http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish inflate stream: %s", zError(status));
     604               0 :         return FAILURE;
     605                 : }
     606                 : /* }}} */
     607                 : 
     608                 : /* {{{ void http_encoding_deflate_stream_dtor(http_encoding_stream *) */
     609                 : PHP_HTTP_API void _http_encoding_deflate_stream_dtor(http_encoding_stream *s TSRMLS_DC)
     610              12 : {
     611              12 :         if (s) {
     612              12 :                 if (s->stream.opaque) {
     613              12 :                         phpstr_free((phpstr **) &s->stream.opaque);
     614                 :                 }
     615              12 :                 deflateEnd(&s->stream);
     616                 :         }
     617              12 : }
     618                 : /* }}} */
     619                 : 
     620                 : /* {{{ void http_encoding_inflate_stream_dtor(http_encoding_stream *) */
     621                 : PHP_HTTP_API void _http_encoding_inflate_stream_dtor(http_encoding_stream *s TSRMLS_DC)
     622               7 : {
     623               7 :         if (s) {
     624               7 :                 if (s->stream.opaque) {
     625               7 :                         phpstr_free((phpstr **) &s->stream.opaque);
     626                 :                 }
     627               7 :                 inflateEnd(&s->stream);
     628                 :         }
     629               7 : }
     630                 : /* }}} */
     631                 : 
     632                 : /* {{{ void http_encoding_deflate_stream_free(http_encoding_stream **) */
     633                 : PHP_HTTP_API void _http_encoding_deflate_stream_free(http_encoding_stream **s TSRMLS_DC)
     634               9 : {
     635               9 :         if (s) {
     636               9 :                 http_encoding_deflate_stream_dtor(*s);
     637               9 :                 if (*s) {
     638               9 :                         pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT);
     639                 :                 }
     640               9 :                 *s = NULL;
     641                 :         }
     642               9 : }
     643                 : /* }}} */
     644                 : 
     645                 : /* {{{ void http_encoding_inflate_stream_free(http_encoding_stream **) */
     646                 : PHP_HTTP_API void _http_encoding_inflate_stream_free(http_encoding_stream **s TSRMLS_DC)
     647               4 : {
     648               4 :         if (s) {
     649               4 :                 http_encoding_inflate_stream_dtor(*s);
     650               4 :                 if (*s) {
     651               4 :                         pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT);
     652                 :                 }
     653               4 :                 *s = NULL;
     654                 :         }
     655               4 : }
     656                 : /* }}} */
     657                 : 
     658                 : /* {{{ void http_ob_deflatehandler(char *, uint, char **, uint *, int) */
     659                 : void _http_ob_deflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
     660               1 : {
     661                 :         int encoding;
     662                 :         
     663               1 :         *handled_output = NULL;
     664               1 :         *handled_output_len = 0;
     665                 :         
     666               1 :         if (mode & PHP_OUTPUT_HANDLER_START) {
     667                 :                 int flags;
     668                 :                 
     669               1 :                 if (HTTP_G->send.deflate.stream) {
     670               0 :                         zend_error(E_ERROR, "ob_deflatehandler() can only be used once");
     671               0 :                         return;
     672                 :                 }
     673                 :                 
     674               1 :                 HTTP_G->send.deflate.response = 1;
     675               1 :                 encoding = http_encoding_response_start(0, 1);
     676               1 :                 HTTP_G->send.deflate.response = 0;
     677                 :                 
     678               1 :                 switch (encoding) {
     679                 :                         case HTTP_ENCODING_GZIP:
     680               1 :                                 flags = HTTP_DEFLATE_TYPE_GZIP;
     681               1 :                                 break;
     682                 :                         
     683                 :                         case HTTP_ENCODING_DEFLATE:
     684               0 :                                 flags = HTTP_DEFLATE_TYPE_ZLIB;
     685               0 :                                 break;
     686                 :                         
     687                 :                         default:
     688               0 :                                 goto deflate_passthru_plain;
     689                 :                 }
     690                 :                 
     691               1 :                 flags |= (HTTP_G->send.deflate.start_flags &~ 0xf0);
     692               1 :                 HTTP_G->send.deflate.stream = http_encoding_deflate_stream_init(NULL, flags);
     693                 :         }
     694                 :         
     695               1 :         if (HTTP_G->send.deflate.stream) {
     696               1 :                 if (output_len) {
     697               1 :                         http_encoding_deflate_stream_update((http_encoding_stream *) HTTP_G->send.deflate.stream, output, output_len, handled_output, handled_output_len);
     698                 :                 }
     699                 :                 
     700               1 :                 if (mode & PHP_OUTPUT_HANDLER_END) {
     701               1 :                         char *remaining = NULL;
     702               1 :                         size_t remaining_len = 0;
     703                 :                         
     704               1 :                         http_encoding_deflate_stream_finish((http_encoding_stream *) HTTP_G->send.deflate.stream, &remaining, &remaining_len);
     705               1 :                         http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream);
     706               1 :                         if (remaining) {
     707               1 :                                 *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1);
     708               1 :                                 memcpy(*handled_output + *handled_output_len, remaining, remaining_len);
     709               1 :                                 (*handled_output)[*handled_output_len += remaining_len] = '\0';
     710               1 :                                 efree(remaining);
     711                 :                         }
     712                 :                 }
     713                 :         } else {
     714               0 : deflate_passthru_plain:
     715               0 :                 *handled_output = estrndup(output, *handled_output_len = output_len);
     716                 :         }
     717                 : }
     718                 : /* }}} */
     719                 : 
     720                 : /* {{{ void http_ob_inflatehandler(char *, uint, char **, uint *, int) */
     721                 : void _http_ob_inflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
     722               1 : {
     723               1 :         *handled_output = NULL;
     724               1 :         *handled_output_len = 0;
     725                 :         
     726               1 :         if (mode & PHP_OUTPUT_HANDLER_START) {
     727               1 :                 if (HTTP_G->send.inflate.stream) {
     728               0 :                         zend_error(E_ERROR, "ob_inflatehandler() can only be used once");
     729               0 :                         return;
     730                 :                 }
     731               1 :                 HTTP_G->send.inflate.stream = http_encoding_inflate_stream_init(NULL, (HTTP_G->send.inflate.start_flags &~ 0xf0));
     732                 :         }
     733                 :         
     734               1 :         if (HTTP_G->send.inflate.stream) {
     735               1 :                 if (output_len) {
     736               1 :                         http_encoding_inflate_stream_update((http_encoding_stream *) HTTP_G->send.inflate.stream, output, output_len, handled_output, handled_output_len);
     737                 :                 }
     738                 :                 
     739               1 :                 if (mode & PHP_OUTPUT_HANDLER_END) {
     740               1 :                         char *remaining = NULL;
     741               1 :                         size_t remaining_len = 0;
     742                 :                         
     743               1 :                         http_encoding_inflate_stream_finish((http_encoding_stream *) HTTP_G->send.inflate.stream, &remaining, &remaining_len);
     744               1 :                         http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream);
     745               1 :                         if (remaining) {
     746               0 :                                 *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1);
     747               0 :                                 memcpy(*handled_output + *handled_output_len, remaining, remaining_len);
     748               0 :                                 (*handled_output)[*handled_output_len += remaining_len] = '\0';
     749               0 :                                 efree(remaining);
     750                 :                         }
     751                 :                 }
     752                 :         } else {
     753               0 :                 *handled_output = estrndup(output, *handled_output_len = output_len);
     754                 :         }
     755                 : }
     756                 : /* }}} */
     757                 : 
     758                 : #endif /* HTTP_HAVE_ZLIB */
     759                 : 
     760                 : /*
     761                 :  * Local variables:
     762                 :  * tab-width: 4
     763                 :  * c-basic-offset: 4
     764                 :  * End:
     765                 :  * vim600: noet sw=4 ts=4 fdm=marker
     766                 :  * vim<600: noet sw=4 ts=4
     767                 :  */
     768                 : 

Generated by: LTP GCOV extension version 1.5