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