ad4385369c62a7c95022e5b5fb26f75142672c13
[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 if (EXPECTED(ss = (*s)->ops->init(*s))) {
168 *s = ss;
169 return SUCCESS;
170 }
171 return FAILURE;
172 }
173
174 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)
175 {
176 if (UNEXPECTED(!s->ops->update)) {
177 return FAILURE;
178 }
179 return s->ops->update(s, in_str, in_len, out_str, out_len);
180 }
181
182 ZEND_RESULT_CODE php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
183 {
184 if (!s->ops->flush) {
185 *out_str = NULL;
186 *out_len = 0;
187 return SUCCESS;
188 }
189 return s->ops->flush(s, out_str, out_len);
190 }
191
192 zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s)
193 {
194 if (!s->ops->done) {
195 return 0;
196 }
197 return s->ops->done(s);
198 }
199
200 ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
201 {
202 if (!s->ops->finish) {
203 *out_str = NULL;
204 *out_len = 0;
205 return SUCCESS;
206 }
207 return s->ops->finish(s, out_str, out_len);
208 }
209
210 void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s)
211 {
212 if (EXPECTED(s->ops->dtor)) {
213 s->ops->dtor(s);
214 }
215 }
216
217 void php_http_encoding_stream_free(php_http_encoding_stream_t **s)
218 {
219 if (EXPECTED(*s)) {
220 if (EXPECTED((*s)->ops->dtor)) {
221 (*s)->ops->dtor(*s);
222 }
223 pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
224 *s = NULL;
225 }
226 }
227
228 struct dechunk_ctx {
229 php_http_buffer_t buffer;
230 ulong hexlen;
231 unsigned zeroed:1;
232 };
233
234 static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s)
235 {
236 struct dechunk_ctx *ctx = pecalloc(1, sizeof(*ctx), (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
237
238 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)) {
239 return NULL;
240 }
241
242 ctx->hexlen = 0;
243 ctx->zeroed = 0;
244 s->ctx = ctx;
245
246 return s;
247 }
248
249 static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
250 {
251 int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
252 struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = pemalloc(sizeof(*to_ctx), p);
253
254 if (php_http_buffer_init_ex(&to_ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) {
255 to_ctx->hexlen = from_ctx->hexlen;
256 to_ctx->zeroed = from_ctx->zeroed;
257 php_http_buffer_append(&to_ctx->buffer, from_ctx->buffer.data, from_ctx->buffer.used);
258 to->ctx = to_ctx;
259 return to;
260 }
261 pefree(to_ctx, p);
262 php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: out of memory");
263 return NULL;
264 }
265
266 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)
267 {
268 php_http_buffer_t tmp;
269 struct dechunk_ctx *ctx = s->ctx;
270
271 if (ctx->zeroed) {
272 php_error_docref(NULL, E_WARNING, "Dechunk encoding stream has already reached the end of chunked input");
273 return FAILURE;
274 }
275 if ((PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(&ctx->buffer, data, data_len)) || !php_http_buffer_fix(&ctx->buffer)) {
276 /* OOM */
277 return FAILURE;
278 }
279
280 *decoded = NULL;
281 *decoded_len = 0;
282
283 php_http_buffer_init(&tmp);
284
285 /* we have data in our buffer */
286 while (ctx->buffer.used) {
287
288 /* we already know the size of the chunk and are waiting for data */
289 if (ctx->hexlen) {
290
291 /* not enough data buffered */
292 if (ctx->buffer.used < ctx->hexlen) {
293
294 /* flush anyway? */
295 if (s->flags & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) {
296 /* flush all data (should only be chunk data) */
297 php_http_buffer_append(&tmp, ctx->buffer.data, ctx->buffer.used);
298 /* waiting for less data now */
299 ctx->hexlen -= ctx->buffer.used;
300 /* no more buffered data */
301 php_http_buffer_reset(&ctx->buffer);
302 /* break */
303 }
304
305 /* we have too less data and don't need to flush */
306 else {
307 break;
308 }
309 }
310
311 /* we seem to have all data of the chunk */
312 else {
313 php_http_buffer_append(&tmp, ctx->buffer.data, ctx->hexlen);
314 /* remove outgoing data from the buffer */
315 php_http_buffer_cut(&ctx->buffer, 0, ctx->hexlen);
316 /* reset hexlen */
317 ctx->hexlen = 0;
318 /* continue */
319 }
320 }
321
322 /* we don't know the length of the chunk yet */
323 else {
324 size_t off = 0;
325
326 /* ignore preceeding CRLFs (too loose?) */
327 while (off < ctx->buffer.used && (
328 ctx->buffer.data[off] == '\n' ||
329 ctx->buffer.data[off] == '\r')) {
330 ++off;
331 }
332 if (off) {
333 php_http_buffer_cut(&ctx->buffer, 0, off);
334 }
335
336 /* still data there? */
337 if (ctx->buffer.used) {
338 int eollen;
339 const char *eolstr;
340
341 /* we need eol, so we can be sure we have all hex digits */
342 php_http_buffer_fix(&ctx->buffer);
343 if ((eolstr = php_http_locate_bin_eol(ctx->buffer.data, ctx->buffer.used, &eollen))) {
344 char *stop = NULL;
345
346 /* read in chunk size */
347 ctx->hexlen = strtoul(ctx->buffer.data, &stop, 16);
348
349 /* if strtoul() stops at the beginning of the buffered data
350 there's something oddly wrong, i.e. bad input */
351 if (stop == ctx->buffer.data) {
352 php_error_docref(NULL, E_WARNING, "Failed to parse chunk len from '%.*s'", (int) MIN(16, ctx->buffer.used), ctx->buffer.data);
353 php_http_buffer_dtor(&tmp);
354 return FAILURE;
355 }
356
357 /* cut out <chunk size hex><chunk extension><eol> */
358 php_http_buffer_cut(&ctx->buffer, 0, eolstr + eollen - ctx->buffer.data);
359 /* buffer->hexlen is 0 now or contains the size of the next chunk */
360 if (!ctx->hexlen) {
361 size_t off = 0;
362
363 /* ignore following CRLFs (too loose?) */
364 while (off < ctx->buffer.used && (
365 ctx->buffer.data[off] == '\n' ||
366 ctx->buffer.data[off] == '\r')) {
367 ++off;
368 }
369 if (off) {
370 php_http_buffer_cut(&ctx->buffer, 0, off);
371 }
372
373 ctx->zeroed = 1;
374 break;
375 }
376 /* continue */
377 } else {
378 /* we have not enough data buffered to read in chunk size */
379 break;
380 }
381 }
382 /* break */
383 }
384 }
385
386 php_http_buffer_fix(&tmp);
387 *decoded = tmp.data;
388 *decoded_len = tmp.used;
389
390 return SUCCESS;
391 }
392
393 static ZEND_RESULT_CODE dechunk_flush(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
394 {
395 struct dechunk_ctx *ctx = s->ctx;
396
397 if (ctx->hexlen) {
398 /* flush all data (should only be chunk data) */
399 php_http_buffer_fix(&ctx->buffer);
400 php_http_buffer_data(&ctx->buffer, decoded, decoded_len);
401 /* waiting for less data now */
402 ctx->hexlen -= ctx->buffer.used;
403 /* no more buffered data */
404 php_http_buffer_reset(&ctx->buffer);
405 } else {
406 *decoded = NULL;
407 *decoded_len = 0;
408 }
409
410 return SUCCESS;
411 }
412
413
414
415 static zend_bool dechunk_done(php_http_encoding_stream_t *s)
416 {
417 return ((struct dechunk_ctx *) s->ctx)->zeroed;
418 }
419
420 static void dechunk_dtor(php_http_encoding_stream_t *s)
421 {
422 if (s->ctx) {
423 struct dechunk_ctx *ctx = s->ctx;
424
425 php_http_buffer_dtor(&ctx->buffer);
426 pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
427 s->ctx = NULL;
428 }
429 }
430
431 static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops = {
432 dechunk_init,
433 dechunk_copy,
434 dechunk_update,
435 dechunk_flush,
436 dechunk_done,
437 NULL,
438 dechunk_dtor
439 };
440
441 php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void)
442 {
443 return &php_http_encoding_dechunk_ops;
444 }
445
446 static zend_object_handlers php_http_encoding_stream_object_handlers;
447
448 zend_object *php_http_encoding_stream_object_new(zend_class_entry *ce)
449 {
450 return &php_http_encoding_stream_object_new_ex(ce, NULL)->zo;
451 }
452
453 php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s)
454 {
455 php_http_encoding_stream_object_t *o;
456
457 o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
458 zend_object_std_init(&o->zo, ce);
459 object_properties_init(&o->zo, ce);
460
461 if (s) {
462 o->stream = s;
463 }
464
465 o->zo.handlers = &php_http_encoding_stream_object_handlers;
466
467 return o;
468 }
469
470 zend_object *php_http_encoding_stream_object_clone(zval *object)
471 {
472 php_http_encoding_stream_object_t *new_obj, *old_obj = PHP_HTTP_OBJ(NULL, object);
473 php_http_encoding_stream_t *cpy = php_http_encoding_stream_copy(old_obj->stream, NULL);
474
475 new_obj = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, cpy);
476 zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
477
478 return &new_obj->zo;
479 }
480
481 void php_http_encoding_stream_object_free(zend_object *object)
482 {
483 php_http_encoding_stream_object_t *o = PHP_HTTP_OBJ(object, NULL);
484
485 if (o->stream) {
486 php_http_encoding_stream_free(&o->stream);
487 }
488 zend_object_std_dtor(object);
489 }
490
491 static zend_class_entry *php_http_encoding_stream_class_entry;
492 zend_class_entry *php_http_get_encoding_stream_class_entry(void)
493 {
494 return php_http_encoding_stream_class_entry;
495 }
496
497 static zend_class_entry *php_http_dechunk_stream_class_entry;
498 zend_class_entry *php_http_get_dechunk_stream_class_entry(void)
499 {
500 return php_http_dechunk_stream_class_entry;
501 }
502
503 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream___construct, 0, 0, 0)
504 ZEND_ARG_INFO(0, flags)
505 ZEND_END_ARG_INFO();
506 static PHP_METHOD(HttpEncodingStream, __construct)
507 {
508 zend_long flags = 0;
509 php_http_encoding_stream_object_t *obj;
510 php_http_encoding_stream_ops_t *ops;
511
512 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags), invalid_arg, return);
513
514 obj = PHP_HTTP_OBJ(NULL, getThis());
515
516 if (UNEXPECTED(obj->stream)) {
517 php_http_throw(bad_method_call, "http\\Encoding\\Stream cannot be initialized twice", NULL);
518 return;
519 }
520
521 if (instanceof_function(obj->zo.ce, php_http_get_deflate_stream_class_entry())) {
522 ops = php_http_encoding_stream_get_deflate_ops();
523 } else if (instanceof_function(obj->zo.ce, php_http_get_inflate_stream_class_entry())) {
524 ops = php_http_encoding_stream_get_inflate_ops();
525 } else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry)) {
526 ops = &php_http_encoding_dechunk_ops;
527 } else if (instanceof_function(obj->zo.ce, php_http_get_enbrotli_stream_class_entry())) {
528 ops = php_http_encoding_stream_get_enbrotli_ops();
529 } else if (instanceof_function(obj->zo.ce, php_http_get_debrotli_stream_class_entry())) {
530 ops = php_http_encoding_stream_get_debrotli_ops();
531 } else {
532 php_http_throw(runtime, "Unknown http\\Encoding\\Stream class '%s'", obj->zo.ce->name->val);
533 return;
534 }
535
536 php_http_expect(obj->stream = php_http_encoding_stream_init(obj->stream, ops, flags), runtime, return);
537 }
538
539 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_update, 0, 0, 1)
540 ZEND_ARG_INFO(0, data)
541 ZEND_END_ARG_INFO();
542 static PHP_METHOD(HttpEncodingStream, update)
543 {
544 size_t data_len;
545 char *data_str;
546
547 if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len))) {
548 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
549
550 if (EXPECTED(obj->stream)) {
551 char *encoded_str = NULL;
552 size_t encoded_len;
553
554 if (EXPECTED(SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len))) {
555 if (EXPECTED(encoded_str)) {
556 RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
557 } else {
558 RETURN_EMPTY_STRING();
559 }
560 }
561 }
562 }
563 }
564
565 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush, 0, 0, 0)
566 ZEND_END_ARG_INFO();
567 static PHP_METHOD(HttpEncodingStream, flush)
568 {
569 if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
570 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
571
572 if (EXPECTED(obj->stream)) {
573 char *encoded_str = NULL;
574 size_t encoded_len;
575
576 if (EXPECTED(SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len))) {
577 if (encoded_str) {
578 RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
579 } else {
580 RETURN_EMPTY_STRING();
581 }
582 }
583 }
584 }
585 }
586
587 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done, 0, 0, 0)
588 ZEND_END_ARG_INFO();
589 static PHP_METHOD(HttpEncodingStream, done)
590 {
591 if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
592 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
593
594 if (EXPECTED(obj->stream)) {
595 RETURN_BOOL(php_http_encoding_stream_done(obj->stream));
596 }
597 }
598 }
599
600 ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish, 0, 0, 0)
601 ZEND_END_ARG_INFO();
602 static PHP_METHOD(HttpEncodingStream, finish)
603 {
604 if (EXPECTED(SUCCESS == zend_parse_parameters_none())) {
605 php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
606
607 if (EXPECTED(obj->stream)) {
608 char *encoded_str = NULL;
609 size_t encoded_len;
610
611 if (EXPECTED(SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len))) {
612 if (EXPECTED(SUCCESS == php_http_encoding_stream_reset(&obj->stream))) {
613 if (encoded_str) {
614 RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
615 } else {
616 RETURN_EMPTY_STRING();
617 }
618 } else {
619 PTR_FREE(encoded_str);
620 }
621 }
622 }
623 }
624 }
625
626 static zend_function_entry php_http_encoding_stream_methods[] = {
627 PHP_ME(HttpEncodingStream, __construct, ai_HttpEncodingStream___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
628 PHP_ME(HttpEncodingStream, update, ai_HttpEncodingStream_update, ZEND_ACC_PUBLIC)
629 PHP_ME(HttpEncodingStream, flush, ai_HttpEncodingStream_flush, ZEND_ACC_PUBLIC)
630 PHP_ME(HttpEncodingStream, done, ai_HttpEncodingStream_done, ZEND_ACC_PUBLIC)
631 PHP_ME(HttpEncodingStream, finish, ai_HttpEncodingStream_finish, ZEND_ACC_PUBLIC)
632 EMPTY_FUNCTION_ENTRY
633 };
634
635 ZEND_BEGIN_ARG_INFO_EX(ai_HttpDechunkStream_decode, 0, 0, 1)
636 ZEND_ARG_INFO(0, data)
637 ZEND_ARG_INFO(1, decoded_len)
638 ZEND_END_ARG_INFO();
639 static PHP_METHOD(HttpDechunkStream, decode)
640 {
641 char *str;
642 size_t len;
643 zval *zlen = NULL;
644
645 if (EXPECTED(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &str, &len, &zlen))) {
646 const char *end_ptr;
647 char *enc_str = NULL;
648 size_t enc_len;
649
650 if (EXPECTED(end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len))) {
651 if (zlen) {
652 ZVAL_DEREF(zlen);
653 zval_dtor(zlen);
654 ZVAL_LONG(zlen, str + len - end_ptr);
655 }
656 if (enc_str) {
657 RETURN_STR(php_http_cs2zs(enc_str, enc_len));
658 } else {
659 RETURN_EMPTY_STRING();
660 }
661 }
662 }
663 RETURN_FALSE;
664 }
665
666 static zend_function_entry php_http_dechunk_stream_methods[] = {
667 PHP_ME(HttpDechunkStream, decode, ai_HttpDechunkStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
668 EMPTY_FUNCTION_ENTRY
669 };
670
671 PHP_MINIT_FUNCTION(http_encoding)
672 {
673 zend_class_entry ce = {0};
674
675 INIT_NS_CLASS_ENTRY(ce, "http\\Encoding", "Stream", php_http_encoding_stream_methods);
676 php_http_encoding_stream_class_entry = zend_register_internal_class(&ce);
677 php_http_encoding_stream_class_entry->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
678 php_http_encoding_stream_class_entry->create_object = php_http_encoding_stream_object_new;
679 memcpy(&php_http_encoding_stream_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
680 php_http_encoding_stream_object_handlers.offset = XtOffsetOf(php_http_encoding_stream_object_t, zo);
681 php_http_encoding_stream_object_handlers.clone_obj = php_http_encoding_stream_object_clone;
682 php_http_encoding_stream_object_handlers.free_obj = php_http_encoding_stream_object_free;
683
684 zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE);
685 zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC);
686 zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL);
687
688 memset(&ce, 0, sizeof(ce));
689 INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods);
690 php_http_dechunk_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
691 php_http_dechunk_stream_class_entry->create_object = php_http_encoding_stream_object_new;
692
693 return SUCCESS;
694 }
695
696 /*
697 * Local variables:
698 * tab-width: 4
699 * c-basic-offset: 4
700 * End:
701 * vim600: noet sw=4 ts=4 fdm=marker
702 * vim<600: noet sw=4 ts=4
703 */
704