2 +--------------------------------------------------------------------+
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-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 /* $Id: http_encoding_api.c 298592 2010-04-26 11:47:29Z mike $ */
19 static inline int eol_match(char **line
, int *eol_len
)
23 while (' ' == *ptr
) ++ptr
;
25 if (ptr
== php_http_locate_eol(*line
, eol_len
)) {
33 PHP_HTTP_API
const char *php_http_encoding_dechunk(const char *encoded
, size_t encoded_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
37 const char *e_ptr
= encoded
;
40 *decoded
= ecalloc(1, encoded_len
);
42 while ((encoded
+ encoded_len
- e_ptr
) > 0) {
43 ulong chunk_len
= 0, rest
;
45 chunk_len
= strtoul(e_ptr
, &n_ptr
, 16);
47 /* we could not read in chunk size */
50 * if this is the first turn and there doesn't seem to be a chunk
51 * size at the begining of the body, do not fail on apparently
52 * not encoded data and return a copy
54 if (e_ptr
== encoded
) {
55 php_http_error(HE_NOTICE
, PHP_HTTP_E_ENCODING
, "Data does not seem to be chunked encoded");
56 memcpy(*decoded
, encoded
, encoded_len
);
57 *decoded_len
= encoded_len
;
58 return encoded
+ encoded_len
;
61 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Expected chunk size at pos %tu of %zu but got trash", n_ptr
- encoded
, encoded_len
);
68 /* move over '0' chunked encoding terminator and any new lines */
81 /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
82 if (*n_ptr
&& !eol_match(&n_ptr
, &eol_len
)) {
84 php_http_error(HE_WARNING
, PHP_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));
86 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr
- encoded
, encoded_len
, *n_ptr
);
91 /* chunk size pretends more data than we actually got, so it's probably a truncated message */
92 if (chunk_len
> (rest
= encoded
+ encoded_len
- n_ptr
)) {
93 php_http_error(HE_WARNING
, PHP_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
);
98 memcpy(*decoded
+ *decoded_len
, n_ptr
, chunk_len
);
99 *decoded_len
+= chunk_len
;
101 if (chunk_len
== rest
) {
102 e_ptr
= n_ptr
+ chunk_len
;
105 /* advance to next chunk */
106 e_ptr
= n_ptr
+ chunk_len
+ eol_len
;
113 static inline int php_http_inflate_rounds(z_stream
*Z
, int flush
, char **buf
, size_t *len
)
115 int status
= 0, round
= 0;
116 php_http_buffer_t buffer
;
121 php_http_buffer_init_ex(&buffer
, Z
->avail_in
, PHP_HTTP_BUFFER_INIT_PREALLOC
);
124 if (PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_resize_ex(&buffer
, buffer
.size
, 0, 1)) {
125 status
= Z_MEM_ERROR
;
127 Z
->avail_out
= buffer
.free
;
128 Z
->next_out
= (Bytef
*) buffer
.data
+ buffer
.used
;
130 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
);
132 status
= inflate(Z
, flush
);
134 buffer
.used
+= buffer
.free
- Z
->avail_out
;
135 buffer
.free
= Z
->avail_out
;
137 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
);
139 PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer
.size
);
141 } while ((Z_BUF_ERROR
== status
|| (Z_OK
== status
&& Z
->avail_in
)) && ++round
< PHP_HTTP_INFLATE_ROUNDS
);
143 if (status
== Z_OK
|| status
== Z_STREAM_END
) {
144 php_http_buffer_shrink(&buffer
);
145 php_http_buffer_fix(&buffer
);
149 php_http_buffer_dtor(&buffer
);
155 PHP_HTTP_API STATUS
php_http_encoding_deflate(int flags
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
157 int status
, level
, wbits
, strategy
;
160 PHP_HTTP_DEFLATE_LEVEL_SET(flags
, level
);
161 PHP_HTTP_DEFLATE_WBITS_SET(flags
, wbits
);
162 PHP_HTTP_DEFLATE_STRATEGY_SET(flags
, strategy
);
164 memset(&Z
, 0, sizeof(z_stream
));
168 status
= deflateInit2(&Z
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
);
169 if (Z_OK
== status
) {
170 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len
);
171 *encoded
= emalloc(*encoded_len
);
173 Z
.next_in
= (Bytef
*) data
;
174 Z
.next_out
= (Bytef
*) *encoded
;
175 Z
.avail_in
= data_len
;
176 Z
.avail_out
= *encoded_len
;
178 status
= deflate(&Z
, Z_FINISH
);
181 if (Z_STREAM_END
== status
) {
182 /* size buffer down to actual length */
183 *encoded
= erealloc(*encoded
, Z
.total_out
+ 1);
184 (*encoded
)[*encoded_len
= Z
.total_out
] = '\0';
187 STR_SET(*encoded
, NULL
);
192 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Could not deflate data: %s", zError(status
));
196 PHP_HTTP_API STATUS
php_http_encoding_inflate(const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
199 int status
, wbits
= PHP_HTTP_WINDOW_BITS_ANY
;
201 memset(&Z
, 0, sizeof(z_stream
));
204 status
= inflateInit2(&Z
, wbits
);
205 if (Z_OK
== status
) {
206 Z
.next_in
= (Bytef
*) data
;
207 Z
.avail_in
= data_len
;
209 switch (status
= php_http_inflate_rounds(&Z
, Z_NO_FLUSH
, decoded
, decoded_len
)) {
215 status
= Z_DATA_ERROR
;
219 /* raw deflated data? */
220 if (PHP_HTTP_WINDOW_BITS_ANY
== wbits
) {
222 wbits
= PHP_HTTP_WINDOW_BITS_RAW
;
223 goto retry_raw_inflate
;
228 if (decoded_len
&& *decoded
) {
233 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Could not inflate data: %s", zError(status
));
237 PHP_HTTP_API 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
)
242 s
= pemalloc(sizeof(*s
), (flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
244 memset(s
, 0, sizeof(*s
));
247 TSRMLS_SET_CTX(s
->ts
);
249 if ((s
->ops
= ops
)) {
250 php_http_encoding_stream_t
*ss
= s
->ops
->init(s
);
260 pefree(s
, (flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
265 PHP_HTTP_API php_http_encoding_stream_t
*php_http_encoding_stream_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
267 TSRMLS_FETCH_FROM_CTX(from
->ts
);
269 if (!from
->ops
->copy
) {
273 return from
->ops
->copy(from
, php_http_encoding_stream_init(to
, from
->ops
, from
->flags TSRMLS_CC
));
276 PHP_HTTP_API STATUS
php_http_encoding_stream_reset(php_http_encoding_stream_t
**s
)
278 php_http_encoding_stream_t
*ss
;
279 if ((*s
)->ops
->dtor
) {
282 if ((ss
= (*s
)->ops
->init(*s
))) {
289 PHP_HTTP_API 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
)
291 if (!s
->ops
->update
) {
294 return s
->ops
->update(s
, in_str
, in_len
, out_str
, out_len
);
297 PHP_HTTP_API STATUS
php_http_encoding_stream_flush(php_http_encoding_stream_t
*s
, char **out_str
, size_t *out_len
)
299 if (!s
->ops
->flush
) {
304 return s
->ops
->flush(s
, out_str
, out_len
);
307 PHP_HTTP_API zend_bool
php_http_encoding_stream_done(php_http_encoding_stream_t
*s
)
312 return s
->ops
->done(s
);
315 PHP_HTTP_API STATUS
php_http_encoding_stream_finish(php_http_encoding_stream_t
*s
, char **out_str
, size_t *out_len
)
317 if (!s
->ops
->finish
) {
322 return s
->ops
->finish(s
, out_str
, out_len
);
325 PHP_HTTP_API
void php_http_encoding_stream_dtor(php_http_encoding_stream_t
*s
)
332 PHP_HTTP_API
void php_http_encoding_stream_free(php_http_encoding_stream_t
**s
)
335 if ((*s
)->ops
->dtor
) {
338 pefree(*s
, ((*s
)->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
344 php_http_buffer_t buffer
;
349 static php_http_encoding_stream_t
*deflate_init(php_http_encoding_stream_t
*s
)
351 int status
, level
, wbits
, strategy
, p
= (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
);
352 z_streamp ctx
= pecalloc(1, sizeof(z_stream
), p
);
353 TSRMLS_FETCH_FROM_CTX(s
->ts
);
355 PHP_HTTP_DEFLATE_LEVEL_SET(s
->flags
, level
);
356 PHP_HTTP_DEFLATE_WBITS_SET(s
->flags
, wbits
);
357 PHP_HTTP_DEFLATE_STRATEGY_SET(s
->flags
, strategy
);
359 if (Z_OK
== (status
= deflateInit2(ctx
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
))) {
360 if ((ctx
->opaque
= php_http_buffer_init_ex(NULL
, PHP_HTTP_DEFLATE_BUFFER_SIZE
, p
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0))) {
365 status
= Z_MEM_ERROR
;
368 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to initialize deflate encoding stream: %s", zError(status
));
372 static php_http_encoding_stream_t
*inflate_init(php_http_encoding_stream_t
*s
)
374 int status
, wbits
, p
= (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
);
375 z_streamp ctx
= pecalloc(1, sizeof(z_stream
), p
);
376 TSRMLS_FETCH_FROM_CTX(s
->ts
);
378 PHP_HTTP_INFLATE_WBITS_SET(s
->flags
, wbits
);
380 if (Z_OK
== (status
= inflateInit2(ctx
, wbits
))) {
381 if ((ctx
->opaque
= php_http_buffer_init_ex(NULL
, PHP_HTTP_DEFLATE_BUFFER_SIZE
, p
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0))) {
386 status
= Z_MEM_ERROR
;
389 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to initialize inflate stream: %s", zError(status
));
393 static php_http_encoding_stream_t
*dechunk_init(php_http_encoding_stream_t
*s
)
395 struct dechunk_ctx
*ctx
= pecalloc(1, sizeof(*ctx
), (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
396 TSRMLS_FETCH_FROM_CTX(s
->ts
);
398 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)) {
409 static php_http_encoding_stream_t
*deflate_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
411 z_streamp from_ctx
= from
->ctx
, to_ctx
= to
->ctx
;
413 deflateCopy(to_ctx
, from_ctx
);
414 php_http_buffer_append(to_ctx
->opaque
, PHP_HTTP_BUFFER_VAL(from_ctx
->opaque
), PHP_HTTP_BUFFER_LEN(from_ctx
->opaque
));
419 static php_http_encoding_stream_t
*inflate_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
421 z_streamp from_ctx
= from
->ctx
, to_ctx
= to
->ctx
;
423 inflateCopy(to_ctx
, from_ctx
);
424 php_http_buffer_append(to_ctx
->opaque
, PHP_HTTP_BUFFER_VAL(from_ctx
->opaque
), PHP_HTTP_BUFFER_LEN(from_ctx
->opaque
));
429 static php_http_encoding_stream_t
*dechunk_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
431 struct dechunk_ctx
*from_ctx
= from
->ctx
, *to_ctx
= to
->ctx
;
433 to_ctx
->hexlen
= from_ctx
->hexlen
;
434 to_ctx
->zeroed
= from_ctx
->zeroed
;
435 php_http_buffer_append(&to_ctx
->buffer
, PHP_HTTP_BUFFER_VAL(&from_ctx
->buffer
), PHP_HTTP_BUFFER_LEN(&from_ctx
->buffer
));
440 static STATUS
deflate_update(php_http_encoding_stream_t
*s
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len
)
443 z_streamp ctx
= s
->ctx
;
444 TSRMLS_FETCH_FROM_CTX(s
->ts
);
446 /* append input to our buffer */
447 php_http_buffer_append(PHP_HTTP_BUFFER(ctx
->opaque
), data
, data_len
);
449 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER_VAL(ctx
->opaque
);
450 ctx
->avail_in
= PHP_HTTP_BUFFER_LEN(ctx
->opaque
);
453 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len
);
454 *encoded
= emalloc(*encoded_len
);
455 ctx
->avail_out
= *encoded_len
;
456 ctx
->next_out
= (Bytef
*) *encoded
;
458 switch (status
= deflate(ctx
, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s
->flags
))) {
461 /* cut processed chunk off the buffer */
463 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER_LEN(ctx
->opaque
) - ctx
->avail_in
);
465 php_http_buffer_reset(PHP_HTTP_BUFFER(ctx
->opaque
));
468 /* size buffer down to actual size */
469 *encoded_len
-= ctx
->avail_out
;
470 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
471 (*encoded
)[*encoded_len
] = '\0';
475 STR_SET(*encoded
, NULL
);
477 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to update deflate stream: %s", zError(status
));
481 static STATUS
inflate_update(php_http_encoding_stream_t
*s
, const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len
)
484 z_streamp ctx
= s
->ctx
;
485 TSRMLS_FETCH_FROM_CTX(s
->ts
);
487 /* append input to buffer */
488 php_http_buffer_append(PHP_HTTP_BUFFER(ctx
->opaque
), data
, data_len
);
491 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER_VAL(ctx
->opaque
);
492 ctx
->avail_in
= PHP_HTTP_BUFFER_LEN(ctx
->opaque
);
494 switch (status
= php_http_inflate_rounds(ctx
, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s
->flags
), decoded
, decoded_len
)) {
499 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER_LEN(ctx
->opaque
) - ctx
->avail_in
);
501 php_http_buffer_reset(PHP_HTTP_BUFFER(ctx
->opaque
));
506 /* raw deflated data ? */
507 if (!(s
->flags
& PHP_HTTP_INFLATE_TYPE_RAW
) && !ctx
->total_out
) {
509 s
->flags
|= PHP_HTTP_INFLATE_TYPE_RAW
;
510 inflateInit2(ctx
, PHP_HTTP_WINDOW_BITS_RAW
);
511 goto retry_raw_inflate
;
515 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to update inflate stream: %s", zError(status
));
519 static STATUS
dechunk_update(php_http_encoding_stream_t
*s
, const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len
)
521 php_http_buffer_t tmp
;
522 struct dechunk_ctx
*ctx
= s
->ctx
;
523 TSRMLS_FETCH_FROM_CTX(s
->ts
);
526 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Dechunk encoding stream has already reached the end of chunked input");
529 if ((PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_append(&ctx
->buffer
, data
, data_len
)) || !php_http_buffer_fix(&ctx
->buffer
)) {
537 php_http_buffer_init(&tmp
);
539 /* we have data in our buffer */
540 while (PHP_HTTP_BUFFER_LEN(&ctx
->buffer
)) {
542 /* we already know the size of the chunk and are waiting for data */
545 /* not enough data buffered */
546 if (PHP_HTTP_BUFFER_LEN(&ctx
->buffer
) < ctx
->hexlen
) {
549 if (s
->flags
& PHP_HTTP_ENCODING_STREAM_FLUSH_FULL
) {
550 /* flush all data (should only be chunk data) */
551 php_http_buffer_append(&tmp
, PHP_HTTP_BUFFER_VAL(&ctx
->buffer
), PHP_HTTP_BUFFER_LEN(&ctx
->buffer
));
552 /* waiting for less data now */
553 ctx
->hexlen
-= PHP_HTTP_BUFFER_LEN(&ctx
->buffer
);
554 /* no more buffered data */
555 php_http_buffer_reset(&ctx
->buffer
);
559 /* we have too less data and don't need to flush */
565 /* we seem to have all data of the chunk */
567 php_http_buffer_append(&tmp
, PHP_HTTP_BUFFER_VAL(&ctx
->buffer
), ctx
->hexlen
);
568 /* remove outgoing data from the buffer */
569 php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx
->buffer
), 0, ctx
->hexlen
);
576 /* we don't know the length of the chunk yet */
580 /* ignore preceeding CRLFs (too loose?) */
581 while (off
< PHP_HTTP_BUFFER_LEN(&ctx
->buffer
) && (
582 PHP_HTTP_BUFFER_VAL(&ctx
->buffer
)[off
] == '\n' ||
583 PHP_HTTP_BUFFER_VAL(&ctx
->buffer
)[off
] == '\r')) {
587 php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx
->buffer
), 0, off
);
590 /* still data there? */
591 if (PHP_HTTP_BUFFER_LEN(&ctx
->buffer
)) {
595 /* we need eol, so we can be sure we have all hex digits */
596 php_http_buffer_fix(&ctx
->buffer
);
597 if ((eolstr
= php_http_locate_bin_eol(PHP_HTTP_BUFFER_VAL(&ctx
->buffer
), PHP_HTTP_BUFFER_LEN(&ctx
->buffer
), &eollen
))) {
600 /* read in chunk size */
601 ctx
->hexlen
= strtoul(PHP_HTTP_BUFFER_VAL(&ctx
->buffer
), &stop
, 16);
603 /* if strtoul() stops at the beginning of the buffered data
604 there's domething oddly wrong, i.e. bad input */
605 if (stop
== PHP_HTTP_BUFFER_VAL(&ctx
->buffer
)) {
606 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to parse chunk len from '%.*s'", MIN(16, ctx
->buffer
.used
), ctx
->buffer
.data
);
607 php_http_buffer_dtor(&tmp
);
611 /* cut out <chunk size hex><chunk extension><eol> */
612 php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx
->buffer
), 0, eolstr
+ eollen
- PHP_HTTP_BUFFER_VAL(&ctx
->buffer
));
613 /* buffer->hexlen is 0 now or contains the size of the next chunk */
617 /* ignore following CRLFs (too loose?) */
618 while (off
< PHP_HTTP_BUFFER_LEN(&ctx
->buffer
) && (
619 PHP_HTTP_BUFFER_VAL(&ctx
->buffer
)[off
] == '\n' ||
620 PHP_HTTP_BUFFER_VAL(&ctx
->buffer
)[off
] == '\r')) {
624 php_http_buffer_cut(PHP_HTTP_BUFFER(&ctx
->buffer
), 0, off
);
632 /* we have not enough data buffered to read in chunk size */
640 php_http_buffer_fix(&tmp
);
641 *decoded
= PHP_HTTP_BUFFER_VAL(&tmp
);
642 *decoded_len
= PHP_HTTP_BUFFER_LEN(&tmp
);
647 static STATUS
deflate_flush(php_http_encoding_stream_t
*s
, char **encoded
, size_t *encoded_len
)
650 z_streamp ctx
= s
->ctx
;
651 TSRMLS_FETCH_FROM_CTX(s
->ts
);
653 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE
;
654 *encoded
= emalloc(*encoded_len
);
658 ctx
->avail_out
= *encoded_len
;
659 ctx
->next_out
= (Bytef
*) *encoded
;
661 switch (status
= deflate(ctx
, Z_FULL_FLUSH
)) {
664 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE
- ctx
->avail_out
;
665 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
666 (*encoded
)[*encoded_len
] = '\0';
670 STR_SET(*encoded
, NULL
);
672 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to flush deflate stream: %s", zError(status
));
676 static STATUS
dechunk_flush(php_http_encoding_stream_t
*s
, char **decoded
, size_t *decoded_len
)
678 struct dechunk_ctx
*ctx
= s
->ctx
;
681 /* flush all data (should only be chunk data) */
682 php_http_buffer_fix(&ctx
->buffer
);
683 php_http_buffer_data(&ctx
->buffer
, decoded
, decoded_len
);
684 /* waiting for less data now */
685 ctx
->hexlen
-= PHP_HTTP_BUFFER_LEN(&ctx
->buffer
);
686 /* no more buffered data */
687 php_http_buffer_reset(&ctx
->buffer
);
696 static STATUS
deflate_finish(php_http_encoding_stream_t
*s
, char **encoded
, size_t *encoded_len
)
699 z_streamp ctx
= s
->ctx
;
700 TSRMLS_FETCH_FROM_CTX(s
->ts
);
702 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE
;
703 *encoded
= emalloc(*encoded_len
);
705 /* deflate remaining input */
706 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER_VAL(ctx
->opaque
);
707 ctx
->avail_in
= PHP_HTTP_BUFFER_LEN(ctx
->opaque
);
709 ctx
->avail_out
= *encoded_len
;
710 ctx
->next_out
= (Bytef
*) *encoded
;
713 status
= deflate(ctx
, Z_FINISH
);
714 } while (Z_OK
== status
);
716 if (Z_STREAM_END
== status
) {
717 /* cut processed intp off */
718 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER_LEN(ctx
->opaque
) - ctx
->avail_in
);
721 *encoded_len
-= ctx
->avail_out
;
722 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
723 (*encoded
)[*encoded_len
] = '\0';
727 STR_SET(*encoded
, NULL
);
729 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to finish deflate stream: %s", zError(status
));
733 static STATUS
inflate_finish(php_http_encoding_stream_t
*s
, char **decoded
, size_t *decoded_len
)
736 z_streamp ctx
= s
->ctx
;
737 TSRMLS_FETCH_FROM_CTX(s
->ts
);
739 if (!PHP_HTTP_BUFFER_LEN(ctx
->opaque
)) {
745 *decoded_len
= (PHP_HTTP_BUFFER_LEN(ctx
->opaque
) + 1) * PHP_HTTP_INFLATE_ROUNDS
;
746 *decoded
= emalloc(*decoded_len
);
748 /* inflate remaining input */
749 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER_VAL(ctx
->opaque
);
750 ctx
->avail_in
= PHP_HTTP_BUFFER_LEN(ctx
->opaque
);
752 ctx
->avail_out
= *decoded_len
;
753 ctx
->next_out
= (Bytef
*) *decoded
;
755 if (Z_STREAM_END
== (status
= inflate(ctx
, Z_FINISH
))) {
756 /* cut processed input off */
757 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER_LEN(ctx
->opaque
) - ctx
->avail_in
);
760 *decoded_len
-= ctx
->avail_out
;
761 *decoded
= erealloc(*decoded
, *decoded_len
+ 1);
762 (*decoded
)[*decoded_len
] = '\0';
766 STR_SET(*decoded
, NULL
);
768 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Failed to finish inflate stream: %s", zError(status
));
772 static zend_bool
deflate_done(php_http_encoding_stream_t
*s
)
774 z_streamp ctx
= s
->ctx
;
775 return !ctx
->avail_in
&& !PHP_HTTP_BUFFER_LEN(ctx
->opaque
);
778 static zend_bool
inflate_done(php_http_encoding_stream_t
*s
)
780 z_streamp ctx
= s
->ctx
;
781 return !ctx
->avail_in
&& !PHP_HTTP_BUFFER_LEN(ctx
->opaque
);
784 static zend_bool
dechunk_done(php_http_encoding_stream_t
*s
)
786 return ((struct dechunk_ctx
*) s
->ctx
)->zeroed
;
789 static void deflate_dtor(php_http_encoding_stream_t
*s
)
792 z_streamp ctx
= s
->ctx
;
795 php_http_buffer_free((php_http_buffer_t
**) &ctx
->opaque
);
798 pefree(ctx
, (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
803 static void inflate_dtor(php_http_encoding_stream_t
*s
)
806 z_streamp ctx
= s
->ctx
;
809 php_http_buffer_free((php_http_buffer_t
**) &ctx
->opaque
);
812 pefree(ctx
, (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
817 static void dechunk_dtor(php_http_encoding_stream_t
*s
)
820 struct dechunk_ctx
*ctx
= s
->ctx
;
822 php_http_buffer_dtor(&ctx
->buffer
);
823 pefree(ctx
, (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
828 static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops
= {
838 PHP_HTTP_API php_http_encoding_stream_ops_t
*php_http_encoding_stream_get_deflate_ops(void)
840 return &php_http_encoding_deflate_ops
;
843 static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops
= {
853 PHP_HTTP_API php_http_encoding_stream_ops_t
*php_http_encoding_stream_get_inflate_ops(void)
855 return &php_http_encoding_inflate_ops
;
858 static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops
= {
868 PHP_HTTP_API php_http_encoding_stream_ops_t
*php_http_encoding_stream_get_dechunk_ops(void)
870 return &php_http_encoding_dechunk_ops
;
873 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpEncodingStream, method, 0, req_args)
874 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpEncodingStream, method, 0)
875 #define PHP_HTTP_ENCSTREAM_ME(method, visibility) PHP_ME(HttpEncodingStream, method, PHP_HTTP_ARGS(HttpEncodingStream, method), visibility)
877 PHP_HTTP_BEGIN_ARGS(__construct
, 0)
878 PHP_HTTP_ARG_VAL(flags
, 0)
881 PHP_HTTP_BEGIN_ARGS(update
, 1)
882 PHP_HTTP_ARG_VAL(data
, 0)
885 PHP_HTTP_EMPTY_ARGS(flush
);
886 PHP_HTTP_EMPTY_ARGS(done
);
887 PHP_HTTP_EMPTY_ARGS(finish
);
889 zend_class_entry
*php_http_encoding_stream_class_entry
;
890 zend_function_entry php_http_encoding_stream_method_entry
[] = {
891 PHP_HTTP_ENCSTREAM_ME(__construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
892 PHP_HTTP_ENCSTREAM_ME(update
, ZEND_ACC_PUBLIC
)
893 PHP_HTTP_ENCSTREAM_ME(flush
, ZEND_ACC_PUBLIC
)
894 PHP_HTTP_ENCSTREAM_ME(done
, ZEND_ACC_PUBLIC
)
895 PHP_HTTP_ENCSTREAM_ME(finish
, ZEND_ACC_PUBLIC
)
899 static zend_object_handlers php_http_encoding_stream_object_handlers
;
901 zend_object_value
php_http_encoding_stream_object_new(zend_class_entry
*ce TSRMLS_DC
)
903 return php_http_encoding_stream_object_new_ex(ce
, NULL
, NULL TSRMLS_CC
);
906 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
)
908 zend_object_value ov
;
909 php_http_encoding_stream_object_t
*o
;
911 o
= ecalloc(1, sizeof(*o
));
912 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
913 object_properties_init((zend_object
*) o
, ce
);
923 ov
.handle
= zend_objects_store_put((zend_object
*) o
, NULL
, php_http_encoding_stream_object_free
, NULL TSRMLS_CC
);
924 ov
.handlers
= &php_http_encoding_stream_object_handlers
;
929 zend_object_value
php_http_encoding_stream_object_clone(zval
*this_ptr TSRMLS_DC
)
931 zend_object_value new_ov
;
932 php_http_encoding_stream_object_t
*new_obj
= NULL
, *old_obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
934 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
);
935 zend_objects_clone_members(&new_obj
->zo
, new_ov
, &old_obj
->zo
, Z_OBJ_HANDLE_P(this_ptr
) TSRMLS_CC
);
940 void php_http_encoding_stream_object_free(void *object TSRMLS_DC
)
942 php_http_encoding_stream_object_t
*o
= (php_http_encoding_stream_object_t
*) object
;
945 php_http_encoding_stream_free(&o
->stream TSRMLS_CC
);
947 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
951 PHP_METHOD(HttpEncodingStream
, __construct
)
953 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
956 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &flags
)) {
957 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(encoding
)) {
958 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
961 php_http_encoding_stream_ops_t
*ops
= NULL
;
963 if (instanceof_function(obj
->zo
.ce
, php_http_deflate_stream_class_entry TSRMLS_CC
)) {
964 ops
= &php_http_encoding_deflate_ops
;
965 } else if (instanceof_function(obj
->zo
.ce
, php_http_inflate_stream_class_entry TSRMLS_CC
)) {
966 ops
= &php_http_encoding_inflate_ops
;
967 } else if (instanceof_function(obj
->zo
.ce
, php_http_dechunk_stream_class_entry TSRMLS_CC
)) {
968 ops
= &php_http_encoding_dechunk_ops
;
972 obj
->stream
= php_http_encoding_stream_init(obj
->stream
, ops
, flags TSRMLS_CC
);
974 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "Unknown HttpEncodingStream class %s", obj
->zo
.ce
->name
);
978 php_http_error(HE_WARNING
, PHP_HTTP_E_ENCODING
, "HttpEncodingStream cannot be initialized twice");
980 } end_error_handling();
982 } end_error_handling();
985 PHP_METHOD(HttpEncodingStream
, update
)
990 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &data_str
, &data_len
)) {
991 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
997 if (SUCCESS
== php_http_encoding_stream_update(obj
->stream
, data_str
, data_len
, &encoded_str
, &encoded_len TSRMLS_CC
)) {
998 RETURN_STRINGL(encoded_str
, encoded_len
, 0);
1005 PHP_METHOD(HttpEncodingStream
, flush
)
1007 if (SUCCESS
== zend_parse_parameters_none()) {
1008 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1014 if (SUCCESS
== php_http_encoding_stream_flush(obj
->stream
, &encoded_str
, &encoded_len TSRMLS_CC
)) {
1015 RETURN_STRINGL(encoded_str
, encoded_len
, 0);
1022 PHP_METHOD(HttpEncodingStream
, done
)
1024 if (SUCCESS
== zend_parse_parameters_none()) {
1025 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1028 RETURN_BOOL(php_http_encoding_stream_done(obj
->stream
));
1034 PHP_METHOD(HttpEncodingStream
, finish
)
1036 if (SUCCESS
== zend_parse_parameters_none()) {
1037 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1043 if (SUCCESS
== php_http_encoding_stream_finish(obj
->stream
, &encoded_str
, &encoded_len TSRMLS_CC
)) {
1044 if (SUCCESS
== php_http_encoding_stream_reset(&obj
->stream
)) {
1045 RETURN_STRINGL(encoded_str
, encoded_len
, 0);
1047 STR_FREE(encoded_str
);
1055 #undef PHP_HTTP_BEGIN_ARGS
1056 #undef PHP_HTTP_EMPTY_ARGS
1057 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpDeflateStream, method, 0, req_args)
1058 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpDeflateStream, method, 0)
1059 #define PHP_HTTP_DEFLATE_ME(method, visibility) PHP_ME(HttpDeflateStream, method, PHP_HTTP_ARGS(HttpDeflateStream, method), visibility)
1061 PHP_HTTP_BEGIN_ARGS(encode
, 1)
1062 PHP_HTTP_ARG_VAL(data
, 0)
1063 PHP_HTTP_ARG_VAL(flags
, 0)
1066 zend_class_entry
*php_http_deflate_stream_class_entry
;
1067 zend_function_entry php_http_deflate_stream_method_entry
[] = {
1068 PHP_HTTP_DEFLATE_ME(encode
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
1070 EMPTY_FUNCTION_ENTRY
1073 PHP_METHOD(HttpDeflateStream
, encode
)
1079 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|l", &str
, &len
, &flags
)) {
1083 if (SUCCESS
== php_http_encoding_deflate(flags
, str
, len
, &enc_str
, &enc_len TSRMLS_CC
)) {
1084 RETURN_STRINGL(enc_str
, enc_len
, 0);
1090 #undef PHP_HTTP_BEGIN_ARGS
1091 #undef PHP_HTTP_EMPTY_ARGS
1092 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpInflateStream, method, 0, req_args)
1093 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpInflateStream, method, 0)
1094 #define PHP_HTTP_INFLATE_ME(method, visibility) PHP_ME(HttpInflateStream, method, PHP_HTTP_ARGS(HttpInflateStream, method), visibility)
1096 PHP_HTTP_BEGIN_ARGS(decode
, 1)
1097 PHP_HTTP_ARG_VAL(data
, 0)
1100 zend_class_entry
*php_http_inflate_stream_class_entry
;
1101 zend_function_entry php_http_inflate_stream_method_entry
[] = {
1102 PHP_HTTP_INFLATE_ME(decode
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
1104 EMPTY_FUNCTION_ENTRY
1107 PHP_METHOD(HttpInflateStream
, decode
)
1112 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &str
, &len
)) {
1116 if (SUCCESS
== php_http_encoding_inflate(str
, len
, &enc_str
, &enc_len TSRMLS_CC
)) {
1117 RETURN_STRINGL(enc_str
, enc_len
, 0);
1123 #undef PHP_HTTP_BEGIN_ARGS
1124 #undef PHP_HTTP_EMPTY_ARGS
1125 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpDechunkStream, method, 0, req_args)
1126 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpDechunkStream, method, 0)
1127 #define PHP_HTTP_DECHUNK_ME(method, visibility) PHP_ME(HttpDechunkStream, method, PHP_HTTP_ARGS(HttpDechunkStream, method), visibility)
1129 PHP_HTTP_BEGIN_ARGS(decode
, 1)
1130 PHP_HTTP_ARG_VAL(data
, 0)
1131 PHP_HTTP_ARG_VAL(decoded_len
, 1)
1134 zend_class_entry
*php_http_dechunk_stream_class_entry
;
1135 zend_function_entry php_http_dechunk_stream_method_entry
[] = {
1136 PHP_HTTP_DECHUNK_ME(decode
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
1138 EMPTY_FUNCTION_ENTRY
1141 PHP_METHOD(HttpDechunkStream
, decode
)
1147 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|z!", &str
, &len
, &zlen
)) {
1148 const char *end_ptr
;
1152 if ((end_ptr
= php_http_encoding_dechunk(str
, len
, &enc_str
, &enc_len TSRMLS_CC
))) {
1155 ZVAL_LONG(zlen
, str
+ len
- end_ptr
);
1157 RETURN_STRINGL(enc_str
, enc_len
, 0);
1163 PHP_MINIT_FUNCTION(http_encoding
)
1165 PHP_HTTP_REGISTER_CLASS(http
\\encoding
, Stream
, http_encoding_stream
, php_http_object_class_entry
, ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
);
1166 php_http_encoding_stream_class_entry
->create_object
= php_http_encoding_stream_object_new
;
1167 memcpy(&php_http_encoding_stream_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1168 php_http_encoding_stream_object_handlers
.clone_obj
= php_http_encoding_stream_object_clone
;
1170 zend_declare_class_constant_long(php_http_encoding_stream_class_entry
, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC
);
1171 zend_declare_class_constant_long(php_http_encoding_stream_class_entry
, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC
);
1172 zend_declare_class_constant_long(php_http_encoding_stream_class_entry
, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC
);
1174 PHP_HTTP_REGISTER_CLASS(http
\\encoding
\\stream
, Deflate
, http_deflate_stream
, php_http_encoding_stream_class_entry
, 0);
1176 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC
);
1177 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC
);
1178 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW TSRMLS_CC
);
1179 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF TSRMLS_CC
);
1180 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN TSRMLS_CC
);
1181 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX TSRMLS_CC
);
1182 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF TSRMLS_CC
);
1183 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT TSRMLS_CC
);
1184 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF TSRMLS_CC
);
1185 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE TSRMLS_CC
);
1186 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED TSRMLS_CC
);
1188 PHP_HTTP_REGISTER_CLASS(http
\\encoding
\\stream
, Inflate
, http_inflate_stream
, php_http_encoding_stream_class_entry
, 0);
1189 PHP_HTTP_REGISTER_CLASS(http
\\encoding
\\stream
, Dechunk
, http_dechunk_stream
, php_http_encoding_stream_class_entry
, 0);
1200 * vim600: noet sw=4 ts=4 fdm=marker
1201 * vim<600: noet sw=4 ts=4