LCOV - code coverage report
Current view: top level - ext/http - php_http_encoding.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 470 568 82.7 %
Date: 2015-02-17 20:30:22 Functions: 49 49 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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-2014, Michael Wallner <mike@php.net>            |
      10             :     +--------------------------------------------------------------------+
      11             : */
      12             : 
      13             : #include "php_http_api.h"
      14             : 
      15             : #include <zlib.h>
      16             : 
      17          20 : static inline int eol_match(char **line, int *eol_len)
      18             : {
      19          20 :         char *ptr = *line;
      20             :         
      21          20 :         while (' ' == *ptr) ++ptr;
      22             : 
      23          20 :         if (ptr == php_http_locate_eol(*line, eol_len)) {
      24          18 :                 *line = ptr;
      25          18 :                 return 1;
      26             :         } else {
      27           2 :                 return 0;
      28             :         }
      29             : }
      30             : 
      31           5 : const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC)
      32             : {
      33           5 :         int eol_len = 0;
      34           5 :         char *n_ptr = NULL;
      35           5 :         const char *e_ptr = encoded;
      36             :         
      37           5 :         *decoded_len = 0;
      38           5 :         *decoded = ecalloc(1, encoded_len + 1);
      39             : 
      40          28 :         while ((encoded + encoded_len - e_ptr) > 0) {
      41          23 :                 ulong chunk_len = 0, rest;
      42             : 
      43          23 :                 chunk_len = strtoul(e_ptr, &n_ptr, 16);
      44             : 
      45             :                 /* we could not read in chunk size */
      46          23 :                 if (n_ptr == e_ptr) {
      47             :                         /*
      48             :                          * if this is the first turn and there doesn't seem to be a chunk
      49             :                          * size at the begining of the body, do not fail on apparently
      50             :                          * not encoded data and return a copy
      51             :                          */
      52           2 :                         if (e_ptr == encoded) {
      53           1 :                                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Data does not seem to be chunked encoded");
      54           1 :                                 memcpy(*decoded, encoded, encoded_len);
      55           1 :                                 *decoded_len = encoded_len;
      56           1 :                                 return encoded + encoded_len;
      57             :                         } else {
      58           1 :                                 efree(*decoded);
      59           1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len);
      60           1 :                                 return NULL;
      61             :                         }
      62             :                 }
      63             :                 
      64             :                 /* reached the end */
      65          21 :                 if (!chunk_len) {
      66             :                         /* move over '0' chunked encoding terminator and any new lines */
      67             :                         do {
      68           1 :                                 switch (*e_ptr) {
      69             :                                         case '0':
      70             :                                         case '\r':
      71             :                                         case '\n':
      72           1 :                                                 ++e_ptr;
      73           1 :                                                 continue;
      74             :                                 }
      75             :                         } while (0);
      76           1 :                         break;
      77             :                 }
      78             : 
      79             :                 /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
      80          20 :                 if (*n_ptr && !eol_match(&n_ptr, &eol_len)) {
      81           2 :                         if (eol_len == 2) {
      82           1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr - encoded, encoded_len, *n_ptr, *(n_ptr + 1));
      83             :                         } else {
      84           1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr);
      85             :                         }
      86             :                 }
      87          20 :                 n_ptr += eol_len;
      88             :                 
      89             :                 /* chunk size pretends more data than we actually got, so it's probably a truncated message */
      90          20 :                 if (chunk_len > (rest = encoded + encoded_len - n_ptr)) {
      91           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len, rest, n_ptr - encoded, encoded_len);
      92           2 :                         chunk_len = rest;
      93             :                 }
      94             : 
      95             :                 /* copy the chunk */
      96          20 :                 memcpy(*decoded + *decoded_len, n_ptr, chunk_len);
      97          20 :                 *decoded_len += chunk_len;
      98             :                 
      99          20 :                 if (chunk_len == rest) {
     100           2 :                         e_ptr = n_ptr + chunk_len;
     101           2 :                         break;
     102             :                 } else {
     103             :                         /* advance to next chunk */
     104          18 :                         e_ptr = n_ptr + chunk_len + eol_len;
     105             :                 }
     106             :         }
     107             : 
     108           3 :         return e_ptr;
     109             : }
     110             : 
     111          46 : static inline int php_http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
     112             : {
     113          46 :         int status = 0, round = 0;
     114             :         php_http_buffer_t buffer;
     115             :         
     116          46 :         *buf = NULL;
     117          46 :         *len = 0;
     118             :         
     119          46 :         php_http_buffer_init_ex(&buffer, Z->avail_in, PHP_HTTP_BUFFER_INIT_PREALLOC);
     120             :         
     121             :         do {
     122          55 :                 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(&buffer, buffer.size, 0, 1)) {
     123           0 :                         status = Z_MEM_ERROR;
     124             :                 } else {
     125          55 :                         Z->avail_out = buffer.free;
     126          55 :                         Z->next_out = (Bytef *) buffer.data + buffer.used;
     127             : #if 0
     128             :                         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);
     129             : #endif
     130          55 :                         status = inflate(Z, flush);
     131          55 :                         php_http_buffer_account(&buffer, buffer.free - Z->avail_out);
     132             : #if 0
     133             :                         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);
     134             : #endif
     135          55 :                         PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
     136             :                 }
     137          55 :         } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < PHP_HTTP_INFLATE_ROUNDS);
     138             :         
     139          46 :         if (status == Z_OK || status == Z_STREAM_END) {
     140          43 :                 php_http_buffer_shrink(&buffer);
     141          43 :                 php_http_buffer_fix(&buffer);
     142          43 :                 *buf = buffer.data;
     143          43 :                 *len = buffer.used;
     144             :         } else {
     145           3 :                 php_http_buffer_dtor(&buffer);
     146             :         }
     147             :         
     148          46 :         return status;
     149             : }
     150             : 
     151           3 : STATUS php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC)
     152             : {
     153             :         int status, level, wbits, strategy;
     154             :         z_stream Z;
     155             :         
     156           3 :         PHP_HTTP_DEFLATE_LEVEL_SET(flags, level);
     157           3 :         PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits);
     158           3 :         PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
     159             :         
     160           3 :         memset(&Z, 0, sizeof(z_stream));
     161           3 :         *encoded = NULL;
     162           3 :         *encoded_len = 0;
     163             :         
     164           3 :         status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy);
     165           3 :         if (Z_OK == status) {
     166           3 :                 *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
     167           3 :                 *encoded = emalloc(*encoded_len);
     168             :                 
     169           3 :                 Z.next_in = (Bytef *) data;
     170           3 :                 Z.next_out = (Bytef *) *encoded;
     171           3 :                 Z.avail_in = data_len;
     172           3 :                 Z.avail_out = *encoded_len;
     173             :                 
     174           3 :                 status = deflate(&Z, Z_FINISH);
     175           3 :                 deflateEnd(&Z);
     176             :                 
     177           3 :                 if (Z_STREAM_END == status) {
     178             :                         /* size buffer down to actual length */
     179           3 :                         *encoded = erealloc(*encoded, Z.total_out + 1);
     180           3 :                         (*encoded)[*encoded_len = Z.total_out] = '\0';
     181           3 :                         return SUCCESS;
     182             :                 } else {
     183           0 :                         PTR_SET(*encoded, NULL);
     184           0 :                         *encoded_len = 0;
     185             :                 }
     186             :         }
     187             :         
     188           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not deflate data: %s", zError(status));
     189           0 :         return FAILURE;
     190             : }
     191             : 
     192           5 : STATUS php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC)
     193             : {
     194             :         z_stream Z;
     195           5 :         int status, wbits = PHP_HTTP_WINDOW_BITS_ANY;
     196             :         
     197           5 :         memset(&Z, 0, sizeof(z_stream));
     198             :         
     199             : retry_raw_inflate:
     200           7 :         status = inflateInit2(&Z, wbits);
     201           7 :         if (Z_OK == status) {
     202           7 :                 Z.next_in = (Bytef *) data;
     203           7 :                 Z.avail_in = data_len + 1; /* include the terminating NULL, see #61287 */
     204             :                 
     205           7 :                 switch (status = php_http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) {
     206             :                         case Z_STREAM_END:
     207           4 :                                 inflateEnd(&Z);
     208           4 :                                 return SUCCESS;
     209             : 
     210             :                         case Z_OK:
     211           0 :                                 status = Z_DATA_ERROR;
     212           0 :                                 break;
     213             :                         
     214             :                         case Z_DATA_ERROR:
     215             :                                 /* raw deflated data? */
     216           3 :                                 if (PHP_HTTP_WINDOW_BITS_ANY == wbits) {
     217           2 :                                         inflateEnd(&Z);
     218           2 :                                         wbits = PHP_HTTP_WINDOW_BITS_RAW;
     219           2 :                                         goto retry_raw_inflate;
     220             :                                 }
     221           1 :                                 break;
     222             :                 }
     223           1 :                 inflateEnd(&Z);
     224             : 
     225           1 :                 if (decoded_len && *decoded) {
     226           0 :                         efree(*decoded);
     227             :                 }
     228             :         }
     229             :         
     230           1 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not inflate data: %s", zError(status));
     231           1 :         return FAILURE;
     232             : }
     233             : 
     234          22 : php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags TSRMLS_DC)
     235             : {
     236             :         int freeme;
     237             : 
     238          22 :         if ((freeme = !s)) {
     239          22 :                 s = pemalloc(sizeof(*s), (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     240             :         }
     241          22 :         memset(s, 0, sizeof(*s));
     242             : 
     243          22 :         s->flags = flags;
     244             :         TSRMLS_SET_CTX(s->ts);
     245             : 
     246          22 :         if ((s->ops = ops)) {
     247          22 :                 php_http_encoding_stream_t *ss = s->ops->init(s);
     248             : 
     249          22 :                 if (ss) {
     250          22 :                         return ss;
     251             :                 }
     252             :         } else {
     253           0 :                 return s;
     254             :         }
     255             : 
     256           0 :         if (freeme) {
     257           0 :                 pefree(s, (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     258             :         }
     259           0 :         return NULL;
     260             : }
     261             : 
     262          76 : php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
     263             : {
     264             :         TSRMLS_FETCH_FROM_CTX(from->ts);
     265             : 
     266          76 :         if (from->ops->copy) {
     267             :                 int freeme;
     268             :                 php_http_encoding_stream_t *ns;
     269             : 
     270          76 :                 if ((freeme = !to)) {
     271          76 :                         to = pemalloc(sizeof(*to), (from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     272             :                 }
     273          76 :                 memset(to, 0, sizeof(*to));
     274             : 
     275          76 :                 to->flags = from->flags;
     276          76 :                 to->ops = from->ops;
     277             :                 TSRMLS_SET_CTX(to->ts);
     278             : 
     279          76 :                 if ((ns = to->ops->copy(from, to))) {
     280          76 :                         return ns;
     281             :                 } else {
     282           0 :                         return to;
     283             :                 }
     284             : 
     285             :                 if (freeme) {
     286             :                         pefree(to, (to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     287             :                 }
     288             :         }
     289             : 
     290           0 :         return NULL;
     291             : }
     292             : 
     293           8 : STATUS php_http_encoding_stream_reset(php_http_encoding_stream_t **s)
     294             : {
     295             :         php_http_encoding_stream_t *ss;
     296           8 :         if ((*s)->ops->dtor) {
     297           8 :                 (*s)->ops->dtor(*s);
     298             :         }
     299           8 :         if ((ss = (*s)->ops->init(*s))) {
     300           8 :                 *s = ss;
     301           8 :                 return SUCCESS;
     302             :         }
     303           0 :         return FAILURE;
     304             : }
     305             : 
     306         186 : STATUS php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len)
     307             : {
     308         186 :         if (!s->ops->update) {
     309           0 :                 return FAILURE;
     310             :         }
     311         186 :         return s->ops->update(s, in_str, in_len, out_str, out_len);
     312             : }
     313             : 
     314         162 : STATUS php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
     315             : {
     316         162 :         if (!s->ops->flush) {
     317          59 :                 *out_str = NULL;
     318          59 :                 *out_len = 0;
     319          59 :                 return SUCCESS;
     320             :         }
     321         103 :         return s->ops->flush(s, out_str, out_len);
     322             : }
     323             : 
     324          71 : zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s)
     325             : {
     326          71 :         if (!s->ops->done) {
     327           0 :                 return 0;
     328             :         }
     329          71 :         return s->ops->done(s);
     330             : }
     331             : 
     332          17 : STATUS php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
     333             : {
     334          17 :         if (!s->ops->finish) {
     335           5 :                 *out_str = NULL;
     336           5 :                 *out_len = 0;
     337           5 :                 return SUCCESS;
     338             :         }
     339          12 :         return s->ops->finish(s, out_str, out_len);
     340             : }
     341             : 
     342           4 : void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s)
     343             : {
     344           4 :         if (s->ops->dtor) {
     345           4 :                 s->ops->dtor(s);
     346             :         }
     347           4 : }
     348             : 
     349          98 : void php_http_encoding_stream_free(php_http_encoding_stream_t **s)
     350             : {
     351          98 :         if (*s) {
     352          98 :                 if ((*s)->ops->dtor) {
     353          98 :                         (*s)->ops->dtor(*s);
     354             :                 }
     355          98 :                 pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     356          98 :                 *s = NULL;
     357             :         }
     358          98 : }
     359             : 
     360             : struct dechunk_ctx {
     361             :         php_http_buffer_t buffer;
     362             :         ulong hexlen;
     363             :         unsigned zeroed:1;
     364             : };
     365             : 
     366          13 : static php_http_encoding_stream_t *deflate_init(php_http_encoding_stream_t *s)
     367             : {
     368          13 :         int status, level, wbits, strategy, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
     369          13 :         z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
     370             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     371             :         
     372          13 :         PHP_HTTP_DEFLATE_LEVEL_SET(s->flags, level);
     373          13 :         PHP_HTTP_DEFLATE_WBITS_SET(s->flags, wbits);
     374          13 :         PHP_HTTP_DEFLATE_STRATEGY_SET(s->flags, strategy);
     375             :         
     376          13 :         if (Z_OK == (status = deflateInit2(ctx, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) {
     377          13 :                 if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
     378          13 :                         s->ctx = ctx;
     379          13 :                         return s;
     380             :                 }
     381           0 :                 deflateEnd(ctx);
     382           0 :                 status = Z_MEM_ERROR;
     383             :         }
     384           0 :         pefree(ctx, p);
     385           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize deflate encoding stream: %s", zError(status));
     386           0 :         return NULL;
     387             : }
     388             : 
     389          10 : static php_http_encoding_stream_t *inflate_init(php_http_encoding_stream_t *s)
     390             : {
     391          10 :         int status, wbits, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
     392          10 :         z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
     393             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     394             :         
     395          10 :         PHP_HTTP_INFLATE_WBITS_SET(s->flags, wbits);
     396             :         
     397          10 :         if (Z_OK == (status = inflateInit2(ctx, wbits))) {
     398          10 :                 if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
     399          10 :                         s->ctx = ctx;
     400          10 :                         return s;
     401             :                 }
     402           0 :                 inflateEnd(ctx);
     403           0 :                 status = Z_MEM_ERROR;
     404             :         }
     405           0 :         pefree(ctx, p);
     406           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize inflate stream: %s", zError(status));
     407           0 :         return NULL;
     408             : }
     409             : 
     410           7 : static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s)
     411             : {
     412           7 :         struct dechunk_ctx *ctx = pecalloc(1, sizeof(*ctx), (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     413             : 
     414           7 :         if (!php_http_buffer_init_ex(&ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT) ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) {
     415           0 :                 return NULL;
     416             :         }
     417             : 
     418           7 :         ctx->hexlen = 0;
     419           7 :         ctx->zeroed = 0;
     420           7 :         s->ctx = ctx;
     421             : 
     422           7 :         return s;
     423             : }
     424             : 
     425          25 : static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
     426             : {
     427          25 :         int status, p = to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
     428          25 :         z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
     429             :         TSRMLS_FETCH_FROM_CTX(from->ts);
     430             : 
     431          25 :         if (Z_OK == (status = deflateCopy(to_ctx, from_ctx))) {
     432          25 :                 if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
     433          25 :                         php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
     434          25 :                         to->ctx = to_ctx;
     435          25 :                         return to;
     436             :                 }
     437           0 :                 deflateEnd(to_ctx);
     438           0 :                 status = Z_MEM_ERROR;
     439             :         }
     440           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to copy deflate encoding stream: %s", zError(status));
     441           0 :         return NULL;
     442             : }
     443             : 
     444          25 : static php_http_encoding_stream_t *inflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
     445             : {
     446          25 :         int status, p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
     447          25 :         z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
     448             :         TSRMLS_FETCH_FROM_CTX(from->ts);
     449             : 
     450          25 :         if (Z_OK == (status = inflateCopy(to_ctx, from_ctx))) {
     451          25 :                 if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
     452          25 :                         php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
     453          25 :                         to->ctx = to_ctx;
     454          25 :                         return to;
     455             :                 }
     456           0 :                 inflateEnd(to_ctx);
     457           0 :                 status = Z_MEM_ERROR;
     458             :         }
     459           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to copy inflate encoding stream: %s", zError(status));
     460           0 :         return NULL;
     461             : }
     462             : 
     463          26 : static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
     464             : {
     465          26 :         int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
     466          26 :         struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = pemalloc(sizeof(*to_ctx), p);
     467             :         TSRMLS_FETCH_FROM_CTX(from->ts);
     468             : 
     469          26 :         if (php_http_buffer_init_ex(&to_ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) {
     470          26 :                 to_ctx->hexlen = from_ctx->hexlen;
     471          26 :                 to_ctx->zeroed = from_ctx->zeroed;
     472          26 :                 php_http_buffer_append(&to_ctx->buffer, from_ctx->buffer.data, from_ctx->buffer.used);
     473          26 :                 to->ctx = to_ctx;
     474          26 :                 return to;
     475             :         }
     476           0 :         pefree(to_ctx, p);
     477           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to copy inflate encoding stream: out of memory");
     478           0 :         return NULL;
     479             : }
     480             : 
     481          81 : static STATUS deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
     482             : {
     483             :         int status;
     484          81 :         z_streamp ctx = s->ctx;
     485             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     486             :         
     487             :         /* append input to our buffer */
     488          81 :         php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
     489             :         
     490          81 :         ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
     491          81 :         ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
     492             :         
     493             :         /* deflate */
     494          81 :         *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
     495          81 :         *encoded = emalloc(*encoded_len);
     496          81 :         ctx->avail_out = *encoded_len;
     497          81 :         ctx->next_out = (Bytef *) *encoded;
     498             :         
     499          81 :         switch (status = deflate(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) {
     500             :                 case Z_OK:
     501             :                 case Z_STREAM_END:
     502             :                         /* cut processed chunk off the buffer */
     503          81 :                         if (ctx->avail_in) {
     504           0 :                                 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
     505             :                         } else {
     506          81 :                                 php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
     507             :                         }
     508             :                         
     509             :                         /* size buffer down to actual size */
     510          81 :                         *encoded_len -= ctx->avail_out;
     511          81 :                         *encoded = erealloc(*encoded, *encoded_len + 1);
     512          81 :                         (*encoded)[*encoded_len] = '\0';
     513          81 :                         return SUCCESS;
     514             :         }
     515             :         
     516           0 :         PTR_SET(*encoded, NULL);
     517           0 :         *encoded_len = 0;
     518           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to update deflate stream: %s", zError(status));
     519           0 :         return FAILURE;
     520             : }
     521             : 
     522          39 : static STATUS inflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
     523             : {
     524             :         int status;
     525          39 :         z_streamp ctx = s->ctx;
     526             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     527             :         
     528             :         /* append input to buffer */
     529          39 :         php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
     530             : 
     531             : retry_raw_inflate:
     532          39 :         ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
     533          39 :         ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
     534             :         
     535          39 :         switch (status = php_http_inflate_rounds(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) {
     536             :                 case Z_OK:
     537             :                 case Z_STREAM_END:
     538             :                         /* cut off */
     539          39 :                         if (ctx->avail_in) {
     540           0 :                                 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
     541             :                         } else {
     542          39 :                                 php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
     543             :                         }
     544          39 :                         return SUCCESS;
     545             :                 
     546             :                 case Z_DATA_ERROR:
     547             :                         /* raw deflated data ? */
     548           0 :                         if (!(s->flags & PHP_HTTP_INFLATE_TYPE_RAW) && !ctx->total_out) {
     549           0 :                                 inflateEnd(ctx);
     550           0 :                                 s->flags |= PHP_HTTP_INFLATE_TYPE_RAW;
     551           0 :                                 inflateInit2(ctx, PHP_HTTP_WINDOW_BITS_RAW);
     552           0 :                                 goto retry_raw_inflate;
     553             :                         }
     554           0 :                         break;
     555             :         }
     556             :         
     557           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to update inflate stream: %s", zError(status));
     558           0 :         return FAILURE;
     559             : }
     560             : 
     561          66 : static STATUS dechunk_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
     562             : {
     563             :         php_http_buffer_t tmp;
     564          66 :         struct dechunk_ctx *ctx = s->ctx;
     565             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     566             : 
     567          66 :         if (ctx->zeroed) {
     568           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dechunk encoding stream has already reached the end of chunked input");
     569           0 :                 return FAILURE;
     570             :         }
     571          66 :         if ((PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(&ctx->buffer, data, data_len)) || !php_http_buffer_fix(&ctx->buffer)) {
     572             :                 /* OOM */
     573           0 :                 return FAILURE;
     574             :         }
     575             : 
     576          66 :         *decoded = NULL;
     577          66 :         *decoded_len = 0;
     578             : 
     579          66 :         php_http_buffer_init(&tmp);
     580             : 
     581             :         /* we have data in our buffer */
     582          66 :         while (ctx->buffer.used) {
     583             : 
     584             :                 /* we already know the size of the chunk and are waiting for data */
     585          98 :                 if (ctx->hexlen) {
     586             : 
     587             :                         /* not enough data buffered */
     588          32 :                         if (ctx->buffer.used < ctx->hexlen) {
     589             : 
     590             :                                 /* flush anyway? */
     591           0 :                                 if (s->flags & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) {
     592             :                                         /* flush all data (should only be chunk data) */
     593           0 :                                         php_http_buffer_append(&tmp, ctx->buffer.data, ctx->buffer.used);
     594             :                                         /* waiting for less data now */
     595           0 :                                         ctx->hexlen -= ctx->buffer.used;
     596             :                                         /* no more buffered data */
     597           0 :                                         php_http_buffer_reset(&ctx->buffer);
     598             :                                         /* break */
     599             :                                 }
     600             : 
     601             :                                 /* we have too less data and don't need to flush */
     602             :                                 else {
     603           0 :                                         break;
     604             :                                 }
     605             :                         }
     606             : 
     607             :                         /* we seem to have all data of the chunk */
     608             :                         else {
     609          32 :                                 php_http_buffer_append(&tmp, ctx->buffer.data, ctx->hexlen);
     610             :                                 /* remove outgoing data from the buffer */
     611          32 :                                 php_http_buffer_cut(&ctx->buffer, 0, ctx->hexlen);
     612             :                                 /* reset hexlen */
     613          32 :                                 ctx->hexlen = 0;
     614             :                                 /* continue */
     615             :                         }
     616             :                 }
     617             : 
     618             :                 /* we don't know the length of the chunk yet */
     619             :                 else {
     620          66 :                         size_t off = 0;
     621             : 
     622             :                         /* ignore preceeding CRLFs (too loose?) */
     623         285 :                         while (off < ctx->buffer.used && (
     624         158 :                                         ctx->buffer.data[off] == '\n' ||
     625          63 :                                         ctx->buffer.data[off] == '\r')) {
     626          58 :                                 ++off;
     627             :                         }
     628          66 :                         if (off) {
     629          32 :                                 php_http_buffer_cut(&ctx->buffer, 0, off);
     630             :                         }
     631             : 
     632             :                         /* still data there? */
     633          66 :                         if (ctx->buffer.used) {
     634             :                                 int eollen;
     635             :                                 const char *eolstr;
     636             : 
     637             :                                 /* we need eol, so we can be sure we have all hex digits */
     638          37 :                                 php_http_buffer_fix(&ctx->buffer);
     639          37 :                                 if ((eolstr = php_http_locate_bin_eol(ctx->buffer.data, ctx->buffer.used, &eollen))) {
     640          37 :                                         char *stop = NULL;
     641             : 
     642             :                                         /* read in chunk size */
     643          37 :                                         ctx->hexlen = strtoul(ctx->buffer.data, &stop, 16);
     644             : 
     645             :                                         /*      if strtoul() stops at the beginning of the buffered data
     646             :                                                 there's something oddly wrong, i.e. bad input */
     647          37 :                                         if (stop == ctx->buffer.data) {
     648           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse chunk len from '%.*s'", (int) MIN(16, ctx->buffer.used), ctx->buffer.data);
     649           0 :                                                 php_http_buffer_dtor(&tmp);
     650           0 :                                                 return FAILURE;
     651             :                                         }
     652             : 
     653             :                                         /* cut out <chunk size hex><chunk extension><eol> */
     654          37 :                                         php_http_buffer_cut(&ctx->buffer, 0, eolstr + eollen - ctx->buffer.data);
     655             :                                         /* buffer->hexlen is 0 now or contains the size of the next chunk */
     656          37 :                                         if (!ctx->hexlen) {
     657           5 :                                                 size_t off = 0;
     658             : 
     659             :                                                 /* ignore following CRLFs (too loose?) */
     660          14 :                                                 while (off < ctx->buffer.used && (
     661           2 :                                                                 ctx->buffer.data[off] == '\n' ||
     662           0 :                                                                 ctx->buffer.data[off] == '\r')) {
     663           2 :                                                         ++off;
     664             :                                                 }
     665           5 :                                                 if (off) {
     666           2 :                                                         php_http_buffer_cut(&ctx->buffer, 0, off);
     667             :                                                 }
     668             : 
     669           5 :                                                 ctx->zeroed = 1;
     670           5 :                                                 break;
     671             :                                         }
     672             :                                         /* continue */
     673             :                                 } else {
     674             :                                         /* we have not enough data buffered to read in chunk size */
     675           0 :                                         break;
     676             :                                 }
     677             :                         }
     678             :                         /* break */
     679             :                 }
     680             :         }
     681             : 
     682          66 :         php_http_buffer_fix(&tmp);
     683          66 :         *decoded = tmp.data;
     684          66 :         *decoded_len = tmp.used;
     685             : 
     686          66 :         return SUCCESS;
     687             : }
     688             : 
     689          51 : static STATUS deflate_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
     690             : {
     691             :         int status;
     692          51 :         z_streamp ctx = s->ctx;
     693             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     694             :         
     695          51 :         *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
     696          51 :         *encoded = emalloc(*encoded_len);
     697             :         
     698          51 :         ctx->avail_in = 0;
     699          51 :         ctx->next_in = NULL;
     700          51 :         ctx->avail_out = *encoded_len;
     701          51 :         ctx->next_out = (Bytef *) *encoded;
     702             :         
     703          51 :         switch (status = deflate(ctx, Z_FULL_FLUSH)) {
     704             :                 case Z_OK:
     705             :                 case Z_STREAM_END:
     706          51 :                         *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE - ctx->avail_out;
     707          51 :                         *encoded = erealloc(*encoded, *encoded_len + 1);
     708          51 :                         (*encoded)[*encoded_len] = '\0';
     709          51 :                         return SUCCESS;
     710             :         }
     711             :         
     712           0 :         PTR_SET(*encoded, NULL);
     713           0 :         *encoded_len = 0;
     714           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to flush deflate stream: %s", zError(status));
     715           0 :         return FAILURE;
     716             : }
     717             : 
     718          52 : static STATUS dechunk_flush(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
     719             : {
     720          52 :         struct dechunk_ctx *ctx = s->ctx;
     721             : 
     722          52 :         if (ctx->hexlen) {
     723             :                 /* flush all data (should only be chunk data) */
     724          13 :                 php_http_buffer_fix(&ctx->buffer);
     725          13 :                 php_http_buffer_data(&ctx->buffer, decoded, decoded_len);
     726             :                 /* waiting for less data now */
     727          13 :                 ctx->hexlen -= ctx->buffer.used;
     728             :                 /* no more buffered data */
     729          13 :                 php_http_buffer_reset(&ctx->buffer);
     730             :         } else {
     731          39 :                 *decoded = NULL;
     732          39 :                 *decoded_len = 0;
     733             :         }
     734             : 
     735          52 :         return SUCCESS;
     736             : }
     737             : 
     738           8 : static STATUS deflate_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
     739             : {
     740             :         int status;
     741           8 :         z_streamp ctx = s->ctx;
     742             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     743             :         
     744           8 :         *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
     745           8 :         *encoded = emalloc(*encoded_len);
     746             :         
     747             :         /* deflate remaining input */
     748           8 :         ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
     749           8 :         ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
     750             :         
     751           8 :         ctx->avail_out = *encoded_len;
     752           8 :         ctx->next_out = (Bytef *) *encoded;
     753             :         
     754             :         do {
     755           8 :                 status = deflate(ctx, Z_FINISH);
     756           8 :         } while (Z_OK == status);
     757             :         
     758           8 :         if (Z_STREAM_END == status) {
     759             :                 /* cut processed input off */
     760           8 :                 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
     761             :                 
     762             :                 /* size down */
     763           8 :                 *encoded_len -= ctx->avail_out;
     764           8 :                 *encoded = erealloc(*encoded, *encoded_len + 1);
     765           8 :                 (*encoded)[*encoded_len] = '\0';
     766           8 :                 return SUCCESS;
     767             :         }
     768             :         
     769           0 :         PTR_SET(*encoded, NULL);
     770           0 :         *encoded_len = 0;
     771           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish deflate stream: %s", zError(status));
     772           0 :         return FAILURE;
     773             : }
     774             : 
     775           4 : static STATUS inflate_finish(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
     776             : {
     777             :         int status;
     778           4 :         z_streamp ctx = s->ctx;
     779             :         TSRMLS_FETCH_FROM_CTX(s->ts);
     780             :         
     781           4 :         if (!PHP_HTTP_BUFFER(ctx->opaque)->used) {
     782           4 :                 *decoded = NULL;
     783           4 :                 *decoded_len = 0;
     784           4 :                 return SUCCESS;
     785             :         }
     786             :         
     787           0 :         *decoded_len = (PHP_HTTP_BUFFER(ctx->opaque)->used + 1) * PHP_HTTP_INFLATE_ROUNDS;
     788           0 :         *decoded = emalloc(*decoded_len);
     789             :         
     790             :         /* inflate remaining input */
     791           0 :         ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
     792           0 :         ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
     793             :         
     794           0 :         ctx->avail_out = *decoded_len;
     795           0 :         ctx->next_out = (Bytef *) *decoded;
     796             :         
     797           0 :         if (Z_STREAM_END == (status = inflate(ctx, Z_FINISH))) {
     798             :                 /* cut processed input off */
     799           0 :                 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
     800             :                 
     801             :                 /* size down */
     802           0 :                 *decoded_len -= ctx->avail_out;
     803           0 :                 *decoded = erealloc(*decoded, *decoded_len + 1);
     804           0 :                 (*decoded)[*decoded_len] = '\0';
     805           0 :                 return SUCCESS;
     806             :         }
     807             :         
     808           0 :         PTR_SET(*decoded, NULL);
     809           0 :         *decoded_len = 0;
     810           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish inflate stream: %s", zError(status));
     811           0 :         return FAILURE;
     812             : }
     813             : 
     814          30 : static zend_bool deflate_done(php_http_encoding_stream_t *s)
     815             : {
     816          30 :         z_streamp ctx = s->ctx;
     817          30 :         return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
     818             : }
     819             : 
     820           1 : static zend_bool inflate_done(php_http_encoding_stream_t *s)
     821             : {
     822           1 :         z_streamp ctx = s->ctx;
     823           1 :         return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
     824             : }
     825             : 
     826          40 : static zend_bool dechunk_done(php_http_encoding_stream_t *s)
     827             : {
     828          40 :         return ((struct dechunk_ctx *) s->ctx)->zeroed;
     829             : }
     830             : 
     831          38 : static void deflate_dtor(php_http_encoding_stream_t *s)
     832             : {
     833          38 :         if (s->ctx) {
     834          38 :                 z_streamp ctx = s->ctx;
     835             : 
     836          38 :                 if (ctx->opaque) {
     837          38 :                         php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
     838             :                 }
     839          38 :                 deflateEnd(ctx);
     840          38 :                 pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     841          38 :                 s->ctx = NULL;
     842             :         }
     843          38 : }
     844             : 
     845          35 : static void inflate_dtor(php_http_encoding_stream_t *s)
     846             : {
     847          35 :         if (s->ctx) {
     848          35 :                 z_streamp ctx = s->ctx;
     849             : 
     850          35 :                 if (ctx->opaque) {
     851          35 :                         php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
     852             :                 }
     853          35 :                 inflateEnd(ctx);
     854          35 :                 pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     855          35 :                 s->ctx = NULL;
     856             :         }
     857          35 : }
     858             : 
     859          37 : static void dechunk_dtor(php_http_encoding_stream_t *s)
     860             : {
     861          37 :         if (s->ctx) {
     862          33 :                 struct dechunk_ctx *ctx = s->ctx;
     863             : 
     864          33 :                 php_http_buffer_dtor(&ctx->buffer);
     865          33 :                 pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
     866          33 :                 s->ctx = NULL;
     867             :         }
     868          37 : }
     869             : 
     870             : static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops = {
     871             :         deflate_init,
     872             :         deflate_copy,
     873             :         deflate_update,
     874             :         deflate_flush,
     875             :         deflate_done,
     876             :         deflate_finish,
     877             :         deflate_dtor
     878             : };
     879             : 
     880           4 : php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void)
     881             : {
     882           4 :         return &php_http_encoding_deflate_ops;
     883             : }
     884             : 
     885             : static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops = {
     886             :         inflate_init,
     887             :         inflate_copy,
     888             :         inflate_update,
     889             :         NULL,
     890             :         inflate_done,
     891             :         inflate_finish,
     892             :         inflate_dtor
     893             : };
     894             : 
     895           3 : php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void)
     896             : {
     897           3 :         return &php_http_encoding_inflate_ops;
     898             : }
     899             : 
     900             : static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops = {
     901             :         dechunk_init,
     902             :         dechunk_copy,
     903             :         dechunk_update,
     904             :         dechunk_flush,
     905             :         dechunk_done,
     906             :         NULL,
     907             :         dechunk_dtor
     908             : };
     909             : 
     910           4 : php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void)
     911             : {
     912           4 :         return &php_http_encoding_dechunk_ops;
     913             : }
     914             : 
     915             : static zend_object_handlers php_http_encoding_stream_object_handlers;
     916             : 
     917          14 : zend_object_value php_http_encoding_stream_object_new(zend_class_entry *ce TSRMLS_DC)
     918             : {
     919          14 :         return php_http_encoding_stream_object_new_ex(ce, NULL, NULL TSRMLS_CC);
     920             : }
     921             : 
     922          90 : zend_object_value php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s, php_http_encoding_stream_object_t **ptr TSRMLS_DC)
     923             : {
     924             :         php_http_encoding_stream_object_t *o;
     925             : 
     926          90 :         o = ecalloc(1, sizeof(*o));
     927          90 :         zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
     928          90 :         object_properties_init((zend_object *) o, ce);
     929             : 
     930          90 :         if (ptr) {
     931          76 :                 *ptr = o;
     932             :         }
     933             : 
     934          90 :         if (s) {
     935          76 :                 o->stream = s;
     936             :         }
     937             : 
     938          90 :         o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_encoding_stream_object_free, NULL TSRMLS_CC);
     939          90 :         o->zv.handlers = &php_http_encoding_stream_object_handlers;
     940             : 
     941          90 :         return o->zv;
     942             : }
     943             : 
     944          76 : zend_object_value php_http_encoding_stream_object_clone(zval *this_ptr TSRMLS_DC)
     945             : {
     946             :         zend_object_value new_ov;
     947          76 :         php_http_encoding_stream_object_t *new_obj = NULL, *old_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     948             : 
     949          76 :         new_ov = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, php_http_encoding_stream_copy(old_obj->stream, NULL), &new_obj TSRMLS_CC);
     950          76 :         zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
     951             : 
     952          76 :         return new_ov;
     953             : }
     954             : 
     955          90 : void php_http_encoding_stream_object_free(void *object TSRMLS_DC)
     956             : {
     957          90 :         php_http_encoding_stream_object_t *o = (php_http_encoding_stream_object_t *) object;
     958             : 
     959          90 :         if (o->stream) {
     960          87 :                 php_http_encoding_stream_free(&o->stream);
     961             :         }
     962          90 :         zend_object_std_dtor((zend_object *) o TSRMLS_CC);
     963          90 :         efree(o);
     964          90 : }
     965             : 
     966             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream___construct, 0, 0, 0)
     967             :         ZEND_ARG_INFO(0, flags)
     968             : ZEND_END_ARG_INFO();
     969          11 : static PHP_METHOD(HttpEncodingStream, __construct)
     970             : {
     971          11 :         long flags = 0;
     972             :         php_http_encoding_stream_object_t *obj;
     973             :         php_http_encoding_stream_ops_t *ops;
     974             : 
     975          11 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags), invalid_arg, return);
     976             : 
     977          11 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     978             : 
     979          11 :         if (obj->stream) {
     980           0 :                 php_http_throw(bad_method_call, "http\\Encoding\\Stream cannot be initialized twice", NULL);
     981           0 :                 return;
     982             :         }
     983             : 
     984          11 :         if (instanceof_function(obj->zo.ce, php_http_deflate_stream_class_entry TSRMLS_CC)) {
     985           5 :                 ops = &php_http_encoding_deflate_ops;
     986           6 :         } else if (instanceof_function(obj->zo.ce, php_http_inflate_stream_class_entry TSRMLS_CC)) {
     987           4 :                 ops = &php_http_encoding_inflate_ops;
     988           2 :         } else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry TSRMLS_CC)) {
     989           2 :                 ops = &php_http_encoding_dechunk_ops;
     990             :         } else {
     991           0 :                 php_http_throw(runtime, "Unknown http\\Encoding\\Stream class '%s'", obj->zo.ce->name);
     992           0 :                 return;
     993             :         }
     994             : 
     995          11 :         php_http_expect(obj->stream = php_http_encoding_stream_init(obj->stream, ops, flags TSRMLS_CC), runtime, return);
     996             : }
     997             : 
     998             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_update, 0, 0, 1)
     999             :         ZEND_ARG_INFO(0, data)
    1000             : ZEND_END_ARG_INFO();
    1001         145 : static PHP_METHOD(HttpEncodingStream, update)
    1002             : {
    1003             :         int data_len;
    1004             :         char *data_str;
    1005             : 
    1006         145 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len)) {
    1007         145 :                 php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
    1008             : 
    1009         145 :                 if (obj->stream) {
    1010             :                         size_t encoded_len;
    1011             :                         char *encoded_str;
    1012             : 
    1013         145 :                         if (SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len)) {
    1014         145 :                                 RETURN_STRINGL(encoded_str, encoded_len, 0);
    1015             :                         }
    1016             :                 }
    1017             :         }
    1018             : }
    1019             : 
    1020             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush, 0, 0, 0)
    1021             : ZEND_END_ARG_INFO();
    1022         140 : static PHP_METHOD(HttpEncodingStream, flush)
    1023             : {
    1024         140 :         if (SUCCESS == zend_parse_parameters_none()) {
    1025         140 :                 php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
    1026             : 
    1027         140 :                 if (obj->stream) {
    1028             :                         char *encoded_str;
    1029             :                         size_t encoded_len;
    1030             : 
    1031         140 :                         if (SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len)) {
    1032         140 :                                 if (encoded_str) {
    1033         182 :                                         RETURN_STRINGL(encoded_str, encoded_len, 0);
    1034             :                                 } else {
    1035          98 :                                         RETURN_EMPTY_STRING();
    1036             :                                 }
    1037             :                         }
    1038             :                 }
    1039             :         }
    1040             : }
    1041             : 
    1042             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done, 0, 0, 0)
    1043             : ZEND_END_ARG_INFO();
    1044          58 : static PHP_METHOD(HttpEncodingStream, done)
    1045             : {
    1046          58 :         if (SUCCESS == zend_parse_parameters_none()) {
    1047          58 :                 php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
    1048             : 
    1049          58 :                 if (obj->stream) {
    1050          58 :                         RETURN_BOOL(php_http_encoding_stream_done(obj->stream));
    1051             :                 }
    1052             :         }
    1053             : }
    1054             : 
    1055             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish, 0, 0, 0)
    1056             : ZEND_END_ARG_INFO();
    1057           8 : static PHP_METHOD(HttpEncodingStream, finish)
    1058             : {
    1059           8 :         if (SUCCESS == zend_parse_parameters_none()) {
    1060           8 :                 php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
    1061             : 
    1062           8 :                 if (obj->stream) {
    1063             :                         char *encoded_str;
    1064             :                         size_t encoded_len;
    1065             : 
    1066           8 :                         if (SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len)) {
    1067           8 :                                 if (SUCCESS == php_http_encoding_stream_reset(&obj->stream)) {
    1068           8 :                                         if (encoded_str) {
    1069          12 :                                                 RETURN_STRINGL(encoded_str, encoded_len, 0);
    1070             :                                         } else {
    1071           4 :                                                 RETURN_EMPTY_STRING();
    1072             :                                         }
    1073             :                                 } else {
    1074           0 :                                         PTR_FREE(encoded_str);
    1075             :                                 }
    1076             :                         }
    1077             :                 }
    1078             :         }
    1079             : }
    1080             : 
    1081             : static zend_function_entry php_http_encoding_stream_methods[] = {
    1082             :         PHP_ME(HttpEncodingStream, __construct,  ai_HttpEncodingStream___construct,  ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
    1083             :         PHP_ME(HttpEncodingStream, update,       ai_HttpEncodingStream_update,       ZEND_ACC_PUBLIC)
    1084             :         PHP_ME(HttpEncodingStream, flush,        ai_HttpEncodingStream_flush,        ZEND_ACC_PUBLIC)
    1085             :         PHP_ME(HttpEncodingStream, done,         ai_HttpEncodingStream_done,         ZEND_ACC_PUBLIC)
    1086             :         PHP_ME(HttpEncodingStream, finish,       ai_HttpEncodingStream_finish,       ZEND_ACC_PUBLIC)
    1087             :         EMPTY_FUNCTION_ENTRY
    1088             : };
    1089             : 
    1090             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpDeflateStream_encode, 0, 0, 1)
    1091             :         ZEND_ARG_INFO(0, data)
    1092             :         ZEND_ARG_INFO(0, flags)
    1093             : ZEND_END_ARG_INFO();
    1094           3 : static PHP_METHOD(HttpDeflateStream, encode)
    1095             : {
    1096             :         char *str;
    1097             :         int len;
    1098           3 :         long flags = 0;
    1099             : 
    1100           3 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &len, &flags)) {
    1101             :                 char *enc_str;
    1102             :                 size_t enc_len;
    1103             : 
    1104           3 :                 if (SUCCESS == php_http_encoding_deflate(flags, str, len, &enc_str, &enc_len TSRMLS_CC)) {
    1105           3 :                         RETURN_STRINGL(enc_str, enc_len, 0);
    1106             :                 }
    1107             :         }
    1108           0 :         RETURN_FALSE;
    1109             : }
    1110             : 
    1111             : static zend_function_entry php_http_deflate_stream_methods[] = {
    1112             :         PHP_ME(HttpDeflateStream, encode, ai_HttpDeflateStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
    1113             :         EMPTY_FUNCTION_ENTRY
    1114             : };
    1115             : 
    1116             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpInflateStream_decode, 0, 0, 1)
    1117             :         ZEND_ARG_INFO(0, data)
    1118             : ZEND_END_ARG_INFO();
    1119           5 : static PHP_METHOD(HttpInflateStream, decode)
    1120             : {
    1121             :         char *str;
    1122             :         int len;
    1123             : 
    1124           5 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
    1125             :                 char *enc_str;
    1126             :                 size_t enc_len;
    1127             : 
    1128           5 :                 if (SUCCESS == php_http_encoding_inflate(str, len, &enc_str, &enc_len TSRMLS_CC)) {
    1129           4 :                         RETURN_STRINGL(enc_str, enc_len, 0);
    1130             :                 }
    1131             :         }
    1132           1 :         RETURN_FALSE;
    1133             : }
    1134             : 
    1135             : static zend_function_entry php_http_inflate_stream_methods[] = {
    1136             :         PHP_ME(HttpInflateStream, decode, ai_HttpInflateStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
    1137             :         EMPTY_FUNCTION_ENTRY
    1138             : };
    1139             : 
    1140             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpDechunkStream_decode, 0, 0, 1)
    1141             :         ZEND_ARG_INFO(0, data)
    1142             :         ZEND_ARG_INFO(1, decoded_len)
    1143             : ZEND_END_ARG_INFO();
    1144           5 : static PHP_METHOD(HttpDechunkStream, decode)
    1145             : {
    1146             :         char *str;
    1147             :         int len;
    1148           5 :         zval *zlen = NULL;
    1149             : 
    1150           5 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!", &str, &len, &zlen)) {
    1151             :                 const char *end_ptr;
    1152             :                 char *enc_str;
    1153             :                 size_t enc_len;
    1154             : 
    1155           5 :                 if ((end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len TSRMLS_CC))) {
    1156           4 :                         if (zlen) {
    1157           0 :                                 zval_dtor(zlen);
    1158           0 :                                 ZVAL_LONG(zlen, str + len - end_ptr);
    1159             :                         }
    1160           4 :                         RETURN_STRINGL(enc_str, enc_len, 0);
    1161             :                 }
    1162             :         }
    1163           1 :         RETURN_FALSE;
    1164             : }
    1165             : 
    1166             : static zend_function_entry php_http_dechunk_stream_methods[] = {
    1167             :         PHP_ME(HttpDechunkStream, decode, ai_HttpDechunkStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
    1168             :         EMPTY_FUNCTION_ENTRY
    1169             : };
    1170             : 
    1171             : zend_class_entry *php_http_encoding_stream_class_entry;
    1172             : zend_class_entry *php_http_deflate_stream_class_entry;
    1173             : zend_class_entry *php_http_inflate_stream_class_entry;
    1174             : zend_class_entry *php_http_dechunk_stream_class_entry;
    1175             : 
    1176         374 : PHP_MINIT_FUNCTION(http_encoding)
    1177             : {
    1178         374 :         zend_class_entry ce = {0};
    1179             : 
    1180         374 :         INIT_NS_CLASS_ENTRY(ce, "http\\Encoding", "Stream", php_http_encoding_stream_methods);
    1181         374 :         php_http_encoding_stream_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
    1182         374 :         php_http_encoding_stream_class_entry->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
    1183         374 :         php_http_encoding_stream_class_entry->create_object = php_http_encoding_stream_object_new;
    1184         374 :         memcpy(&php_http_encoding_stream_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    1185         374 :         php_http_encoding_stream_object_handlers.clone_obj = php_http_encoding_stream_object_clone;
    1186             : 
    1187         374 :         zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC);
    1188         374 :         zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC);
    1189         374 :         zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC);
    1190             : 
    1191         374 :         memset(&ce, 0, sizeof(ce));
    1192         374 :         INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Deflate", php_http_deflate_stream_methods);
    1193         374 :         php_http_deflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry, NULL TSRMLS_CC);
    1194             : 
    1195         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC);
    1196         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC);
    1197         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW TSRMLS_CC);
    1198         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF TSRMLS_CC);
    1199         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN TSRMLS_CC);
    1200         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX TSRMLS_CC);
    1201         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF TSRMLS_CC);
    1202         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT TSRMLS_CC);
    1203         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF TSRMLS_CC);
    1204         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE TSRMLS_CC);
    1205         374 :         zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED TSRMLS_CC);
    1206             : 
    1207         374 :         memset(&ce, 0, sizeof(ce));
    1208         374 :         INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Inflate", php_http_inflate_stream_methods);
    1209         374 :         php_http_inflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry, NULL TSRMLS_CC);
    1210             : 
    1211         374 :         memset(&ce, 0, sizeof(ce));
    1212         374 :         INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods);
    1213         374 :         php_http_dechunk_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry, NULL TSRMLS_CC);
    1214             : 
    1215         374 :         return SUCCESS;
    1216             : }
    1217             : 
    1218             : 
    1219             : /*
    1220             :  * Local variables:
    1221             :  * tab-width: 4
    1222             :  * c-basic-offset: 4
    1223             :  * End:
    1224             :  * vim600: noet sw=4 ts=4 fdm=marker
    1225             :  * vim<600: noet sw=4 ts=4
    1226             :  */
    1227             : 

Generated by: LCOV version 1.11