2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
23 #include "php_http_std_defs.h"
24 #include "php_http_api.h"
25 #include "php_http_filter_api.h"
27 #include "phpstr/phpstr.h"
29 #include "php_streams.h"
31 #ifndef HTTP_DEBUG_FILTERS
32 # define HTTP_DEBUG_FILTERS 0
36 * TODO: phpstr is not persistent aware
49 http_filter_status status
;
52 #define PHP_STREAM_FILTER_OP_FILTER_PARAMS \
54 php_stream_filter *this, \
55 php_stream_bucket_brigade *buckets_in, \
56 php_stream_bucket_brigade *buckets_out, \
57 size_t *bytes_consumed, int flags \
59 #define PHP_STREAM_FILTER_OP_FILTER(function) \
60 static php_stream_filter_status_t function(PHP_STREAM_FILTER_OP_FILTER_PARAMS)
62 #define NEW_BUCKET(data, length) \
63 php_stream_bucket_append(buckets_out, php_stream_bucket_new(stream, pestrndup(data, length, this->is_persistent), (length), 1, this->is_persistent TSRMLS_CC) TSRMLS_CC);
65 inline void *pestrndup(const char *s
, size_t l
, int p
)
67 void *d
= pemalloc(l
+ 1, p
);
75 PHP_STREAM_FILTER_OP_FILTER(http_filter_chunked_decode
)
77 php_stream_bucket
*ptr
, *nxt
;
78 http_filter_buffer
*buffer
= (http_filter_buffer
*) (this->abstract
);
84 if (!buckets_in
->head
) {
88 #if HTTP_DEBUG_FILTERS
89 fprintf(stderr
, "Reading in bucket buffers ");
92 /* fetch available bucket data */
93 for (ptr
= buckets_in
->head
; ptr
; ptr
= nxt
) {
95 phpstr_append(PHPSTR(buffer
), ptr
->buf
, ptr
->buflen
);
96 php_stream_bucket_unlink(ptr TSRMLS_CC
);
97 php_stream_bucket_delref(ptr TSRMLS_CC
);
99 #if HTTP_DEBUG_FILTERS
100 fprintf(stderr
, ".");
103 if (bytes_consumed
) {
104 *bytes_consumed
= PHPSTR_LEN(buffer
);
106 phpstr_fix(PHPSTR(buffer
));
108 #if HTTP_DEBUG_FILTERS
109 fprintf(stderr
, " done\nCurrent buffer length: %lu bytes\n", PHPSTR_LEN(buffer
));
114 if (buffer
->status
== HFS_HEX
) {
119 #if HTTP_DEBUG_FILTERS
120 fprintf(stderr
, "Status HFS_HEX: ");
123 if (!(eol
= http_locate_eol(PHPSTR_VAL(buffer
), &buffer
->eollen
))) {
124 #if HTTP_DEBUG_FILTERS
125 fprintf(stderr
, "return PFSF_FEED_ME (no eol)\n");
127 return buffer
->passon
? PSFS_PASS_ON
: PSFS_FEED_ME
;
129 if (!(clen
= strtoul(PHPSTR_VAL(buffer
), &stop
, 16))) {
130 #if HTTP_DEBUG_FILTERS
131 fprintf(stderr
, "return PFSF_FEED_ME (no len)\n");
133 phpstr_dtor(PHPSTR(buffer
));
134 return buffer
->passon
? PSFS_PASS_ON
: PSFS_FEED_ME
;
137 buffer
->status
= HFS_DATA
;
138 buffer
->wanted
= clen
;
139 phpstr_cut(PHPSTR(buffer
), 0, eol
+ buffer
->eollen
- PHPSTR_VAL(buffer
));
141 #if HTTP_DEBUG_FILTERS
142 fprintf(stderr
, "read %lu bytes chunk size\n", buffer
->wanted
);
146 #if HTTP_DEBUG_FILTERS
147 fprintf(stderr
, "Current status: %s\n", buffer
->status
== HFS_DATA
?"HFS_DATA":"HFS_HEX");
148 fprintf(stderr
, "Current buffer length: %lu bytes\n", PHPSTR_LEN(buffer
));
151 if (buffer
->status
== HFS_DATA
&& buffer
->wanted
> 0 && buffer
->wanted
<= PHPSTR_LEN(buffer
)) {
153 #if HTTP_DEBUG_FILTERS
154 fprintf(stderr
, "Passing on %lu(%lu) bytes\n", buffer
->wanted
, PHPSTR_LEN(buffer
));
157 NEW_BUCKET(PHPSTR_VAL(buffer
), buffer
->wanted
);
158 phpstr_cut(PHPSTR(buffer
), 0, buffer
->wanted
+ buffer
->eollen
);
162 buffer
->status
= HFS_HEX
;
165 return buffer
->passon
? PSFS_PASS_ON
: PSFS_FEED_ME
;
171 static void http_filter_chunked_decode_dtor(php_stream_filter
*this TSRMLS_DC
)
173 http_filter_buffer
*b
= (http_filter_buffer
*) (this->abstract
);
175 phpstr_dtor(PHPSTR(b
));
176 pefree(b
, this->is_persistent
);
179 PHP_STREAM_FILTER_OP_FILTER(http_filter_chunked_encode
)
182 php_stream_bucket
*ptr
, *nxt
;
184 if (bytes_consumed
) {
188 if (!buckets_in
->head
) {
193 for (ptr
= buckets_in
->head
; ptr
; ptr
= nxt
) {
194 if (bytes_consumed
) {
195 *bytes_consumed
+= ptr
->buflen
;
199 phpstr_appendf(&buf
, "%x" HTTP_CRLF
, ptr
->buflen
);
200 phpstr_append(&buf
, ptr
->buf
, ptr
->buflen
);
201 phpstr_appends(&buf
, HTTP_CRLF
);
202 NEW_BUCKET(PHPSTR_VAL(&buf
), PHPSTR_LEN(&buf
));
203 PHPSTR_LEN(&buf
) = 0;
205 php_stream_bucket_unlink(ptr TSRMLS_CC
);
206 php_stream_bucket_delref(ptr TSRMLS_CC
);
210 if (flags
& PSFS_FLAG_FLUSH_CLOSE
) {
211 NEW_BUCKET("0"HTTP_CRLF
, lenof("0"HTTP_CRLF
));
217 static php_stream_filter_ops http_filter_ops_chunked_decode
= {
218 http_filter_chunked_decode
,
219 http_filter_chunked_decode_dtor
,
220 "http.chunked_decode"
223 static php_stream_filter_ops http_filter_ops_chunked_encode
= {
224 http_filter_chunked_encode
,
226 "http.chunked_encode"
229 static php_stream_filter
*http_filter_create(const char *name
, zval
*params
, int p TSRMLS_DC
)
231 php_stream_filter
*f
= NULL
;
234 if (!strcasecmp(name
, "http.chunked_decode")) {
235 if (b
= pecalloc(1, sizeof(http_filter_buffer
), p
)) {
236 phpstr_init(PHPSTR(b
));
237 if (!(f
= php_stream_filter_alloc(&http_filter_ops_chunked_decode
, b
, p
))) {
242 if (!strcasecmp(name
, "http.chunked_encode")) {
243 f
= php_stream_filter_alloc(&http_filter_ops_chunked_encode
, NULL
, p
);
249 php_stream_filter_factory http_filter_factory
= {
253 PHP_MINIT_FUNCTION(http_filter
)
255 php_stream_filter_register_factory("http.*", &http_filter_factory TSRMLS_CC
);
264 * vim600: noet sw=4 ts=4 fdm=marker
265 * vim<600: noet sw=4 ts=4