- win32 build now has libcurl v7.16.0
[m6w6/ext-http] / http_request_object.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-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_CURL
16 #include "php_http.h"
17
18 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
19
20 #include "zend_interfaces.h"
21
22 #include "php_http_api.h"
23 #include "php_http_cookie_api.h"
24 #include "php_http_exception_object.h"
25 #include "php_http_message_api.h"
26 #include "php_http_message_object.h"
27 #include "php_http_request_api.h"
28 #include "php_http_request_object.h"
29 #include "php_http_request_pool_api.h"
30 #include "php_http_url_api.h"
31
32 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpRequest, method, 0, req_args)
33 #define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpRequest, method, 0)
34 #define HTTP_REQUEST_ME(method, visibility) PHP_ME(HttpRequest, method, HTTP_ARGS(HttpRequest, method), visibility)
35 #define HTTP_REQUEST_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpRequest, method))
36
37 HTTP_BEGIN_ARGS(__construct, 0)
38 HTTP_ARG_VAL(url, 0)
39 HTTP_ARG_VAL(method, 0)
40 HTTP_ARG_VAL(options, 0)
41 HTTP_END_ARGS;
42
43 HTTP_EMPTY_ARGS(getOptions);
44 HTTP_BEGIN_ARGS(setOptions, 0)
45 HTTP_ARG_VAL(options, 0)
46 HTTP_END_ARGS;
47
48 HTTP_EMPTY_ARGS(getSslOptions);
49 HTTP_BEGIN_ARGS(setSslOptions, 0)
50 HTTP_ARG_VAL(ssl_options, 0)
51 HTTP_END_ARGS;
52
53 HTTP_BEGIN_ARGS(addSslOptions, 0)
54 HTTP_ARG_VAL(ssl_optins, 0)
55 HTTP_END_ARGS;
56
57 HTTP_EMPTY_ARGS(getHeaders);
58 HTTP_BEGIN_ARGS(setHeaders, 0)
59 HTTP_ARG_VAL(headers, 0)
60 HTTP_END_ARGS;
61
62 HTTP_BEGIN_ARGS(addHeaders, 1)
63 HTTP_ARG_VAL(headers, 0)
64 HTTP_END_ARGS;
65
66 HTTP_EMPTY_ARGS(getCookies);
67 HTTP_BEGIN_ARGS(setCookies, 0)
68 HTTP_ARG_VAL(cookies, 0)
69 HTTP_END_ARGS;
70
71 HTTP_BEGIN_ARGS(addCookies, 1)
72 HTTP_ARG_VAL(cookies, 0)
73 HTTP_END_ARGS;
74
75 HTTP_EMPTY_ARGS(enableCookies);
76 #if HTTP_CURL_VERSION(7,14,1)
77 HTTP_BEGIN_ARGS(resetCookies, 0)
78 HTTP_ARG_VAL(session_only, 0)
79 HTTP_END_ARGS;
80 #endif
81
82 HTTP_EMPTY_ARGS(getUrl);
83 HTTP_BEGIN_ARGS(setUrl, 1)
84 HTTP_ARG_VAL(url, 0)
85 HTTP_END_ARGS;
86
87 HTTP_EMPTY_ARGS(getMethod);
88 HTTP_BEGIN_ARGS(setMethod, 1)
89 HTTP_ARG_VAL(request_method, 0)
90 HTTP_END_ARGS;
91
92 HTTP_EMPTY_ARGS(getContentType);
93 HTTP_BEGIN_ARGS(setContentType, 1)
94 HTTP_ARG_VAL(content_type, 0)
95 HTTP_END_ARGS;
96
97 HTTP_EMPTY_ARGS(getQueryData);
98 HTTP_BEGIN_ARGS(setQueryData, 0)
99 HTTP_ARG_VAL(query_data, 0)
100 HTTP_END_ARGS;
101
102 HTTP_BEGIN_ARGS(addQueryData, 1)
103 HTTP_ARG_VAL(query_data, 0)
104 HTTP_END_ARGS;
105
106 HTTP_EMPTY_ARGS(getPostFields);
107 HTTP_BEGIN_ARGS(setPostFields, 0)
108 HTTP_ARG_VAL(post_fields, 0)
109 HTTP_END_ARGS;
110
111 HTTP_BEGIN_ARGS(addPostFields, 1)
112 HTTP_ARG_VAL(post_fields, 0)
113 HTTP_END_ARGS;
114
115 HTTP_EMPTY_ARGS(getPostFiles);
116 HTTP_BEGIN_ARGS(setPostFiles, 0)
117 HTTP_ARG_VAL(post_files, 0)
118 HTTP_END_ARGS;
119
120 HTTP_BEGIN_ARGS(addPostFile, 2)
121 HTTP_ARG_VAL(formname, 0)
122 HTTP_ARG_VAL(filename, 0)
123 HTTP_ARG_VAL(content_type, 0)
124 HTTP_END_ARGS;
125
126 HTTP_EMPTY_ARGS(getRawPostData);
127 HTTP_BEGIN_ARGS(setRawPostData, 0)
128 HTTP_ARG_VAL(raw_post_data, 0)
129 HTTP_END_ARGS;
130
131 HTTP_BEGIN_ARGS(addRawPostData, 1)
132 HTTP_ARG_VAL(raw_post_data, 0)
133 HTTP_END_ARGS;
134
135 HTTP_EMPTY_ARGS(getPutFile);
136 HTTP_BEGIN_ARGS(setPutFile, 0)
137 HTTP_ARG_VAL(filename, 0)
138 HTTP_END_ARGS;
139
140 HTTP_EMPTY_ARGS(getPutData);
141 HTTP_BEGIN_ARGS(setPutData, 0)
142 HTTP_ARG_VAL(put_data, 0)
143 HTTP_END_ARGS;
144
145 HTTP_BEGIN_ARGS(addPutData, 1)
146 HTTP_ARG_VAL(put_data, 0)
147 HTTP_END_ARGS;
148
149 HTTP_EMPTY_ARGS(getResponseData);
150 HTTP_BEGIN_ARGS(getResponseHeader, 0)
151 HTTP_ARG_VAL(name, 0)
152 HTTP_END_ARGS;
153
154 HTTP_BEGIN_ARGS(getResponseCookies, 0)
155 HTTP_ARG_VAL(flags, 0)
156 HTTP_ARG_VAL(allowed_extras, 0)
157 HTTP_END_ARGS;
158
159 HTTP_EMPTY_ARGS(getResponseBody);
160 HTTP_EMPTY_ARGS(getResponseCode);
161 HTTP_EMPTY_ARGS(getResponseStatus);
162 HTTP_BEGIN_ARGS(getResponseInfo, 0)
163 HTTP_ARG_VAL(name, 0)
164 HTTP_END_ARGS;
165
166 HTTP_EMPTY_ARGS(getResponseMessage);
167 HTTP_EMPTY_ARGS(getRawResponseMessage);
168 HTTP_EMPTY_ARGS(getRequestMessage);
169 HTTP_EMPTY_ARGS(getRawRequestMessage);
170 HTTP_EMPTY_ARGS(getHistory);
171 HTTP_EMPTY_ARGS(clearHistory);
172 HTTP_EMPTY_ARGS(send);
173
174 HTTP_BEGIN_ARGS(get, 1)
175 HTTP_ARG_VAL(url, 0)
176 HTTP_ARG_VAL(options, 0)
177 HTTP_ARG_VAL(info, 1)
178 HTTP_END_ARGS;
179
180 HTTP_BEGIN_ARGS(head, 1)
181 HTTP_ARG_VAL(url, 0)
182 HTTP_ARG_VAL(options, 0)
183 HTTP_ARG_VAL(info, 1)
184 HTTP_END_ARGS;
185
186 HTTP_BEGIN_ARGS(postData, 2)
187 HTTP_ARG_VAL(url, 0)
188 HTTP_ARG_VAL(data, 0)
189 HTTP_ARG_VAL(options, 0)
190 HTTP_ARG_VAL(info, 1)
191 HTTP_END_ARGS;
192
193 HTTP_BEGIN_ARGS(postFields, 2)
194 HTTP_ARG_VAL(url, 0)
195 HTTP_ARG_VAL(data, 0)
196 HTTP_ARG_VAL(options, 0)
197 HTTP_ARG_VAL(info, 1)
198 HTTP_END_ARGS;
199
200 HTTP_BEGIN_ARGS(putData, 2)
201 HTTP_ARG_VAL(url, 0)
202 HTTP_ARG_VAL(data, 0)
203 HTTP_ARG_VAL(options, 0)
204 HTTP_ARG_VAL(info, 1)
205 HTTP_END_ARGS;
206
207 HTTP_BEGIN_ARGS(putFile, 2)
208 HTTP_ARG_VAL(url, 0)
209 HTTP_ARG_VAL(file, 0)
210 HTTP_ARG_VAL(options, 0)
211 HTTP_ARG_VAL(info, 1)
212 HTTP_END_ARGS;
213
214 HTTP_BEGIN_ARGS(putStream, 2)
215 HTTP_ARG_VAL(url, 0)
216 HTTP_ARG_VAL(stream, 0)
217 HTTP_ARG_VAL(options, 0)
218 HTTP_ARG_VAL(info, 1)
219 HTTP_END_ARGS;
220
221 HTTP_BEGIN_ARGS(methodRegister, 1)
222 HTTP_ARG_VAL(method_name, 0)
223 HTTP_END_ARGS;
224
225 HTTP_BEGIN_ARGS(methodUnregister, 1)
226 HTTP_ARG_VAL(method, 0)
227 HTTP_END_ARGS;
228
229 HTTP_BEGIN_ARGS(methodName, 1)
230 HTTP_ARG_VAL(method_id, 0)
231 HTTP_END_ARGS;
232
233 HTTP_BEGIN_ARGS(methodExists, 1)
234 HTTP_ARG_VAL(method, 0)
235 HTTP_END_ARGS;
236
237 #ifdef HAVE_CURL_GETFORMDATA
238 HTTP_BEGIN_ARGS(encodeBody, 2)
239 HTTP_ARG_VAL(fields, 0)
240 HTTP_ARG_VAL(files, 0)
241 HTTP_END_ARGS;
242 #endif
243
244 #define OBJ_PROP_CE http_request_object_ce
245 zend_class_entry *http_request_object_ce;
246 zend_function_entry http_request_object_fe[] = {
247 HTTP_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
248
249 HTTP_REQUEST_ME(setOptions, ZEND_ACC_PUBLIC)
250 HTTP_REQUEST_ME(getOptions, ZEND_ACC_PUBLIC)
251 HTTP_REQUEST_ME(setSslOptions, ZEND_ACC_PUBLIC)
252 HTTP_REQUEST_ME(getSslOptions, ZEND_ACC_PUBLIC)
253 HTTP_REQUEST_ME(addSslOptions, ZEND_ACC_PUBLIC)
254
255 HTTP_REQUEST_ME(addHeaders, ZEND_ACC_PUBLIC)
256 HTTP_REQUEST_ME(getHeaders, ZEND_ACC_PUBLIC)
257 HTTP_REQUEST_ME(setHeaders, ZEND_ACC_PUBLIC)
258
259 HTTP_REQUEST_ME(addCookies, ZEND_ACC_PUBLIC)
260 HTTP_REQUEST_ME(getCookies, ZEND_ACC_PUBLIC)
261 HTTP_REQUEST_ME(setCookies, ZEND_ACC_PUBLIC)
262
263 HTTP_REQUEST_ME(enableCookies, ZEND_ACC_PUBLIC)
264 #if HTTP_CURL_VERSION(7,14,1)
265 HTTP_REQUEST_ME(resetCookies, ZEND_ACC_PUBLIC)
266 #endif
267
268 HTTP_REQUEST_ME(setMethod, ZEND_ACC_PUBLIC)
269 HTTP_REQUEST_ME(getMethod, ZEND_ACC_PUBLIC)
270
271 HTTP_REQUEST_ME(setUrl, ZEND_ACC_PUBLIC)
272 HTTP_REQUEST_ME(getUrl, ZEND_ACC_PUBLIC)
273
274 HTTP_REQUEST_ME(setContentType, ZEND_ACC_PUBLIC)
275 HTTP_REQUEST_ME(getContentType, ZEND_ACC_PUBLIC)
276
277 HTTP_REQUEST_ME(setQueryData, ZEND_ACC_PUBLIC)
278 HTTP_REQUEST_ME(getQueryData, ZEND_ACC_PUBLIC)
279 HTTP_REQUEST_ME(addQueryData, ZEND_ACC_PUBLIC)
280
281 HTTP_REQUEST_ME(setPostFields, ZEND_ACC_PUBLIC)
282 HTTP_REQUEST_ME(getPostFields, ZEND_ACC_PUBLIC)
283 HTTP_REQUEST_ME(addPostFields, ZEND_ACC_PUBLIC)
284
285 HTTP_REQUEST_ME(setRawPostData, ZEND_ACC_PUBLIC)
286 HTTP_REQUEST_ME(getRawPostData, ZEND_ACC_PUBLIC)
287 HTTP_REQUEST_ME(addRawPostData, ZEND_ACC_PUBLIC)
288
289 HTTP_REQUEST_ME(setPostFiles, ZEND_ACC_PUBLIC)
290 HTTP_REQUEST_ME(addPostFile, ZEND_ACC_PUBLIC)
291 HTTP_REQUEST_ME(getPostFiles, ZEND_ACC_PUBLIC)
292
293 HTTP_REQUEST_ME(setPutFile, ZEND_ACC_PUBLIC)
294 HTTP_REQUEST_ME(getPutFile, ZEND_ACC_PUBLIC)
295
296 HTTP_REQUEST_ME(setPutData, ZEND_ACC_PUBLIC)
297 HTTP_REQUEST_ME(getPutData, ZEND_ACC_PUBLIC)
298 HTTP_REQUEST_ME(addPutData, ZEND_ACC_PUBLIC)
299
300 HTTP_REQUEST_ME(send, ZEND_ACC_PUBLIC)
301
302 HTTP_REQUEST_ME(getResponseData, ZEND_ACC_PUBLIC)
303 HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC)
304 HTTP_REQUEST_ME(getResponseCookies, ZEND_ACC_PUBLIC)
305 HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC)
306 HTTP_REQUEST_ME(getResponseStatus, ZEND_ACC_PUBLIC)
307 HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC)
308 HTTP_REQUEST_ME(getResponseInfo, ZEND_ACC_PUBLIC)
309 HTTP_REQUEST_ME(getResponseMessage, ZEND_ACC_PUBLIC)
310 HTTP_REQUEST_ME(getRawResponseMessage, ZEND_ACC_PUBLIC)
311 HTTP_REQUEST_ME(getRequestMessage, ZEND_ACC_PUBLIC)
312 HTTP_REQUEST_ME(getRawRequestMessage, ZEND_ACC_PUBLIC)
313 HTTP_REQUEST_ME(getHistory, ZEND_ACC_PUBLIC)
314 HTTP_REQUEST_ME(clearHistory, ZEND_ACC_PUBLIC)
315
316 HTTP_REQUEST_ALIAS(get, http_get)
317 HTTP_REQUEST_ALIAS(head, http_head)
318 HTTP_REQUEST_ALIAS(postData, http_post_data)
319 HTTP_REQUEST_ALIAS(postFields, http_post_fields)
320 HTTP_REQUEST_ALIAS(putData, http_put_data)
321 HTTP_REQUEST_ALIAS(putFile, http_put_file)
322 HTTP_REQUEST_ALIAS(putStream, http_put_stream)
323
324 HTTP_REQUEST_ALIAS(methodRegister, http_request_method_register)
325 HTTP_REQUEST_ALIAS(methodUnregister, http_request_method_unregister)
326 HTTP_REQUEST_ALIAS(methodName, http_request_method_name)
327 HTTP_REQUEST_ALIAS(methodExists, http_request_method_exists)
328 #ifdef HAVE_CURL_GETFORMDATA
329 HTTP_REQUEST_ALIAS(encodeBody, http_request_body_encode)
330 #endif
331 EMPTY_FUNCTION_ENTRY
332 };
333 static zend_object_handlers http_request_object_handlers;
334
335 PHP_MINIT_FUNCTION(http_request_object)
336 {
337 HTTP_REGISTER_CLASS_EX(HttpRequest, http_request_object, NULL, 0);
338 http_request_object_handlers.clone_obj = _http_request_object_clone_obj;
339
340 DCL_PROP_N(PRIVATE, options);
341 DCL_PROP_N(PRIVATE, postFields);
342 DCL_PROP_N(PRIVATE, postFiles);
343 DCL_PROP_N(PRIVATE, responseInfo);
344 DCL_PROP_N(PRIVATE, responseMessage);
345 DCL_PROP(PRIVATE, long, responseCode, 0);
346 DCL_PROP(PRIVATE, string, responseStatus, "");
347 DCL_PROP(PRIVATE, long, method, HTTP_GET);
348 DCL_PROP(PRIVATE, string, url, "");
349 DCL_PROP(PRIVATE, string, contentType, "");
350 DCL_PROP(PRIVATE, string, rawPostData, "");
351 DCL_PROP(PRIVATE, string, queryData, "");
352 DCL_PROP(PRIVATE, string, putFile, "");
353 DCL_PROP(PRIVATE, string, putData, "");
354 DCL_PROP_N(PRIVATE, history);
355 DCL_PROP(PUBLIC, bool, recordHistory, 0);
356
357 #ifndef WONKY
358 /*
359 * Request Method Constants
360 */
361 /* HTTP/1.1 */
362 DCL_CONST(long, "METH_GET", HTTP_GET);
363 DCL_CONST(long, "METH_HEAD", HTTP_HEAD);
364 DCL_CONST(long, "METH_POST", HTTP_POST);
365 DCL_CONST(long, "METH_PUT", HTTP_PUT);
366 DCL_CONST(long, "METH_DELETE", HTTP_DELETE);
367 DCL_CONST(long, "METH_OPTIONS", HTTP_OPTIONS);
368 DCL_CONST(long, "METH_TRACE", HTTP_TRACE);
369 DCL_CONST(long, "METH_CONNECT", HTTP_CONNECT);
370 /* WebDAV - RFC 2518 */
371 DCL_CONST(long, "METH_PROPFIND", HTTP_PROPFIND);
372 DCL_CONST(long, "METH_PROPPATCH", HTTP_PROPPATCH);
373 DCL_CONST(long, "METH_MKCOL", HTTP_MKCOL);
374 DCL_CONST(long, "METH_COPY", HTTP_COPY);
375 DCL_CONST(long, "METH_MOVE", HTTP_MOVE);
376 DCL_CONST(long, "METH_LOCK", HTTP_LOCK);
377 DCL_CONST(long, "METH_UNLOCK", HTTP_UNLOCK);
378 /* WebDAV Versioning - RFC 3253 */
379 DCL_CONST(long, "METH_VERSION_CONTROL", HTTP_VERSION_CONTROL);
380 DCL_CONST(long, "METH_REPORT", HTTP_REPORT);
381 DCL_CONST(long, "METH_CHECKOUT", HTTP_CHECKOUT);
382 DCL_CONST(long, "METH_CHECKIN", HTTP_CHECKIN);
383 DCL_CONST(long, "METH_UNCHECKOUT", HTTP_UNCHECKOUT);
384 DCL_CONST(long, "METH_MKWORKSPACE", HTTP_MKWORKSPACE);
385 DCL_CONST(long, "METH_UPDATE", HTTP_UPDATE);
386 DCL_CONST(long, "METH_LABEL", HTTP_LABEL);
387 DCL_CONST(long, "METH_MERGE", HTTP_MERGE);
388 DCL_CONST(long, "METH_BASELINE_CONTROL", HTTP_BASELINE_CONTROL);
389 DCL_CONST(long, "METH_MKACTIVITY", HTTP_MKACTIVITY);
390 /* WebDAV Access Control - RFC 3744 */
391 DCL_CONST(long, "METH_ACL", HTTP_ACL);
392
393 /*
394 * HTTP Protocol Version Constants
395 */
396 DCL_CONST(long, "VERSION_1_0", CURL_HTTP_VERSION_1_0);
397 DCL_CONST(long, "VERSION_1_1", CURL_HTTP_VERSION_1_1);
398 DCL_CONST(long, "VERSION_NONE", CURL_HTTP_VERSION_NONE); /* to be removed */
399 DCL_CONST(long, "VERSION_ANY", CURL_HTTP_VERSION_NONE);
400
401 /*
402 * SSL Version Constants
403 */
404 DCL_CONST(long, "SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1);
405 DCL_CONST(long, "SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2);
406 DCL_CONST(long, "SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3);
407 DCL_CONST(long, "SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT);
408
409 /*
410 * DNS IPvX resolving
411 */
412 DCL_CONST(long, "IPRESOLVE_V4", CURL_IPRESOLVE_V4);
413 DCL_CONST(long, "IPRESOLVE_V6", CURL_IPRESOLVE_V6);
414 DCL_CONST(long, "IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER);
415
416 /*
417 * Auth Constants
418 */
419 DCL_CONST(long, "AUTH_BASIC", CURLAUTH_BASIC);
420 DCL_CONST(long, "AUTH_DIGEST", CURLAUTH_DIGEST);
421 DCL_CONST(long, "AUTH_NTLM", CURLAUTH_NTLM);
422 DCL_CONST(long, "AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE);
423 DCL_CONST(long, "AUTH_ANY", CURLAUTH_ANY);
424
425 /*
426 * Proxy Type Constants
427 */
428 # if HTTP_CURL_VERSION(7,15,2)
429 DCL_CONST(long, "PROXY_SOCKS4", CURLPROXY_SOCKS4);
430 # endif
431 DCL_CONST(long, "PROXY_SOCKS5", CURLPROXY_SOCKS5);
432 DCL_CONST(long, "PROXY_HTTP", CURLPROXY_HTTP);
433 #endif /* WONKY */
434
435 return SUCCESS;
436 }
437
438 zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC)
439 {
440 return http_request_object_new_ex(ce, NULL, NULL);
441 }
442
443 zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL *ch, http_request_object **ptr TSRMLS_DC)
444 {
445 zend_object_value ov;
446 http_request_object *o;
447
448 o = ecalloc(1, sizeof(http_request_object));
449 o->zo.ce = ce;
450 o->request = http_request_init_ex(NULL, ch, 0, NULL);
451
452 if (ptr) {
453 *ptr = o;
454 }
455
456 ALLOC_HASHTABLE(OBJ_PROP(o));
457 zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
458 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
459
460 ov.handle = putObject(http_request_object, o);
461 ov.handlers = &http_request_object_handlers;
462
463 return ov;
464 }
465
466 zend_object_value _http_request_object_clone_obj(zval *this_ptr TSRMLS_DC)
467 {
468 zend_object_value new_ov;
469 http_request_object *new_obj;
470 getObject(http_request_object, old_obj);
471
472 new_ov = http_request_object_new_ex(old_obj->zo.ce, NULL, &new_obj);
473 if (old_obj->request->ch) {
474 http_curl_init_ex(curl_easy_duphandle(old_obj->request->ch), new_obj->request);
475 }
476
477 zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
478 phpstr_append(&new_obj->request->conv.request, old_obj->request->conv.request.data, old_obj->request->conv.request.used);
479 phpstr_append(&new_obj->request->conv.response, old_obj->request->conv.response.data, old_obj->request->conv.response.used);
480
481 return new_ov;
482 }
483
484 void _http_request_object_free(zend_object *object TSRMLS_DC)
485 {
486 http_request_object *o = (http_request_object *) object;
487
488 http_request_free(&o->request);
489 freeObject(o);
490 }
491
492 #define http_request_object_check_request_content_type(t) _http_request_object_check_request_content_type((t) TSRMLS_CC)
493 static inline void _http_request_object_check_request_content_type(zval *this_ptr TSRMLS_DC)
494 {
495 zval *ctype = GET_PROP(contentType);
496
497 if (Z_STRLEN_P(ctype)) {
498 zval **headers, *opts = GET_PROP(options);
499
500 if ( (Z_TYPE_P(opts) == IS_ARRAY) &&
501 (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void *) &headers)) &&
502 (Z_TYPE_PP(headers) == IS_ARRAY)) {
503 zval **ct_header;
504
505 /* only override if not already set */
506 if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(headers), "Content-Type", sizeof("Content-Type"), (void *) &ct_header))) {
507 add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
508 } else
509 /* or not a string, zero length string or a string of spaces */
510 if ((Z_TYPE_PP(ct_header) != IS_STRING) || !Z_STRLEN_PP(ct_header)) {
511 add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
512 } else {
513 int i, only_space = 1;
514
515 /* check for spaces only */
516 for (i = 0; i < Z_STRLEN_PP(ct_header); ++i) {
517 if (!HTTP_IS_CTYPE(space, Z_STRVAL_PP(ct_header)[i])) {
518 only_space = 0;
519 break;
520 }
521 }
522 if (only_space) {
523 add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
524 }
525 }
526 } else {
527 zval *headers;
528
529 MAKE_STD_ZVAL(headers);
530 array_init(headers);
531 add_assoc_stringl(headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
532 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, headers);
533 zval_ptr_dtor(&headers);
534 }
535 }
536 }
537
538 STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr TSRMLS_DC)
539 {
540 STATUS status = SUCCESS;
541
542 http_request_reset(obj->request);
543 HTTP_CHECK_CURL_INIT(obj->request->ch, http_curl_init(obj->request), return FAILURE);
544
545 obj->request->url = http_absolute_url(Z_STRVAL_P(GET_PROP(url)));
546
547 switch (obj->request->meth = Z_LVAL_P(GET_PROP(method)))
548 {
549 case HTTP_GET:
550 case HTTP_HEAD:
551 break;
552
553 case HTTP_PUT:
554 {
555 zval *put_file = GET_PROP(putFile);
556
557 http_request_object_check_request_content_type(getThis());
558
559 if (Z_STRLEN_P(put_file)) {
560 php_stream_statbuf ssb;
561 php_stream *stream = php_stream_open_wrapper_ex(Z_STRVAL_P(put_file), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT);
562
563 if (stream && SUCCESS == php_stream_stat(stream, &ssb)) {
564 obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 1);
565 } else {
566 status = FAILURE;
567 }
568 } else {
569 zval *put_data = GET_PROP(putData);
570 obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_CSTRING,
571 estrndup(Z_STRVAL_P(put_data), Z_STRLEN_P(put_data)), Z_STRLEN_P(put_data), 1);
572 }
573 break;
574 }
575
576 case HTTP_POST:
577 default:
578 {
579 /* check for raw post data */
580 zval *raw_data = GET_PROP(rawPostData);
581
582 if (Z_STRLEN_P(raw_data)) {
583 http_request_object_check_request_content_type(getThis());
584 obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_CSTRING,
585 estrndup(Z_STRVAL_P(raw_data), Z_STRLEN_P(raw_data)), Z_STRLEN_P(raw_data), 1);
586 } else {
587 zval *zfields = GET_PROP(postFields), *zfiles = GET_PROP(postFiles);
588 HashTable *fields;
589 HashTable *files;
590
591 fields = (Z_TYPE_P(zfields) == IS_ARRAY) ? Z_ARRVAL_P(zfields) : NULL;
592 files = (Z_TYPE_P(zfiles) == IS_ARRAY) ? Z_ARRVAL_P(zfiles) : NULL;
593
594 if ((fields && zend_hash_num_elements(fields)) || (files && zend_hash_num_elements(files))) {
595 if (!(obj->request->body = http_request_body_fill(obj->request->body, fields, files))) {
596 status = FAILURE;
597 }
598 }
599 }
600 break;
601 }
602 }
603
604 if (status == SUCCESS) {
605 zval *qdata = GET_PROP(queryData);
606 zval *options = GET_PROP(options);
607
608 if (Z_STRLEN_P(qdata)) {
609 if (!strchr(obj->request->url, '?')) {
610 strlcat(obj->request->url, "?", HTTP_URL_MAXLEN);
611 } else {
612 strlcat(obj->request->url, "&", HTTP_URL_MAXLEN);
613 }
614 strlcat(obj->request->url, Z_STRVAL_P(qdata), HTTP_URL_MAXLEN);
615 }
616
617 http_request_prepare(obj->request, Z_ARRVAL_P(options));
618
619 /* check if there's a onProgress method and add it as progress callback if one isn't already set */
620 if (zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, "onprogress", sizeof("onprogress"))) {
621 zval **entry, *pcb;
622
623 if ( (Z_TYPE_P(options) != IS_ARRAY)
624 || (SUCCESS != zend_hash_find(Z_ARRVAL_P(options), "onprogress", sizeof("onprogress"), (void *) &entry)
625 || (!zval_is_true(*entry)))) {
626 MAKE_STD_ZVAL(pcb);
627 array_init(pcb);
628 ZVAL_ADDREF(getThis());
629 add_next_index_zval(pcb, getThis());
630 add_next_index_stringl(pcb, "onprogress", lenof("onprogress"), 1);
631 http_request_set_progress_callback(obj->request, pcb);
632 zval_ptr_dtor(&pcb);
633 }
634 }
635 }
636
637 return status;
638 }
639
640 STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr TSRMLS_DC)
641 {
642 STATUS ret;
643 zval *info;
644 http_message *msg;
645
646 /* always fetch info */
647 MAKE_STD_ZVAL(info);
648 array_init(info);
649 http_request_info(obj->request, Z_ARRVAL_P(info));
650 SET_PROP(responseInfo, info);
651 zval_ptr_dtor(&info);
652
653 /* parse response message */
654 phpstr_fix(&obj->request->conv.request);
655 phpstr_fix(&obj->request->conv.response);
656
657 if ((msg = http_message_parse(PHPSTR_VAL(&obj->request->conv.response), PHPSTR_LEN(&obj->request->conv.response)))) {
658 zval *message;
659
660 if (zval_is_true(GET_PROP(recordHistory))) {
661 zval *hist, *history = GET_PROP(history);
662 http_message *response = http_message_parse(PHPSTR_VAL(&obj->request->conv.response), PHPSTR_LEN(&obj->request->conv.response));
663 http_message *request = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request));
664
665 MAKE_STD_ZVAL(hist);
666 ZVAL_OBJVAL(hist, http_message_object_new_ex(http_message_object_ce, http_message_interconnect(response, request), NULL), 0);
667 if (Z_TYPE_P(history) == IS_OBJECT) {
668 http_message_object_prepend(hist, history);
669 }
670 SET_PROP(history, hist);
671 zval_ptr_dtor(&hist);
672 }
673
674 UPD_PROP(long, responseCode, msg->http.info.response.code);
675 UPD_PROP(string, responseStatus, STR_PTR(msg->http.info.response.status));
676
677 MAKE_STD_ZVAL(message);
678 ZVAL_OBJVAL(message, http_message_object_new_ex(http_message_object_ce, msg, NULL), 0);
679 SET_PROP(responseMessage, message);
680 zval_ptr_dtor(&message);
681
682 ret = SUCCESS;
683 } else {
684 /* update properties with empty values*/
685 zval *znull;
686
687 MAKE_STD_ZVAL(znull);
688 ZVAL_NULL(znull);
689 SET_PROP(responseMessage, znull);
690 zval_ptr_dtor(&znull);
691
692 UPD_PROP(long, responseCode, 0);
693 UPD_PROP(string, responseStatus, "");
694
695 /* append request message to history */
696 if (zval_is_true(GET_PROP(recordHistory))) {
697 http_message *request;
698
699 if ((request = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request)))) {
700 zval *hist, *history = GET_PROP(history);
701
702 MAKE_STD_ZVAL(hist);
703 ZVAL_OBJVAL(hist, http_message_object_new_ex(http_message_object_ce, request, NULL), 0);
704 if (Z_TYPE_P(history) == IS_OBJECT) {
705 http_message_object_prepend(hist, history);
706 }
707 SET_PROP(history, hist);
708 zval_ptr_dtor(&hist);
709 }
710 }
711
712 ret = FAILURE;
713 }
714
715 if (!EG(exception) && zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, "onfinish", sizeof("onfinish"))) {
716 zval *param;
717
718 MAKE_STD_ZVAL(param);
719 ZVAL_BOOL(param, ret == SUCCESS);
720 with_error_handling(EH_NORMAL, NULL) {
721 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "onfinish", NULL, param);
722 } end_error_handling();
723 zval_ptr_dtor(&param);
724 }
725
726 return ret;
727 }
728
729 static int apply_pretty_key(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
730 {
731 if (hash_key->nKeyLength > 1) {
732 hash_key->h = zend_get_hash_value(pretty_key(hash_key->arKey, hash_key->nKeyLength - 1, 1, 0), hash_key->nKeyLength);
733 }
734 return ZEND_HASH_APPLY_KEEP;
735 }
736
737 #define http_request_object_set_options_subr(key, ow, pk) \
738 _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key), (ow), (pk))
739 static inline void _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len, int overwrite, int prettify_keys)
740 {
741 zval *old_opts, *new_opts, *opts = NULL, **entry = NULL;
742
743 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &opts)) {
744 RETURN_FALSE;
745 }
746
747 MAKE_STD_ZVAL(new_opts);
748 array_init(new_opts);
749 old_opts = GET_PROP(options);
750 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
751 array_copy(old_opts, new_opts);
752 }
753
754 if (prettify_keys && opts) {
755 zend_hash_apply_with_arguments(Z_ARRVAL_P(opts), apply_pretty_key, 0);
756 }
757 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) {
758 if (overwrite) {
759 zend_hash_clean(Z_ARRVAL_PP(entry));
760 }
761 if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
762 if (overwrite) {
763 array_copy(opts, *entry);
764 } else {
765 array_merge(opts, *entry);
766 }
767 }
768 } else if (opts) {
769 ZVAL_ADDREF(opts);
770 add_assoc_zval(new_opts, key, opts);
771 }
772 SET_PROP(options, new_opts);
773 zval_ptr_dtor(&new_opts);
774
775 RETURN_TRUE;
776 }
777
778 #define http_request_object_get_options_subr(key) \
779 _http_request_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key))
780 static inline void _http_request_get_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len)
781 {
782 NO_ARGS;
783
784 if (return_value_used) {
785 zval *opts, **options;
786
787 opts = GET_PROP(options);
788 array_init(return_value);
789
790 if ( (Z_TYPE_P(opts) == IS_ARRAY) &&
791 (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) {
792 convert_to_array(*options);
793 array_copy(*options, return_value);
794 }
795 }
796 }
797
798
799 /* ### USERLAND ### */
800
801 /* {{{ proto void HttpRequest::__construct([string url[, int request_method = HTTP_METH_GET[, array options]]])
802 *
803 * Instantiate a new HttpRequest object.
804 *
805 * Accepts a string as optional parameter containing the target request url.
806 * Additionally accepts an optional int parameter specifying the request method
807 * to use and an associative array as optional third parameter which will be
808 * passed to HttpRequest::setOptions().
809 *
810 * Throws HttpException.
811 */
812 PHP_METHOD(HttpRequest, __construct)
813 {
814 char *URL = NULL;
815 int URL_len;
816 long meth = -1;
817 zval *options = NULL;
818
819 SET_EH_THROW_HTTP();
820 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla!", &URL, &URL_len, &meth, &options)) {
821 if (URL) {
822 UPD_STRL(url, URL, URL_len);
823 }
824 if (meth > -1) {
825 UPD_PROP(long, method, meth);
826 }
827 if (options) {
828 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setoptions", NULL, options);
829 }
830 }
831 SET_EH_NORMAL();
832 }
833 /* }}} */
834
835 /* {{{ proto bool HttpRequest::setOptions([array options])
836 *
837 * Set the request options to use. See http_get() for a full list of available options.
838 *
839 * Accepts an array as optional parameters, which values will overwrite the
840 * currently set request options. If the parameter is empty or omitted,
841 * the options of the HttpRequest object will be reset.
842 *
843 * Returns TRUE on success, or FALSE on failure.
844 */
845 PHP_METHOD(HttpRequest, setOptions)
846 {
847 char *key = NULL;
848 ulong idx = 0;
849 HashPosition pos;
850 zval *opts = NULL, *old_opts, *new_opts, *add_opts, **opt;
851
852 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
853 RETURN_FALSE;
854 }
855
856 MAKE_STD_ZVAL(new_opts);
857 array_init(new_opts);
858
859 if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
860 SET_PROP(options, new_opts);
861 zval_ptr_dtor(&new_opts);
862 RETURN_TRUE;
863 }
864
865 MAKE_STD_ZVAL(add_opts);
866 array_init(add_opts);
867 /* some options need extra attention -- thus cannot use array_merge() directly */
868 FOREACH_KEYVAL(pos, opts, key, idx, opt) {
869 if (key) {
870 if (!strcmp(key, "headers")) {
871 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, *opt);
872 } else if (!strcmp(key, "cookies")) {
873 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addcookies", NULL, *opt);
874 } else if (!strcmp(key, "ssl")) {
875 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addssloptions", NULL, *opt);
876 } else if ((!strcasecmp(key, "url")) || (!strcasecmp(key, "uri"))) {
877 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "seturl", NULL, *opt);
878 } else if (!strcmp(key, "method")) {
879 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmethod", NULL, *opt);
880 #if HTTP_CURL_VERSION(7,14,1)
881 } else if (!strcmp(key, "resetcookies")) {
882 getObject(http_request_object, obj);
883 http_request_reset_cookies(obj->request, 0);
884 #endif
885 } else if (!strcmp(key, "enablecookies")) {
886 getObject(http_request_object, obj);
887 http_request_enable_cookies(obj->request);
888 } else if (!strcasecmp(key, "recordHistory")) {
889 UPD_PROP(bool, recordHistory, 1);
890 } else {
891 ZVAL_ADDREF(*opt);
892 add_assoc_zval(add_opts, key, *opt);
893 }
894 /* reset */
895 key = NULL;
896 }
897 }
898
899 old_opts = GET_PROP(options);
900 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
901 array_copy(old_opts, new_opts);
902 }
903 array_merge(add_opts, new_opts);
904 SET_PROP(options, new_opts);
905 zval_ptr_dtor(&new_opts);
906 zval_ptr_dtor(&add_opts);
907
908 RETURN_TRUE;
909 }
910 /* }}} */
911
912 /* {{{ proto array HttpRequest::getOptions()
913 *
914 * Get currently set options.
915 *
916 * Returns an associative array containing currently set options.
917 */
918 PHP_METHOD(HttpRequest, getOptions)
919 {
920 NO_ARGS;
921
922 if (return_value_used) {
923 RETURN_PROP(options);
924 }
925 }
926 /* }}} */
927
928 /* {{{ proto bool HttpRequest::setSslOptions([array options])
929 *
930 * Set SSL options.
931 *
932 * Accepts an associative array as parameter containing any SSL specific options.
933 * If the parameter is empty or omitted, the SSL options will be reset.
934 *
935 * Returns TRUE on success, or FALSE on failure.
936 */
937 PHP_METHOD(HttpRequest, setSslOptions)
938 {
939 http_request_object_set_options_subr("ssl", 1, 0);
940 }
941 /* }}} */
942
943 /* {{{ proto bool HttpRequest::addSslOptions(array options)
944 *
945 * Set additional SSL options.
946 *
947 * Expects an associative array as parameter containing additional SSL specific options.
948 *
949 * Returns TRUE on success, or FALSE on failure.
950 */
951 PHP_METHOD(HttpRequest, addSslOptions)
952 {
953 http_request_object_set_options_subr("ssl", 0, 0);
954 }
955 /* }}} */
956
957 /* {{{ proto array HttpRequest::getSslOtpions()
958 *
959 * Get previously set SSL options.
960 *
961 * Returns an associative array containing any previously set SSL options.
962 */
963 PHP_METHOD(HttpRequest, getSslOptions)
964 {
965 http_request_object_get_options_subr("ssl");
966 }
967 /* }}} */
968
969 /* {{{ proto bool HttpRequest::addHeaders(array headers)
970 *
971 * Add request header name/value pairs.
972 *
973 * Expects an associative array as parameter containing additional header
974 * name/value pairs.
975 *
976 * Returns TRUE on success, or FALSE on failure.
977 */
978 PHP_METHOD(HttpRequest, addHeaders)
979 {
980 http_request_object_set_options_subr("headers", 0, 1);
981 }
982
983 /* {{{ proto bool HttpRequest::setHeaders([array headers])
984 *
985 * Set request header name/value pairs.
986 *
987 * Accepts an associative array as parameter containing header name/value pairs.
988 * If the parameter is empty or omitted, all previously set headers will be unset.
989 *
990 * Returns TRUE on success, or FALSE on failure.
991 */
992 PHP_METHOD(HttpRequest, setHeaders)
993 {
994 http_request_object_set_options_subr("headers", 1, 1);
995 }
996 /* }}} */
997
998 /* {{{ proto array HttpRequest::getHeaders()
999 *
1000 * Get previously set request headers.
1001 *
1002 * Returns an associative array containing all currently set headers.
1003 */
1004 PHP_METHOD(HttpRequest, getHeaders)
1005 {
1006 http_request_object_get_options_subr("headers");
1007 }
1008 /* }}} */
1009
1010 /* {{{ proto bool HttpRequest::setCookies([array cookies])
1011 *
1012 * Set cookies.
1013 *
1014 * Accepts an associative array as parameter containing cookie name/value pairs.
1015 * If the parameter is empty or omitted, all previously set cookies will be unset.
1016 *
1017 * Returns TRUE on success, or FALSE on failure.
1018 */
1019 PHP_METHOD(HttpRequest, setCookies)
1020 {
1021 http_request_object_set_options_subr("cookies", 1, 0);
1022 }
1023 /* }}} */
1024
1025 /* {{{ proto bool HttpRequest::addCookies(array cookies)
1026 *
1027 * Add cookies.
1028 *
1029 * Expects an associative array as parameter containing any cookie name/value
1030 * pairs to add.
1031 *
1032 * Returns TRUE on success, or FALSE on failure.
1033 */
1034 PHP_METHOD(HttpRequest, addCookies)
1035 {
1036 http_request_object_set_options_subr("cookies", 0, 0);
1037 }
1038 /* }}} */
1039
1040 /* {{{ proto array HttpRequest::getCookies()
1041 *
1042 * Get previously set cookies.
1043 *
1044 * Returns an associative array containing any previously set cookies.
1045 */
1046 PHP_METHOD(HttpRequest, getCookies)
1047 {
1048 http_request_object_get_options_subr("cookies");
1049 }
1050 /* }}} */
1051
1052 /* {{{ proto bool HttpRequest::enableCookies()
1053 *
1054 * Enable automatic sending of received cookies.
1055 * Note that cuutomly set cookies will be sent anyway.
1056 */
1057 PHP_METHOD(HttpRequest, enableCookies)
1058 {
1059 NO_ARGS {
1060 getObject(http_request_object, obj);
1061 RETURN_SUCCESS(http_request_enable_cookies(obj->request));
1062 }
1063
1064 }
1065 /* }}} */
1066
1067 /* {{{ proto bool HttpRequest::resetCookies([bool session_only = FALSE])
1068 *
1069 * Reset all automatically received/sent cookies.
1070 * Note that customly set cookies are not affected.
1071 *
1072 * Accepts an optional bool parameter specifying
1073 * whether only session cookies should be reset
1074 * (needs libcurl >= v7.15.4, else libcurl >= v7.14.1).
1075 *
1076 * Returns TRUE on success, or FALSE on failure.
1077 */
1078 PHP_METHOD(HttpRequest, resetCookies)
1079 {
1080 zend_bool session_only = 0;
1081 getObject(http_request_object, obj);
1082
1083 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &session_only)) {
1084 RETURN_FALSE;
1085 }
1086 RETURN_SUCCESS(http_request_reset_cookies(obj->request, session_only));
1087 }
1088 /* }}} */
1089
1090 /* {{{ proto bool HttpRequest::setUrl(string url)
1091 *
1092 * Set the request URL.
1093 *
1094 * Expects a string as parameter specifying the request url.
1095 *
1096 * Returns TRUE on success, or FALSE on failure.
1097 */
1098 PHP_METHOD(HttpRequest, setUrl)
1099 {
1100 char *URL = NULL;
1101 int URL_len;
1102
1103 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
1104 RETURN_FALSE;
1105 }
1106
1107 UPD_STRL(url, URL, URL_len);
1108 RETURN_TRUE;
1109 }
1110 /* }}} */
1111
1112 /* {{{ proto string HttpRequest::getUrl()
1113 *
1114 * Get the previously set request URL.
1115 *
1116 * Returns the currently set request url as string.
1117 */
1118 PHP_METHOD(HttpRequest, getUrl)
1119 {
1120 NO_ARGS;
1121
1122 if (return_value_used) {
1123 RETURN_PROP(url);
1124 }
1125 }
1126 /* }}} */
1127
1128 /* {{{ proto bool HttpRequest::setMethod(int request_method)
1129 *
1130 * Set the request method.
1131 *
1132 * Expects an int as parameter specifying the request method to use.
1133 * In PHP 5.1+ HttpRequest::METH_*, otherwise the HTTP_METH_* constants can be used.
1134 *
1135 * Returns TRUE on success, or FALSE on failure.
1136 */
1137 PHP_METHOD(HttpRequest, setMethod)
1138 {
1139 long meth;
1140
1141 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
1142 RETURN_FALSE;
1143 }
1144
1145 UPD_PROP(long, method, meth);
1146 RETURN_TRUE;
1147 }
1148 /* }}} */
1149
1150 /* {{{ proto int HttpRequest::getMethod()
1151 *
1152 * Get the previously set request method.
1153 *
1154 * Returns the currently set request method.
1155 */
1156 PHP_METHOD(HttpRequest, getMethod)
1157 {
1158 NO_ARGS;
1159
1160 if (return_value_used) {
1161 RETURN_PROP(method);
1162 }
1163 }
1164 /* }}} */
1165
1166 /* {{{ proto bool HttpRequest::setContentType(string content_type)
1167 *
1168 * Set the content type the post request should have.
1169 *
1170 * Expects a string as parameters containing the content type of the request
1171 * (primary/secondary).
1172 *
1173 * Returns TRUE on success, or FALSE if the content type does not seem to
1174 * contain a primary and a secondary part.
1175 */
1176 PHP_METHOD(HttpRequest, setContentType)
1177 {
1178 char *ctype;
1179 int ct_len;
1180
1181 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
1182 RETURN_FALSE;
1183 }
1184
1185 if (ct_len) {
1186 HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE);
1187 }
1188 UPD_STRL(contentType, ctype, ct_len);
1189 RETURN_TRUE;
1190 }
1191 /* }}} */
1192
1193 /* {{{ proto string HttpRequest::getContentType()
1194 *
1195 * Get the previously content type.
1196 *
1197 * Returns the previously set content type as string.
1198 */
1199 PHP_METHOD(HttpRequest, getContentType)
1200 {
1201 NO_ARGS;
1202
1203 if (return_value_used) {
1204 RETURN_PROP(contentType);
1205 }
1206 }
1207 /* }}} */
1208
1209 /* {{{ proto bool HttpRequest::setQueryData([mixed query_data])
1210 *
1211 * Set the URL query parameters to use, overwriting previously set query parameters.
1212 * Affects any request types.
1213 *
1214 * Accepts a string or associative array parameter containing the pre-encoded
1215 * query string or to be encoded query fields. If the parameter is empty or
1216 * omitted, the query data will be unset.
1217 *
1218 * Returns TRUE on success, or FALSE on failure.
1219 */
1220 PHP_METHOD(HttpRequest, setQueryData)
1221 {
1222 zval *qdata = NULL;
1223
1224 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &qdata)) {
1225 RETURN_FALSE;
1226 }
1227
1228 if ((!qdata) || Z_TYPE_P(qdata) == IS_NULL) {
1229 UPD_STRL(queryData, "", 0);
1230 } else if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1231 char *query_data = NULL;
1232
1233 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1234 RETURN_FALSE;
1235 }
1236
1237 UPD_PROP(string, queryData, query_data);
1238 efree(query_data);
1239 } else {
1240 zval *orig = qdata;
1241
1242 convert_to_string_ex(&qdata);
1243 UPD_STRL(queryData, Z_STRVAL_P(qdata), Z_STRLEN_P(qdata));
1244 if (orig != qdata) {
1245 zval_ptr_dtor(&qdata);
1246 }
1247 }
1248 RETURN_TRUE;
1249 }
1250 /* }}} */
1251
1252 /* {{{ proto string HttpRequest::getQueryData()
1253 *
1254 * Get the current query data in form of an urlencoded query string.
1255 *
1256 * Returns a string containing the urlencoded query.
1257 */
1258 PHP_METHOD(HttpRequest, getQueryData)
1259 {
1260 NO_ARGS;
1261
1262 if (return_value_used) {
1263 RETURN_PROP(queryData);
1264 }
1265 }
1266 /* }}} */
1267
1268 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1269 *
1270 * Add parameters to the query parameter list, leaving previously set unchanged.
1271 * Affects any request type.
1272 *
1273 * Expects an associative array as parameter containing the query fields to add.
1274 *
1275 * Returns TRUE on success, or FALSE on failure.
1276 */
1277 PHP_METHOD(HttpRequest, addQueryData)
1278 {
1279 zval *qdata, *old_qdata;
1280 char *query_data = NULL;
1281 size_t query_data_len = 0;
1282
1283 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &qdata)) {
1284 RETURN_FALSE;
1285 }
1286
1287 old_qdata = GET_PROP(queryData);
1288
1289 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, &query_data_len)) {
1290 RETURN_FALSE;
1291 }
1292
1293 UPD_STRL(queryData, query_data, query_data_len);
1294 efree(query_data);
1295
1296 RETURN_TRUE;
1297 }
1298 /* }}} */
1299
1300 /* {{{ proto bool HttpRequest::addPostFields(array post_data)
1301 *
1302 * Adds POST data entries, leaving previously set unchanged, unless a
1303 * post entry with the same name already exists.
1304 * Affects only POST and custom requests.
1305 *
1306 * Expects an associative array as parameter containing the post fields.
1307 *
1308 * Returns TRUE on success, or FALSE on failure.
1309 */
1310 PHP_METHOD(HttpRequest, addPostFields)
1311 {
1312 zval *post_data, *old_post, *new_post;
1313
1314 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &post_data)) {
1315 RETURN_FALSE;
1316 }
1317
1318 if (zend_hash_num_elements(Z_ARRVAL_P(post_data))) {
1319 MAKE_STD_ZVAL(new_post);
1320 array_init(new_post);
1321 old_post = GET_PROP(postFields);
1322 if (Z_TYPE_P(old_post) == IS_ARRAY) {
1323 array_copy(old_post, new_post);
1324 }
1325 array_merge(post_data, new_post);
1326 SET_PROP(postFields, new_post);
1327 zval_ptr_dtor(&new_post);
1328 }
1329
1330 RETURN_TRUE;
1331 }
1332 /* }}} */
1333
1334 /* {{{ proto bool HttpRequest::setPostFields([array post_data])
1335 *
1336 * Set the POST data entries, overwriting previously set POST data.
1337 * Affects only POST and custom requests.
1338 *
1339 * Accepts an associative array as parameter containing the post fields.
1340 * If the parameter is empty or omitted, the post data will be unset.
1341 *
1342 * Returns TRUE on success, or FALSE on failure.
1343 */
1344 PHP_METHOD(HttpRequest, setPostFields)
1345 {
1346 zval *post, *post_data = NULL;
1347
1348 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &post_data)) {
1349 RETURN_FALSE;
1350 }
1351
1352 MAKE_STD_ZVAL(post);
1353 array_init(post);
1354 if (post_data && zend_hash_num_elements(Z_ARRVAL_P(post_data))) {
1355 array_copy(post_data, post);
1356 }
1357 SET_PROP(postFields, post);
1358 zval_ptr_dtor(&post);
1359
1360 RETURN_TRUE;
1361 }
1362 /* }}}*/
1363
1364 /* {{{ proto array HttpRequest::getPostFields()
1365 *
1366 * Get previously set POST data.
1367 *
1368 * Returns the currently set post fields as associative array.
1369 */
1370 PHP_METHOD(HttpRequest, getPostFields)
1371 {
1372 NO_ARGS;
1373
1374 if (return_value_used) {
1375 RETURN_PROP(postFields);
1376 }
1377 }
1378 /* }}} */
1379
1380 /* {{{ proto bool HttpRequest::setRawPostData([string raw_post_data])
1381 *
1382 * Set raw post data to send, overwriting previously set raw post data. Don't
1383 * forget to specify a content type. Affects only POST and custom requests.
1384 * Only either post fields or raw post data can be used for each request.
1385 * Raw post data has higher precedence and will be used even if post fields
1386 * are set.
1387 *
1388 * Accepts a string as parameter containing the *raw* post data.
1389 *
1390 * Returns TRUE on success, or FALSE on failure.
1391 */
1392 PHP_METHOD(HttpRequest, setRawPostData)
1393 {
1394 char *raw_data = NULL;
1395 int data_len = 0;
1396
1397 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &raw_data, &data_len)) {
1398 RETURN_FALSE;
1399 }
1400
1401 if (!raw_data) {
1402 raw_data = "";
1403 }
1404
1405 UPD_STRL(rawPostData, raw_data, data_len);
1406 RETURN_TRUE;
1407 }
1408 /* }}} */
1409
1410 /* {{{ proto bool HttpRequest::addRawPostData(string raw_post_data)
1411 *
1412 * Add raw post data, leaving previously set raw post data unchanged.
1413 * Affects only POST and custom requests.
1414 *
1415 * Expects a string as parameter containing the raw post data to concatenate.
1416 *
1417 * Returns TRUE on success, or FALSE on failure.
1418 */
1419 PHP_METHOD(HttpRequest, addRawPostData)
1420 {
1421 char *raw_data;
1422 int data_len;
1423
1424 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &raw_data, &data_len)) {
1425 RETURN_FALSE;
1426 }
1427
1428 if (data_len) {
1429 zval *data = GET_PROP(rawPostData);
1430
1431 if (Z_STRLEN_P(data)) {
1432 Z_STRVAL_P(data) = erealloc(Z_STRVAL_P(data), (Z_STRLEN_P(data) += data_len) + 1);
1433 Z_STRVAL_P(data)[Z_STRLEN_P(data)] = '\0';
1434 memcpy(Z_STRVAL_P(data) + Z_STRLEN_P(data) - data_len, raw_data, data_len);
1435 } else {
1436 UPD_STRL(putData, raw_data, data_len);
1437 }
1438 }
1439
1440 RETURN_TRUE;
1441 }
1442 /* }}} */
1443
1444 /* {{{ proto string HttpRequest::getRawPostData()
1445 *
1446 * Get previously set raw post data.
1447 *
1448 * Returns a string containing the currently set raw post data.
1449 */
1450 PHP_METHOD(HttpRequest, getRawPostData)
1451 {
1452 NO_ARGS;
1453
1454 if (return_value_used) {
1455 RETURN_PROP(rawPostData);
1456 }
1457 }
1458 /* }}} */
1459
1460 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1461 *
1462 * Add a file to the POST request, leaving previously set files unchanged.
1463 * Affects only POST and custom requests. Cannot be used with raw post data.
1464 *
1465 * Expects a string parameter containing the form element name, and a string
1466 * paremeter containing the path to the file which should be uploaded.
1467 * Additionally accepts an optional string parameter which should contain
1468 * the content type of the file.
1469 *
1470 * Returns TRUE on success, or FALSE if the content type seems not to contain a
1471 * primary and a secondary content type part.
1472 */
1473 PHP_METHOD(HttpRequest, addPostFile)
1474 {
1475 zval *entry, *old_post, *new_post;
1476 char *name, *file, *type = NULL;
1477 int name_len, file_len, type_len = 0;
1478
1479 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1480 RETURN_FALSE;
1481 }
1482
1483 if (type_len) {
1484 HTTP_CHECK_CONTENT_TYPE(type, RETURN_FALSE);
1485 } else {
1486 type = "application/x-octetstream";
1487 type_len = sizeof("application/x-octetstream") - 1;
1488 }
1489
1490 MAKE_STD_ZVAL(entry);
1491 array_init(entry);
1492
1493 add_assoc_stringl(entry, "name", name, name_len, 1);
1494 add_assoc_stringl(entry, "type", type, type_len, 1);
1495 add_assoc_stringl(entry, "file", file, file_len, 1);
1496
1497 MAKE_STD_ZVAL(new_post);
1498 array_init(new_post);
1499 old_post = GET_PROP(postFiles);
1500 if (Z_TYPE_P(old_post) == IS_ARRAY) {
1501 array_copy(old_post, new_post);
1502 }
1503 add_next_index_zval(new_post, entry);
1504 SET_PROP(postFiles, new_post);
1505 zval_ptr_dtor(&new_post);
1506
1507 RETURN_TRUE;
1508 }
1509 /* }}} */
1510
1511 /* {{{ proto bool HttpRequest::setPostFiles([array post_files])
1512 *
1513 * Set files to post, overwriting previously set post files.
1514 * Affects only POST and requests. Cannot be used with raw post data.
1515 *
1516 * Accepts an array containing the files to post. Each entry should be an
1517 * associative array with "name", "file" and "type" keys. If the parameter
1518 * is empty or omitted the post files will be unset.
1519 *
1520 * Returns TRUE on success, or FALSE on failure.
1521 */
1522 PHP_METHOD(HttpRequest, setPostFiles)
1523 {
1524 zval *files = NULL, *post;
1525
1526 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!/", &files)) {
1527 RETURN_FALSE;
1528 }
1529
1530 MAKE_STD_ZVAL(post);
1531 array_init(post);
1532 if (files && (Z_TYPE_P(files) == IS_ARRAY)) {
1533 array_copy(files, post);
1534 }
1535 SET_PROP(postFiles, post);
1536 zval_ptr_dtor(&post);
1537
1538 RETURN_TRUE;
1539 }
1540 /* }}} */
1541
1542 /* {{{ proto array HttpRequest::getPostFiles()
1543 *
1544 * Get all previously added POST files.
1545 *
1546 * Returns an array containing currently set post files.
1547 */
1548 PHP_METHOD(HttpRequest, getPostFiles)
1549 {
1550 NO_ARGS;
1551
1552 if (return_value_used) {
1553 RETURN_PROP(postFiles);
1554 }
1555 }
1556 /* }}} */
1557
1558 /* {{{ proto bool HttpRequest::setPutFile([string file])
1559 *
1560 * Set file to put. Affects only PUT requests.
1561 *
1562 * Accepts a string as parameter referencing the path to file.
1563 * If the parameter is empty or omitted the put file will be unset.
1564 *
1565 * Returns TRUE on success, or FALSE on failure.
1566 */
1567 PHP_METHOD(HttpRequest, setPutFile)
1568 {
1569 char *file = "";
1570 int file_len = 0;
1571
1572 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &file, &file_len)) {
1573 RETURN_FALSE;
1574 }
1575
1576 UPD_STRL(putFile, file, file_len);
1577 RETURN_TRUE;
1578 }
1579 /* }}} */
1580
1581 /* {{{ proto string HttpRequest::getPutFile()
1582 *
1583 * Get previously set put file.
1584 *
1585 * Returns a string containing the path to the currently set put file.
1586 */
1587 PHP_METHOD(HttpRequest, getPutFile)
1588 {
1589 NO_ARGS;
1590
1591 if (return_value_used) {
1592 RETURN_PROP(putFile);
1593 }
1594 }
1595 /* }}} */
1596
1597 /* {{{ proto bool HttpRequest::setPutData([string put_data])
1598 *
1599 * Set PUT data to send, overwriting previously set PUT data.
1600 * Affects only PUT requests.
1601 * Only either PUT data or PUT file can be used for each request.
1602 * PUT data has higher precedence and will be used even if a PUT
1603 * file is set.
1604 *
1605 * Accepts a string as parameter containing the data to upload.
1606 *
1607 * Returns TRUE on success, or FALSE on failure.
1608 */
1609 PHP_METHOD(HttpRequest, setPutData)
1610 {
1611 char *put_data = NULL;
1612 int data_len = 0;
1613
1614 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &put_data, &data_len)) {
1615 RETURN_FALSE;
1616 }
1617
1618 if (!put_data) {
1619 put_data = "";
1620 }
1621
1622 UPD_STRL(putData, put_data, data_len);
1623 RETURN_TRUE;
1624 }
1625 /* }}} */
1626
1627 /* {{{ proto bool HttpRequest::addPutData(string put_data)
1628 *
1629 * Add PUT data, leaving previously set PUT data unchanged.
1630 * Affects only PUT requests.
1631 *
1632 * Expects a string as parameter containing the data to concatenate.
1633 *
1634 * Returns TRUE on success, or FALSE on failure.
1635 */
1636 PHP_METHOD(HttpRequest, addPutData)
1637 {
1638 char *put_data;
1639 int data_len;
1640
1641 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &put_data, &data_len)) {
1642 RETURN_FALSE;
1643 }
1644
1645 if (data_len) {
1646 zval *data = GET_PROP(putData);
1647
1648 if (Z_STRLEN_P(data)) {
1649 Z_STRVAL_P(data) = erealloc(Z_STRVAL_P(data), (Z_STRLEN_P(data) += data_len) + 1);
1650 Z_STRVAL_P(data)[Z_STRLEN_P(data)] = '\0';
1651 memcpy(Z_STRVAL_P(data) + Z_STRLEN_P(data) - data_len, put_data, data_len);
1652 } else {
1653 UPD_STRL(putData, put_data, data_len);
1654 }
1655 }
1656
1657 RETURN_TRUE;
1658 }
1659 /* }}} */
1660
1661 /* {{{ proto string HttpRequest::getPutData()
1662 *
1663 * Get previously set PUT data.
1664 *
1665 * Returns a string containing the currently set raw post data.
1666 */
1667 PHP_METHOD(HttpRequest, getPutData)
1668 {
1669 NO_ARGS;
1670
1671 if (return_value_used) {
1672 RETURN_PROP(putData);
1673 }
1674 }
1675 /* }}} */
1676
1677 /* {{{ proto array HttpRequest::getResponseData()
1678 *
1679 * Get all response data after the request has been sent.
1680 *
1681 * Returns an associative array with the key "headers" containing an associative
1682 * array holding all response headers, as well as the key "body" containing a
1683 * string with the response body.
1684 *
1685 * If redirects were allowed and several responses were received, the data
1686 * references the last received response.
1687 */
1688 PHP_METHOD(HttpRequest, getResponseData)
1689 {
1690 NO_ARGS;
1691
1692 if (return_value_used) {
1693 char *body;
1694 size_t body_len;
1695 zval *headers, *message = GET_PROP(responseMessage);
1696
1697 if (Z_TYPE_P(message) == IS_OBJECT) {
1698 getObjectEx(http_message_object, msg, message);
1699
1700 array_init(return_value);
1701
1702 MAKE_STD_ZVAL(headers);
1703 array_init(headers);
1704 zend_hash_copy(Z_ARRVAL_P(headers), &msg->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
1705 add_assoc_zval(return_value, "headers", headers);
1706
1707 phpstr_data(PHPSTR(msg->message), &body, &body_len);
1708 add_assoc_stringl(return_value, "body", body, body_len, 0);
1709 }
1710 }
1711 }
1712 /* }}} */
1713
1714 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1715 *
1716 * Get response header(s) after the request has been sent.
1717 *
1718 * Accepts an string as optional parameter specifying a certain header to read.
1719 * If the parameter is empty or omitted all response headers will be returned.
1720 *
1721 * Returns either a string with the value of the header matching name if requested,
1722 * FALSE on failure, or an associative array containing all response headers.
1723 *
1724 * If redirects were allowed and several responses were received, the data
1725 * references the last received response.
1726 */
1727 PHP_METHOD(HttpRequest, getResponseHeader)
1728 {
1729 if (return_value_used) {
1730 zval *header;
1731 char *header_name = NULL;
1732 int header_len = 0;
1733
1734 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1735 zval *message = GET_PROP(responseMessage);
1736
1737 if (Z_TYPE_P(message) == IS_OBJECT) {
1738 getObjectEx(http_message_object, msg, message);
1739
1740 if (header_len) {
1741 if ((header = http_message_header_ex(msg->message, pretty_key(header_name, header_len, 1, 1), header_len + 1, 0))) {
1742 RETURN_ZVAL(header, 1, 1);
1743 }
1744 } else {
1745 array_init(return_value);
1746 zend_hash_copy(Z_ARRVAL_P(return_value), &msg->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
1747 return;
1748 }
1749 }
1750 }
1751 RETURN_FALSE;
1752 }
1753 }
1754 /* }}} */
1755
1756 /* {{{ proto array HttpRequest::getResponseCookies([int flags[, array allowed_extras]])
1757 *
1758 * Get response cookie(s) after the request has been sent.
1759 *
1760 * Returns an array of stdClass objects like http_parse_cookie would return.
1761 *
1762 * If redirects were allowed and several responses were received, the data
1763 * references the last received response.
1764 */
1765 PHP_METHOD(HttpRequest, getResponseCookies)
1766 {
1767 if (return_value_used) {
1768 long flags = 0;
1769 zval *allowed_extras_array = NULL;
1770
1771 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|la!", &flags, &allowed_extras_array)) {
1772 int i = 0;
1773 ulong idx = 0;
1774 char *key = NULL, **allowed_extras = NULL;
1775 zval **header = NULL, **entry = NULL, *message = GET_PROP(responseMessage);
1776 HashPosition pos, pos1, pos2;
1777
1778 if (Z_TYPE_P(message) == IS_OBJECT) {
1779 getObjectEx(http_message_object, msg, message);
1780
1781 array_init(return_value);
1782
1783 if (allowed_extras_array) {
1784 allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
1785 FOREACH_VAL(pos, allowed_extras_array, entry) {
1786 ZVAL_ADDREF(*entry);
1787 convert_to_string_ex(entry);
1788 allowed_extras[i++] = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
1789 zval_ptr_dtor(entry);
1790 }
1791 }
1792
1793 FOREACH_HASH_KEYVAL(pos1, &msg->message->hdrs, key, idx, header) {
1794 if (key && !strcasecmp(key, "Set-Cookie")) {
1795 http_cookie_list list;
1796
1797 if (Z_TYPE_PP(header) == IS_ARRAY) {
1798 zval **single_header;
1799
1800 FOREACH_VAL(pos2, *header, single_header) {
1801 ZVAL_ADDREF(*single_header);
1802 convert_to_string_ex(single_header);
1803 if (http_parse_cookie_ex(&list, Z_STRVAL_PP(single_header), flags, allowed_extras)) {
1804 zval *cookie;
1805
1806 MAKE_STD_ZVAL(cookie);
1807 object_init(cookie);
1808 http_cookie_list_tostruct(&list, cookie);
1809 add_next_index_zval(return_value, cookie);
1810 http_cookie_list_dtor(&list);
1811 }
1812 zval_ptr_dtor(single_header);
1813 }
1814 } else {
1815 ZVAL_ADDREF(*header);
1816 convert_to_string_ex(header);
1817 if (http_parse_cookie_ex(&list, Z_STRVAL_PP(header), flags, allowed_extras)) {
1818 zval *cookie;
1819
1820 MAKE_STD_ZVAL(cookie);
1821 object_init(cookie);
1822 http_cookie_list_tostruct(&list, cookie);
1823 add_next_index_zval(return_value, cookie);
1824 http_cookie_list_dtor(&list);
1825 }
1826 zval_ptr_dtor(header);
1827 }
1828 }
1829 /* reset key */
1830 key = NULL;
1831 }
1832
1833 if (allowed_extras) {
1834 for (i = 0; allowed_extras[i]; ++i) {
1835 efree(allowed_extras[i]);
1836 }
1837 efree(allowed_extras);
1838 }
1839
1840 return;
1841 }
1842 }
1843 RETURN_FALSE;
1844 }
1845 }
1846 /* }}} */
1847
1848 /* {{{ proto string HttpRequest::getResponseBody()
1849 *
1850 * Get the response body after the request has been sent.
1851 *
1852 * Returns a string containing the response body.
1853 *
1854 * If redirects were allowed and several responses were received, the data
1855 * references the last received response.
1856 */
1857 PHP_METHOD(HttpRequest, getResponseBody)
1858 {
1859 NO_ARGS;
1860
1861 if (return_value_used) {
1862 zval *message = GET_PROP(responseMessage);
1863
1864 if (Z_TYPE_P(message) == IS_OBJECT) {
1865 getObjectEx(http_message_object, msg, message);
1866 RETURN_PHPSTR_DUP(&msg->message->body);
1867 } else {
1868 RETURN_FALSE;
1869 }
1870 }
1871 }
1872 /* }}} */
1873
1874 /* {{{ proto int HttpRequest::getResponseCode()
1875 *
1876 * Get the response code after the request has been sent.
1877 *
1878 * Returns an int representing the response code.
1879 *
1880 * If redirects were allowed and several responses were received, the data
1881 * references the last received response.
1882 */
1883 PHP_METHOD(HttpRequest, getResponseCode)
1884 {
1885 NO_ARGS;
1886
1887 if (return_value_used) {
1888 RETURN_PROP(responseCode);
1889 }
1890 }
1891 /* }}} */
1892
1893 /* {{{ proto string HttpRequest::getResponseStatus()
1894 *
1895 * Get the response status (i.e. the string after the response code) after the message has been sent.
1896 *
1897 * Returns a string containing the response status text.
1898 */
1899 PHP_METHOD(HttpRequest, getResponseStatus)
1900 {
1901 NO_ARGS;
1902
1903 if (return_value_used) {
1904 RETURN_PROP(responseStatus);
1905 }
1906 }
1907 /* }}} */
1908
1909 /* {{{ proto mixed HttpRequest::getResponseInfo([string name])
1910 *
1911 * Get response info after the request has been sent.
1912 * See http_get() for a full list of returned info.
1913 *
1914 * Accepts a string as optional parameter specifying the info to read.
1915 * If the parameter is empty or omitted, an associative array containing
1916 * all available info will be returned.
1917 *
1918 * Returns either a scalar containing the value of the info matching name if
1919 * requested, FALSE on failure, or an associative array containing all
1920 * available info.
1921 *
1922 * If redirects were allowed and several responses were received, the data
1923 * references the last received response.
1924 */
1925 PHP_METHOD(HttpRequest, getResponseInfo)
1926 {
1927 if (return_value_used) {
1928 zval *info, **infop;
1929 char *info_name = NULL;
1930 int info_len = 0;
1931
1932 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1933 RETURN_FALSE;
1934 }
1935
1936 info = GET_PROP(responseInfo);
1937
1938 if (Z_TYPE_P(info) != IS_ARRAY) {
1939 RETURN_FALSE;
1940 }
1941
1942 if (info_len && info_name) {
1943 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void *) &infop)) {
1944 RETURN_ZVAL(*infop, 1, 0);
1945 } else {
1946 http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Could not find response info named %s", info_name);
1947 RETURN_FALSE;
1948 }
1949 } else {
1950 RETURN_ZVAL(info, 1, 0);
1951 }
1952 }
1953 }
1954 /* }}}*/
1955
1956 /* {{{ proto HttpMessage HttpRequest::getResponseMessage()
1957 *
1958 * Get the full response as HttpMessage object after the request has been sent.
1959 *
1960 * Returns an HttpMessage object of the response.
1961 *
1962 * If redirects were allowed and several responses were received, the data
1963 * references the last received response. Use HttpMessage::getParentMessage()
1964 * to access the data of previously received responses within this request
1965 * cycle.
1966 *
1967 * Throws HttpException, HttpRuntimeException.
1968 */
1969 PHP_METHOD(HttpRequest, getResponseMessage)
1970 {
1971 NO_ARGS {
1972 zval *message;
1973
1974 SET_EH_THROW_HTTP();
1975 message = GET_PROP(responseMessage);
1976 if (Z_TYPE_P(message) == IS_OBJECT) {
1977 RETVAL_OBJECT(message, 1);
1978 } else {
1979 http_error(HE_WARNING, HTTP_E_RUNTIME, "HttpRequest does not contain a response message");
1980 }
1981 SET_EH_NORMAL();
1982 }
1983 }
1984 /* }}} */
1985
1986 /* {{{ proto HttpMessage HttpRequest::getRequestMessage()
1987 *
1988 * Get sent HTTP message.
1989 *
1990 * Returns an HttpMessage object representing the sent request.
1991 *
1992 * If redirects were allowed and several responses were received, the data
1993 * references the last received response. Use HttpMessage::getParentMessage()
1994 * to access the data of previously sent requests within this request
1995 * cycle.
1996 *
1997 * Note that the internal request message is immutable, that means that the
1998 * request message received through HttpRequest::getRequestMessage() will
1999 * always look the same for the same request, regardless of any changes you
2000 * may have made to the returned object.
2001 *
2002 * Throws HttpMalformedHeadersException, HttpEncodingException.
2003 */
2004 PHP_METHOD(HttpRequest, getRequestMessage)
2005 {
2006 NO_ARGS;
2007
2008 if (return_value_used) {
2009 http_message *msg;
2010 getObject(http_request_object, obj);
2011
2012 SET_EH_THROW_HTTP();
2013 if ((msg = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request)))) {
2014 RETVAL_OBJVAL(http_message_object_new_ex(http_message_object_ce, msg, NULL), 0);
2015 }
2016 SET_EH_NORMAL();
2017 }
2018 }
2019 /* }}} */
2020
2021 /* {{{ proto string HttpRequest::getRawRequestMessage()
2022 *
2023 * Get sent HTTP message.
2024 *
2025 * Returns an HttpMessage in a form of a string
2026 */
2027 PHP_METHOD(HttpRequest, getRawRequestMessage)
2028 {
2029 NO_ARGS;
2030
2031 if (return_value_used) {
2032 getObject(http_request_object, obj);
2033
2034 RETURN_PHPSTR_DUP(&obj->request->conv.request);
2035 }
2036 }
2037 /* }}} */
2038
2039 /* {{{ proto string HttpRequest::getRawResponseMessage()
2040 *
2041 * Get the entire HTTP response.
2042 *
2043 * Returns the complete web server response, including the headers in a form of a string.
2044 */
2045 PHP_METHOD(HttpRequest, getRawResponseMessage)
2046 {
2047 NO_ARGS;
2048
2049 if (return_value_used) {
2050 getObject(http_request_object, obj);
2051
2052 RETURN_PHPSTR_DUP(&obj->request->conv.response);
2053 }
2054 }
2055 /* }}} */
2056
2057 /* {{{ proto HttpMessage HttpRequest::getHistory()
2058 *
2059 * Get all sent requests and received responses as an HttpMessage object.
2060 *
2061 * If you want to record history, set the instance variable
2062 * HttpRequest::$recordHistory to TRUE.
2063 *
2064 * Returns an HttpMessage object representing the complete request/response
2065 * history.
2066 *
2067 * The object references the last received response, use HttpMessage::getParentMessage()
2068 * to access the data of previously sent requests and received responses.
2069 *
2070 * Throws HttpRuntimeException.
2071 */
2072 PHP_METHOD(HttpRequest, getHistory)
2073 {
2074 NO_ARGS;
2075
2076 if (return_value_used) {
2077 zval *hist;
2078
2079 SET_EH_THROW_HTTP();
2080 hist = GET_PROP(history);
2081 if (Z_TYPE_P(hist) == IS_OBJECT) {
2082 RETVAL_OBJECT(hist, 1);
2083 } else {
2084 http_error(HE_WARNING, HTTP_E_RUNTIME, "The history is empty");
2085 }
2086 SET_EH_NORMAL();
2087 }
2088 }
2089 /* }}} */
2090
2091 /* {{{ proto void HttpRequest::clearHistory()
2092 *
2093 * Clear the history.
2094 */
2095 PHP_METHOD(HttpRequest, clearHistory)
2096 {
2097 NO_ARGS {
2098 zval *hist;
2099
2100 MAKE_STD_ZVAL(hist);
2101 ZVAL_NULL(hist);
2102 SET_PROP(history, hist);
2103 zval_ptr_dtor(&hist);
2104 }
2105 }
2106 /* }}} */
2107
2108 /* {{{ proto HttpMessage HttpRequest::send()
2109 *
2110 * Send the HTTP request.
2111 *
2112 * Returns the received response as HttpMessage object.
2113 *
2114 * NOTE: While an exception may be thrown, the transfer could have succeeded
2115 * at least partially, so you might want to check the return values of various
2116 * HttpRequest::getResponse*() methods.
2117 *
2118 * Throws HttpRuntimeException, HttpRequestException,
2119 * HttpMalformedHeaderException, HttpEncodingException.
2120 *
2121 * GET example:
2122 * <pre>
2123 * <?php
2124 * $r = new HttpRequest('http://example.com/feed.rss', HttpRequest::METH_GET);
2125 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
2126 * $r->addQueryData(array('category' => 3));
2127 * try {
2128 * $r->send();
2129 * if ($r->getResponseCode() == 200) {
2130 * file_put_contents('local.rss', $r->getResponseBody());
2131 * }
2132 * } catch (HttpException $ex) {
2133 * echo $ex;
2134 * }
2135 * ?>
2136 * </pre>
2137 *
2138 * POST example:
2139 * <pre>
2140 * <?php
2141 * $r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
2142 * $r->setOptions(array('cookies' => array('lang' => 'de')));
2143 * $r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
2144 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
2145 * try {
2146 * echo $r->send()->getBody();
2147 * } catch (HttpException $ex) {
2148 * echo $ex;
2149 * }
2150 * ?>
2151 * </pre>
2152 */
2153 PHP_METHOD(HttpRequest, send)
2154 {
2155 getObject(http_request_object, obj);
2156
2157 NO_ARGS;
2158
2159 SET_EH_THROW_HTTP();
2160
2161 RETVAL_FALSE;
2162
2163 if (obj->pool) {
2164 http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot perform HttpRequest::send() while attached to an HttpRequestPool");
2165 } else if (SUCCESS == http_request_object_requesthandler(obj, getThis())) {
2166 http_request_exec(obj->request);
2167 if (SUCCESS == http_request_object_responsehandler(obj, getThis())) {
2168 RETVAL_OBJECT(GET_PROP(responseMessage), 1);
2169 }
2170 }
2171
2172 SET_EH_NORMAL();
2173 }
2174 /* }}} */
2175
2176 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
2177
2178 /*
2179 * Local variables:
2180 * tab-width: 4
2181 * c-basic-offset: 4
2182 * End:
2183 * vim600: noet sw=4 ts=4 fdm=marker
2184 * vim<600: noet sw=4 ts=4
2185 */
2186