fix problem with dechunk/inflate stream usage
[m6w6/ext-http] / php_http_message_body.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-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id: http_message_body.c 292841 2009-12-31 08:48:57Z mike $ */
14
15 #include "php_http.h"
16
17 typedef struct curl_httppost *post_data[2];
18
19 static inline STATUS add_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len);
20 static inline STATUS add_file(php_http_message_body_t *body, const char *name, const char *path, const char *ctype);
21 static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC);
22 static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC);
23
24 PHP_HTTP_API php_http_message_body_t *php_http_message_body_init(php_http_message_body_t *body, php_stream *stream TSRMLS_DC)
25 {
26 if (!body) {
27 body = emalloc(sizeof(php_http_message_body_t));
28 }
29
30 if (stream) {
31 php_stream_auto_cleanup(stream);
32 body->stream_id = php_stream_get_resource_id(stream);
33 zend_list_addref(body->stream_id);
34 } else {
35 stream = php_stream_temp_new();
36 php_stream_auto_cleanup(stream);
37 body->stream_id = php_stream_get_resource_id(stream);
38 }
39 TSRMLS_SET_CTX(body->ts);
40
41 return body;
42 }
43
44 PHP_HTTP_API php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to, zend_bool dup_internal_stream_and_contents)
45 {
46 if (!from) {
47 return NULL;
48 } else {
49 TSRMLS_FETCH_FROM_CTX(from->ts);
50
51 if (dup_internal_stream_and_contents) {
52 to = php_http_message_body_init(to, NULL TSRMLS_CC);
53 php_http_message_body_to_stream(from, php_http_message_body_stream(to), 0, 0);
54 } else {
55 to = php_http_message_body_init(to, php_http_message_body_stream(from) TSRMLS_CC);
56 }
57
58 return to;
59 }
60 }
61
62 PHP_HTTP_API void php_http_message_body_dtor(php_http_message_body_t *body)
63 {
64 if (body) {
65 /* NO FIXME: shows leakinfo in DEBUG mode */
66 zend_list_delete(body->stream_id);
67 }
68 }
69
70 PHP_HTTP_API void php_http_message_body_free(php_http_message_body_t **body)
71 {
72 if (*body) {
73 php_http_message_body_dtor(*body);
74 efree(*body);
75 *body = NULL;
76 }
77 }
78
79 PHP_HTTP_API php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body)
80 {
81 TSRMLS_FETCH_FROM_CTX(body->ts);
82 php_stream_stat(php_http_message_body_stream(body), &body->ssb);
83 return &body->ssb;
84 }
85
86 PHP_HTTP_API char *php_http_message_body_etag(php_http_message_body_t *body)
87 {
88 TSRMLS_FETCH_FROM_CTX(body->ts);
89 php_stream_statbuf *ssb = php_http_message_body_stat(body);
90
91 /* real file or temp buffer ? */
92 if (body->ssb.sb.st_mtime) {
93 char *etag;
94
95 spprintf(&etag, 0, "%lx-%lx-%lx", ssb->sb.st_ino, ssb->sb.st_mtime, ssb->sb.st_size);
96 return etag;
97 } else {
98 void *ctx = php_http_etag_init(TSRMLS_C);
99
100 php_http_message_body_to_callback(body, php_http_etag_update, ctx, 0, 0);
101 return php_http_etag_finish(ctx TSRMLS_CC);
102 }
103 }
104
105 PHP_HTTP_API void php_http_message_body_to_string(php_http_message_body_t *body, char **buf, size_t *len, off_t offset, size_t forlen)
106 {
107 TSRMLS_FETCH_FROM_CTX(body->ts);
108 php_stream *s = php_http_message_body_stream(body);
109
110 php_stream_seek(s, offset, SEEK_SET);
111 if (!forlen) {
112 forlen = -1;
113 }
114 *len = php_stream_copy_to_mem(s, buf, forlen, 0);
115 }
116
117 PHP_HTTP_API void php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *dst, off_t offset, size_t forlen)
118 {
119 TSRMLS_FETCH_FROM_CTX(body->ts);
120 php_stream *s = php_http_message_body_stream(body);
121
122 php_stream_seek(s, offset, SEEK_SET);
123 if (!forlen) {
124 forlen = -1;
125 }
126 php_stream_copy_to_stream_ex(s, dst, forlen, NULL);
127 }
128
129 PHP_HTTP_API void php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen)
130 {
131 TSRMLS_FETCH_FROM_CTX(body->ts);
132 php_stream *s = php_http_message_body_stream(body);
133
134 php_stream_seek(s, offset, SEEK_SET);
135
136 if (!forlen) {
137 forlen = -1;
138 }
139 while (!php_stream_eof(s)) {
140 char buf[0x1000];
141 size_t read = php_stream_read(s, buf, MIN(forlen, sizeof(buf)));
142
143 if (read) {
144 cb(cb_arg, buf, read);
145 }
146
147 if (read < MIN(forlen, sizeof(buf))) {
148 break;
149 }
150
151 if (forlen && !(forlen -= read)) {
152 break;
153 }
154 }
155 }
156
157 PHP_HTTP_API STATUS php_http_message_body_to_callback_in_chunks(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, HashTable *chunks)
158 {
159 TSRMLS_FETCH_FROM_CTX(body->ts);
160 php_stream *s = php_http_message_body_stream(body);
161 HashPosition pos;
162 zval **chunk;
163
164 FOREACH_HASH_VAL(pos, chunks, chunk) {
165 zval **begin, **end;
166
167 if (IS_ARRAY == Z_TYPE_PP(chunk)
168 && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(chunk), 0, (void *) &begin)
169 && IS_LONG == Z_TYPE_PP(begin)
170 && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(chunk), 1, (void *) &end)
171 && IS_LONG == Z_TYPE_PP(end)
172 ) {
173 if (SUCCESS != php_stream_seek(s, Z_LVAL_PP(begin), SEEK_SET)) {
174 return FAILURE;
175 } else {
176 long length = Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1;
177
178 while (length > 0 && !php_stream_eof(s)) {
179 char buf[0x1000];
180 size_t read = php_stream_read(s, buf, MIN(length, sizeof(buf)));
181
182 if (read) {
183 cb(cb_arg, buf, read);
184 }
185
186 if (read < MIN(length, sizeof(buf))) {
187 break;
188 }
189
190 length -= read;
191 }
192 }
193 }
194 }
195
196 return SUCCESS;
197 }
198
199 PHP_HTTP_API size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len)
200 {
201 TSRMLS_FETCH_FROM_CTX(body->ts);
202 php_stream *s = php_http_message_body_stream(body);
203
204 php_stream_seek(s, 0, SEEK_END);
205 return php_stream_write(s, buf, len);
206 }
207
208 PHP_HTTP_API STATUS php_http_message_body_add(php_http_message_body_t *body, HashTable *fields, HashTable *files)
209 {
210 post_data http_post_data = {NULL, NULL};
211 TSRMLS_FETCH_FROM_CTX(body->ts);
212
213 if (fields && SUCCESS != recursive_fields(http_post_data, fields, NULL TSRMLS_CC)) {
214 return FAILURE;
215 }
216 if (files && (zend_hash_num_elements(files) > 0) && (SUCCESS != recursive_files(http_post_data, files, NULL TSRMLS_CC))) {
217 return FAILURE;
218 }
219 if (CURLE_OK != curl_formget(http_post_data[0], body, (curl_formget_callback) php_http_message_body_append)) {
220 return FAILURE;
221 }
222 return SUCCESS;
223 }
224
225 PHP_HTTP_API STATUS php_http_message_body_add_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len)
226 {
227 return add_field(body, name, value_str, value_len);
228 }
229
230 PHP_HTTP_API STATUS php_http_message_body_add_file(php_http_message_body_t *body, const char *name, const char *path, const char *ctype)
231 {
232 return add_file(body, name, path, ctype);
233 }
234
235 static inline char *format_key(uint type, char *str, ulong num, const char *prefix, int numeric_key_for_empty_prefix) {
236 char *new_key = NULL;
237
238 if (prefix && *prefix) {
239 if (type == HASH_KEY_IS_STRING) {
240 spprintf(&new_key, 0, "%s[%s]", prefix, str);
241 } else {
242 spprintf(&new_key, 0, "%s[%lu]", prefix, num);
243 }
244 } else if (type == HASH_KEY_IS_STRING) {
245 new_key = estrdup(str);
246 } else if (numeric_key_for_empty_prefix) {
247 spprintf(&new_key, 0, "%lu", num);
248 }
249
250 return new_key;
251 }
252
253 static inline STATUS add_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len)
254 {
255 post_data http_post_data = {NULL, NULL};
256 CURLcode err;
257
258 err = curl_formadd(&http_post_data[0], &http_post_data[1],
259 CURLFORM_COPYNAME, name,
260 CURLFORM_COPYCONTENTS, value_str,
261 CURLFORM_CONTENTSLENGTH, (long) value_len,
262 CURLFORM_END
263 );
264
265 if (CURLE_OK != err) {
266 return FAILURE;
267 }
268
269 err = curl_formget(http_post_data[0], body, (curl_formget_callback) php_http_message_body_append);
270
271 if (CURLE_OK != err) {
272 curl_formfree(http_post_data[0]);
273 return FAILURE;
274 }
275
276 curl_formfree(http_post_data[0]);
277 return SUCCESS;
278 }
279
280 static inline STATUS add_file(php_http_message_body_t *body, const char *name, const char *path, const char *ctype)
281 {
282 post_data http_post_data = {NULL, NULL};
283 CURLcode err;
284
285 err = curl_formadd(&http_post_data[0], &http_post_data[1],
286 CURLFORM_COPYNAME, name,
287 CURLFORM_FILE, path,
288 CURLFORM_CONTENTTYPE, ctype ? ctype : "application/octet-stream",
289 CURLFORM_END
290 );
291
292 if (CURLE_OK != err) {
293 return FAILURE;
294 }
295
296 err = curl_formget(http_post_data[0], body, (curl_formget_callback) php_http_message_body_append);
297
298 if (CURLE_OK != err) {
299 curl_formfree(http_post_data[0]);
300 return FAILURE;
301 }
302
303 curl_formfree(http_post_data[0]);
304 return SUCCESS;
305 }
306
307 static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC) {
308 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
309 zval **data_ptr;
310 HashPosition pos;
311 char *new_key = NULL;
312 CURLcode err = 0;
313
314 if (fields && !fields->nApplyCount) {
315 FOREACH_HASH_KEYVAL(pos, fields, key, data_ptr) {
316 if (key.type != HASH_KEY_IS_STRING || *key.str) {
317 new_key = format_key(key.type, key.str, key.num, prefix, 1);
318
319 switch (Z_TYPE_PP(data_ptr)) {
320 case IS_ARRAY:
321 case IS_OBJECT: {
322 STATUS status;
323
324 ++fields->nApplyCount;
325 status = recursive_fields(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
326 --fields->nApplyCount;
327
328 if (SUCCESS != status) {
329 goto error;
330 }
331 break;
332 }
333
334 default: {
335 zval *data = php_http_zsep(IS_STRING, *data_ptr);
336
337 err = curl_formadd(&http_post_data[0], &http_post_data[1],
338 CURLFORM_COPYNAME, new_key,
339 CURLFORM_COPYCONTENTS, Z_STRVAL_P(data),
340 CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_P(data),
341 CURLFORM_END
342 );
343
344 zval_ptr_dtor(&data);
345
346 if (CURLE_OK != err) {
347 goto error;
348 }
349 break;
350 }
351 }
352 STR_FREE(new_key);
353 }
354 }
355 }
356
357 return SUCCESS;
358
359 error:
360 if (new_key) {
361 efree(new_key);
362 }
363 if (http_post_data[0]) {
364 curl_formfree(http_post_data[0]);
365 }
366 if (err) {
367 php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
368 } else {
369 php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post fields: unknown error");
370 }
371 return FAILURE;
372 }
373
374 static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC) {
375 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
376 zval **data_ptr;
377 HashPosition pos;
378 char *new_key = NULL;
379 CURLcode err = 0;
380
381 if (files && !files->nApplyCount) {
382 FOREACH_HASH_KEYVAL(pos, files, key, data_ptr) {
383 zval **file_ptr, **type_ptr, **name_ptr;
384
385 if (key.type != HASH_KEY_IS_STRING || *key.str) {
386 new_key = format_key(key.type, key.str, key.num, prefix, 0);
387
388 if (Z_TYPE_PP(data_ptr) != IS_ARRAY && Z_TYPE_PP(data_ptr) != IS_OBJECT) {
389 if (new_key || key.type == HASH_KEY_IS_STRING) {
390 php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%s'", new_key ? new_key : key.str);
391 } else {
392 php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%lu'", key.num);
393 }
394 } else if ( SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "name", sizeof("name"), (void *) &name_ptr) ||
395 SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "type", sizeof("type"), (void *) &type_ptr) ||
396 SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "file", sizeof("file"), (void *) &file_ptr)) {
397 STATUS status;
398
399 ++files->nApplyCount;
400 status = recursive_files(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
401 --files->nApplyCount;
402
403 if (SUCCESS != status) {
404 goto error;
405 }
406 } else {
407 const char *path;
408 zval *file = php_http_zsep(IS_STRING, *file_ptr);
409 zval *type = php_http_zsep(IS_STRING, *type_ptr);
410 zval *name = php_http_zsep(IS_STRING, *name_ptr);
411
412 if (SUCCESS != php_check_open_basedir(Z_STRVAL_P(file) TSRMLS_CC)) {
413 goto error;
414 }
415
416 /* this is blatant but should be sufficient for most cases */
417 if (strncasecmp(Z_STRVAL_P(file), "file://", lenof("file://"))) {
418 path = Z_STRVAL_P(file);
419 } else {
420 path = Z_STRVAL_P(file) + lenof("file://");
421 }
422
423 if (new_key) {
424 char *tmp_key = format_key(HASH_KEY_IS_STRING, Z_STRVAL_P(name), 0, new_key, 0);
425 STR_SET(new_key, tmp_key);
426 }
427
428 err = curl_formadd(&http_post_data[0], &http_post_data[1],
429 CURLFORM_COPYNAME, new_key ? new_key : Z_STRVAL_P(name),
430 CURLFORM_FILE, path,
431 CURLFORM_CONTENTTYPE, Z_STRVAL_P(type),
432 CURLFORM_END
433 );
434
435 zval_ptr_dtor(&file);
436 zval_ptr_dtor(&type);
437 zval_ptr_dtor(&name);
438
439 if (CURLE_OK != err) {
440 goto error;
441 }
442 }
443 STR_FREE(new_key);
444 }
445 }
446 }
447
448 return SUCCESS;
449
450 error:
451 if (new_key) {
452 efree(new_key);
453 }
454 if (http_post_data[0]) {
455 curl_formfree(http_post_data[0]);
456 }
457 if (err) {
458 php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
459 } else {
460 php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Could not encode post files: unknown error");
461 }
462 return FAILURE;
463 }
464
465 /* PHP */
466
467 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpMessageBody, method, 0, req_args)
468 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpMessageBody, method, 0)
469 #define PHP_HTTP_MESSAGE_BODY_ME(method, visibility) PHP_ME(HttpMessageBody, method, PHP_HTTP_ARGS(HttpMessageBody, method), visibility)
470
471 PHP_HTTP_BEGIN_ARGS(__construct, 0)
472 PHP_HTTP_ARG_VAL(stream, 0)
473 PHP_HTTP_END_ARGS;
474
475 PHP_HTTP_EMPTY_ARGS(__toString);
476
477 PHP_HTTP_BEGIN_ARGS(toStream, 1)
478 PHP_HTTP_ARG_VAL(stream, 0)
479 PHP_HTTP_END_ARGS;
480
481 PHP_HTTP_BEGIN_ARGS(toCallback, 1)
482 PHP_HTTP_ARG_VAL(callback, 0)
483 PHP_HTTP_END_ARGS;
484
485 PHP_HTTP_BEGIN_ARGS(append, 1)
486 PHP_HTTP_ARG_VAL(string, 0)
487 PHP_HTTP_END_ARGS;
488
489 PHP_HTTP_BEGIN_ARGS(add, 0)
490 PHP_HTTP_ARG_VAL(fields, 0)
491 PHP_HTTP_ARG_VAL(files, 0)
492 PHP_HTTP_END_ARGS;
493
494
495 zend_class_entry *php_http_message_body_class_entry;
496 zend_function_entry php_http_message_body_method_entry[] = {
497 PHP_HTTP_MESSAGE_BODY_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
498 PHP_HTTP_MESSAGE_BODY_ME(__toString, ZEND_ACC_PUBLIC)
499 PHP_MALIAS(HttpMessageBody, toString, __toString, args_for_HttpMessageBody___toString, ZEND_ACC_PUBLIC)
500 PHP_HTTP_MESSAGE_BODY_ME(toStream, ZEND_ACC_PUBLIC)
501 PHP_HTTP_MESSAGE_BODY_ME(toCallback, ZEND_ACC_PUBLIC)
502 PHP_HTTP_MESSAGE_BODY_ME(append, ZEND_ACC_PUBLIC)
503 PHP_HTTP_MESSAGE_BODY_ME(add, ZEND_ACC_PUBLIC)
504 EMPTY_FUNCTION_ENTRY
505 };
506 static zend_object_handlers php_http_message_body_object_handlers;
507
508 PHP_MINIT_FUNCTION(http_message_body)
509 {
510 PHP_HTTP_REGISTER_CLASS(http\\message, Body, http_message_body, php_http_object_class_entry, 0);
511 php_http_message_body_class_entry->create_object = php_http_message_body_object_new;
512 memcpy(&php_http_message_body_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
513 php_http_message_body_object_handlers.clone_obj = php_http_message_body_object_clone;
514
515 return SUCCESS;
516 }
517
518 zend_object_value php_http_message_body_object_new(zend_class_entry *ce TSRMLS_DC)
519 {
520 return php_http_message_body_object_new_ex(ce, NULL, NULL TSRMLS_CC);
521 }
522
523 zend_object_value php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body, php_http_message_body_object_t **ptr TSRMLS_DC)
524 {
525 zend_object_value ov;
526 php_http_message_body_object_t *o;
527
528 o = ecalloc(1, sizeof(php_http_message_body_object_t));
529 zend_object_std_init((zend_object *) o, php_http_message_body_class_entry TSRMLS_CC);
530 object_properties_init((zend_object *) o, ce);
531
532 if (ptr) {
533 *ptr = o;
534 }
535
536 if (body) {
537 o->body = body;
538 }
539
540 ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_body_object_free, NULL TSRMLS_CC);
541 ov.handlers = &php_http_message_body_object_handlers;
542
543 return ov;
544 }
545
546 zend_object_value php_http_message_body_object_clone(zval *object TSRMLS_DC)
547 {
548 zend_object_value new_ov;
549 php_http_message_body_object_t *new_obj = NULL;
550 php_http_message_body_object_t *old_obj = zend_object_store_get_object(object TSRMLS_CC);
551
552 new_ov = php_http_message_body_object_new_ex(old_obj->zo.ce, php_http_message_body_copy(old_obj->body, NULL, 1), &new_obj);
553 zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC);
554
555 return new_ov;
556 }
557
558 void php_http_message_body_object_free(void *object TSRMLS_DC)
559 {
560 php_http_message_body_object_t *obj = object;
561
562 php_http_message_body_free(&obj->body);
563
564 zend_object_std_dtor((zend_object *) obj TSRMLS_CC);
565 efree(obj);
566 }
567
568 PHP_METHOD(HttpMessageBody, __construct)
569 {
570 php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
571 zval *zstream;
572 php_stream *stream;
573
574 with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
575 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream)) {
576 php_stream_from_zval(stream, &zstream);
577
578 if (stream) {
579 if (obj->body) {
580 php_http_message_body_dtor(obj->body);
581 }
582 obj->body = php_http_message_body_init(obj->body, stream TSRMLS_CC);
583 }
584 }
585 } end_error_handling();
586 }
587
588 PHP_METHOD(HttpMessageBody, __toString)
589 {
590 if (SUCCESS == zend_parse_parameters_none()) {
591 php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
592 char *str;
593 size_t len;
594
595 php_http_message_body_to_string(obj->body, &str, &len, 0, 0);
596 if (str) {
597 RETURN_STRINGL(str, len, 0);
598 }
599 }
600 RETURN_EMPTY_STRING();
601 }
602
603 PHP_METHOD(HttpMessageBody, toStream)
604 {
605 zval *zstream;
606 long offset = 0, forlen = 0;
607
608 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ll", &zstream, &offset, &forlen)) {
609 php_stream *stream;
610 php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
611
612 php_stream_from_zval(stream, &zstream);
613 php_http_message_body_to_stream(obj->body, stream, offset, forlen);
614 RETURN_TRUE;
615 }
616 RETURN_FALSE;
617 }
618
619 struct fcd {
620 zval *fcz;
621 zend_fcall_info *fci;
622 zend_fcall_info_cache *fcc;
623 };
624
625 static size_t pass(void *cb_arg, const char *str, size_t len TSRMLS_DC)
626 {
627 struct fcd *fcd = cb_arg;
628 zval *zdata;
629
630 MAKE_STD_ZVAL(zdata);
631 ZVAL_STRINGL(zdata, str, len, 1);
632 if (SUCCESS == zend_fcall_info_argn(fcd->fci TSRMLS_CC, 2, fcd->fcz, zdata)) {
633 zend_fcall_info_call(fcd->fci, fcd->fcc, NULL, NULL TSRMLS_CC);
634 zend_fcall_info_args_clear(fcd->fci, 0);
635 }
636 zval_ptr_dtor(&zdata);
637 return len;
638 }
639
640 PHP_METHOD(HttpMessageBody, toCallback)
641 {
642 struct fcd fcd;
643 long offset = 0, forlen = 0;
644
645 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f|ll", &fcd.fci, &fcd.fcc, &offset, &forlen)) {
646 php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
647 fcd.fcz = getThis();
648 Z_ADDREF_P(fcd.fcz);
649 php_http_message_body_to_callback(obj->body, pass, &fcd, offset, forlen);
650 zval_ptr_dtor(&fcd.fcz);
651 RETURN_TRUE;
652 }
653 RETURN_FALSE;
654 }
655
656 PHP_METHOD(HttpMessageBody, append)
657 {
658 char *str;
659 int len;
660
661 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
662 php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
663
664 RETURN_LONG(php_http_message_body_append(obj->body, str, len));
665 }
666 RETURN_FALSE;
667 }
668
669 PHP_METHOD(HttpMessageBody, add)
670 {
671 HashTable *fields = NULL, *files = NULL;
672
673 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|hh", &fields, &files)) {
674 php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
675
676 RETURN_SUCCESS(php_http_message_body_add(obj->body, fields, files));
677 }
678 RETURN_FALSE;
679 }
680 /*
681 * Local variables:
682 * tab-width: 4
683 * c-basic-offset: 4
684 * End:
685 * vim600: noet sw=4 ts=4 fdm=marker
686 * vim<600: noet sw=4 ts=4
687 */