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