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-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
17 static inline int eol_match(char **line
, int *eol_len
)
21 while (' ' == *ptr
) ++ptr
;
23 if (ptr
== php_http_locate_eol(*line
, eol_len
)) {
31 const char *php_http_encoding_dechunk(const char *encoded
, size_t encoded_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
35 const char *e_ptr
= encoded
;
38 *decoded
= ecalloc(1, encoded_len
+ 1);
40 while ((encoded
+ encoded_len
- e_ptr
) > 0) {
41 ulong chunk_len
= 0, rest
;
43 chunk_len
= strtoul(e_ptr
, &n_ptr
, 16);
45 /* we could not read in chunk size */
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
52 if (e_ptr
== encoded
) {
53 php_error_docref(NULL TSRMLS_CC
, E_NOTICE
, "Data does not seem to be chunked encoded");
54 memcpy(*decoded
, encoded
, encoded_len
);
55 *decoded_len
= encoded_len
;
56 return encoded
+ encoded_len
;
59 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Expected chunk size at pos %tu of %zu but got trash", n_ptr
- encoded
, encoded_len
);
66 /* move over '0' chunked encoding terminator and any new lines */
79 /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
80 if (*n_ptr
&& !eol_match(&n_ptr
, &eol_len
)) {
82 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));
84 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
);
89 /* chunk size pretends more data than we actually got, so it's probably a truncated message */
90 if (chunk_len
> (rest
= encoded
+ encoded_len
- n_ptr
)) {
91 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
);
96 memcpy(*decoded
+ *decoded_len
, n_ptr
, chunk_len
);
97 *decoded_len
+= chunk_len
;
99 if (chunk_len
== rest
) {
100 e_ptr
= n_ptr
+ chunk_len
;
103 /* advance to next chunk */
104 e_ptr
= n_ptr
+ chunk_len
+ eol_len
;
111 static inline int php_http_inflate_rounds(z_stream
*Z
, int flush
, char **buf
, size_t *len
)
113 int status
= 0, round
= 0;
114 php_http_buffer_t buffer
;
119 php_http_buffer_init_ex(&buffer
, Z
->avail_in
, PHP_HTTP_BUFFER_INIT_PREALLOC
);
122 if (PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_resize_ex(&buffer
, buffer
.size
, 0, 1)) {
123 status
= Z_MEM_ERROR
;
125 Z
->avail_out
= buffer
.free
;
126 Z
->next_out
= (Bytef
*) buffer
.data
+ buffer
.used
;
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
);
130 status
= inflate(Z
, flush
);
131 php_http_buffer_account(&buffer
, buffer
.free
- Z
->avail_out
);
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
);
135 PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer
.size
);
137 } while ((Z_BUF_ERROR
== status
|| (Z_OK
== status
&& Z
->avail_in
)) && ++round
< PHP_HTTP_INFLATE_ROUNDS
);
139 if (status
== Z_OK
|| status
== Z_STREAM_END
) {
140 php_http_buffer_shrink(&buffer
);
141 php_http_buffer_fix(&buffer
);
145 php_http_buffer_dtor(&buffer
);
151 ZEND_RESULT_CODE
php_http_encoding_deflate(int flags
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
153 int status
, level
, wbits
, strategy
;
156 PHP_HTTP_DEFLATE_LEVEL_SET(flags
, level
);
157 PHP_HTTP_DEFLATE_WBITS_SET(flags
, wbits
);
158 PHP_HTTP_DEFLATE_STRATEGY_SET(flags
, strategy
);
160 memset(&Z
, 0, sizeof(z_stream
));
164 status
= deflateInit2(&Z
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
);
165 if (Z_OK
== status
) {
166 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len
);
167 *encoded
= emalloc(*encoded_len
);
169 Z
.next_in
= (Bytef
*) data
;
170 Z
.next_out
= (Bytef
*) *encoded
;
171 Z
.avail_in
= data_len
;
172 Z
.avail_out
= *encoded_len
;
174 status
= deflate(&Z
, Z_FINISH
);
177 if (Z_STREAM_END
== status
) {
178 /* size buffer down to actual length */
179 *encoded
= erealloc(*encoded
, Z
.total_out
+ 1);
180 (*encoded
)[*encoded_len
= Z
.total_out
] = '\0';
183 PTR_SET(*encoded
, NULL
);
188 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Could not deflate data: %s", zError(status
));
192 ZEND_RESULT_CODE
php_http_encoding_inflate(const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
195 int status
, wbits
= PHP_HTTP_WINDOW_BITS_ANY
;
197 memset(&Z
, 0, sizeof(z_stream
));
200 status
= inflateInit2(&Z
, wbits
);
201 if (Z_OK
== status
) {
202 Z
.next_in
= (Bytef
*) data
;
203 Z
.avail_in
= data_len
+ 1; /* include the terminating NULL, see #61287 */
205 switch (status
= php_http_inflate_rounds(&Z
, Z_NO_FLUSH
, decoded
, decoded_len
)) {
211 status
= Z_DATA_ERROR
;
215 /* raw deflated data? */
216 if (PHP_HTTP_WINDOW_BITS_ANY
== wbits
) {
218 wbits
= PHP_HTTP_WINDOW_BITS_RAW
;
219 goto retry_raw_inflate
;
225 if (decoded_len
&& *decoded
) {
230 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Could not inflate data: %s", zError(status
));
234 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
)
239 s
= pemalloc(sizeof(*s
), (flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
241 memset(s
, 0, sizeof(*s
));
244 TSRMLS_SET_CTX(s
->ts
);
246 if ((s
->ops
= ops
)) {
247 php_http_encoding_stream_t
*ss
= s
->ops
->init(s
);
257 pefree(s
, (flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
262 php_http_encoding_stream_t
*php_http_encoding_stream_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
264 TSRMLS_FETCH_FROM_CTX(from
->ts
);
266 if (from
->ops
->copy
) {
268 php_http_encoding_stream_t
*ns
;
270 if ((freeme
= !to
)) {
271 to
= pemalloc(sizeof(*to
), (from
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
273 memset(to
, 0, sizeof(*to
));
275 to
->flags
= from
->flags
;
277 TSRMLS_SET_CTX(to
->ts
);
279 if ((ns
= to
->ops
->copy(from
, to
))) {
286 pefree(to
, (to
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
293 ZEND_RESULT_CODE
php_http_encoding_stream_reset(php_http_encoding_stream_t
**s
)
295 php_http_encoding_stream_t
*ss
;
296 if ((*s
)->ops
->dtor
) {
299 if ((ss
= (*s
)->ops
->init(*s
))) {
306 ZEND_RESULT_CODE
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
)
308 if (!s
->ops
->update
) {
311 return s
->ops
->update(s
, in_str
, in_len
, out_str
, out_len
);
314 ZEND_RESULT_CODE
php_http_encoding_stream_flush(php_http_encoding_stream_t
*s
, char **out_str
, size_t *out_len
)
316 if (!s
->ops
->flush
) {
321 return s
->ops
->flush(s
, out_str
, out_len
);
324 zend_bool
php_http_encoding_stream_done(php_http_encoding_stream_t
*s
)
329 return s
->ops
->done(s
);
332 ZEND_RESULT_CODE
php_http_encoding_stream_finish(php_http_encoding_stream_t
*s
, char **out_str
, size_t *out_len
)
334 if (!s
->ops
->finish
) {
339 return s
->ops
->finish(s
, out_str
, out_len
);
342 void php_http_encoding_stream_dtor(php_http_encoding_stream_t
*s
)
349 void php_http_encoding_stream_free(php_http_encoding_stream_t
**s
)
352 if ((*s
)->ops
->dtor
) {
355 pefree(*s
, ((*s
)->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
361 php_http_buffer_t buffer
;
366 static php_http_encoding_stream_t
*deflate_init(php_http_encoding_stream_t
*s
)
368 int status
, level
, wbits
, strategy
, p
= (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
);
369 z_streamp ctx
= pecalloc(1, sizeof(z_stream
), p
);
370 TSRMLS_FETCH_FROM_CTX(s
->ts
);
372 PHP_HTTP_DEFLATE_LEVEL_SET(s
->flags
, level
);
373 PHP_HTTP_DEFLATE_WBITS_SET(s
->flags
, wbits
);
374 PHP_HTTP_DEFLATE_STRATEGY_SET(s
->flags
, strategy
);
376 if (Z_OK
== (status
= deflateInit2(ctx
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
))) {
377 if ((ctx
->opaque
= php_http_buffer_init_ex(NULL
, PHP_HTTP_DEFLATE_BUFFER_SIZE
, p
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0))) {
382 status
= Z_MEM_ERROR
;
385 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to initialize deflate encoding stream: %s", zError(status
));
389 static php_http_encoding_stream_t
*inflate_init(php_http_encoding_stream_t
*s
)
391 int status
, wbits
, p
= (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
);
392 z_streamp ctx
= pecalloc(1, sizeof(z_stream
), p
);
393 TSRMLS_FETCH_FROM_CTX(s
->ts
);
395 PHP_HTTP_INFLATE_WBITS_SET(s
->flags
, wbits
);
397 if (Z_OK
== (status
= inflateInit2(ctx
, wbits
))) {
398 if ((ctx
->opaque
= php_http_buffer_init_ex(NULL
, PHP_HTTP_DEFLATE_BUFFER_SIZE
, p
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0))) {
403 status
= Z_MEM_ERROR
;
406 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to initialize inflate stream: %s", zError(status
));
410 static php_http_encoding_stream_t
*dechunk_init(php_http_encoding_stream_t
*s
)
412 struct dechunk_ctx
*ctx
= pecalloc(1, sizeof(*ctx
), (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
414 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)) {
425 static php_http_encoding_stream_t
*deflate_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
427 int status
, p
= to
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
;
428 z_streamp from_ctx
= from
->ctx
, to_ctx
= pecalloc(1, sizeof(*to_ctx
), p
);
429 TSRMLS_FETCH_FROM_CTX(from
->ts
);
431 if (Z_OK
== (status
= deflateCopy(to_ctx
, from_ctx
))) {
432 if ((to_ctx
->opaque
= php_http_buffer_init_ex(NULL
, PHP_HTTP_DEFLATE_BUFFER_SIZE
, p
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0))) {
433 php_http_buffer_append(to_ctx
->opaque
, PHP_HTTP_BUFFER(from_ctx
->opaque
)->data
, PHP_HTTP_BUFFER(from_ctx
->opaque
)->used
);
438 status
= Z_MEM_ERROR
;
440 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to copy deflate encoding stream: %s", zError(status
));
444 static php_http_encoding_stream_t
*inflate_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
446 int status
, p
= from
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
;
447 z_streamp from_ctx
= from
->ctx
, to_ctx
= pecalloc(1, sizeof(*to_ctx
), p
);
448 TSRMLS_FETCH_FROM_CTX(from
->ts
);
450 if (Z_OK
== (status
= inflateCopy(to_ctx
, from_ctx
))) {
451 if ((to_ctx
->opaque
= php_http_buffer_init_ex(NULL
, PHP_HTTP_DEFLATE_BUFFER_SIZE
, p
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0))) {
452 php_http_buffer_append(to_ctx
->opaque
, PHP_HTTP_BUFFER(from_ctx
->opaque
)->data
, PHP_HTTP_BUFFER(from_ctx
->opaque
)->used
);
457 status
= Z_MEM_ERROR
;
459 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to copy inflate encoding stream: %s", zError(status
));
463 static php_http_encoding_stream_t
*dechunk_copy(php_http_encoding_stream_t
*from
, php_http_encoding_stream_t
*to
)
465 int p
= from
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
;
466 struct dechunk_ctx
*from_ctx
= from
->ctx
, *to_ctx
= pemalloc(sizeof(*to_ctx
), p
);
467 TSRMLS_FETCH_FROM_CTX(from
->ts
);
469 if (php_http_buffer_init_ex(&to_ctx
->buffer
, PHP_HTTP_BUFFER_DEFAULT_SIZE
, p
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0)) {
470 to_ctx
->hexlen
= from_ctx
->hexlen
;
471 to_ctx
->zeroed
= from_ctx
->zeroed
;
472 php_http_buffer_append(&to_ctx
->buffer
, from_ctx
->buffer
.data
, from_ctx
->buffer
.used
);
477 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to copy inflate encoding stream: out of memory");
481 static ZEND_RESULT_CODE
deflate_update(php_http_encoding_stream_t
*s
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len
)
484 z_streamp ctx
= s
->ctx
;
485 TSRMLS_FETCH_FROM_CTX(s
->ts
);
487 /* append input to our buffer */
488 php_http_buffer_append(PHP_HTTP_BUFFER(ctx
->opaque
), data
, data_len
);
490 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER(ctx
->opaque
)->data
;
491 ctx
->avail_in
= PHP_HTTP_BUFFER(ctx
->opaque
)->used
;
494 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len
);
495 *encoded
= emalloc(*encoded_len
);
496 ctx
->avail_out
= *encoded_len
;
497 ctx
->next_out
= (Bytef
*) *encoded
;
499 switch (status
= deflate(ctx
, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s
->flags
))) {
502 /* cut processed chunk off the buffer */
504 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER(ctx
->opaque
)->used
- ctx
->avail_in
);
506 php_http_buffer_reset(PHP_HTTP_BUFFER(ctx
->opaque
));
509 /* size buffer down to actual size */
510 *encoded_len
-= ctx
->avail_out
;
511 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
512 (*encoded
)[*encoded_len
] = '\0';
516 PTR_SET(*encoded
, NULL
);
518 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to update deflate stream: %s", zError(status
));
522 static ZEND_RESULT_CODE
inflate_update(php_http_encoding_stream_t
*s
, const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len
)
525 z_streamp ctx
= s
->ctx
;
526 TSRMLS_FETCH_FROM_CTX(s
->ts
);
528 /* append input to buffer */
529 php_http_buffer_append(PHP_HTTP_BUFFER(ctx
->opaque
), data
, data_len
);
532 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER(ctx
->opaque
)->data
;
533 ctx
->avail_in
= PHP_HTTP_BUFFER(ctx
->opaque
)->used
;
535 switch (status
= php_http_inflate_rounds(ctx
, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s
->flags
), decoded
, decoded_len
)) {
540 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER(ctx
->opaque
)->used
- ctx
->avail_in
);
542 php_http_buffer_reset(PHP_HTTP_BUFFER(ctx
->opaque
));
547 /* raw deflated data ? */
548 if (!(s
->flags
& PHP_HTTP_INFLATE_TYPE_RAW
) && !ctx
->total_out
) {
550 s
->flags
|= PHP_HTTP_INFLATE_TYPE_RAW
;
551 inflateInit2(ctx
, PHP_HTTP_WINDOW_BITS_RAW
);
552 goto retry_raw_inflate
;
557 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to update inflate stream: %s", zError(status
));
561 static ZEND_RESULT_CODE
dechunk_update(php_http_encoding_stream_t
*s
, const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len
)
563 php_http_buffer_t tmp
;
564 struct dechunk_ctx
*ctx
= s
->ctx
;
565 TSRMLS_FETCH_FROM_CTX(s
->ts
);
568 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Dechunk encoding stream has already reached the end of chunked input");
571 if ((PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_append(&ctx
->buffer
, data
, data_len
)) || !php_http_buffer_fix(&ctx
->buffer
)) {
579 php_http_buffer_init(&tmp
);
581 /* we have data in our buffer */
582 while (ctx
->buffer
.used
) {
584 /* we already know the size of the chunk and are waiting for data */
587 /* not enough data buffered */
588 if (ctx
->buffer
.used
< ctx
->hexlen
) {
591 if (s
->flags
& PHP_HTTP_ENCODING_STREAM_FLUSH_FULL
) {
592 /* flush all data (should only be chunk data) */
593 php_http_buffer_append(&tmp
, ctx
->buffer
.data
, ctx
->buffer
.used
);
594 /* waiting for less data now */
595 ctx
->hexlen
-= ctx
->buffer
.used
;
596 /* no more buffered data */
597 php_http_buffer_reset(&ctx
->buffer
);
601 /* we have too less data and don't need to flush */
607 /* we seem to have all data of the chunk */
609 php_http_buffer_append(&tmp
, ctx
->buffer
.data
, ctx
->hexlen
);
610 /* remove outgoing data from the buffer */
611 php_http_buffer_cut(&ctx
->buffer
, 0, ctx
->hexlen
);
618 /* we don't know the length of the chunk yet */
622 /* ignore preceeding CRLFs (too loose?) */
623 while (off
< ctx
->buffer
.used
&& (
624 ctx
->buffer
.data
[off
] == '\n' ||
625 ctx
->buffer
.data
[off
] == '\r')) {
629 php_http_buffer_cut(&ctx
->buffer
, 0, off
);
632 /* still data there? */
633 if (ctx
->buffer
.used
) {
637 /* we need eol, so we can be sure we have all hex digits */
638 php_http_buffer_fix(&ctx
->buffer
);
639 if ((eolstr
= php_http_locate_bin_eol(ctx
->buffer
.data
, ctx
->buffer
.used
, &eollen
))) {
642 /* read in chunk size */
643 ctx
->hexlen
= strtoul(ctx
->buffer
.data
, &stop
, 16);
645 /* if strtoul() stops at the beginning of the buffered data
646 there's something oddly wrong, i.e. bad input */
647 if (stop
== ctx
->buffer
.data
) {
648 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 php_http_buffer_dtor(&tmp
);
653 /* cut out <chunk size hex><chunk extension><eol> */
654 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 */
659 /* ignore following CRLFs (too loose?) */
660 while (off
< ctx
->buffer
.used
&& (
661 ctx
->buffer
.data
[off
] == '\n' ||
662 ctx
->buffer
.data
[off
] == '\r')) {
666 php_http_buffer_cut(&ctx
->buffer
, 0, off
);
674 /* we have not enough data buffered to read in chunk size */
682 php_http_buffer_fix(&tmp
);
684 *decoded_len
= tmp
.used
;
689 static ZEND_RESULT_CODE
deflate_flush(php_http_encoding_stream_t
*s
, char **encoded
, size_t *encoded_len
)
692 z_streamp ctx
= s
->ctx
;
693 TSRMLS_FETCH_FROM_CTX(s
->ts
);
695 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE
;
696 *encoded
= emalloc(*encoded_len
);
700 ctx
->avail_out
= *encoded_len
;
701 ctx
->next_out
= (Bytef
*) *encoded
;
703 switch (status
= deflate(ctx
, Z_FULL_FLUSH
)) {
706 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE
- ctx
->avail_out
;
707 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
708 (*encoded
)[*encoded_len
] = '\0';
712 PTR_SET(*encoded
, NULL
);
714 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to flush deflate stream: %s", zError(status
));
718 static ZEND_RESULT_CODE
dechunk_flush(php_http_encoding_stream_t
*s
, char **decoded
, size_t *decoded_len
)
720 struct dechunk_ctx
*ctx
= s
->ctx
;
723 /* flush all data (should only be chunk data) */
724 php_http_buffer_fix(&ctx
->buffer
);
725 php_http_buffer_data(&ctx
->buffer
, decoded
, decoded_len
);
726 /* waiting for less data now */
727 ctx
->hexlen
-= ctx
->buffer
.used
;
728 /* no more buffered data */
729 php_http_buffer_reset(&ctx
->buffer
);
738 static ZEND_RESULT_CODE
deflate_finish(php_http_encoding_stream_t
*s
, char **encoded
, size_t *encoded_len
)
741 z_streamp ctx
= s
->ctx
;
742 TSRMLS_FETCH_FROM_CTX(s
->ts
);
744 *encoded_len
= PHP_HTTP_DEFLATE_BUFFER_SIZE
;
745 *encoded
= emalloc(*encoded_len
);
747 /* deflate remaining input */
748 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER(ctx
->opaque
)->data
;
749 ctx
->avail_in
= PHP_HTTP_BUFFER(ctx
->opaque
)->used
;
751 ctx
->avail_out
= *encoded_len
;
752 ctx
->next_out
= (Bytef
*) *encoded
;
755 status
= deflate(ctx
, Z_FINISH
);
756 } while (Z_OK
== status
);
758 if (Z_STREAM_END
== status
) {
759 /* cut processed input off */
760 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER(ctx
->opaque
)->used
- ctx
->avail_in
);
763 *encoded_len
-= ctx
->avail_out
;
764 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
765 (*encoded
)[*encoded_len
] = '\0';
769 PTR_SET(*encoded
, NULL
);
771 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to finish deflate stream: %s", zError(status
));
775 static ZEND_RESULT_CODE
inflate_finish(php_http_encoding_stream_t
*s
, char **decoded
, size_t *decoded_len
)
778 z_streamp ctx
= s
->ctx
;
779 TSRMLS_FETCH_FROM_CTX(s
->ts
);
781 if (!PHP_HTTP_BUFFER(ctx
->opaque
)->used
) {
787 *decoded_len
= (PHP_HTTP_BUFFER(ctx
->opaque
)->used
+ 1) * PHP_HTTP_INFLATE_ROUNDS
;
788 *decoded
= emalloc(*decoded_len
);
790 /* inflate remaining input */
791 ctx
->next_in
= (Bytef
*) PHP_HTTP_BUFFER(ctx
->opaque
)->data
;
792 ctx
->avail_in
= PHP_HTTP_BUFFER(ctx
->opaque
)->used
;
794 ctx
->avail_out
= *decoded_len
;
795 ctx
->next_out
= (Bytef
*) *decoded
;
797 if (Z_STREAM_END
== (status
= inflate(ctx
, Z_FINISH
))) {
798 /* cut processed input off */
799 php_http_buffer_cut(PHP_HTTP_BUFFER(ctx
->opaque
), 0, PHP_HTTP_BUFFER(ctx
->opaque
)->used
- ctx
->avail_in
);
802 *decoded_len
-= ctx
->avail_out
;
803 *decoded
= erealloc(*decoded
, *decoded_len
+ 1);
804 (*decoded
)[*decoded_len
] = '\0';
808 PTR_SET(*decoded
, NULL
);
810 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to finish inflate stream: %s", zError(status
));
814 static zend_bool
deflate_done(php_http_encoding_stream_t
*s
)
816 z_streamp ctx
= s
->ctx
;
817 return !ctx
->avail_in
&& !PHP_HTTP_BUFFER(ctx
->opaque
)->used
;
820 static zend_bool
inflate_done(php_http_encoding_stream_t
*s
)
822 z_streamp ctx
= s
->ctx
;
823 return !ctx
->avail_in
&& !PHP_HTTP_BUFFER(ctx
->opaque
)->used
;
826 static zend_bool
dechunk_done(php_http_encoding_stream_t
*s
)
828 return ((struct dechunk_ctx
*) s
->ctx
)->zeroed
;
831 static void deflate_dtor(php_http_encoding_stream_t
*s
)
834 z_streamp ctx
= s
->ctx
;
837 php_http_buffer_free((php_http_buffer_t
**) &ctx
->opaque
);
840 pefree(ctx
, (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
845 static void inflate_dtor(php_http_encoding_stream_t
*s
)
848 z_streamp ctx
= s
->ctx
;
851 php_http_buffer_free((php_http_buffer_t
**) &ctx
->opaque
);
854 pefree(ctx
, (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
859 static void dechunk_dtor(php_http_encoding_stream_t
*s
)
862 struct dechunk_ctx
*ctx
= s
->ctx
;
864 php_http_buffer_dtor(&ctx
->buffer
);
865 pefree(ctx
, (s
->flags
& PHP_HTTP_ENCODING_STREAM_PERSISTENT
));
870 static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops
= {
880 php_http_encoding_stream_ops_t
*php_http_encoding_stream_get_deflate_ops(void)
882 return &php_http_encoding_deflate_ops
;
885 static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops
= {
895 php_http_encoding_stream_ops_t
*php_http_encoding_stream_get_inflate_ops(void)
897 return &php_http_encoding_inflate_ops
;
900 static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops
= {
910 php_http_encoding_stream_ops_t
*php_http_encoding_stream_get_dechunk_ops(void)
912 return &php_http_encoding_dechunk_ops
;
915 static zend_object_handlers php_http_encoding_stream_object_handlers
;
917 zend_object_value
php_http_encoding_stream_object_new(zend_class_entry
*ce TSRMLS_DC
)
919 return php_http_encoding_stream_object_new_ex(ce
, NULL
, NULL TSRMLS_CC
);
922 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
)
924 php_http_encoding_stream_object_t
*o
;
926 o
= ecalloc(1, sizeof(*o
));
927 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
928 object_properties_init((zend_object
*) o
, ce
);
938 o
->zv
.handle
= zend_objects_store_put((zend_object
*) o
, NULL
, php_http_encoding_stream_object_free
, NULL TSRMLS_CC
);
939 o
->zv
.handlers
= &php_http_encoding_stream_object_handlers
;
944 zend_object_value
php_http_encoding_stream_object_clone(zval
*this_ptr TSRMLS_DC
)
946 zend_object_value new_ov
;
947 php_http_encoding_stream_object_t
*new_obj
= NULL
, *old_obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
949 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 zend_objects_clone_members(&new_obj
->zo
, new_ov
, &old_obj
->zo
, Z_OBJ_HANDLE_P(this_ptr
) TSRMLS_CC
);
955 void php_http_encoding_stream_object_free(void *object TSRMLS_DC
)
957 php_http_encoding_stream_object_t
*o
= (php_http_encoding_stream_object_t
*) object
;
960 php_http_encoding_stream_free(&o
->stream
);
962 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
966 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream___construct
, 0, 0, 0)
967 ZEND_ARG_INFO(0, flags
)
969 static PHP_METHOD(HttpEncodingStream
, __construct
)
972 php_http_encoding_stream_object_t
*obj
;
973 php_http_encoding_stream_ops_t
*ops
;
975 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &flags
), invalid_arg
, return);
977 obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
980 php_http_throw(bad_method_call
, "http\\Encoding\\Stream cannot be initialized twice", NULL
);
984 if (instanceof_function(obj
->zo
.ce
, php_http_deflate_stream_class_entry TSRMLS_CC
)) {
985 ops
= &php_http_encoding_deflate_ops
;
986 } else if (instanceof_function(obj
->zo
.ce
, php_http_inflate_stream_class_entry TSRMLS_CC
)) {
987 ops
= &php_http_encoding_inflate_ops
;
988 } else if (instanceof_function(obj
->zo
.ce
, php_http_dechunk_stream_class_entry TSRMLS_CC
)) {
989 ops
= &php_http_encoding_dechunk_ops
;
991 php_http_throw(runtime
, "Unknown http\\Encoding\\Stream class '%s'", obj
->zo
.ce
->name
);
995 php_http_expect(obj
->stream
= php_http_encoding_stream_init(obj
->stream
, ops
, flags TSRMLS_CC
), runtime
, return);
998 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_update
, 0, 0, 1)
999 ZEND_ARG_INFO(0, data
)
1000 ZEND_END_ARG_INFO();
1001 static PHP_METHOD(HttpEncodingStream
, update
)
1006 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &data_str
, &data_len
)) {
1007 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1013 if (SUCCESS
== php_http_encoding_stream_update(obj
->stream
, data_str
, data_len
, &encoded_str
, &encoded_len
)) {
1014 RETURN_STRINGL(encoded_str
, encoded_len
, 0);
1020 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush
, 0, 0, 0)
1021 ZEND_END_ARG_INFO();
1022 static PHP_METHOD(HttpEncodingStream
, flush
)
1024 if (SUCCESS
== zend_parse_parameters_none()) {
1025 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1031 if (SUCCESS
== php_http_encoding_stream_flush(obj
->stream
, &encoded_str
, &encoded_len
)) {
1033 RETURN_STRINGL(encoded_str
, encoded_len
, 0);
1035 RETURN_EMPTY_STRING();
1042 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done
, 0, 0, 0)
1043 ZEND_END_ARG_INFO();
1044 static PHP_METHOD(HttpEncodingStream
, done
)
1046 if (SUCCESS
== zend_parse_parameters_none()) {
1047 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1050 RETURN_BOOL(php_http_encoding_stream_done(obj
->stream
));
1055 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish
, 0, 0, 0)
1056 ZEND_END_ARG_INFO();
1057 static PHP_METHOD(HttpEncodingStream
, finish
)
1059 if (SUCCESS
== zend_parse_parameters_none()) {
1060 php_http_encoding_stream_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1066 if (SUCCESS
== php_http_encoding_stream_finish(obj
->stream
, &encoded_str
, &encoded_len
)) {
1067 if (SUCCESS
== php_http_encoding_stream_reset(&obj
->stream
)) {
1069 RETURN_STRINGL(encoded_str
, encoded_len
, 0);
1071 RETURN_EMPTY_STRING();
1074 PTR_FREE(encoded_str
);
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
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 static PHP_METHOD(HttpDeflateStream
, encode
)
1100 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|l", &str
, &len
, &flags
)) {
1104 if (SUCCESS
== php_http_encoding_deflate(flags
, str
, len
, &enc_str
, &enc_len TSRMLS_CC
)) {
1105 RETURN_STRINGL(enc_str
, enc_len
, 0);
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
1116 ZEND_BEGIN_ARG_INFO_EX(ai_HttpInflateStream_decode
, 0, 0, 1)
1117 ZEND_ARG_INFO(0, data
)
1118 ZEND_END_ARG_INFO();
1119 static PHP_METHOD(HttpInflateStream
, decode
)
1124 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &str
, &len
)) {
1128 if (SUCCESS
== php_http_encoding_inflate(str
, len
, &enc_str
, &enc_len TSRMLS_CC
)) {
1129 RETURN_STRINGL(enc_str
, enc_len
, 0);
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
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 static PHP_METHOD(HttpDechunkStream
, decode
)
1150 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|z!", &str
, &len
, &zlen
)) {
1151 const char *end_ptr
;
1155 if ((end_ptr
= php_http_encoding_dechunk(str
, len
, &enc_str
, &enc_len TSRMLS_CC
))) {
1158 ZVAL_LONG(zlen
, str
+ len
- end_ptr
);
1160 RETURN_STRINGL(enc_str
, enc_len
, 0);
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
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
;
1176 PHP_MINIT_FUNCTION(http_encoding
)
1178 zend_class_entry ce
= {0};
1180 INIT_NS_CLASS_ENTRY(ce
, "http\\Encoding", "Stream", php_http_encoding_stream_methods
);
1181 php_http_encoding_stream_class_entry
= zend_register_internal_class(&ce TSRMLS_CC
);
1182 php_http_encoding_stream_class_entry
->ce_flags
|= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
;
1183 php_http_encoding_stream_class_entry
->create_object
= php_http_encoding_stream_object_new
;
1184 memcpy(&php_http_encoding_stream_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1185 php_http_encoding_stream_object_handlers
.clone_obj
= php_http_encoding_stream_object_clone
;
1187 zend_declare_class_constant_long(php_http_encoding_stream_class_entry
, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC
);
1188 zend_declare_class_constant_long(php_http_encoding_stream_class_entry
, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC
);
1189 zend_declare_class_constant_long(php_http_encoding_stream_class_entry
, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC
);
1191 memset(&ce
, 0, sizeof(ce
));
1192 INIT_NS_CLASS_ENTRY(ce
, "http\\Encoding\\Stream", "Deflate", php_http_deflate_stream_methods
);
1193 php_http_deflate_stream_class_entry
= zend_register_internal_class_ex(&ce
, php_http_encoding_stream_class_entry
, NULL TSRMLS_CC
);
1195 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC
);
1196 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC
);
1197 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW TSRMLS_CC
);
1198 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF TSRMLS_CC
);
1199 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN TSRMLS_CC
);
1200 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX TSRMLS_CC
);
1201 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF TSRMLS_CC
);
1202 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT TSRMLS_CC
);
1203 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF TSRMLS_CC
);
1204 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE TSRMLS_CC
);
1205 zend_declare_class_constant_long(php_http_deflate_stream_class_entry
, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED TSRMLS_CC
);
1207 memset(&ce
, 0, sizeof(ce
));
1208 INIT_NS_CLASS_ENTRY(ce
, "http\\Encoding\\Stream", "Inflate", php_http_inflate_stream_methods
);
1209 php_http_inflate_stream_class_entry
= zend_register_internal_class_ex(&ce
, php_http_encoding_stream_class_entry
, NULL TSRMLS_CC
);
1211 memset(&ce
, 0, sizeof(ce
));
1212 INIT_NS_CLASS_ENTRY(ce
, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods
);
1213 php_http_dechunk_stream_class_entry
= zend_register_internal_class_ex(&ce
, php_http_encoding_stream_class_entry
, NULL TSRMLS_CC
);
1224 * vim600: noet sw=4 ts=4 fdm=marker
1225 * vim<600: noet sw=4 ts=4