c20e1630b4efcdbca028d94dd124b1695d03d8f9
[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 static inline int eol_match(char **line, int *eol_len)
16 {
17 char *ptr = *line;
18
19 while (' ' == *ptr) ++ptr;
20
21 if (ptr == php_http_locate_eol(*line, eol_len)) {
22 *line = ptr;
23 return 1;
24 } else {
25 return 0;
26 }
27 }
28
29 const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len)
30 {
31 int eol_len = 0;
32 char *n_ptr = NULL;
33 const char *e_ptr = encoded;
34
35 *decoded_len = 0;
36 *decoded = ecalloc(1, encoded_len + 1);
37
38 while ((encoded + encoded_len - e_ptr) > 0) {
39 ulong chunk_len = 0, rest;
40
41 chunk_len = strtoul(e_ptr, &n_ptr, 16);
42
43 /* we could not read in chunk size */
44 if (n_ptr == e_ptr) {
45 /*
46 * if this is the first turn and there doesn't seem to be a chunk
47 * size at the begining of the body, do not fail on apparently
48 * not encoded data and return a copy
49 */
50 if (e_ptr == encoded) {
51 php_error_docref(NULL, E_NOTICE, "Data does not seem to be chunked encoded");
52 memcpy(*decoded, encoded, encoded_len);
53 *decoded_len = encoded_len;
54 return encoded + encoded_len;
55 } else {
56 efree(*decoded);
57 php_error_docref(NULL, E_WARNING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len);
58 return NULL;
59 }
60 }
61
62 /* reached the end */
63 if (!chunk_len) {
64 /* move over '0' chunked encoding terminator and any new lines */
65 while(1) {
66 switch (*e_ptr) {
67 case '0':
68 case '\r':
69 case '\n':
70 ++e_ptr;
71 continue;
72 }
73 break;
74 }
75 break;
76 }
77
78 /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
79 if (*n_ptr && !eol_match(&n_ptr, &eol_len)) {
80 if (eol_len == 2) {
81 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));
82 } else {
83 php_error_docref(NULL, E_WARNING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr);
84 }
85 }
86 n_ptr += eol_len;
87
88 /* chunk size pretends more data than we actually got, so it's probably a truncated message */
89 if (chunk_len > (rest = encoded + encoded_len - n_ptr)) {
90 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);
91 chunk_len = rest;
92 }
93
94 /* copy the chunk */
95 memcpy(*decoded + *decoded_len, n_ptr, chunk_len);
96 *decoded_len += chunk_len;
97
98 if (chunk_len == rest) {
99 e_ptr = n_ptr + chunk_len;
100 break;
101 } else {
102 /* advance to next chunk */
103 e_ptr = n_ptr + chunk_len + eol_len;
104 }
105 }
106
107 return e_ptr;
108 }
109
110 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)
111 {
112 int freeme;
113
114 if ((freeme = !s)) {
115 s = pemalloc(sizeof(*s), (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
116 }
117 memset(s, 0, sizeof(*s));
118
119 s->flags = flags;
120
121 if (EXPECTED(s->ops = ops)) {
122 php_http_encoding_stream_t *ss = s->ops->init(s);
123
124 if (EXPECTED(ss)) {
125 return ss;
126 }
127 } else {
128 return s;
129 }
130
131 if (freeme) {
132 pefree(s, (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
133 }
134 return NULL;
135 }
136
137 php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
138 {
139 if (from->ops->copy) {
140 php_http_encoding_stream_t *ns;
141
142 if (!to) {
143 to = pemalloc(sizeof(*to), (from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
144 }
145 memset(to, 0, sizeof(*to));
146
147 to->flags = from->flags;
148 to->ops = from->ops;
149
150 if ((ns = to->ops->copy(from, to))) {
151 return ns;
152 } else {
153 return to;
154 }
155 }
156
157 return NULL;
158 }
159
160 ZEND_RESULT_CODE php_http_encoding_stream_reset(php_http_encoding_stream_t **s)
161 {
162 php_http_encoding_stream_t *ss;
163
164 if (EXPECTED((*s)->ops->dtor)) {
165 (*s)->ops->dtor(*s);
166 }
167
168 if (EXPECTED(ss = (*s)->ops->init(*s))) {
169 ss->flags &= ~PHP_HTTP_ENCODING_STREAM_DIRTY;
170 *s = ss;
171 return SUCCESS;
172 }
173 return FAILURE;
174 }
175
176 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)
177 {
178 ZEND_RESULT_CODE rc = FAILURE;
179
180 if (EXPECTED(s->ops->update)) {
181 rc = s->ops->update(s, in_str, in_len, out_str, out_len);
182 }
183
184 s->flags |= PHP_HTTP_ENCODING_STREAM_DIRTY;
185
186 return rc;
187 }
188
189 ZEND_RESULT_CODE php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
190 {
191 if (!s->ops->flush) {
192 *out_str = NULL;
193 *out_len = 0;
194 return SUCCESS;
195 }
196 return s->ops->flush(s, out_str, out_len);
197 }
198
199 zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s)
200 {
201 if (!s->ops->done) {
202 return !(s->flags & PHP_HTTP_ENCODING_STREAM_DIRTY);
203 }
204 return s->ops->done(s);
205 }
206
207 ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
208 {
209 if (!s->ops->finish) {
210 *out_str = NULL;
211 *out_len = 0;
212
213 s->flags &= ~PHP_HTTP_ENCODING_STREAM_DIRTY;
214
215 return SUCCESS;
216 }
217 return s->ops->finish(s, out_str, out_len);
218 }
219
220 void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s)
221 {
222 if (EXPECTED(s->ops->dtor)) {
223 s->ops->dtor(s);
224 }
225 }
226
227 void php_http_encoding_stream_free(php_http_encoding_stream_t **s)
228 {
229 if (EXPECTED(*s)) {
230 if (EXPECTED((*s)->ops->dtor)) {
231 (*s)->ops->dtor(*s);
232 }
233 pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
234 *s = NULL;
235 }
236 }
237
238 struct dechunk_ctx {
239 php_http_buffer_t buffer;
240 ulong hexlen;
241 unsigned zeroed:1;
242 };
243
244 static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s)
245 {
246 struct dechunk_ctx *ctx = pecalloc(1, sizeof(*ctx), (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
247
248 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)) {
249 return NULL;
250 }
251
252 ctx->hexlen = 0;
253 ctx->zeroed = 0;
254 s->ctx = ctx;
255
256 return s;
257 }
258
259 static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
260 {
261 int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
262 struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = pemalloc(sizeof(*to_ctx), p);
263
264 if (php_http_buffer_init_ex(&to_ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) {
265 to_ctx->hexlen = from_ctx->hexlen;
266 to_ctx->zeroed = from_ctx->zeroed;
267 php_http_buffer_append(&to_ctx->buffer, from_ctx->buffer.data, from_ctx->buffer.used);
268 to->ctx = to_ctx;
269 return to;
270 }
271 pefree(to_ctx, p);
272 php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: out of memory");
273 return NULL;
274 }
275
276 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)
277 {
278 php_http_buffer_t tmp;
279 struct dechunk_ctx *ctx = s->ctx;
280
281 if (ctx->zeroed) {
282 php_error_docref(NULL, E_WARNING, "Dechunk encoding stream has already reached the end of chunked input");
283 return FAILURE;
284 }
285 if ((PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(&ctx->buffer, data, data_len)) || !php_http_buffer_fix(&ctx->buffer)) {
286 /* OOM */
287 return FAILURE;
288 }
289
290 *decoded = NULL;
291 *decoded_len = 0;
292
293 php_http_buffer_init(&tmp);
294
295 /* we have data in our buffer */
296 while (ctx->buffer.used) {
297
298 /* we already know the size of the chunk and are waiting for data */
299 if (ctx->hexlen) {
300
301 /* not enough data buffered */
302 if (ctx->buffer.used < ctx->hexlen) {
303
304 /* flush anyway? */
305 if (s->flags & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) {
306 /* flush all data (should only be chunk data) */
307 php_http_buffer_append(&tmp, ctx->buffer.data, ctx->buffer.used);
308 /* waiting for less data now */
309 ctx->hexlen -= ctx->buffer.used;
310 /* no more buffered data */
311 php_http_buffer_reset(&ctx->buffer);
312 /* break */
313 }
314
315 /* we have too less data and don't need to flush */
316 else {
317 break;
318 }
319 }
320
321 /* we seem to have all data of the chunk */
322 else {
323 php_http_buffer_append(&tmp, ctx->buffer.data, ctx->hexlen);
324 /* remove outgoing data from the buffer */
325 php_http_buffer_cut(&ctx->buffer, 0, ctx->hexlen);
326 /* reset hexlen */
327 ctx->hexlen = 0;
328 /* continue */
329 }
330 }
331
332 /* we don't know the length of the chunk yet */
333 else {
334 size_t off = 0;
335
336 /* ignore preceeding CRLFs (too loose?) */
337 while (off < ctx->buffer.used && (
338 ctx->buffer.data[off] == '\n' ||
339 ctx->buffer.data[off] == '\r')) {
340 ++off;
341 }
342 if (off) {
343 php_http_buffer_cut(&ctx->buffer, 0, off);
344 }
345
346 /* still data there? */
347 if (ctx->buffer.used) {
348 int eollen;
349 const char *eolstr;
350
351 /* we need eol, so we can be sure we have all hex digits */
352 php_http_buffer_fix(&ctx->buffer);
353 if ((eolstr = php_http_locate_bin_eol(ctx->buffer.data, ctx->buffer.used, &eollen))) {
354 char *stop = NULL;
355
356 /* read in chunk size */
357 ctx->hexlen = strtoul(ctx->buffer.data, &stop, 16);
358
359 /* if strtoul() stops at the beginning of the buffered data
360 there's something oddly wrong, i.e. bad input */
361 if (stop == ctx->buffer.data) {
362 php_error_docref(NULL, E_WARNING, "Failed to parse chunk len from '%.*s'", (int) MIN(16, ctx->buffer.used), ctx->buffer.data);
363 php_http_buffer_dtor(&tmp);
364 return FAILURE;
365 }
366
367 /* cut out <chunk size hex><chunk extension><eol> */
368 php_http_buffer_cut(&ctx->buffer, 0, eolstr + eollen - ctx->buffer.data);
369 /* buffer->hexlen is 0 now or contains the size of the next chunk */
370 if (!ctx->hexlen) {
371 size_t off = 0;
372
373 /* ignore following CRLFs (too loose?) */
374 while (off < ctx->buffer.used && (
375 ctx->buffer.data[off] == '\n' ||
376 ctx->buffer.data[off] == '\r')) {
377 ++off;
378 }
379 if (off) {
380 php_http_buffer_cut(&ctx->buffer, 0, off);
381 }
382
383 ctx->zeroed = 1;
384 break;
385 }
386 /* continue */
387 } else {
388 /* we have not enough data buffered to read in chunk size */
389 break;
390 }
391 }
392 /* break */
393 }
394 }
395
396 php_http_buffer_fix(&tmp);
397 *decoded = tmp.data;
398 *decoded_len = tmp.used;
399
400 return SUCCESS;
401 }
402
403 static ZEND_RESULT_CODE dechunk_flush(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
404 {
405 struct dechunk_ctx *ctx = s->ctx;
406
407 if (ctx->hexlen) {
408 /* flush all data (should only be chunk data) */
409 php_http_buffer_fix(&ctx->buffer);
410 php_http_buffer_data(&ctx->buffer, decoded, decoded_len);
411 /* waiting for less data now */
412 ctx->hexlen -= ctx->buffer.used;
413 /* no more buffered data */
414 php_http_buffer_reset(&ctx->buffer);
415 } else {
416 *decoded = NULL;
417 *decoded_len = 0;
418 }
419
420 return SUCCESS;
421 }
422
423
424
425 static zend_bool dechunk_done(php_http_encoding_stream_t *s)
426 {
427 return ((struct dechunk_ctx *) s->ctx)->zeroed;
428 }
429
430 static void dechunk_dtor(php_http_encoding_stream_t *s)
431 {
432 if (s->ctx) {
433 struct dechunk_ctx *ctx = s->ctx;
434
435 php_http_buffer_dtor(&ctx->buffer);
436 pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
437 s->ctx = NULL;
438 }
439 }
440
441 static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops = {
442 dechunk_init,
443 dechunk_copy,
444 dechunk_update,
445 dechunk_flush,
446 dechunk_done,
447 NULL,
448 dechunk_dtor
449 };
450
451 php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void)
452 {
453 return &php_http_encoding_dechunk_ops;
454 }
455
456 static zend_object_handlers php_http_encoding_stream_object_handlers;
457
458 zend_object *php_http_encoding_stream_object_new(zend_class_entry *ce)
459 {
460 return &php_http_encoding_stream_object_new_ex(ce, NULL)->zo;
461 }
462
463 php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s)
464 {
465 php_http_encoding_stream_object_t *o;
466
467 o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
468 zend_object_std_init(&o->zo, ce);
469 object_properties_init(&o->zo, ce);
470
471 if (s) {
472 o->stream = s;
473 }
474
475 o->zo.handlers = &php_http_encoding_stream_object_handlers;
476
477 return o;
478 }
479
480 zend_object *php_http_encoding_stream_object_clone(zval *object)
481 {
482 php_http_encoding_stream_object_t *new_obj, *old_obj = PHP_HTTP_OBJ(NULL, object);
483 php_http_encoding_stream_t *cpy = php_http_encoding_stream_copy(old_obj->stream, NULL);
484
485 if (!cpy) {
486 return NULL;
487 }
488
489 new_obj = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, cpy);
490 zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
491
492 return &new_obj->zo;
493 }
494
495 void php_http_encoding_stream_object_free(zend_object *object)
496 {
497 php_http_encoding_stream_object_t *o = PHP_HTTP_OBJ(object, NULL);
498
499 if (o->stream) {
500 php_http_encoding_stream_free(&o->stream);
501 }
502 zend_object_std_dtor(object);
503 }
504
505 static zend_class_entry *php_http_encoding_stream_class_entry;
506 zend_class_entry *php_http_get_encoding_stream_class_entry(void)
507 {
508 return php_http_encoding_stream_class_entry;
509 }
510
511 static zend_class_entry *php_http_dechunk_stream_class_entry;
512 zend_class_entry *php_http_get_dechunk_stream_class_entry(void)
513 {
514 return php_http_dechunk_stream_class_entry;
515 }
516
517 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream___construct, 0, 0, 0)
518 ZEND_ARG_INFO(0, flags)
519 ZEND_END_ARG_INFO();
520 static PHP_METHOD(HttpEncodingStream, __construct)
521 {
522 zend_long flags = 0;
523 php_http_encoding_stream_object_t *obj;
524 php_http_encoding_stream_ops_t *ops;
525
526 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags), invalid_arg, return);
527
528 obj = PHP_HTTP_OBJ(NULL, getThis());
529
530 if (UNEXPECTED(obj->stream)) {
531 php_http_throw(bad_method_call, "http\\Encoding\\Stream cannot be initialized twice", NULL);
532 return;
533 }
534
535 if (instanceof_function(obj->zo.ce, php_http_get_deflate_stream_class_entry())) {
536 ops = php_http_encoding_stream_get_deflate_ops();
537 } else if (instanceof_function(obj->zo.ce, php_http_get_inflate_stream_class_entry())) {
538 ops = php_http_encoding_stream_get_inflate_ops();
539 } else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry)) {
540 ops = &php_http_encoding_dechunk_ops;
541 #if PHP_HTTP_HAVE_LIBBROTLI
542 } else if (instanceof_function(obj->zo.ce, php_http_get_enbrotli_stream_class_entry())) {
543 ops = php_http_encoding_stream_get_enbrotli_ops();
544 } else if (instanceof_function(obj->zo.ce, php_http_get_debrotli_stream_class_entry())) {
545 ops = php_http_encoding_stream_get_debrotli_ops();
546 #endif
547 } else {
548 php_http_throw(runtime, "Unknown http\\Encoding\\Stream class '%s'", obj->zo.ce->name->val);
549 return;
550 }
551
552 php_http_expect(obj->stream = php_http_encoding_stream_init(obj->stream, ops, flags), runtime, return);
553 }
554
555 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_update, 0, 0, 1)
556 ZEND_ARG_INFO(0, data)
557 ZEND_END_ARG_INFO();
558 static PHP_METHOD(HttpEncodingStream, update)
559 {
560 size_t data_len;
561 char *data_str;
562
563 if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len))) {
564 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
565
566 if (EXPECTED(obj->stream)) {
567 char *encoded_str = NULL;
568 size_t encoded_len;
569
570 if (EXPECTED(SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len))) {
571 if (EXPECTED(encoded_str)) {
572 RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
573 } else {
574 RETURN_EMPTY_STRING();
575 }
576 }
577 }
578 }
579 }
580
581 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush, 0, 0, 0)
582 ZEND_END_ARG_INFO();
583 static PHP_METHOD(HttpEncodingStream, flush)
584 {
585 if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
586 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
587
588 if (EXPECTED(obj->stream)) {
589 char *encoded_str = NULL;
590 size_t encoded_len;
591
592 if (EXPECTED(SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len))) {
593 if (encoded_str) {
594 RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
595 } else {
596 RETURN_EMPTY_STRING();
597 }
598 }
599 }
600 }
601 }
602
603 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done, 0, 0, 0)
604 ZEND_END_ARG_INFO();
605 static PHP_METHOD(HttpEncodingStream, done)
606 {
607 if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
608 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
609
610 if (EXPECTED(obj->stream)) {
611 RETURN_BOOL(php_http_encoding_stream_done(obj->stream));
612 }
613 }
614 }
615
616 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish, 0, 0, 0)
617 ZEND_END_ARG_INFO();
618 static PHP_METHOD(HttpEncodingStream, finish)
619 {
620 if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
621 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
622
623 if (EXPECTED(obj->stream)) {
624 char *encoded_str = NULL;
625 size_t encoded_len;
626
627 if (EXPECTED(SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len))) {
628 if (EXPECTED(SUCCESS == php_http_encoding_stream_reset(&obj->stream))) {
629 if (encoded_str) {
630 RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
631 } else {
632 RETURN_EMPTY_STRING();
633 }
634 } else {
635 PTR_FREE(encoded_str);
636 }
637 }
638 }
639 }
640 }
641
642 static zend_function_entry php_http_encoding_stream_methods[] = {
643 PHP_ME(HttpEncodingStream, __construct, ai_HttpEncodingStream___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
644 PHP_ME(HttpEncodingStream, update, ai_HttpEncodingStream_update, ZEND_ACC_PUBLIC)
645 PHP_ME(HttpEncodingStream, flush, ai_HttpEncodingStream_flush, ZEND_ACC_PUBLIC)
646 PHP_ME(HttpEncodingStream, done, ai_HttpEncodingStream_done, ZEND_ACC_PUBLIC)
647 PHP_ME(HttpEncodingStream, finish, ai_HttpEncodingStream_finish, ZEND_ACC_PUBLIC)
648 EMPTY_FUNCTION_ENTRY
649 };
650
651 ZEND_BEGIN_ARG_INFO_EX(ai_HttpDechunkStream_decode, 0, 0, 1)
652 ZEND_ARG_INFO(0, data)
653 ZEND_ARG_INFO(1, decoded_len)
654 ZEND_END_ARG_INFO();
655 static PHP_METHOD(HttpDechunkStream, decode)
656 {
657 char *str;
658 size_t len;
659 zval *zlen = NULL;
660
661 if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &str, &len, &zlen))) {
662 const char *end_ptr;
663 char *enc_str = NULL;
664 size_t enc_len;
665
666 if (EXPECTED(end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len))) {
667 if (zlen) {
668 ZVAL_DEREF(zlen);
669 zval_dtor(zlen);
670 ZVAL_LONG(zlen, str + len - end_ptr);
671 }
672 if (enc_str) {
673 RETURN_STR(php_http_cs2zs(enc_str, enc_len));
674 } else {
675 RETURN_EMPTY_STRING();
676 }
677 }
678 }
679 RETURN_FALSE;
680 }
681
682 static zend_function_entry php_http_dechunk_stream_methods[] = {
683 PHP_ME(HttpDechunkStream, decode, ai_HttpDechunkStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
684 EMPTY_FUNCTION_ENTRY
685 };
686
687 PHP_MINIT_FUNCTION(http_encoding)
688 {
689 zend_class_entry ce = {0};
690
691 INIT_NS_CLASS_ENTRY(ce, "http\\Encoding", "Stream", php_http_encoding_stream_methods);
692 php_http_encoding_stream_class_entry = zend_register_internal_class(&ce);
693 php_http_encoding_stream_class_entry->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
694 php_http_encoding_stream_class_entry->create_object = php_http_encoding_stream_object_new;
695 memcpy(&php_http_encoding_stream_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
696 php_http_encoding_stream_object_handlers.offset = XtOffsetOf(php_http_encoding_stream_object_t, zo);
697 php_http_encoding_stream_object_handlers.clone_obj = php_http_encoding_stream_object_clone;
698 php_http_encoding_stream_object_handlers.free_obj = php_http_encoding_stream_object_free;
699
700 zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE);
701 zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC);
702 zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL);
703
704 memset(&ce, 0, sizeof(ce));
705 INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods);
706 php_http_dechunk_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
707 php_http_dechunk_stream_class_entry->create_object = php_http_encoding_stream_object_new;
708
709 return SUCCESS;
710 }
711
712 /*
713 * Local variables:
714 * tab-width: 4
715 * c-basic-offset: 4
716 * End:
717 * vim600: noet sw=4 ts=4 fdm=marker
718 * vim<600: noet sw=4 ts=4
719 */
720