[packages] php5: PECL: include support for http
[packages.git] / lang / php5 / patches / 030-PECL-add-http.patch
1 --- /dev/null
2 +++ b/ext/http/CREDITS
3 @@ -0,0 +1,2 @@
4 +HTTP extension for PHP
5 +Michael Wallner
6 --- /dev/null
7 +++ b/ext/http/KnownIssues.txt
8 @@ -0,0 +1,33 @@
9 +Known Issues
10 +============
11 +$Id: KnownIssues.txt 292753 2009-12-29 12:30:43Z mike $
12 +
13 +PHP < 5.1.3:
14 +       HttpResponse::getHeader() does not work with Apache2 SAPIs.
15 +       Using an encoding stream filter on a stream you read from doesn't work.
16 +
17 +Windows:
18 +       If you keep getting "SSL connect error" when trying to issue 
19 +               requests, try another (newer) libeay32.dll/ssleay32.dll pair.
20 +
21 +Internals:
22 +       Our http_urlencode_hash() does not differentiate between prefixes
23 +               for numeric or string keys.
24 +       Inflating raw deflated data causes a re-initialization of the inflate
25 +               stream where the corresponding window bits are modified to tell libz
26 +               to not check for zlib header bytes.  This is not preventable AFAICS.
27 +       LFS dependant parts of libcurl are left out because of off_t,
28 +               respectively off64_t confusion.
29 +       Persistent handles and "cookiestore" request option do interfere,
30 +               as libcurl saves the cookies to the file on curl_easy_destroy(),
31 +               cookies are not saved until the CURL handle will be recycled.
32 +                       Thus one would either need to
33 +                               * run PHP with http.persistent.handles.limit = 0
34 +                               * call http_persistent_handles_clean() every request
35 +                               * call $HttpRequest->flushCookies(), which is available
36 +                                 since libcurl v7.17.1 and does not work with the
37 +                                 procedural API
38 +                       Anyway, none of these options is really perfect.
39 +       HTTP and Proxy authentication information (username/password) can not be
40 +               unset with NULL prior libcurl v7.19.6 and separate options for setting
41 +               username and password--which work--are only available since v7.19.6.
42 --- /dev/null
43 +++ b/ext/http/LICENSE
44 @@ -0,0 +1,47 @@
45 +Copyright (c) 2004-2010, Michael Wallner <mike@iworks.at>.
46 +All rights reserved.
47 +
48 +Redistribution and use in source and binary forms, with or without 
49 +modification, are permitted provided that the following conditions are met:
50 +
51 +    * Redistributions of source code must retain the above copyright notice, 
52 +      this list of conditions and the following disclaimer.
53 +    * Redistributions in binary form must reproduce the above copyright 
54 +      notice, this list of conditions and the following disclaimer in the 
55 +      documentation and/or other materials provided with the distribution.
56 +
57 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
58 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
59 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
60 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
61 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
62 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
63 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
64 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
65 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
66 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 +
68 +===============================================================================
69 +
70 +The date parser in file http_date_api.c is derived from the implementation
71 +found in the original libcurl source, licensed under the following conditions:
72 +
73 +Copyright (c) 1996 - 2006, Daniel Stenberg, <daniel@haxx.se>.
74 +All rights reserved.
75 +
76 +Permission to use, copy, modify, and distribute this software for any purpose
77 +with or without fee is hereby granted, provided that the above copyright
78 +notice and this permission notice appear in all copies.
79 +
80 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
81 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
82 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
83 +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
84 +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
85 +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
86 +OR OTHER DEALINGS IN THE SOFTWARE.
87 +
88 +Except as contained in this notice, the name of a copyright holder shall not
89 +be used in advertising or otherwise to promote the sale, use or other dealings
90 +in this Software without prior written authorization of the copyright holder.
91 +
92 --- /dev/null
93 +++ b/ext/http/Makefile.frag
94 @@ -0,0 +1,23 @@
95 +# vim: noet ts=1 sw=1
96 +
97 +phpincludedir=$(prefix)/include/php
98 +
99 +install-http: install install-http-headers
100 +
101 +install-http-headers:
102 +       @echo "Installing HTTP headers:          $(INSTALL_ROOT)$(phpincludedir)/ext/http/"
103 +       @$(mkinstalldirs) $(INSTALL_ROOT)$(phpincludedir)/ext/http
104 +       @for f in $(PHP_HTTP_HEADERS); do \
105 +               if test -f "$(top_srcdir)/$$f"; then \
106 +                       $(INSTALL_DATA) $(top_srcdir)/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/http; \
107 +               elif test -f "$(top_builddir)/$$f"; then \
108 +                       $(INSTALL_DATA) $(top_builddir)/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/http; \
109 +               elif test -f "$(top_srcdir)/ext/http/$$f"; then \
110 +                       $(INSTALL_DATA) $(top_srcdir)/ext/http/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/http; \
111 +               elif test -f "$(top_builddir)/ext/http/$$f"; then \
112 +                       $(INSTALL_DATA) $(top_builddir)/ext/http/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/http; \
113 +               else \
114 +                       echo "WTF? $$f"; \
115 +               fi \
116 +       done;
117 +
118 --- /dev/null
119 +++ b/ext/http/ThanksTo.txt
120 @@ -0,0 +1,20 @@
121 +Thanks To
122 +=========
123 +$Id: ThanksTo.txt 275653 2009-02-12 13:11:05Z mike $
124 +
125 +People who repeatedly reported issues with this extension in a manner
126 +so they could be fixed in a reasonable way, or suggested useful features
127 +to implement, in alphabetical order:
128 +
129 +       Ilia Alshanetsky (ilia at php dot net)
130 +       Petr Czaderna (petr at hroch dot info)
131 +       David James (james82 at gmail dot com)
132 +       Thomas Landro Johnsen (thomas dot l dot johnsen at gmail dot com)
133 +       Clay Loveless (clay at killersoft dot com)
134 +       Felipe Pena (felipe at php dot net)
135 +       David Sklar (sklar at sklar dot com)
136 +       Travis Swicegood (travis at mashery dot com)
137 +       Alexey Zakhlestin (indeyets at gmail dot com)
138 +       Alexander Zhuravlev (zaa at zaa dot pp dot ru)
139 +
140 +Thanks a lot!
141 --- /dev/null
142 +++ b/ext/http/config.m4
143 @@ -0,0 +1,5 @@
144 +dnl phpize stub of config9.m4 for pecl/http
145 +dnl $Id: config.m4 214417 2006-06-07 21:05:34Z mike $
146 +dnl vim: noet ts=1 sw=1
147 +
148 +sinclude(config9.m4)
149 --- /dev/null
150 +++ b/ext/http/config.w32
151 @@ -0,0 +1,129 @@
152 +// config.w32 for pecl/http
153 +// $Id: config.w32 287971 2009-09-02 14:36:08Z pajoye $
154 +
155 +ARG_ENABLE("http", "whether to enable extended HTTP support", "no");
156 +
157 +function check_for_main_ext(ext, header)
158 +{
159 +       if (!header) {
160 +               header = "php_"+ ext +".h";
161 +       }
162 +
163 +       /* When in configure, we're always in the root of PHP source */
164 +       var ext_path = "ext\\" + ext;
165 +       
166 +       STDOUT.Write("Checking for ext/"+ ext +" ...  ");
167 +
168 +       if (FSO.FileExists(ext_path + "\\" + header)) {
169 +               STDOUT.WriteLine(ext_path);
170 +               return ext_path;
171 +       }
172 +
173 +       STDOUT.WriteLine("<not found>");
174 +       return false;
175 +}
176 +
177 +function check_for_pecl_ext(ext, header)
178 +{
179 +       if (!header) {
180 +               header = "php_"+ ext +".h";
181 +       }
182 +       
183 +       var g;
184 +       var s = ext +"\\"+ header;
185 +       
186 +       STDOUT.Write("Checking for pecl/"+ ext +" ...  ");
187 +       if (    (g = glob(configure_module_dirname +"\\..\\"+ s)) ||
188 +                       (g = glob(configure_module_dirname +"\\..\\..\\..\\pecl\\"+ s))) {
189 +               var f = g[0].substr(0, g[0].length - header.length - 1);
190 +               STDOUT.WriteLine(f);
191 +               return f;
192 +       }
193 +       STDOUT.WriteLine("<not found>");
194 +       return false;
195 +}
196 +
197 +if (PHP_HTTP != "no") {
198 +
199 +       EXTENSION("http",
200 +               "missing.c http.c http_functions.c http_exception_object.c "+
201 +               "http_util_object.c http_message_object.c http_requestpool_object.c "+
202 +               "http_request_object.c http_response_object.c "+
203 +               "http_api.c http_cache_api.c http_request_pool_api.c "+
204 +               "http_request_api.c http_date_api.c http_headers_api.c "+
205 +               "http_message_api.c http_send_api.c http_url_api.c "+
206 +               "http_info_api.c http_request_method_api.c http_encoding_api.c "+
207 +               "http_filter_api.c http_request_body_api.c http_querystring_object.c "+
208 +               "http_deflatestream_object.c http_inflatestream_object.c "+
209 +               "http_cookie_api.c http_querystring_api.c http_request_datashare_api.c "+
210 +               "http_requestdatashare_object.c http_request_info.c http_persistent_handle_api.c",
211 +               null,
212 +               "/I\"" + configure_module_dirname + "/phpstr\"");
213 +       ADD_SOURCES(configure_module_dirname + "/phpstr", "phpstr.c", "http");
214 +       AC_DEFINE("HAVE_HTTP", 1, "Have extended HTTP support");
215 +       AC_DEFINE("HTTP_SHARED_DEPS", 1, "Depend on shared extensions");
216 +       
217 +       AC_DEFINE("HAVE_GETHOSTNAME", 1);
218 +       AC_DEFINE("HAVE_GETSERVBYPORT", 1);
219 +       AC_DEFINE("HAVE_GETSERVBYNAME", 1);
220 +       
221 +       if (PHP_DEBUG != "no") {
222 +               ADD_FLAG("CFLAGS_HTTP", "/W3");
223 +       }
224 +       
225 +       if (CHECK_HEADER_ADD_INCLUDE('zlib.h', 'CFLAGS_HTTP', '..\\zlib;' + php_usual_include_suspects)) {
226 +               AC_DEFINE('HTTP_HAVE_ZLIB', 1, "Have zlib library");
227 +               ADD_FLAG("LDFLAGS_HTTP", "/FORCE:MULTIPLE");
228 +       } else {
229 +               WARNING("zlib encoding functions not enabled; libraries and headers not found");
230 +       }
231 +       
232 +       if (typeof(PHP_HASH) != "undefined" && PHP_HASH != "no") {
233 +               var f;
234 +               
235 +               if ((f = check_for_pecl_ext("hash")) || (f = check_for_main_ext("hash"))) {
236 +                       ADD_FLAG("CFLAGS_HTTP", '/I "' + f + '" /DHTTP_HAVE_PHP_HASH_H=1');
237 +                       ADD_EXTENSION_DEP("http", "hash", true);
238 +               }
239 +       }
240 +       
241 +       if (PHP_SESSION != "no") {
242 +               ADD_EXTENSION_DEP("http", "session", true);
243 +       }
244 +       
245 +       if (PHP_ICONV != "no") {
246 +               ADD_EXTENSION_DEP("http", "iconv", true);
247 +       }
248 +       
249 +       CURL_LIB="libcurl_a.lib;libcurl.lib;" + (PHP_DEBUG != "no" ? "libcurld.lib":"libcurl.lib");
250 +       if (CHECK_HEADER_ADD_INCLUDE("curl/curl.h", "CFLAGS_HTTP") &&
251 +                       CHECK_HEADER_ADD_INCLUDE("openssl/crypto.h", "CFLAGS_HTTP") &&
252 +                       CHECK_LIB(CURL_LIB, "http", PHP_HTTP) &&
253 +                       CHECK_LIB("ssleay32.lib", "http", PHP_HTTP) &&
254 +                       CHECK_LIB("libeay32.lib", "http", PHP_HTTP) &&
255 +                       CHECK_LIB("zlib.lib;zlib_a.lib", "http", PHP_HTTP) &&
256 +                       CHECK_LIB("winmm.lib", "http", PHP_HTTP)) {
257 +               AC_DEFINE("HTTP_HAVE_CURL", 1, "Have CURL library");
258 +               AC_DEFINE("HTTP_HAVE_SSL", 1, "Have SSL");
259 +               AC_DEFINE("HAVE_CURL_MULTI_STRERROR", 1, "");
260 +               AC_DEFINE("HAVE_CURL_SHARE_STRERROR", 1, "");
261 +               AC_DEFINE("HAVE_CURL_EASY_STRERROR", 1, "");
262 +               AC_DEFINE("HAVE_CURL_EASY_RESET", 1, "");
263 +               AC_DEFINE("HAVE_CURL_GETFORMDATA", 1, "");
264 +               AC_DEFINE("HAVE_CURL_FORMGET", 1, "");
265 +               AC_DEFINE("HAVE_CURL_MULTI_SETOPT", 1, "");
266 +               AC_DEFINE("HAVE_CURL_MULTI_TIMEOUT", 1, "");
267 +       } else {
268 +               WARNING("curl convenience functions not enabled; libraries and headers not found");
269 +       }
270 +/*
271 +//     MAGIC_LIB = PHP_DEBUG != "no" ? "libmagic-staticd.lib":"libmagic-static.lib";
272 +//     if (CHECK_HEADER_ADD_INCLUDE("magic.h", "CFLAGS_HTTP") &&
273 +//                     CHECK_LIB(MAGIC_LIB, "http", PHP_HTTP)) {
274 +//             AC_DEFINE("HTTP_HAVE_MAGIC", 1, "Have magic library");
275 +//             AC_DEFINE("USE_MAGIC_STATIC", "", "");
276 +//     } else {
277 +//             WARNING("content type guessing not enabled; libraries and headers not found");
278 +//     }
279 +*/
280 +}
281 --- /dev/null
282 +++ b/ext/http/config9.m4
283 @@ -0,0 +1,468 @@
284 +dnl config.m4 for pecl/http
285 +dnl $Id: config9.m4 242664 2007-09-18 19:13:37Z mike $
286 +dnl vim: noet ts=1 sw=1
287 +
288 +PHP_ARG_ENABLE([http], [whether to enable extended HTTP support],
289 +[  --enable-http           Enable extended HTTP support])
290 +PHP_ARG_WITH([http-shared-deps], [whether to depend on extensions which have been built shared],
291 +[  --with-http-shared-deps
292 +                           HTTP: disable to not depend on extensions like hash,
293 +                                 iconv and session (when built shared)], $PHP_HTTP, $PHP_HTTP)
294 +PHP_ARG_WITH([http-curl-requests], [whether to enable cURL HTTP request support],
295 +[  --with-http-curl-requests[=LIBCURLDIR]
296 +                           HTTP: with cURL request support], $PHP_HTTP, $PHP_HTTP)
297 +PHP_ARG_WITH([http-curl-libevent], [whether to enable libevent support fur cURL],
298 +[  --with-http-curl-libevent[=LIBEVENTDIR]
299 +                           HTTP: libevent install directory], $PHP_HTTP_CURL_REQUESTS, "")
300 +PHP_ARG_WITH([http-zlib-compression], [whether to enable zlib encodings support],
301 +[  --with-http-zlib-compression[=LIBZDIR]
302 +                           HTTP: with zlib encodings support], $PHP_HTTP, $PHP_HTTP)
303 +PHP_ARG_WITH([http-magic-mime], [whether to enable response content type guessing],
304 +[  --with-http-magic-mime[=LIBMAGICDIR]
305 +                           HTTP: with magic mime response content type guessing], "no", "no")
306 +
307 +if test "$PHP_HTTP" != "no"; then
308 +
309 +       ifdef([AC_PROG_EGREP], [
310 +               AC_PROG_EGREP
311 +       ], [
312 +               AC_CHECK_PROG(EGREP, egrep, egrep)
313 +       ])
314 +       ifdef([AC_PROG_SED], [
315 +               AC_PROG_SED
316 +       ], [
317 +               ifdef([LT_AC_PROG_SED], [
318 +                       LT_AC_PROG_SED
319 +               ], [
320 +                       AC_CHECK_PROG(SED, sed, sed)
321 +               ])
322 +       ])
323 +       
324 +       AC_PROG_CPP
325 +       
326 +       if test "$PHP_HTTP_SHARED_DEPS" != "no"; then
327 +               AC_DEFINE([HTTP_SHARED_DEPS], [1], [ ])
328 +       else
329 +               AC_DEFINE([HTTP_SHARED_DEPS], [0], [ ])
330 +       fi
331 +       
332 +       dnl
333 +       dnl HTTP_SHARED_DEP(name[, code-if-yes[, code-if-not]])
334 +       dnl
335 +       AC_DEFUN([HTTP_SHARED_DEP], [
336 +               extname=$1
337 +               haveext=$[HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)
338 +               
339 +               AC_MSG_CHECKING([whether to add a dependency on ext/$extname])
340 +               if test "$PHP_HTTP_SHARED_DEPS" = "no"; then
341 +                       AC_MSG_RESULT([no])
342 +                       $3
343 +               elif test "$haveext"; then
344 +                       AC_MSG_RESULT([yes])
345 +                       ifdef([PHP_ADD_EXTENSION_DEP], [
346 +                               PHP_ADD_EXTENSION_DEP([http], $1, true)
347 +                       ])
348 +                       $2
349 +               else
350 +                       AC_MSG_RESULT([no])
351 +                       $3
352 +               fi
353 +       ])
354 +       
355 +       dnl
356 +       dnl HTTP_HAVE_PHP_EXT(name[, code-if-yes[, code-if-not]])
357 +       dnl
358 +       AC_DEFUN([HTTP_HAVE_PHP_EXT], [
359 +               extname=$1
360 +               haveext=$[PHP_]translit($1,a-z_-,A-Z__)
361 +               
362 +               AC_MSG_CHECKING([for ext/$extname support])
363 +               if test -x "$PHP_EXECUTABLE"; then
364 +                       grepext=`$PHP_EXECUTABLE -m | $EGREP ^$extname\$`
365 +                       if test "$grepext" = "$extname"; then
366 +                               [HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1
367 +                               AC_MSG_RESULT([yes])
368 +                               $2
369 +                       else
370 +                               [HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=
371 +                               AC_MSG_RESULT([no])
372 +                               $3
373 +                       fi
374 +               elif test "$haveext" != "no" && test "x$haveext" != "x"; then
375 +                       [HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1
376 +                       AC_MSG_RESULT([yes])
377 +                       $2
378 +               else
379 +                       [HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=
380 +                       AC_MSG_RESULT([no])
381 +                       $3
382 +               fi
383 +       ])
384 +       
385 +       dnl
386 +       dnl odd PHP4 fix
387 +       dnl
388 +       if test "x$PHP_LIBDIR" = "x"; then
389 +               PHP_LIBDIR=lib
390 +       fi
391 +
392 +dnl ----
393 +dnl STDC
394 +dnl ----
395 +       AC_CHECK_HEADERS([netdb.h unistd.h])
396 +       PHP_CHECK_FUNC(gethostname, nsl)
397 +       PHP_CHECK_FUNC(getdomainname, nsl)
398 +       PHP_CHECK_FUNC(getservbyport, nsl)
399 +       PHP_CHECK_FUNC(getservbyname, nsl)
400 +
401 +dnl ----
402 +dnl ZLIB
403 +dnl ----
404 +       if test "$PHP_HTTP_ZLIB_COMPRESSION" != "no"; then
405 +               AC_MSG_CHECKING([for zlib.h])
406 +               ZLIB_DIR=
407 +               for i in "$PHP_HTTP_ZLIB_COMPRESSION" "$PHP_ZLIB_DIR" "$PHP_ZLIB" /usr/local /usr /opt; do
408 +                       if test -f "$i/include/zlib.h"; then
409 +                               ZLIB_DIR=$i
410 +                               break;
411 +                       fi
412 +               done
413 +               if test "x$ZLIB_DIR" = "x"; then
414 +                       AC_MSG_RESULT([not found])
415 +                       AC_MSG_ERROR([could not find zlib.h])
416 +               else
417 +                       AC_MSG_RESULT([found in $ZLIB_DIR])
418 +                       AC_MSG_CHECKING([for zlib version >= 1.2.0.4])
419 +                       ZLIB_VERSION=`$EGREP "define ZLIB_VERSION" $ZLIB_DIR/include/zlib.h | $SED -e 's/[[^0-9\.]]//g'`
420 +                       AC_MSG_RESULT([$ZLIB_VERSION])
421 +                       if test `echo $ZLIB_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*1000000 + $2*10000 + $3*100 + $4}'` -lt 1020004; then
422 +                               AC_MSG_ERROR([libz version greater or equal to 1.2.0.4 required])
423 +                       else
424 +                               PHP_ADD_INCLUDE($ZLIB_DIR/include)
425 +                               PHP_ADD_LIBRARY_WITH_PATH(z, $ZLIB_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
426 +                               AC_DEFINE([HTTP_HAVE_ZLIB], [1], [Have zlib support])
427 +                       fi
428 +               fi
429 +       fi
430 +       
431 +dnl ----
432 +dnl CURL
433 +dnl ----
434 +       if test "$PHP_HTTP_CURL_REQUESTS" != "no"; then
435 +               AC_MSG_CHECKING([for curl/curl.h])
436 +               CURL_DIR=
437 +               for i in "$PHP_HTTP_CURL_REQUESTS" /usr/local /usr /opt; do
438 +                       if test -f "$i/include/curl/curl.h"; then
439 +                               CURL_DIR=$i
440 +                               break
441 +                       fi
442 +               done
443 +               if test "x$CURL_DIR" = "x"; then
444 +                       AC_MSG_RESULT([not found])
445 +                       AC_MSG_ERROR([could not find curl/curl.h])
446 +               else
447 +                       AC_MSG_RESULT([found in $CURL_DIR])
448 +               fi
449 +               
450 +               AC_MSG_CHECKING([for curl-config])
451 +               CURL_CONFIG=
452 +               for i in "$CURL_DIR/bin/curl-config" "$CURL_DIR/curl-config" `which curl-config`; do
453 +                       if test -x "$i"; then
454 +                               CURL_CONFIG=$i
455 +                               break
456 +                       fi
457 +               done
458 +               if test "x$CURL_CONFIG" = "x"; then
459 +                       AC_MSG_RESULT([not found])
460 +                       AC_MSG_ERROR([could not find curl-config])
461 +               else
462 +                       AC_MSG_RESULT([found: $CURL_CONFIG])
463 +               fi
464 +               
465 +               dnl Debian stable has currently 7.13.2 (this is not a typo)
466 +               AC_MSG_CHECKING([for curl version >= 7.12.3])
467 +               CURL_VERSION=`$CURL_CONFIG --version | $SED -e 's/[[^0-9\.]]//g'`
468 +               AC_MSG_RESULT([$CURL_VERSION])
469 +               if test `echo $CURL_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*10000 + $2*100 + $3}'` -lt 71203; then
470 +                       AC_MSG_ERROR([libcurl version greater or equal to 7.12.3 required])
471 +               fi
472 +               
473 +               dnl
474 +               dnl compile tests
475 +               dnl
476 +               
477 +               save_INCLUDES="$INCLUDES"
478 +               INCLUDES=
479 +               save_LIBS="$LIBS"
480 +               LIBS=
481 +               save_CFLAGS="$CFLAGS"
482 +               CFLAGS=`$CURL_CONFIG --cflags`
483 +               save_LDFLAGS="$LDFLAGS"
484 +               LDFLAGS=`$CURL_CONFIG --libs`
485 +               LDFLAGS="$LDFLAGS $ld_runpath_switch$CURL_DIR/$PHP_LIBDIR"
486 +               
487 +               AC_MSG_CHECKING([for SSL support in libcurl])
488 +               CURL_SSL=`$CURL_CONFIG --feature | $EGREP SSL`
489 +               if test "$CURL_SSL" = "SSL"; then
490 +                       AC_MSG_RESULT([yes])
491 +                       AC_DEFINE([HTTP_HAVE_SSL], [1], [ ])
492 +                       
493 +                       AC_MSG_CHECKING([for openssl support in libcurl])
494 +                       AC_TRY_RUN([
495 +                               #include <curl/curl.h>
496 +                               int main(int argc, char *argv[]) {
497 +                                       curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
498 +                                       if (data && data->ssl_version && *data->ssl_version) {
499 +                                               const char *ptr = data->ssl_version;
500 +                                               while(*ptr == ' ') ++ptr;
501 +                                               return strncasecmp(ptr, "OpenSSL", sizeof("OpenSSL")-1);
502 +                                       }
503 +                                       return 1;
504 +                               }
505 +                       ], [
506 +                               AC_MSG_RESULT([yes])
507 +                               AC_CHECK_HEADER([openssl/crypto.h], [
508 +                                       AC_DEFINE([HTTP_HAVE_OPENSSL], [1], [ ])
509 +                               ])
510 +                       ], [
511 +                               AC_MSG_RESULT([no])
512 +                       ], [
513 +                               AC_MSG_RESULT([no])
514 +                       ])
515 +                       
516 +                       AC_MSG_CHECKING([for gnutls support in libcurl])
517 +                       AC_TRY_RUN([
518 +                               #include <curl/curl.h>
519 +                               int main(int argc, char *argv[]) {
520 +                                       curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
521 +                                       if (data && data->ssl_version && *data->ssl_version) {
522 +                                               const char *ptr = data->ssl_version;
523 +                                               while(*ptr == ' ') ++ptr;
524 +                                               return strncasecmp(ptr, "GnuTLS", sizeof("GnuTLS")-1);
525 +                                       }
526 +                                       return 1;
527 +                               }
528 +                       ], [
529 +                               AC_MSG_RESULT([yes])
530 +                               AC_CHECK_HEADER([gcrypt.h], [
531 +                                       AC_DEFINE([HTTP_HAVE_GNUTLS], [1], [ ])
532 +                               ])
533 +                       ], [
534 +                               AC_MSG_RESULT([no])
535 +                       ], [
536 +                               AC_MSG_RESULT([no])
537 +                       ])
538 +               else
539 +                       AC_MSG_RESULT([no])
540 +               fi
541 +               
542 +               INCLUDES="$save_INCLUDES"
543 +               LIBS="$save_LIBS"
544 +               CFLAGS="$save_CFLAGS"
545 +               LDFLAGS="$save_LDFLAGS"
546 +               
547 +               dnl end compile tests
548 +               
549 +               AC_MSG_CHECKING([for bundled SSL CA info])
550 +               CURL_CAINFO=
551 +               for i in `$CURL_CONFIG --ca` "/etc/ssl/certs/ca-certificates.crt"; do
552 +                       if test -f "$i"; then
553 +                               CURL_CAINFO="$i"
554 +                               break
555 +                       fi
556 +               done
557 +               if test "x$CURL_CAINFO" = "x"; then
558 +                       AC_MSG_RESULT([not found])
559 +               else
560 +                       AC_MSG_RESULT([$CURL_CAINFO])
561 +                       AC_DEFINE_UNQUOTED([HTTP_CURL_CAINFO], ["$CURL_CAINFO"], [path to bundled SSL CA info])
562 +               fi
563 +               
564 +               PHP_ADD_INCLUDE($CURL_DIR/include)
565 +               PHP_ADD_LIBRARY_WITH_PATH(curl, $CURL_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
566 +               PHP_EVAL_LIBLINE(`$CURL_CONFIG --libs`, HTTP_SHARED_LIBADD)
567 +               AC_DEFINE([HTTP_HAVE_CURL], [1], [Have cURL support])
568 +               
569 +               PHP_CHECK_LIBRARY(curl, curl_share_strerror, 
570 +                       [AC_DEFINE([HAVE_CURL_SHARE_STRERROR], [1], [ ])], [ ],
571 +                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
572 +               )
573 +               PHP_CHECK_LIBRARY(curl, curl_multi_strerror, 
574 +                       [AC_DEFINE([HAVE_CURL_MULTI_STRERROR], [1], [ ])], [ ], 
575 +                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
576 +               )
577 +               PHP_CHECK_LIBRARY(curl, curl_easy_strerror,
578 +                       [AC_DEFINE([HAVE_CURL_EASY_STRERROR], [1], [ ])], [ ],
579 +                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
580 +               )
581 +               PHP_CHECK_LIBRARY(curl, curl_easy_reset,
582 +                       [AC_DEFINE([HAVE_CURL_EASY_RESET], [1], [ ])], [ ],
583 +                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
584 +               )
585 +               PHP_CHECK_LIBRARY(curl, curl_formget,
586 +                       [AC_DEFINE([HAVE_CURL_FORMGET], [1], [ ])], [ ],
587 +                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
588 +               )
589 +               PHP_CHECK_LIBRARY(curl, curl_multi_setopt, 
590 +                       [AC_DEFINE([HAVE_CURL_MULTI_SETOPT], [1], [ ])], [ ], 
591 +                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
592 +               )
593 +               PHP_CHECK_LIBRARY(curl, curl_multi_timeout, 
594 +                       [AC_DEFINE([HAVE_CURL_MULTI_TIMEOUT], [1], [ ])], [ ],
595 +                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
596 +               )
597 +               
598 +               dnl ----
599 +               dnl EVENT
600 +               dnl ----
601 +               
602 +               if test "$PHP_HTTP_CURL_LIBEVENT" != "no"; then
603 +                       HTTP_HAVE_PHP_EXT([event], [
604 +                               AC_MSG_WARN([event support is incompatible with pecl/event; continuing without libevent support])
605 +                       ], [
606 +                               AC_MSG_CHECKING([for event.h])
607 +                               EVENT_DIR=
608 +                               for i in "$PHP_HTTP_CURL_LIBEVENT" /usr/local /usr /opt; do
609 +                                       if test -f "$i/include/event.h"; then
610 +                                               EVENT_DIR=$i
611 +                                               break
612 +                                       fi
613 +                               done
614 +                               if test "x$EVENT_DIR" = "x"; then
615 +                                       AC_MSG_RESULT([not found])
616 +                                       AC_MSG_WARN([continuing without libevent support])
617 +                               else
618 +                                       AC_MSG_RESULT([found in $EVENT_DIR])
619 +                                       
620 +                                       AC_MSG_CHECKING([for libevent version, roughly])
621 +                                       EVENT_VER="1.1b or lower"
622 +                                       if test -f "$EVENT_DIR/include/evhttp.h" && test -f "$EVENT_DIR/include/evdns.h"; then
623 +                                               if test -f "$EVENT_DIR/include/evrpc.h"; then
624 +                                                       EVENT_VER="1.4 or greater"
625 +                                               else
626 +                                                       EVENT_VER="1.2 or greater"
627 +                                               fi
628 +                                       fi
629 +                                       AC_DEFINE_UNQUOTED([HTTP_EVENT_VERSION], ["$EVENT_VER"], [ ])
630 +                                       AC_MSG_RESULT([$EVENT_VER])
631 +                                       
632 +                                       AC_MSG_CHECKING([for libcurl version >= 7.16.0])
633 +                                       AC_MSG_RESULT([$CURL_VERSION])
634 +                                       if test `echo $CURL_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*10000 + $2*100 + $3}'` -lt 71600; then
635 +                                               AC_MSG_WARN([libcurl version greater or equal to 7.16.0 required; continuing without libevent support])
636 +                                       else
637 +                                               PHP_ADD_INCLUDE($EVENT_DIR/include)
638 +                                               PHP_ADD_LIBRARY_WITH_PATH(event, $EVENT_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
639 +                                               AC_DEFINE([HTTP_HAVE_EVENT], [1], [Have libevent support for cURL])
640 +                                               PHP_CHECK_LIBRARY(curl, curl_multi_socket_action, 
641 +                                                       [AC_DEFINE([HAVE_CURL_MULTI_SOCKET_ACTION], [1], [ ])], [ ],
642 +                                                       [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
643 +                                               )
644 +                                       fi
645 +                               fi
646 +                       ])
647 +               fi
648 +       fi
649 +
650 +dnl ----
651 +dnl MAGIC
652 +dnl ----
653 +       if test "$PHP_HTTP_MAGIC_MIME" != "no"; then
654 +               AC_MSG_CHECKING([for magic.h])
655 +               MAGIC_DIR=
656 +               for i in "$PHP_HTTP_MAGIC_MIME" /usr/local /usr /opt; do
657 +                       if test -f "$i/include/magic.h"; then
658 +                               MAGIC_DIR=$i
659 +                               break
660 +                       fi
661 +               done
662 +               if test "x$MAGIC_DIR" = "x"; then
663 +                       AC_MSG_RESULT([not found])
664 +                       AC_MSG_ERROR([could not find magic.h])
665 +               else
666 +                       AC_MSG_RESULT([found in $MAGIC_DIR])
667 +               fi
668 +               
669 +               PHP_ADD_INCLUDE($MAGIC_DIR/include)
670 +               PHP_ADD_LIBRARY_WITH_PATH(magic, $MAGIC_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD)
671 +               AC_DEFINE([HTTP_HAVE_MAGIC], [1], [Have magic mime support])
672 +       fi
673 +
674 +dnl ----
675 +dnl HASH
676 +dnl ----
677 +       HTTP_HAVE_PHP_EXT([hash], [
678 +               AC_MSG_CHECKING([for php_hash.h])
679 +               HTTP_EXT_HASH_INCDIR=
680 +               for i in `echo $INCLUDES | $SED -e's/-I//g'` $abs_srcdir ../hash; do
681 +                       if test -d $i; then
682 +                               if test -f $i/php_hash.h; then
683 +                                       HTTP_EXT_HASH_INCDIR=$i
684 +                                       break
685 +                               elif test -f $i/ext/hash/php_hash.h; then
686 +                                       HTTP_EXT_HASH_INCDIR=$i/ext/hash
687 +                                       break
688 +                               fi
689 +                       fi
690 +               done
691 +               if test "x$HTTP_EXT_HASH_INCDIR" = "x"; then
692 +                       AC_MSG_RESULT([not found])
693 +               else
694 +                       AC_MSG_RESULT([$HTTP_EXT_HASH_INCDIR])
695 +                       AC_DEFINE([HTTP_HAVE_PHP_HASH_H], [1], [Have ext/hash support])
696 +                       PHP_ADD_INCLUDE([$HTTP_EXT_HASH_INCDIR])
697 +               fi
698 +       ])
699 +
700 +dnl ----
701 +dnl ICONV
702 +dnl ----
703 +       HTTP_HAVE_PHP_EXT([iconv])
704 +
705 +dnl ----
706 +dnl SESSION
707 +dnl ----
708 +       HTTP_HAVE_PHP_EXT([session])
709 +
710 +dnl ----
711 +dnl DONE
712 +dnl ----
713 +       PHP_HTTP_SOURCES="missing.c http.c http_functions.c phpstr/phpstr.c \
714 +               http_util_object.c http_message_object.c http_request_object.c http_request_pool_api.c \
715 +               http_response_object.c http_exception_object.c http_requestpool_object.c \
716 +               http_api.c http_cache_api.c http_request_api.c http_request_info.c http_date_api.c \
717 +               http_headers_api.c http_message_api.c http_send_api.c http_url_api.c \
718 +               http_info_api.c http_request_method_api.c http_encoding_api.c \
719 +               http_filter_api.c http_request_body_api.c http_querystring_object.c \
720 +               http_deflatestream_object.c http_inflatestream_object.c http_cookie_api.c \
721 +               http_querystring_api.c http_request_datashare_api.c http_requestdatashare_object.c \
722 +               http_persistent_handle_api.c"
723 +       
724 +       PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, $ext_shared)
725 +       
726 +       dnl shared extension deps
727 +       HTTP_SHARED_DEP([hash])
728 +       HTTP_SHARED_DEP([iconv])
729 +       HTTP_SHARED_DEP([session])
730 +       
731 +       PHP_ADD_BUILD_DIR($ext_builddir/phpstr, 1)
732 +       PHP_SUBST([HTTP_SHARED_LIBADD])
733 +
734 +       PHP_HTTP_HEADERS="php_http_std_defs.h php_http.h php_http_api.h php_http_cache_api.h \
735 +               php_http_date_api.h php_http_headers_api.h php_http_info_api.h php_http_message_api.h \
736 +               php_http_request_api.h php_http_request_method_api.h php_http_send_api.h php_http_url_api.h \
737 +               php_http_encoding_api.h phpstr/phpstr.h missing.h php_http_request_body_api.h \
738 +               php_http_exception_object.h php_http_message_object.h php_http_request_object.h \
739 +               php_http_requestpool_object.h php_http_response_object.h php_http_util_object.h \
740 +               php_http_querystring_object.h php_http_deflatestream_object.h php_http_inflatestream_object.h \
741 +               php_http_cookie_api.h php_http_querystring_api.h php_http_request_datashare_api.h php_http_requestdatashare_object.h \
742 +               php_http_persistent_handle_api.h"
743 +       ifdef([PHP_INSTALL_HEADERS], [
744 +               PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS)
745 +       ], [
746 +               PHP_SUBST([PHP_HTTP_HEADERS])
747 +               PHP_ADD_MAKEFILE_FRAGMENT
748 +       ])
749 +
750 +       AC_DEFINE([HAVE_HTTP], [1], [Have extended HTTP support])
751 +fi
752 --- /dev/null
753 +++ b/ext/http/docs/examples/tutorial.txt
754 @@ -0,0 +1,175 @@
755 +
756 +A Beginners Tutorial
757 +--------------------
758 +$Revision: 208773 $
759 +
760 +
761 +- GET Queries
762 +
763 +       The HttpRequest class can be used to execute any HTTP request method.
764 +       The following example shows a simple GET request where a few query
765 +       parameters are supplied.  Additionally potential cookies will be
766 +       read from and written to a file.
767 +
768 +<?php
769 +$r = new HttpRequest('http://www.google.com/search');
770 +
771 +// store Googles cookies in a dedicated file
772 +touch('google.txt');
773 +$r->setOptions(
774 +       array(  'cookiestore'   => 'google.txt',
775 +       )
776 +);
777 +
778 +$r->setQueryData(
779 +       array(  'q'             => '+"pecl_http" -msg -cvs -list',
780 +                       'hl'    => 'de'
781 +       )
782 +);
783 +
784 +// HttpRequest::send() returns an HttpMessage object
785 +// of type HttpMessage::TYPE_RESPONSE or throws an exception
786 +try {
787 +       print $r->send()->getBody();
788 +} catch (HttpException $e) {
789 +       print $e;
790 +}
791 +?>
792 +
793 +- Multipart Posts
794 +
795 +       The following example shows an multipart POST request, with two form
796 +       fields and an image that's supposed to be uploaded to the server.
797 +       It's a bad habit as well as common practice to issue a redirect after
798 +       an received POST request, so we'll allow a redirect by enabling the
799 +       redirect option.
800 +
801 +<?php
802 +$r = new HttpRequest('http://dev.iworks.at/.print_request.php', HTTP_METH_POST);
803 +
804 +// if redirects is set to true, a single redirect is allowed;
805 +// one can set any reasonable count of allowed redirects
806 +$r->setOptions(
807 +       array(  'cookies'       => array('MyCookie' => 'has a value'),
808 +                       'redirect'      => true,
809 +       )
810 +);
811 +
812 +// common form data
813 +$r->setPostFields(
814 +       array(  'name'  => 'Mike',
815 +                       'mail'  => 'mike@php.net',
816 +       )
817 +);
818 +// add the file to post (form name, file name, file type)
819 +touch('profile.jpg');
820 +$r->addPostFile('image', 'profile.jpg', 'image/jpeg');
821 +
822 +try {
823 +       print $r->send()->getBody();
824 +} catch (HttpException $e) {
825 +       print $e;
826 +}
827 +?>
828 +
829 +- Parallel Requests
830 +
831 +       It's possible to execute several HttpRequests in parallel with the
832 +       HttpRequestPool class.  HttpRequests to send, do not need to perform
833 +       the same request method, but can only be attached to one HttpRequestPool
834 +       at the same time.
835 +
836 +<?php
837 +try {
838 +       $p = new HttpRequestPool;
839 +       // if you want to set _any_ options of the HttpRequest object,
840 +       // you need to do so *prior attaching* to the request pool!
841 +       $p->attach(new HttpRequest('http://pear.php.net', HTTP_METH_HEAD));
842 +       $p->attach(new HttpRequest('http://pecl.php.net', HTTP_METH_HEAD));
843 +} catch (HttpException $e) {
844 +       print $e;
845 +       exit;
846 +}
847 +
848 +try {
849 +       $p->send();
850 +       // HttpRequestPool implements an iterator over attached HttpRequest objects
851 +       foreach ($p as $r) {
852 +               echo "Checking ", $r->getUrl(), " reported ", $r->getResponseCode(), "\n";
853 +       }
854 +} catch (HttpException $e) {
855 +       print $e;
856 +}
857 +?>
858 +
859 +- Parallel Requests?
860 +
861 +       You can use a more advanced approach by using the protected interface of
862 +       the HttpRequestPool class.  This allows you to perform some other tasks
863 +       while the requests are executed.
864 +
865 +<?php
866 +class Pool extends HttpRequestPool
867 +{
868 +       public function __construct()
869 +       {
870 +               parent::__construct(
871 +                       new HttpRequest('http://pear.php.net', HTTP_METH_HEAD),
872 +                       new HttpRequest('http://pecl.php.net', HTTP_METH_HEAD)
873 +               );
874 +
875 +               // HttpRequestPool methods socketPerform() and socketSelect() are
876 +               // protected;  one could use this approach to do something else
877 +               // while the requests are being executed
878 +               print "Executing requests";
879 +               for ($i = 0; $this->socketPerform(); $i++) {
880 +                       $i % 10 or print ".";
881 +                       if (!$this->socketSelect()) {
882 +                               throw new HttpException("Socket error!");
883 +                       }
884 +               }
885 +               print "\nDone!\n";
886 +       }
887 +}
888 +
889 +try {
890 +       foreach (new Pool as $r) {
891 +               echo "Checking ", $r->getUrl(), " reported ", $r->getResponseCode(), "\n";
892 +       }
893 +} catch (HttpException $ex) {
894 +       print $e;
895 +}
896 +?>
897 +
898 +- Cached Responses
899 +
900 +       One of the main key features of HttpResponse is HTTP caching.  HttpResponse
901 +       will calculate an ETag based on the http.etag_mode INI setting as well as
902 +       it will determine the last modification time of the sent entity.  It uses
903 +       those two indicators to decide if the cache entry on the client side is
904 +       still valid and will emit an "304 Not Modified" response if applicable.
905 +
906 +<?php
907 +HttpResponse::setCacheControl('public');
908 +HttpResponse::setCache(true);
909 +HttpResponse::capture();
910 +
911 +print "This will be cached until content changes!\n";
912 +print "Note that this approach will only save the clients download time.\n";
913 +?>
914 +
915 +- Bandwidth Throttling
916 +
917 +       HttpResponse supports a basic throttling mechanism, which is enabled by
918 +       setting a throttle delay and a buffer size.  PHP will sleep the specified
919 +       amount of seconds after each sent chunk of specified bytes.
920 +
921 +<?php
922 +// send 5000 bytes every 0.2 seconds, i.e. max ~25kByte/s
923 +HttpResponse::setThrottleDelay(0.2);
924 +HttpResponse::setBufferSize(5000);
925 +HttpResponse::setCache(true);
926 +HttpResponse::setContentType('application/x-zip');
927 +HttpResponse::setFile('../archive.zip');
928 +HttpResponse::send();
929 +?>
930 --- /dev/null
931 +++ b/ext/http/docs/http.ini
932 @@ -0,0 +1,61 @@
933 +; example INI file for pecl/http
934 +; $Id: http.ini 229420 2007-02-09 14:19:40Z mike $
935 +
936 +[http]
937 +; enable if you want to transform all errors to exceptions (PHP >= 5 only)
938 +;http.only_exceptions = 1
939 +
940 +; disable if you don't want php to exit in case of redirects and cache hits;
941 +; a "NULL" output handler will be started instead, which discards all output
942 +;http.force_exit = 0
943 +
944 +; disable if you don't want 404 Not found status messages being sent,
945 +; if a file attempted to be sent with http_send_file() etc. cannot be found
946 +;http.send.not_found_404 = 0
947 +
948 +; the hashing algorithm with wich ETags are generated (MD5, SHA1, CRC32B);
949 +; if ext/hash is available, this can be set to any hash algorithm ext/hash supports
950 +; MD5 is the default and fallback algorithm
951 +;http.etag.mode = "MD5"
952 +
953 +; allowed request methods
954 +; by default PHP ignores unkown request methods
955 +; PHP will exit with a response status of 405 and an Allow header
956 +; if it encounters a request method not contained in the specified list
957 +;http.request.methods.allowed = "HEAD, GET, POST"
958 +
959 +; custom request methods
960 +;http.request.methods.custom = "KICK, BANN"
961 +
962 +; log file for positive cache hits
963 +;http.log.cache =
964 +
965 +; log file for redirects
966 +;http.log.redirect =
967 +
968 +; log file for responses with http_send_file() etc. where the file's not been found
969 +;http.log.not_found =
970 +
971 +; log file for requests with an unallowed request method
972 +;http.log.allowed_methods =
973 +
974 +; composite log file (i.e. log all messages to this file)
975 +;http.log.composite =
976 +
977 +; automatically deflate content if requested/supported by client
978 +;http.send.deflate.start_auto = 1
979 +;http.send.deflate.start_flags = HTTP_DEFLATE_LEVEL_DEF
980 +
981 +; automatically inflate sent content
982 +;http.send.inflate.start_auto = 0
983 +;http.send.inflate.start_flags =
984 +
985 +; global HttpRequestDataShare settings
986 +;http.request.datashare.cookie = 0
987 +;http.request.datashare.dns = 1
988 +
989 +; limit of idle persistent handles per provider
990 +;http.persistent.handles.limit = -1
991 +
992 +; default ident of persistent handles
993 +;http.persistent.handles.ident = "GLOBAL"
994 --- /dev/null
995 +++ b/ext/http/http.c
996 @@ -0,0 +1,546 @@
997 +/*
998 +    +--------------------------------------------------------------------+
999 +    | PECL :: http                                                       |
1000 +    +--------------------------------------------------------------------+
1001 +    | Redistribution and use in source and binary forms, with or without |
1002 +    | modification, are permitted provided that the conditions mentioned |
1003 +    | in the accompanying LICENSE file are met.                          |
1004 +    +--------------------------------------------------------------------+
1005 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
1006 +    +--------------------------------------------------------------------+
1007 +*/
1008 +
1009 +/* $Id: http.c 300300 2010-06-09 07:29:35Z mike $ */
1010 +
1011 +#define HTTP_WANT_SAPI
1012 +#define HTTP_WANT_CURL
1013 +#define HTTP_WANT_EVENT
1014 +#define HTTP_WANT_ZLIB
1015 +#define HTTP_WANT_MAGIC
1016 +#include "php_http.h"
1017 +
1018 +#include "php_ini.h"
1019 +#include "ext/standard/info.h"
1020 +#include "zend_extensions.h"
1021 +
1022 +#include "php_http_api.h"
1023 +#include "php_http_cache_api.h"
1024 +#include "php_http_cookie_api.h"
1025 +#include "php_http_encoding_api.h"
1026 +#include "php_http_filter_api.h"
1027 +#include "php_http_message_api.h"
1028 +#include "php_http_persistent_handle_api.h"
1029 +#include "php_http_request_api.h"
1030 +#include "php_http_request_datashare_api.h"
1031 +#include "php_http_request_method_api.h"
1032 +#include "php_http_request_pool_api.h"
1033 +#include "php_http_send_api.h"
1034 +#include "php_http_url_api.h"
1035 +
1036 +#include "php_http_deflatestream_object.h"
1037 +#include "php_http_exception_object.h"
1038 +#include "php_http_inflatestream_object.h"
1039 +#include "php_http_message_object.h"
1040 +#include "php_http_querystring_object.h"
1041 +#include "php_http_request_object.h"
1042 +#include "php_http_requestdatashare_object.h"
1043 +#include "php_http_requestpool_object.h"
1044 +#include "php_http_response_object.h"
1045 +#include "php_http_util_object.h"
1046 +
1047 +ZEND_DECLARE_MODULE_GLOBALS(http);
1048 +HTTP_DECLARE_ARG_PASS_INFO();
1049 +
1050 +#ifdef COMPILE_DL_HTTP
1051 +ZEND_GET_MODULE(http)
1052 +#endif
1053 +
1054 +/* {{{ http_functions[] */
1055 +zend_function_entry http_functions[] = {
1056 +       PHP_FE(http_date, NULL)
1057 +       PHP_FE(http_build_url, http_arg_pass_ref_4)
1058 +       PHP_FE(http_build_str, NULL)
1059 +#ifndef ZEND_ENGINE_2
1060 +       PHP_FALIAS(http_build_query, http_build_str, NULL)
1061 +#endif
1062 +       PHP_FE(http_negotiate_language, http_arg_pass_ref_2)
1063 +       PHP_FE(http_negotiate_charset, http_arg_pass_ref_2)
1064 +       PHP_FE(http_negotiate_content_type, http_arg_pass_ref_2)
1065 +       PHP_FE(http_negotiate, http_arg_pass_ref_3)
1066 +       PHP_FE(http_redirect, NULL)
1067 +       PHP_FE(http_throttle, NULL)
1068 +       PHP_FE(http_send_status, NULL)
1069 +       PHP_FE(http_send_last_modified, NULL)
1070 +       PHP_FE(http_send_content_type, NULL)
1071 +       PHP_FE(http_send_content_disposition, NULL)
1072 +       PHP_FE(http_match_modified, NULL)
1073 +       PHP_FE(http_match_etag, NULL)
1074 +       PHP_FE(http_cache_last_modified, NULL)
1075 +       PHP_FE(http_cache_etag, NULL)
1076 +       PHP_FE(http_send_data, NULL)
1077 +       PHP_FE(http_send_file, NULL)
1078 +       PHP_FE(http_send_stream, NULL)
1079 +       PHP_FE(http_chunked_decode, NULL)
1080 +       PHP_FE(http_parse_message, NULL)
1081 +       PHP_FE(http_parse_headers, NULL)
1082 +       PHP_FE(http_parse_cookie, NULL)
1083 +       PHP_FE(http_build_cookie, NULL)
1084 +       PHP_FE(http_parse_params, NULL)
1085 +       PHP_FE(http_get_request_headers, NULL)
1086 +       PHP_FE(http_get_request_body, NULL)
1087 +       PHP_FE(http_get_request_body_stream, NULL)
1088 +       PHP_FE(http_match_request_header, NULL)
1089 +       PHP_FE(http_persistent_handles_count, NULL)
1090 +       PHP_FE(http_persistent_handles_clean, NULL)
1091 +       PHP_FE(http_persistent_handles_ident, NULL)
1092 +#ifdef HTTP_HAVE_CURL
1093 +       PHP_FE(http_get, http_arg_pass_ref_3)
1094 +       PHP_FE(http_head, http_arg_pass_ref_3)
1095 +       PHP_FE(http_post_data, http_arg_pass_ref_4)
1096 +       PHP_FE(http_post_fields, http_arg_pass_ref_5)
1097 +       PHP_FE(http_put_data, http_arg_pass_ref_4)
1098 +       PHP_FE(http_put_file, http_arg_pass_ref_4)
1099 +       PHP_FE(http_put_stream, http_arg_pass_ref_4)
1100 +       PHP_FE(http_request, http_arg_pass_ref_5)
1101 +       PHP_FE(http_request_body_encode, NULL)
1102 +#endif
1103 +       PHP_FE(http_request_method_register, NULL)
1104 +       PHP_FE(http_request_method_unregister, NULL)
1105 +       PHP_FE(http_request_method_exists, NULL)
1106 +       PHP_FE(http_request_method_name, NULL)
1107 +       PHP_FE(ob_etaghandler, NULL)
1108 +#ifdef HTTP_HAVE_ZLIB
1109 +       PHP_FE(http_deflate, NULL)
1110 +       PHP_FE(http_inflate, NULL)
1111 +       PHP_FE(ob_deflatehandler, NULL)
1112 +       PHP_FE(ob_inflatehandler, NULL)
1113 +#endif
1114 +       PHP_FE(http_support, NULL)
1115 +       
1116 +       EMPTY_FUNCTION_ENTRY
1117 +};
1118 +/* }}} */
1119 +
1120 +PHP_MINIT_FUNCTION(http);
1121 +PHP_MSHUTDOWN_FUNCTION(http);
1122 +PHP_RINIT_FUNCTION(http);
1123 +PHP_RSHUTDOWN_FUNCTION(http);
1124 +PHP_MINFO_FUNCTION(http);
1125 +
1126 +/* {{{ http_module_dep */
1127 +#if ZEND_EXTENSION_API_NO >= 220050617
1128 +static zend_module_dep http_module_deps[] = {
1129 +#      ifdef HTTP_HAVE_SPL
1130 +       ZEND_MOD_REQUIRED("spl")
1131 +#      endif
1132 +#      ifdef HTTP_HAVE_HASH
1133 +       ZEND_MOD_REQUIRED("hash")
1134 +#      endif
1135 +#      ifdef HTTP_HAVE_SESSION
1136 +       ZEND_MOD_REQUIRED("session")
1137 +#      endif
1138 +#      ifdef HTTP_HAVE_ICONV
1139 +       ZEND_MOD_REQUIRED("iconv")
1140 +#      endif
1141 +#      ifdef HTTP_HAVE_EVENT
1142 +       ZEND_MOD_CONFLICTS("event")
1143 +#endif
1144 +       {NULL, NULL, NULL, 0}
1145 +};
1146 +#endif
1147 +/* }}} */
1148 +
1149 +/* {{{ http_module_entry */
1150 +zend_module_entry http_module_entry = {
1151 +#if ZEND_EXTENSION_API_NO >= 220050617
1152 +       STANDARD_MODULE_HEADER_EX, NULL,
1153 +       http_module_deps,
1154 +#else
1155 +       STANDARD_MODULE_HEADER,
1156 +#endif
1157 +       "http",
1158 +       http_functions,
1159 +       PHP_MINIT(http),
1160 +       PHP_MSHUTDOWN(http),
1161 +       PHP_RINIT(http),
1162 +       PHP_RSHUTDOWN(http),
1163 +       PHP_MINFO(http),
1164 +       PHP_HTTP_VERSION,
1165 +       STANDARD_MODULE_PROPERTIES
1166 +};
1167 +/* }}} */
1168 +
1169 +int http_module_number;
1170 +
1171 +/* {{{ http_globals */
1172 +static void http_globals_init_once(zend_http_globals *G)
1173 +{
1174 +       memset(G, 0, sizeof(zend_http_globals));
1175 +}
1176 +
1177 +#define http_globals_init(g) _http_globals_init((g) TSRMLS_CC)
1178 +static inline void _http_globals_init(zend_http_globals *G TSRMLS_DC)
1179 +{
1180 +#ifdef HTTP_HAVE_SAPI_RTIME
1181 +       G->request.time = sapi_get_request_time(TSRMLS_C);
1182 +#else
1183 +       G->request.time = time(NULL);
1184 +#endif
1185 +       G->send.buffer_size = 0;
1186 +       G->read_post_data = 0;
1187 +}
1188 +
1189 +#define http_globals_free(g) _http_globals_free((g) TSRMLS_CC)
1190 +static inline void _http_globals_free(zend_http_globals *G TSRMLS_DC)
1191 +{
1192 +       if (G->request.headers) {
1193 +               zend_hash_destroy(G->request.headers);
1194 +               FREE_HASHTABLE(G->request.headers);
1195 +               G->request.headers = NULL;
1196 +       }
1197 +       STR_SET(G->send.content_type, NULL);
1198 +       STR_SET(G->send.unquoted_etag, NULL);
1199 +       if (G->server_var) {
1200 +               zval_ptr_dtor(&G->server_var);
1201 +               G->server_var = NULL;
1202 +       }
1203 +}
1204 +
1205 +#if defined(ZTS) && defined(PHP_DEBUG)
1206 +#if ZTS && PHP_DEBUG
1207 +zend_http_globals *http_globals(void)
1208 +{
1209 +       TSRMLS_FETCH();
1210 +       return HTTP_G;
1211 +}
1212 +#endif
1213 +#endif
1214 +/* }}} */
1215 +
1216 +/* {{{ static inline void http_check_allowed_methods(char *) */
1217 +#define http_check_allowed_methods(m) _http_check_allowed_methods((m) TSRMLS_CC)
1218 +static inline void _http_check_allowed_methods(const char *methods TSRMLS_DC)
1219 +{
1220 +       if (*methods && SG(request_info).request_method) {
1221 +               if (SUCCESS != http_check_method_ex(SG(request_info).request_method, methods)) {
1222 +                       char *header;
1223 +                       spprintf(&header, 0, "Allow: %s", methods);
1224 +                       http_exit(405, header);
1225 +               }
1226 +       }
1227 +}
1228 +/* }}} */
1229 +
1230 +/* {{{ PHP_INI */
1231 +PHP_INI_MH(http_update_allowed_methods)
1232 +{
1233 +       if (*new_value) {
1234 +               http_check_allowed_methods(new_value);
1235 +       }
1236 +       return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
1237 +}
1238 +PHP_INI_MH(http_update_persistent_handle_ident)
1239 +{
1240 +       HTTP_G->persistent.handles.ident.h = zend_hash_func(new_value, HTTP_G->persistent.handles.ident.l = new_value_length+1);
1241 +       return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
1242 +}
1243 +
1244 +#ifndef ZEND_ENGINE_2
1245 +#      define OnUpdateLong OnUpdateInt
1246 +#endif
1247 +
1248 +PHP_INI_BEGIN()
1249 +       HTTP_PHP_INI_ENTRY("http.etag.mode", "MD5", PHP_INI_ALL, OnUpdateString, etag.mode)
1250 +       HTTP_PHP_INI_ENTRY("http.log.cache", "", PHP_INI_ALL, OnUpdateString, log.cache)
1251 +       HTTP_PHP_INI_ENTRY("http.log.redirect", "", PHP_INI_ALL, OnUpdateString, log.redirect)
1252 +       HTTP_PHP_INI_ENTRY("http.log.not_found", "", PHP_INI_ALL, OnUpdateString, log.not_found)
1253 +       HTTP_PHP_INI_ENTRY("http.log.allowed_methods", "", PHP_INI_ALL, OnUpdateString, log.allowed_methods)
1254 +       HTTP_PHP_INI_ENTRY("http.log.composite", "", PHP_INI_ALL, OnUpdateString, log.composite)
1255 +       HTTP_PHP_INI_ENTRY("http.request.methods.allowed", "", PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed)
1256 +       HTTP_PHP_INI_ENTRY("http.request.methods.custom", "", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, request.methods.custom)
1257 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
1258 +       HTTP_PHP_INI_ENTRY("http.request.datashare.cookie", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.cookie)
1259 +       HTTP_PHP_INI_ENTRY("http.request.datashare.dns", "1", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.dns)
1260 +       HTTP_PHP_INI_ENTRY("http.request.datashare.ssl", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.ssl)
1261 +       HTTP_PHP_INI_ENTRY("http.request.datashare.connect", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.connect)
1262 +#endif
1263 +#ifdef HTTP_HAVE_ZLIB
1264 +       HTTP_PHP_INI_ENTRY("http.send.inflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.inflate.start_auto)
1265 +       HTTP_PHP_INI_ENTRY("http.send.inflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.inflate.start_flags)
1266 +       HTTP_PHP_INI_ENTRY("http.send.deflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.deflate.start_auto)
1267 +       HTTP_PHP_INI_ENTRY("http.send.deflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.deflate.start_flags)
1268 +#endif
1269 +       HTTP_PHP_INI_ENTRY("http.persistent.handles.limit", "-1", PHP_INI_SYSTEM, OnUpdateLong, persistent.handles.limit)
1270 +       HTTP_PHP_INI_ENTRY("http.persistent.handles.ident", "GLOBAL", PHP_INI_ALL, http_update_persistent_handle_ident, persistent.handles.ident.s)
1271 +       HTTP_PHP_INI_ENTRY("http.send.not_found_404", "1", PHP_INI_ALL, OnUpdateBool, send.not_found_404)
1272 +#ifdef ZEND_ENGINE_2
1273 +       HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions)
1274 +#endif
1275 +       HTTP_PHP_INI_ENTRY("http.force_exit", "1", PHP_INI_ALL, OnUpdateBool, force_exit)
1276 +PHP_INI_END()
1277 +/* }}} */
1278 +
1279 +/* {{{ PHP_MINIT_FUNCTION */
1280 +PHP_MINIT_FUNCTION(http)
1281 +{
1282 +       http_module_number = module_number;
1283 +       ZEND_INIT_MODULE_GLOBALS(http, http_globals_init_once, NULL);
1284 +       REGISTER_INI_ENTRIES();
1285 +       
1286 +       if (0
1287 +               || SUCCESS != PHP_MINIT_CALL(http_persistent_handle) /* first */
1288 +               || SUCCESS != PHP_MINIT_CALL(http_cookie)
1289 +#ifdef HTTP_HAVE_ZLIB
1290 +               || SUCCESS != PHP_MINIT_CALL(http_encoding)
1291 +#endif
1292 +#ifdef HTTP_HAVE_CURL
1293 +               || SUCCESS != PHP_MINIT_CALL(http_request)
1294 +#      ifdef ZEND_ENGINE_2
1295 +#      endif
1296 +#endif
1297 +               || SUCCESS != PHP_MINIT_CALL(http_request_method)
1298 +               || SUCCESS != PHP_MINIT_CALL(http_send)
1299 +               || SUCCESS != PHP_MINIT_CALL(http_support)
1300 +               || SUCCESS != PHP_MINIT_CALL(http_url)
1301 +               
1302 +#ifdef ZEND_ENGINE_2
1303 +               || SUCCESS != PHP_MINIT_CALL(http_filter)
1304 +               || SUCCESS != PHP_MINIT_CALL(http_exception_object)
1305 +#      ifdef HTTP_HAVE_ZLIB
1306 +               || SUCCESS != PHP_MINIT_CALL(http_deflatestream_object)
1307 +               || SUCCESS != PHP_MINIT_CALL(http_inflatestream_object)
1308 +#      endif
1309 +               || SUCCESS != PHP_MINIT_CALL(http_message_object)
1310 +               || SUCCESS != PHP_MINIT_CALL(http_querystring_object)
1311 +#      ifdef HTTP_HAVE_CURL
1312 +               || SUCCESS != PHP_MINIT_CALL(http_request_datashare)
1313 +               || SUCCESS != PHP_MINIT_CALL(http_request_pool)
1314 +               || SUCCESS != PHP_MINIT_CALL(http_request_object)
1315 +               || SUCCESS != PHP_MINIT_CALL(http_requestdatashare_object)
1316 +               || SUCCESS != PHP_MINIT_CALL(http_requestpool_object)
1317 +#      endif
1318 +#      ifndef WONKY
1319 +               || SUCCESS != PHP_MINIT_CALL(http_response_object)
1320 +#      endif
1321 +               || SUCCESS != PHP_MINIT_CALL(http_util_object)
1322 +#endif
1323 +       ) {
1324 +               return FAILURE;
1325 +       }
1326 +       
1327 +       return SUCCESS;
1328 +}
1329 +/* }}} */
1330 +
1331 +/* {{{ PHP_MSHUTDOWN_FUNCTION */
1332 +PHP_MSHUTDOWN_FUNCTION(http)
1333 +{
1334 +       UNREGISTER_INI_ENTRIES();
1335 +       
1336 +       if (0
1337 +#ifdef HTTP_HAVE_CURL
1338 +               || SUCCESS != PHP_MSHUTDOWN_CALL(http_request)
1339 +#      ifdef ZEND_ENGINE_2
1340 +               || SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare)
1341 +#      endif
1342 +#endif
1343 +               || SUCCESS != PHP_MSHUTDOWN_CALL(http_message_object)
1344 +               || SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle) /* last */
1345 +       ) {
1346 +               return FAILURE;
1347 +       }
1348 +       
1349 +       return SUCCESS;
1350 +}
1351 +/* }}} */
1352 +
1353 +/* {{{ PHP_RINIT_FUNCTION */
1354 +PHP_RINIT_FUNCTION(http)
1355 +{
1356 +       http_globals_init(HTTP_G);
1357 +       
1358 +       if (HTTP_G->request.methods.allowed && *HTTP_G->request.methods.allowed) {
1359 +               http_check_allowed_methods(HTTP_G->request.methods.allowed);
1360 +       }
1361 +       
1362 +       if (0
1363 +#ifdef HTTP_HAVE_ZLIB
1364 +               || SUCCESS != PHP_RINIT_CALL(http_encoding)
1365 +#endif
1366 +#ifdef HTTP_HAVE_CURL
1367 +#      ifdef ZEND_ENGINE_2
1368 +#              ifdef HTTP_HAVE_EVENT
1369 +               || SUCCESS != PHP_RINIT_CALL(http_request_pool)
1370 +#              endif
1371 +               || SUCCESS != PHP_RINIT_CALL(http_request_datashare)
1372 +#      endif
1373 +#endif
1374 +               || SUCCESS != PHP_RINIT_CALL(http_request_method)
1375 +       ) {
1376 +               return FAILURE;
1377 +       }
1378 +       
1379 +       return SUCCESS;
1380 +}
1381 +/* }}} */
1382 +
1383 +/* {{{ PHP_RSHUTDOWN_FUNCTION */
1384 +PHP_RSHUTDOWN_FUNCTION(http)
1385 +{
1386 +       STATUS status = SUCCESS;
1387 +       
1388 +       if (0
1389 +#ifdef HTTP_HAVE_ZLIB
1390 +               || SUCCESS != PHP_RSHUTDOWN_CALL(http_encoding)
1391 +#endif
1392 +#ifdef HTTP_HAVE_CURL
1393 +#      ifdef ZEND_ENGINE_2
1394 +               || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_datashare)
1395 +#      endif
1396 +#endif
1397 +               || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_method)
1398 +       ) {
1399 +               status = FAILURE;
1400 +       }
1401 +       
1402 +       http_globals_free(HTTP_G);
1403 +       return status;
1404 +}
1405 +/* }}} */
1406 +
1407 +/* {{{ PHP_MINFO_FUNCTION */
1408 +PHP_MINFO_FUNCTION(http)
1409 +{
1410 +       php_info_print_table_start();
1411 +       {
1412 +               php_info_print_table_header(2, "HTTP Support", "enabled");
1413 +               php_info_print_table_row(2, "Extension Version", PHP_HTTP_VERSION);
1414 +               php_info_print_table_row(2, "Registered Classes",
1415 +#ifndef ZEND_ENGINE_2
1416 +                       "none"
1417 +#else
1418 +                       "HttpUtil, "
1419 +                       "HttpMessage, "
1420 +#      ifdef HTTP_HAVE_CURL
1421 +                       "HttpRequest, "
1422 +                       "HttpRequestPool, "
1423 +                       "HttpRequestDataShare, "
1424 +#      endif
1425 +#      ifdef HTTP_HAVE_ZLIB
1426 +                       "HttpDeflateStream, "
1427 +                       "HttpInflateStream, "
1428 +#      endif
1429 +#      ifndef WONKY
1430 +                       "HttpResponse, "
1431 +#      endif
1432 +                       "HttpQueryString"
1433 +#endif
1434 +               );
1435 +               php_info_print_table_row(2, "Output Handlers", "ob_deflatehandler, ob_inflatehandler, ob_etaghandler");
1436 +               php_info_print_table_row(2, "Stream Filters", 
1437 +#ifndef ZEND_ENGINE_2
1438 +                       "none"
1439 +#else
1440 +                       "http.chunked_decode, http.chunked_encode, http.deflate, http.inflate"
1441 +#endif
1442 +               );
1443 +       }
1444 +       php_info_print_table_end();
1445 +       
1446 +       php_info_print_table_start();
1447 +       php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
1448 +       {
1449 +#ifdef HTTP_HAVE_CURL
1450 +               curl_version_info_data *cv = curl_version_info(CURLVERSION_NOW);
1451 +               php_info_print_table_row(3, "libcurl", LIBCURL_VERSION, cv->version);
1452 +#else
1453 +               php_info_print_table_row(2, "libcurl", "disabled", "disabled");
1454 +#endif
1455 +#ifdef HTTP_HAVE_EVENT
1456 +               php_info_print_table_row(3, "libevent", HTTP_EVENT_VERSION, event_get_version());
1457 +#else
1458 +               php_info_print_table_row(3, "libevent", "disabled", "disabled");
1459 +#endif
1460 +#ifdef HTTP_HAVE_ZLIB
1461 +               php_info_print_table_row(3, "libz", ZLIB_VERSION, zlibVersion());
1462 +#else
1463 +               php_info_print_table_row(3, "libz", "disabled", "disabled");
1464 +#endif
1465 +#if defined(HTTP_HAVE_MAGIC)
1466 +               php_info_print_table_row(3, "libmagic", "unknown", "unknown");
1467 +#else
1468 +               php_info_print_table_row(3, "libmagic", "disabled", "disabled");
1469 +#endif
1470 +       }
1471 +       php_info_print_table_end();
1472 +       
1473 +       php_info_print_table_start();
1474 +       php_info_print_table_colspan_header(4, "Persistent Handles");
1475 +       php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
1476 +       {
1477 +               HashTable *ht;
1478 +               HashPosition pos1, pos2;
1479 +               HashKey provider = initHashKey(0), ident = initHashKey(0);
1480 +               zval **val, **sub, **zused, **zfree;
1481 +               
1482 +               if ((ht = http_persistent_handle_statall()) && zend_hash_num_elements(ht)) {
1483 +                       FOREACH_HASH_KEYVAL(pos1, ht, provider, val) {
1484 +                               if (zend_hash_num_elements(Z_ARRVAL_PP(val))) {
1485 +                                       FOREACH_KEYVAL(pos2, *val, ident, sub) {
1486 +                                               if (    SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("used"), (void *) &zused) &&
1487 +                                                               SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("free"), (void *) &zfree)) {
1488 +                                                       zval *used = http_zsep(IS_STRING, *zused);
1489 +                                                       zval *free = http_zsep(IS_STRING, *zfree);
1490 +                                                       php_info_print_table_row(4, provider.str, ident.str, Z_STRVAL_P(used), Z_STRVAL_P(free));
1491 +                                                       zval_ptr_dtor(&used);
1492 +                                                       zval_ptr_dtor(&free);
1493 +                                               } else {
1494 +                                                       php_info_print_table_row(4, provider.str, ident.str, "0", "0");
1495 +                                               }
1496 +                                       }
1497 +                               } else {
1498 +                                       php_info_print_table_row(4, provider.str, "N/A", "0", "0");
1499 +                               }
1500 +                       }
1501 +               } else {
1502 +                       php_info_print_table_row(4, "N/A", "N/A", "0", "0");
1503 +               }
1504 +               if (ht) {
1505 +                       zend_hash_destroy(ht);
1506 +                       FREE_HASHTABLE(ht);
1507 +               }
1508 +       }
1509 +       php_info_print_table_end();
1510 +       
1511 +       php_info_print_table_start();
1512 +       php_info_print_table_colspan_header(2, "Request Methods");
1513 +       {
1514 +               HashPosition pos;
1515 +               phpstr *methods = phpstr_new();
1516 +               char **name;
1517 +               
1518 +               FOREACH_HASH_VAL(pos, &HTTP_G->request.methods.registered, name) {
1519 +                       if (pos->h) {
1520 +                               phpstr_appendf(methods, "%s, ", *name);
1521 +                       }
1522 +               }
1523 +               phpstr_fix(methods);
1524 +               php_info_print_table_row(2, "Registered", PHPSTR_VAL(methods));
1525 +               php_info_print_table_row(2, "Allowed", *HTTP_G->request.methods.allowed ? HTTP_G->request.methods.allowed : "(ANY)");
1526 +               phpstr_free(&methods);
1527 +       }
1528 +       php_info_print_table_end();
1529 +       
1530 +       DISPLAY_INI_ENTRIES();
1531 +}
1532 +/* }}} */
1533 +
1534 +/*
1535 + * Local variables:
1536 + * tab-width: 4
1537 + * c-basic-offset: 4
1538 + * End:
1539 + * vim600: noet sw=4 ts=4 fdm=marker
1540 + * vim<600: noet sw=4 ts=4
1541 + */
1542 +
1543 --- /dev/null
1544 +++ b/ext/http/http.dsp
1545 @@ -0,0 +1,257 @@
1546 +# Microsoft Developer Studio Project File - Name="http" - Package Owner=<4>\r
1547 +# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
1548 +# ** DO NOT EDIT **\r
1549 +\r
1550 +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
1551 +\r
1552 +CFG=http - Win32 Release_TS\r
1553 +!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
1554 +!MESSAGE use the Export Makefile command and run\r
1555 +!MESSAGE \r
1556 +!MESSAGE NMAKE /f "http.mak".\r
1557 +!MESSAGE \r
1558 +!MESSAGE You can specify a configuration when running NMAKE\r
1559 +!MESSAGE by defining the macro CFG on the command line. For example:\r
1560 +!MESSAGE \r
1561 +!MESSAGE NMAKE /f "http.mak" CFG="http - Win32 Release_TS"\r
1562 +!MESSAGE \r
1563 +!MESSAGE Possible choices for configuration are:\r
1564 +!MESSAGE \r
1565 +!MESSAGE "http - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
1566 +!MESSAGE "http - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
1567 +!MESSAGE \r
1568 +\r
1569 +# Begin Project\r
1570 +# PROP AllowPerConfigDependencies 0\r
1571 +# PROP Scc_ProjName ""\r
1572 +# PROP Scc_LocalPath ""\r
1573 +CPP=cl.exe\r
1574 +MTL=midl.exe\r
1575 +RSC=rc.exe\r
1576 +\r
1577 +!IF  "$(CFG)" == "http - Win32 Release_TS"\r
1578 +\r
1579 +# PROP BASE Use_MFC 0\r
1580 +# PROP BASE Use_Debug_Libraries 0\r
1581 +# PROP BASE Output_Dir "Release_TS"\r
1582 +# PROP BASE Intermediate_Dir "Release_TS"\r
1583 +# PROP BASE Ignore_Export_Lib 0\r
1584 +# PROP BASE Target_Dir ""\r
1585 +# PROP Use_MFC 0\r
1586 +# PROP Use_Debug_Libraries 0\r
1587 +# PROP Output_Dir "Release_TS"\r
1588 +# PROP Intermediate_Dir "Release_TS"\r
1589 +# PROP Ignore_Export_Lib 0\r
1590 +# PROP Target_Dir ""\r
1591 +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\..\TSRM" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_HTTP" /D ZTS=1 /YX /FD /c\r
1592 +# ADD CPP /nologo /Gd /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HTTP_EXPORTS" /D "COMPILE_DL_HTTP" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_HTTP=1 /D HTTP_HAVE_CURL=1 /D HAVE_CURL_EASY_STRERROR=1 /D HAVE_CURL_SHARE_STRERROR=1 /D HAVE_CURL_MULTI_STRERROR=1 /D HAVE_CURL_EASY_RESET=1 /D HAVE_CURL_FORMGET=1 /D HAVE_GETHOSTNAME=1 /D HAVE_GETSERVBYPORT=1 /D HAVE_GETSERVBYNAME=1 /D "_WINSOCKAPI_=" /FR /YX /FD /c\r
1593 +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
1594 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
1595 +# ADD BASE RSC /l 0x406 /d "NDEBUG"\r
1596 +# ADD RSC /l 0x406 /d "NDEBUG"\r
1597 +BSC32=bscmake.exe\r
1598 +# ADD BASE BSC32 /nologo\r
1599 +# ADD BSC32 /nologo\r
1600 +LINK32=link.exe\r
1601 +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386\r
1602 +# ADD LINK32 libcurl.lib ssleay32.lib libeay32.lib zlib.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib wsock32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_http.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" /libpath:"..\..\..\php_build\curl\lib" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\php4\Release_TS_Inline"\r
1603 +\r
1604 +!ELSEIF  "$(CFG)" == "http - Win32 Debug_TS"\r
1605 +\r
1606 +# PROP BASE Use_MFC 0\r
1607 +# PROP BASE Use_Debug_Libraries 0\r
1608 +# PROP BASE Output_Dir "Debug_TS"\r
1609 +# PROP BASE Intermediate_Dir "Debug_TS"\r
1610 +# PROP BASE Ignore_Export_Lib 0\r
1611 +# PROP BASE Target_Dir ""\r
1612 +# PROP Use_MFC 0\r
1613 +# PROP Use_Debug_Libraries 0\r
1614 +# PROP Output_Dir "Debug_TS"\r
1615 +# PROP Intermediate_Dir "Debug_TS"\r
1616 +# PROP Ignore_Export_Lib 0\r
1617 +# PROP Target_Dir ""\r
1618 +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_HTTP" /D ZTS=1 /YX /FD /c\r
1619 +# ADD CPP /nologo /MDd /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HTTP_EXPORTS" /D "COMPILE_DL_HTTP" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_HTTP=1 /D HTTP_HAVE_CURL=1 /D HAVE_CURL_EASY_STRERROR=1 /D HAVE_CURL_SHARE_STRERROR=1 /D HAVE_CURL_MULTI_STRERROR=1 /D HAVE_CURL_EASY_RESET=1 /D HAVE_CURL_FORMGET=1 /D HAVE_GETHOSTNAME=1 /D HAVE_GETSERVBYPORT=1 /D HAVE_GETSERVBYNAME=1 /D "_WINSOCKAPI_=" /YX /FD /c\r
1620 +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
1621 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
1622 +# ADD BASE RSC /l 0x406 /d "NDEBUG"\r
1623 +# ADD RSC /l 0x406 /d "NDEBUG"\r
1624 +BSC32=bscmake.exe\r
1625 +# ADD BASE BSC32 /nologo\r
1626 +# ADD BSC32 /nologo\r
1627 +LINK32=link.exe\r
1628 +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386\r
1629 +# ADD LINK32 libcurl.lib ssleay32.lib libeay32.lib zlib.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts_debug.lib wsock32.lib /nologo /dll /machine:I386 /out:"..\..\Debug_TS/http.dll" /libpath:"..\..\Debug_TS" /libpath:"..\..\..\php_build\curl\lib" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\php4\Release_TS_Inline"\r
1630 +\r
1631 +!ENDIF \r
1632 +\r
1633 +# Begin Target\r
1634 +\r
1635 +# Name "http - Win32 Release_TS"\r
1636 +# Name "http - Win32 Debug_TS"\r
1637 +# Begin Group "Source Files"\r
1638 +\r
1639 +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
1640 +# Begin Source File\r
1641 +\r
1642 +SOURCE=.\http.c\r
1643 +# End Source File\r
1644 +# Begin Source File\r
1645 +\r
1646 +SOURCE=.\http_api.c\r
1647 +# End Source File\r
1648 +# Begin Source File\r
1649 +\r
1650 +SOURCE=.\http_encoding_api.c\r
1651 +# End Source File\r
1652 +# Begin Source File\r
1653 +\r
1654 +SOURCE=.\http_request_api.c\r
1655 +# End Source File\r
1656 +# Begin Source File\r
1657 +\r
1658 +SOURCE=.\http_request_info.c\r
1659 +# End Source File\r
1660 +# Begin Source File\r
1661 +\r
1662 +SOURCE=.\http_request_body_api.c\r
1663 +# End Source File\r
1664 +# Begin Source File\r
1665 +\r
1666 +SOURCE=.\http_request_method_api.c\r
1667 +# End Source File\r
1668 +# Begin Source File\r
1669 +\r
1670 +SOURCE=.\http_functions.c\r
1671 +# End Source File\r
1672 +# Begin Source File\r
1673 +\r
1674 +SOURCE=.\http_persistent_handle_api.c\r
1675 +# End Source File\r
1676 +# Begin Source File\r
1677 +\r
1678 +SOURCE=.\http_cache_api.c\r
1679 +# End Source File\r
1680 +# Begin Source File\r
1681 +\r
1682 +SOURCE=.\http_cookie_api.c\r
1683 +# End Source File\r
1684 +# Begin Source File\r
1685 +\r
1686 +SOURCE=.\http_date_api.c\r
1687 +# End Source File\r
1688 +# Begin Source File\r
1689 +\r
1690 +SOURCE=.\http_headers_api.c\r
1691 +# End Source File\r
1692 +# Begin Source File\r
1693 +\r
1694 +SOURCE=.\http_message_api.c\r
1695 +# End Source File\r
1696 +# Begin Source File\r
1697 +\r
1698 +SOURCE=.\http_send_api.c\r
1699 +# End Source File\r
1700 +# Begin Source File\r
1701 +\r
1702 +SOURCE=.\http_url_api.c\r
1703 +# End Source File\r
1704 +# Begin Source File\r
1705 +\r
1706 +SOURCE=.\http_querystring_api.c\r
1707 +# End Source File\r
1708 +# Begin Source File\r
1709 +\r
1710 +SOURCE=.\http_info_api.c\r
1711 +# End Source File\r
1712 +# Begin Source File\r
1713 +\r
1714 +SOURCE=.\phpstr\phpstr.c\r
1715 +# End Source File\r
1716 +# End Group\r
1717 +# Begin Group "Header Files"\r
1718 +\r
1719 +# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
1720 +# Begin Source File\r
1721 +\r
1722 +SOURCE=.\php_http.h\r
1723 +# End Source File\r
1724 +# Begin Source File\r
1725 +\r
1726 +SOURCE=.\php_http_api.h\r
1727 +# End Source File\r
1728 +# Begin Source File\r
1729 +\r
1730 +SOURCE=.\php_http_encoding_api.h\r
1731 +# End Source File\r
1732 +# Begin Source File\r
1733 +\r
1734 +SOURCE=.\php_http_request_api.h\r
1735 +# End Source File\r
1736 +# Begin Source File\r
1737 +\r
1738 +SOURCE=.\php_http_request_int.h\r
1739 +# End Source File\r
1740 +# Begin Source File\r
1741 +\r
1742 +SOURCE=.\php_http_request_body_api.h\r
1743 +# End Source File\r
1744 +# Begin Source File\r
1745 +\r
1746 +SOURCE=.\php_http_request_method_api.h\r
1747 +# End Source File\r
1748 +# Begin Source File\r
1749 +\r
1750 +SOURCE=.\php_http_persistent_handle_api.h\r
1751 +# End Source File\r
1752 +# Begin Source File\r
1753 +\r
1754 +SOURCE=.\php_http_cache_api.h\r
1755 +# End Source File\r
1756 +# Begin Source File\r
1757 +\r
1758 +SOURCE=.\php_http_cookie_api.h\r
1759 +# End Source File\r
1760 +# Begin Source File\r
1761 +\r
1762 +SOURCE=.\php_http_date_api.h\r
1763 +# End Source File\r
1764 +# Begin Source File\r
1765 +\r
1766 +SOURCE=.\php_http_message_api.h\r
1767 +# End Source File\r
1768 +# Begin Source File\r
1769 +\r
1770 +SOURCE=.\php_http_send_api.h\r
1771 +# End Source File\r
1772 +# Begin Source File\r
1773 +\r
1774 +SOURCE=.\php_http_headers_api.h\r
1775 +# End Source File\r
1776 +# Begin Source File\r
1777 +\r
1778 +SOURCE=.\php_http_url_api.h\r
1779 +# End Source File\r
1780 +# Begin Source File\r
1781 +\r
1782 +SOURCE=.\php_http_querystring_api.h\r
1783 +# End Source File\r
1784 +# Begin Source File\r
1785 +\r
1786 +SOURCE=.\php_http_info_api.h\r
1787 +# End Source File\r
1788 +# Begin Source File\r
1789 +\r
1790 +SOURCE=.\php_http_std_defs.h\r
1791 +# End Source File\r
1792 +# Begin Source File\r
1793 +\r
1794 +SOURCE=.\phpstr\phpstr.h\r
1795 +# End Source File\r
1796 +# End Group\r
1797 +# Begin Group "Resource Files"\r
1798 +\r
1799 +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
1800 +# End Group\r
1801 +# End Target\r
1802 +# End Project\r
1803 --- /dev/null
1804 +++ b/ext/http/http_api.c
1805 @@ -0,0 +1,745 @@
1806 +/*
1807 +    +--------------------------------------------------------------------+
1808 +    | PECL :: http                                                       |
1809 +    +--------------------------------------------------------------------+
1810 +    | Redistribution and use in source and binary forms, with or without |
1811 +    | modification, are permitted provided that the conditions mentioned |
1812 +    | in the accompanying LICENSE file are met.                          |
1813 +    +--------------------------------------------------------------------+
1814 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
1815 +    +--------------------------------------------------------------------+
1816 +*/
1817 +
1818 +/* $Id: http_api.c 310302 2011-04-18 08:24:49Z rrichards $ */
1819 +
1820 +#define HTTP_WANT_SAPI
1821 +#include "php_http.h"
1822 +
1823 +#include "php_output.h"
1824 +#include "ext/standard/url.h"
1825 +#include "ext/standard/php_lcg.h"
1826 +
1827 +#include "php_http_api.h"
1828 +#include "php_http_send_api.h"
1829 +
1830 +#ifdef ZEND_ENGINE_2
1831 +#      include "php_http_exception_object.h"
1832 +#endif
1833 +
1834 +PHP_MINIT_FUNCTION(http_support)
1835 +{
1836 +       HTTP_LONG_CONSTANT("HTTP_SUPPORT", HTTP_SUPPORT);
1837 +       HTTP_LONG_CONSTANT("HTTP_SUPPORT_REQUESTS", HTTP_SUPPORT_REQUESTS);
1838 +       HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME);
1839 +       HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS);
1840 +       HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS);
1841 +       HTTP_LONG_CONSTANT("HTTP_SUPPORT_EVENTS", HTTP_SUPPORT_EVENTS);
1842 +       
1843 +       HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_COMMA", HTTP_PARAMS_ALLOW_COMMA);
1844 +       HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_FAILURE", HTTP_PARAMS_ALLOW_FAILURE);
1845 +       HTTP_LONG_CONSTANT("HTTP_PARAMS_RAISE_ERROR", HTTP_PARAMS_RAISE_ERROR);
1846 +       HTTP_LONG_CONSTANT("HTTP_PARAMS_DEFAULT", HTTP_PARAMS_DEFAULT);
1847 +       
1848 +       return SUCCESS;
1849 +}
1850 +
1851 +PHP_HTTP_API long _http_support(long feature)
1852 +{
1853 +       long support = HTTP_SUPPORT;
1854 +       
1855 +#ifdef HTTP_HAVE_CURL
1856 +       support |= HTTP_SUPPORT_REQUESTS;
1857 +#      ifdef HTTP_HAVE_SSL
1858 +       support |= HTTP_SUPPORT_SSLREQUESTS;
1859 +#      endif
1860 +#      ifdef HTTP_HAVE_EVENT
1861 +       support |= HTTP_SUPPORT_EVENTS;
1862 +#      endif
1863 +#endif
1864 +#ifdef HTTP_HAVE_MAGIC
1865 +       support |= HTTP_SUPPORT_MAGICMIME;
1866 +#endif
1867 +#ifdef HTTP_HAVE_ZLIB
1868 +       support |= HTTP_SUPPORT_ENCODINGS;
1869 +#endif
1870 +
1871 +       if (feature) {
1872 +               return (feature == (support & feature));
1873 +       }
1874 +       return support;
1875 +}
1876 +
1877 +/* char *pretty_key(char *, size_t, zend_bool, zend_bool) */
1878 +char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
1879 +{
1880 +       size_t i;
1881 +       int wasalpha;
1882 +       
1883 +       if (key && key_len) {
1884 +               if ((wasalpha = HTTP_IS_CTYPE(alpha, key[0]))) {
1885 +                       key[0] = (char) (uctitle ? HTTP_TO_CTYPE(upper, key[0]) : HTTP_TO_CTYPE(lower, key[0]));
1886 +               }
1887 +               for (i = 1; i < key_len; i++) {
1888 +                       if (HTTP_IS_CTYPE(alpha, key[i])) {
1889 +                               key[i] = (char) (((!wasalpha) && uctitle) ? HTTP_TO_CTYPE(upper, key[i]) : HTTP_TO_CTYPE(lower, key[i]));
1890 +                               wasalpha = 1;
1891 +                       } else {
1892 +                               if (xhyphen && (key[i] == '_')) {
1893 +                                       key[i] = '-';
1894 +                               }
1895 +                               wasalpha = 0;
1896 +                       }
1897 +               }
1898 +       }
1899 +       return key;
1900 +}
1901 +/* }}} */
1902 +
1903 +/* {{{ http_boundary(char *, size_t) */
1904 +size_t _http_boundary(char *buf, size_t buf_len TSRMLS_DC)
1905 +{
1906 +       return snprintf(buf, buf_len, "%lu%0.9f", (ulong) HTTP_G->request.time, (float) php_combined_lcg(TSRMLS_C));
1907 +}
1908 +/* }}} */
1909 +
1910 +/* {{{ void http_error(long, long, char*) */
1911 +void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...)
1912 +{
1913 +       va_list args;
1914 +       
1915 +       va_start(args, format);
1916 +#ifdef ZEND_ENGINE_2
1917 +       if ((type == E_THROW) || (GLOBAL_ERROR_HANDLING == EH_THROW)) {
1918 +               char *message;
1919 +               zend_class_entry *ce = http_exception_get_for_code(code);
1920 +               
1921 +               http_try {
1922 +                       vspprintf(&message, 0, format, args);
1923 +                       zend_throw_exception(ce, message, code TSRMLS_CC);
1924 +                       efree(message);
1925 +               } http_catch(GLOBAL_EXCEPTION_CLASS ? GLOBAL_EXCEPTION_CLASS : HTTP_EX_DEF_CE);
1926 +       } else
1927 +#endif
1928 +       php_verror(NULL, "", type, format, args TSRMLS_CC);
1929 +       va_end(args);
1930 +}
1931 +/* }}} */
1932 +
1933 +#ifdef ZEND_ENGINE_2
1934 +static inline void copy_bt_args(zval *from, zval *to TSRMLS_DC)
1935 +{
1936 +       zval **args, **trace_0, *old_trace_0, *trace = NULL;
1937 +       
1938 +       if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), from, "trace", lenof("trace"), 0 TSRMLS_CC))) {
1939 +               if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) {
1940 +                       old_trace_0 = *trace_0;
1941 +                       if (Z_TYPE_PP(trace_0) == IS_ARRAY && SUCCESS == zend_hash_find(Z_ARRVAL_PP(trace_0), "args", sizeof("args"), (void *) &args)) {
1942 +                               if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), to, "trace", lenof("trace"), 0 TSRMLS_CC))) {
1943 +                                       if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) {
1944 +                                               ZVAL_ADDREF(*args);
1945 +                                               add_assoc_zval(*trace_0, "args", *args);
1946 +                                       }
1947 +                               }
1948 +                       }
1949 +               }
1950 +       }
1951 +}
1952 +
1953 +/* {{{ zval *http_exception_wrap(zval *, zval *, zend_class_entry *) */
1954 +zval *_http_exception_wrap(zval *old_exception, zval *new_exception, zend_class_entry *ce TSRMLS_DC)
1955 +{
1956 +       int inner = 1;
1957 +       char *message;
1958 +       zval *sub_exception, *tmp_exception;
1959 +       
1960 +       if (!new_exception) {
1961 +               MAKE_STD_ZVAL(new_exception);
1962 +               object_init_ex(new_exception, ce);
1963 +               
1964 +               zend_update_property(ce, new_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
1965 +               copy_bt_args(old_exception, new_exception TSRMLS_CC);
1966 +               
1967 +               sub_exception = old_exception;
1968 +               
1969 +               while ((sub_exception = zend_read_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(sub_exception) == IS_OBJECT) {
1970 +                       ++inner;
1971 +               }
1972 +               
1973 +               spprintf(&message, 0, "Exception caused by %d inner exception(s)", inner);
1974 +               zend_update_property_string(ZEND_EXCEPTION_GET_DEFAULT(), new_exception, "message", lenof("message"), message TSRMLS_CC);
1975 +               efree(message);
1976 +       } else {
1977 +               sub_exception = new_exception;
1978 +               tmp_exception = new_exception;
1979 +               
1980 +               while ((tmp_exception = zend_read_property(Z_OBJCE_P(tmp_exception), tmp_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(tmp_exception) == IS_OBJECT) {
1981 +                       sub_exception = tmp_exception;
1982 +               }
1983 +               
1984 +               zend_update_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
1985 +               copy_bt_args(old_exception, new_exception TSRMLS_CC);
1986 +               copy_bt_args(old_exception, sub_exception TSRMLS_CC);
1987 +       }
1988 +#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
1989 +       Z_ADDREF_P(old_exception);
1990 +       zend_exception_set_previous(new_exception, old_exception TSRMLS_CC);
1991 +#endif
1992 +       zval_ptr_dtor(&old_exception);
1993 +       return new_exception;
1994 +}
1995 +/* }}} */
1996 +
1997 +/* {{{ STATUS http_object_new(zend_object_value *, const char *, uint, http_object_new_t, zend_class_entry *, void *, void **) */
1998 +STATUS _http_object_new(zend_object_value *ov, const char *cname_str, uint cname_len, http_object_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC)
1999 +{
2000 +       zend_class_entry *ce = parent_ce;
2001 +       
2002 +       if (cname_str && cname_len) {
2003 +               if (!(ce = zend_fetch_class(HTTP_ZAPI_CONST_CAST(char *) cname_str, cname_len, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC))) {
2004 +                       return FAILURE;
2005 +               }
2006 +               if (!instanceof_function(ce, parent_ce TSRMLS_CC)) {
2007 +                       http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Class %s does not extend %s", cname_str, parent_ce->name);
2008 +                       return FAILURE;
2009 +               }
2010 +       }
2011 +       
2012 +       *ov = create(ce, intern_ptr, obj_ptr TSRMLS_CC);
2013 +       return SUCCESS;
2014 +}
2015 +/* }}} */
2016 +#endif /* ZEND_ENGINE_2 */
2017 +
2018 +/* {{{ void http_log(char *, char *, char *) */
2019 +void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC)
2020 +{
2021 +       time_t now;
2022 +       struct tm nowtm;
2023 +       char datetime[20] = {0};
2024 +       
2025 +       now = HTTP_G->request.time;
2026 +       strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
2027 +
2028 +#define HTTP_LOG_WRITE(file, type, msg) \
2029 +       if (file && *file) { \
2030 +               php_stream *log = php_stream_open_wrapper_ex(file, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT); \
2031 +                \
2032 +               if (log) { \
2033 +                       php_stream_printf(log TSRMLS_CC, "%s\t[%s]\t%s\t<%s>%s", datetime, type, msg, SG(request_info).request_uri, PHP_EOL); \
2034 +                       php_stream_close(log); \
2035 +               } \
2036 +        \
2037 +       }
2038 +       
2039 +       HTTP_LOG_WRITE(file, ident, message);
2040 +       HTTP_LOG_WRITE(HTTP_G->log.composite, ident, message);
2041 +}
2042 +/* }}} */
2043 +
2044 +static void http_ob_blackhole(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
2045 +{
2046 +       *handled_output = ecalloc(1,1);
2047 +       *handled_output_len = 0;
2048 +}
2049 +
2050 +/* {{{ STATUS http_exit(int, char*, char*) */
2051 +STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC)
2052 +{
2053 +       if (    (send_header && (SUCCESS != http_send_status_header(status, header))) ||
2054 +                       (status && (SUCCESS != http_send_status(status)))) {
2055 +               http_error_ex(HE_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, STR_PTR(header));
2056 +               STR_FREE(header);
2057 +               STR_FREE(body);
2058 +               return FAILURE;
2059 +       }
2060 +       
2061 +       if (!php_ob_handler_used("zlib output compression") && !php_ob_handler_used("ob_gzhandler") && !OG(ob_lock)) {
2062 +               php_end_ob_buffers(0 TSRMLS_CC);
2063 +       }
2064 +       if ((SUCCESS == sapi_send_headers(TSRMLS_C)) && body) {
2065 +               PHPWRITE(body, strlen(body));
2066 +       }
2067 +       
2068 +       switch (status) {
2069 +               case 301:       http_log(HTTP_G->log.redirect, "301-REDIRECT", header);                 break;
2070 +               case 302:       http_log(HTTP_G->log.redirect, "302-REDIRECT", header);                 break;
2071 +               case 303:       http_log(HTTP_G->log.redirect, "303-REDIRECT", header);                 break;
2072 +               case 305:       http_log(HTTP_G->log.redirect, "305-REDIRECT", header);                 break;
2073 +               case 307:       http_log(HTTP_G->log.redirect, "307-REDIRECT", header);                 break;
2074 +               case 304:       http_log(HTTP_G->log.cache, "304-CACHE", header);                               break;
2075 +               case 404:       http_log(HTTP_G->log.not_found, "404-NOTFOUND", NULL);                  break;
2076 +               case 405:       http_log(HTTP_G->log.allowed_methods, "405-ALLOWED", header);   break;
2077 +               default:        http_log(NULL, header, body);                                                                   break;
2078 +       }
2079 +       
2080 +       STR_FREE(header);
2081 +       STR_FREE(body);
2082 +       
2083 +       if (HTTP_G->force_exit) {
2084 +               zend_bailout();
2085 +       } else {
2086 +               php_ob_set_internal_handler(http_ob_blackhole, 4096, "blackhole", 0 TSRMLS_CC);
2087 +       }
2088 +       
2089 +       return SUCCESS;
2090 +}
2091 +/* }}} */
2092 +
2093 +/* {{{ STATUS http_check_method(char *) */
2094 +STATUS _http_check_method_ex(const char *method, const char *methods)
2095 +{
2096 +       const char *found;
2097 +
2098 +       if (    (found = strstr(methods, method)) &&
2099 +                       (found == method || !HTTP_IS_CTYPE(alpha, found[-1])) &&
2100 +                       (strlen(found) >= strlen(method) && !HTTP_IS_CTYPE(alpha, found[strlen(method)]))) {
2101 +               return SUCCESS;
2102 +       }
2103 +       return FAILURE;
2104 +}
2105 +/* }}} */
2106 +
2107 +/* {{{ zval *http_get_server_var_ex(char *, size_t) */
2108 +PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
2109 +{
2110 +       zval **hsv, **var;
2111 +       char *env;
2112 +       
2113 +       /* if available, this is a lot faster than accessing $_SERVER */
2114 +       if (sapi_module.getenv) {
2115 +               if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) {
2116 +                       return NULL;
2117 +               }
2118 +               if (HTTP_G->server_var) {
2119 +                       zval_ptr_dtor(&HTTP_G->server_var);
2120 +               }
2121 +               MAKE_STD_ZVAL(HTTP_G->server_var);
2122 +               ZVAL_STRING(HTTP_G->server_var, env, 1);
2123 +               return HTTP_G->server_var;
2124 +       }
2125 +       
2126 +#ifdef ZEND_ENGINE_2
2127 +       zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
2128 +#endif
2129 +       
2130 +       if ((SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
2131 +               return NULL;
2132 +       }
2133 +       if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), HTTP_ZAPI_CONST_CAST(char *) key, key_len + 1, (void *) &var))) {
2134 +               return NULL;
2135 +       }
2136 +       if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
2137 +               return NULL;
2138 +       }
2139 +       return *var;
2140 +}
2141 +/* }}} */
2142 +
2143 +/* {{{ STATUS http_get_request_body(char **, size_t *) */
2144 +PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_bool dup TSRMLS_DC)
2145 +{
2146 +       *length = 0;
2147 +       *body = NULL;
2148 +       
2149 +       if (SG(request_info).raw_post_data) {
2150 +               *length = SG(request_info).raw_post_data_length;
2151 +               *body = SG(request_info).raw_post_data;
2152 +               
2153 +               if (dup) {
2154 +                       *body = estrndup(*body, *length);
2155 +               }
2156 +               return SUCCESS;
2157 +       } else if (sapi_module.read_post && !HTTP_G->read_post_data) {
2158 +               char *buf = emalloc(4096);
2159 +               int len;
2160 +               
2161 +               HTTP_G->read_post_data = 1;
2162 +               
2163 +               while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) {
2164 +                       SG(read_post_bytes) += len;
2165 +                       *body = erealloc(*body, *length + len + 1);
2166 +                       memcpy(*body + *length, buf, len);
2167 +                       *length += len;
2168 +                       (*body)[*length] = '\0';
2169 +                       if (len < 4096) {
2170 +                               break;
2171 +                       }
2172 +               }
2173 +               efree(buf);
2174 +               
2175 +               /* check for error */
2176 +               if (len < 0) {
2177 +                       STR_FREE(*body);
2178 +                       *length = 0;
2179 +                       return FAILURE;
2180 +               }
2181 +               
2182 +               SG(request_info).raw_post_data = *body;
2183 +               SG(request_info).raw_post_data_length = *length;
2184 +               
2185 +               if (dup) {
2186 +                       *body = estrndup(*body, *length);
2187 +               }
2188 +               return SUCCESS;
2189 +       }
2190 +       
2191 +       return FAILURE;
2192 +}
2193 +/* }}} */
2194 +
2195 +/* {{{ php_stream *http_get_request_body_stream(void) */
2196 +PHP_HTTP_API php_stream *_http_get_request_body_stream(TSRMLS_D)
2197 +{
2198 +       php_stream *s = NULL;
2199 +       
2200 +       if (SG(request_info).raw_post_data) {
2201 +               s = php_stream_open_wrapper("php://input", "rb", 0, NULL);
2202 +       } else if (sapi_module.read_post && !HTTP_G->read_post_data) {
2203 +               HTTP_G->read_post_data = 1;
2204 +               
2205 +               if ((s = php_stream_temp_new())) {
2206 +                       char *buf = emalloc(4096);
2207 +                       int len;
2208 +                       
2209 +                       while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) {
2210 +                               php_stream_write(s, buf, len);
2211 +                               if (len < 4096) {
2212 +                                       break;
2213 +                               }
2214 +                       }
2215 +                       efree(buf);
2216 +                       
2217 +                       if (len < 0) {
2218 +                               php_stream_close(s);
2219 +                               s = NULL;
2220 +                       } else {
2221 +                               php_stream_rewind(s);
2222 +                       }
2223 +               }
2224 +       }
2225 +       
2226 +       return s;
2227 +}
2228 +/* }}} */
2229 +
2230 +/* {{{ void http_parse_params_default_callback(...) */
2231 +PHP_HTTP_API void _http_parse_params_default_callback(void *arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC)
2232 +{
2233 +       char *kdup;
2234 +       zval tmp, *entry;
2235 +       HashTable *ht = (HashTable *) arg;
2236 +       
2237 +       if (ht) {
2238 +               INIT_ZARR(tmp, ht);
2239 +               
2240 +               if (vallen) {
2241 +                       MAKE_STD_ZVAL(entry);
2242 +                       array_init(entry);
2243 +                       if (keylen) {
2244 +                               kdup = estrndup(key, keylen);
2245 +                               add_assoc_stringl_ex(entry, kdup, keylen + 1, (char *) val, vallen, 1);
2246 +                               efree(kdup);
2247 +                       } else {
2248 +                               add_next_index_stringl(entry, (char *) val, vallen, 1);
2249 +                       }
2250 +                       add_next_index_zval(&tmp, entry);
2251 +               } else {
2252 +                       add_next_index_stringl(&tmp, (char *) key, keylen, 1);
2253 +               }
2254 +       }
2255 +}
2256 +/* }}} */
2257 +
2258 +/* {{{ STATUS http_parse_params(const char *, HashTable *) */
2259 +PHP_HTTP_API STATUS _http_parse_params_ex(const char *param, int flags, http_parse_params_callback cb, void *cb_arg TSRMLS_DC)
2260 +{
2261 +#define ST_QUOTE       1
2262 +#define ST_VALUE       2
2263 +#define ST_KEY         3
2264 +#define ST_ASSIGN      4
2265 +#define ST_ADD         5
2266 +       
2267 +       int st = ST_KEY, keylen = 0, vallen = 0;
2268 +       char *s, *c, *key = NULL, *val = NULL;
2269 +       
2270 +       for(c = s = estrdup(param);;) {
2271 +       continued:
2272 +#if 0
2273 +       {
2274 +               char *tk = NULL, *tv = NULL;
2275 +               
2276 +               if (key) {
2277 +                       if (keylen) {
2278 +                               tk= estrndup(key, keylen);
2279 +                       } else {
2280 +                               tk = ecalloc(1, 7);
2281 +                               memcpy(tk, key, 3);
2282 +                               tk[3]='.'; tk[4]='.'; tk[5]='.';
2283 +                       }
2284 +               }
2285 +               if (val) {
2286 +                       if (vallen) {
2287 +                               tv = estrndup(val, vallen);
2288 +                       } else {
2289 +                               tv = ecalloc(1, 7);
2290 +                               memcpy(tv, val, 3);
2291 +                               tv[3]='.'; tv[4]='.'; tv[5]='.';
2292 +                       }
2293 +               }
2294 +               fprintf(stderr, "[%6s] %c \"%s=%s\"\n",
2295 +                               (
2296 +                                               st == ST_QUOTE ? "QUOTE" :
2297 +                                               st == ST_VALUE ? "VALUE" :
2298 +                                               st == ST_KEY ? "KEY" :
2299 +                                               st == ST_ASSIGN ? "ASSIGN" :
2300 +                                               st == ST_ADD ? "ADD":
2301 +                                               "HUH?"
2302 +                               ), *c?*c:'0', tk, tv
2303 +               );
2304 +               STR_FREE(tk); STR_FREE(tv);
2305 +       }
2306 +#endif
2307 +               switch (st) {
2308 +                       case ST_QUOTE:
2309 +                       quote:
2310 +                               if (*c == '"') {
2311 +                                       if (*(c-1) == '\\') {
2312 +                                               memmove(c-1, c, strlen(c)+1);
2313 +                                               goto quote;
2314 +                                       } else {
2315 +                                               goto add;
2316 +                                       }
2317 +                               } else {
2318 +                                       if (!val) {
2319 +                                               val = c;
2320 +                                       }
2321 +                                       if (!*c) {
2322 +                                               --val;
2323 +                                               st = ST_ADD;
2324 +                                       }
2325 +                               }
2326 +                               break;
2327 +                               
2328 +                       case ST_VALUE:
2329 +                               switch (*c) {
2330 +                                       case '"':
2331 +                                               if (!val) {
2332 +                                                       st = ST_QUOTE;
2333 +                                               }
2334 +                                               break;
2335 +                                       
2336 +                                       case ' ':
2337 +                                               break;
2338 +                                       
2339 +                                       case ';':
2340 +                                       case '\0':
2341 +                                               goto add;
2342 +                                               break;
2343 +                                       case ',':
2344 +                                               if (flags & HTTP_PARAMS_ALLOW_COMMA) {
2345 +                                                       goto add;
2346 +                                               }
2347 +                                       default:
2348 +                                               if (!val) {
2349 +                                                       val = c;
2350 +                                               }
2351 +                                               break;
2352 +                               }
2353 +                               break;
2354 +                               
2355 +                       case ST_KEY:
2356 +                               switch (*c) {
2357 +                                       case ',':
2358 +                                               if (flags & HTTP_PARAMS_ALLOW_COMMA) {
2359 +                                                       goto allow_comma;
2360 +                                               }
2361 +                                       case '\r':
2362 +                                       case '\n':
2363 +                                       case '\t':
2364 +                                       case '\013':
2365 +                                       case '\014':
2366 +                                               goto failure;
2367 +                                               break;
2368 +                                       
2369 +                                       case ' ':
2370 +                                               if (key) {
2371 +                                                       keylen = c - key;
2372 +                                                       st = ST_ASSIGN;
2373 +                                               }
2374 +                                               break;
2375 +                                       
2376 +                                       case ';':
2377 +                                       case '\0':
2378 +                                       allow_comma:
2379 +                                               if (key) {
2380 +                                                       keylen = c-- - key;
2381 +                                                       st = ST_ADD;
2382 +                                               }
2383 +                                               break;
2384 +                                       
2385 +                                       case ':':
2386 +                                               if (!(flags & HTTP_PARAMS_COLON_SEPARATOR)) {
2387 +                                                       goto not_separator;
2388 +                                               }
2389 +                                               if (key) {
2390 +                                                       keylen = c - key;
2391 +                                                       st = ST_VALUE;
2392 +                                               } else {
2393 +                                                       goto failure;
2394 +                                               }
2395 +                                               break;
2396 +                                               
2397 +                                       case '=':
2398 +                                               if (flags & HTTP_PARAMS_COLON_SEPARATOR) {
2399 +                                                       goto not_separator;
2400 +                                               }
2401 +                                               if (key) {
2402 +                                                       keylen = c - key;
2403 +                                                       st = ST_VALUE;
2404 +                                               } else {
2405 +                                                       goto failure;
2406 +                                               }
2407 +                                               break;
2408 +                                       
2409 +                                       default:
2410 +                                       not_separator:
2411 +                                               if (!key) {
2412 +                                                       key = c;
2413 +                                               }
2414 +                                               break;
2415 +                               }
2416 +                               break;
2417 +                               
2418 +                       case ST_ASSIGN:
2419 +                               if (*c == '=') {
2420 +                                       st = ST_VALUE;
2421 +                               } else if (!*c || *c == ';' || ((flags & HTTP_PARAMS_ALLOW_COMMA) && *c == ',')) {
2422 +                                       st = ST_ADD;
2423 +                               } else if (*c != ' ') {
2424 +                                       goto failure;
2425 +                               }
2426 +                               break;
2427 +                               
2428 +                       case ST_ADD:
2429 +                       add:
2430 +                               if (val) {
2431 +                                       vallen = c - val;
2432 +                                       if (st != ST_QUOTE) {
2433 +                                               while (val[vallen-1] == ' ') --vallen;
2434 +                                       }
2435 +                               } else {
2436 +                                       val = "";
2437 +                                       vallen = 0;
2438 +                               }
2439 +                               
2440 +                               cb(cb_arg, key, keylen, val, vallen TSRMLS_CC);
2441 +                               
2442 +                               st = ST_KEY;
2443 +                               key = val = NULL;
2444 +                               keylen = vallen = 0;
2445 +                               break;
2446 +               }
2447 +               if (*c) {
2448 +                       ++c;
2449 +               } else if (st == ST_ADD) {
2450 +                       goto add;
2451 +               } else {
2452 +                       break;
2453 +               }
2454 +       }
2455 +       
2456 +       efree(s);
2457 +       return SUCCESS;
2458 +       
2459 +failure:
2460 +       if (flags & HTTP_PARAMS_RAISE_ERROR) {
2461 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s));
2462 +       }
2463 +       if (flags & HTTP_PARAMS_ALLOW_FAILURE) {
2464 +               if (st == ST_KEY) {
2465 +                       if (key) {
2466 +                               keylen = c - key;
2467 +                       } else {
2468 +                               key = c;
2469 +                       }
2470 +               } else {
2471 +                       --c;
2472 +               }
2473 +               st = ST_ADD;
2474 +               goto continued;
2475 +       }
2476 +       efree(s);
2477 +       return FAILURE;
2478 +}
2479 +/* }}} */
2480 +
2481 +/* {{{ array_join */
2482 +int apply_array_append_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
2483 +{
2484 +       int flags;
2485 +       char *key = NULL;
2486 +       HashTable *dst;
2487 +       zval **data = NULL, **value = (zval **) pDest;
2488 +       
2489 +       dst = va_arg(args, HashTable *);
2490 +       flags = va_arg(args, int);
2491 +       
2492 +       if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
2493 +               if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
2494 +                       key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
2495 +                       zend_hash_find(dst, key, hash_key->nKeyLength, (void *) &data);
2496 +               } else {
2497 +                       zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data);
2498 +               }
2499 +               
2500 +               ZVAL_ADDREF(*value);
2501 +               if (data) {
2502 +                       add_next_index_zval(http_zset(IS_ARRAY, *data), *value);
2503 +               } else if (key) {
2504 +                       zend_hash_add(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL);
2505 +               } else {
2506 +                       zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL);
2507 +               }
2508 +               
2509 +               if (key) {
2510 +                       efree(key);
2511 +               }
2512 +       }
2513 +       
2514 +       return ZEND_HASH_APPLY_KEEP;
2515 +}
2516 +
2517 +int apply_array_merge_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
2518 +{
2519 +       int flags;
2520 +       char *key = NULL;
2521 +       HashTable *dst;
2522 +       zval **value = (zval **) pDest;
2523 +       
2524 +       dst = va_arg(args, HashTable *);
2525 +       flags = va_arg(args, int);
2526 +       
2527 +       if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) {
2528 +               ZVAL_ADDREF(*value);
2529 +               if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) {
2530 +                       key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1);
2531 +                       zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL);
2532 +                       efree(key);
2533 +               } else {
2534 +                       zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL);
2535 +               }
2536 +       }
2537 +       
2538 +       return ZEND_HASH_APPLY_KEEP;
2539 +}
2540 +/* }}} */
2541 +
2542 +/*
2543 + * Local variables:
2544 + * tab-width: 4
2545 + * c-basic-offset: 4
2546 + * End:
2547 + * vim600: noet sw=4 ts=4 fdm=marker
2548 + * vim<600: noet sw=4 ts=4
2549 + */
2550 +
2551 --- /dev/null
2552 +++ b/ext/http/http_cache_api.c
2553 @@ -0,0 +1,256 @@
2554 +/*
2555 +    +--------------------------------------------------------------------+
2556 +    | PECL :: http                                                       |
2557 +    +--------------------------------------------------------------------+
2558 +    | Redistribution and use in source and binary forms, with or without |
2559 +    | modification, are permitted provided that the conditions mentioned |
2560 +    | in the accompanying LICENSE file are met.                          |
2561 +    +--------------------------------------------------------------------+
2562 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
2563 +    +--------------------------------------------------------------------+
2564 +*/
2565 +
2566 +/* $Id: http_cache_api.c 292841 2009-12-31 08:48:57Z mike $ */
2567 +
2568 +#define HTTP_WANT_SAPI
2569 +#include "php_http.h"
2570 +
2571 +#include "php_output.h"
2572 +#include "php_streams.h"
2573 +
2574 +#include "php_http_api.h"
2575 +#include "php_http_cache_api.h"
2576 +#include "php_http_date_api.h"
2577 +#include "php_http_send_api.h"
2578 +
2579 +/* {{{ char *http_etag(void *, size_t, http_send_mode) */
2580 +PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC)
2581 +{
2582 +       void *ctx = http_etag_init();
2583 +       
2584 +       if (data_mode == SEND_DATA) {
2585 +               http_etag_update(ctx, data_ptr, data_len);
2586 +       } else {
2587 +               STATUS ss = FAILURE;
2588 +               php_stream_statbuf ssb;
2589 +               
2590 +               if (data_mode == SEND_RSRC) {
2591 +                       ss = php_stream_stat((php_stream *) data_ptr, &ssb);
2592 +               } else {
2593 +                       ss = php_stream_stat_path((char *) data_ptr, &ssb);
2594 +               }
2595 +               
2596 +               if (SUCCESS != ss) {
2597 +                       efree(ctx);
2598 +                       return NULL;
2599 +               } else {
2600 +                       size_t ssb_len;
2601 +                       char ssb_buf[128];
2602 +                       
2603 +                       ssb_len = snprintf(ssb_buf, sizeof(ssb_buf), "%ld=%ld=%ld", (long) ssb.sb.st_mtime, 
2604 +                                                                                                                       (long) ssb.sb.st_ino, 
2605 +                                                                                                                       (long) ssb.sb.st_size);
2606 +                       http_etag_update(ctx, ssb_buf, ssb_len);
2607 +               }
2608 +       }
2609 +       
2610 +       return http_etag_finish(ctx);
2611 +}
2612 +/* }}} */
2613 +
2614 +/* {{{ time_t http_last_modified(void *, http_send_mode) */
2615 +PHP_HTTP_API time_t _http_last_modified(const void *data_ptr, http_send_mode data_mode TSRMLS_DC)
2616 +{
2617 +       php_stream_statbuf ssb;
2618 +
2619 +       switch (data_mode) {
2620 +               case SEND_DATA: return HTTP_G->request.time;
2621 +               case SEND_RSRC: return php_stream_stat((php_stream *) data_ptr, &ssb) ? 0 : ssb.sb.st_mtime;
2622 +               default:                return php_stream_stat_path((char *) data_ptr, &ssb) ? 0 : ssb.sb.st_mtime;
2623 +       }
2624 +}
2625 +/* }}} */
2626 +
2627 +/* {{{ zend_bool http_match_last_modified(char *, time_t) */
2628 +PHP_HTTP_API zend_bool _http_match_last_modified_ex(const char *entry, time_t t, zend_bool enforce_presence TSRMLS_DC)
2629 +{
2630 +       zend_bool retval;
2631 +       zval *zmodified;
2632 +       char *modified, *chr_ptr;
2633 +
2634 +       if (!(zmodified = http_get_server_var(entry, 1))) {
2635 +               return !enforce_presence;
2636 +       }
2637 +
2638 +       modified = estrndup(Z_STRVAL_P(zmodified), Z_STRLEN_P(zmodified));
2639 +       if ((chr_ptr = strrchr(modified, ';'))) {
2640 +               chr_ptr = 0;
2641 +       }
2642 +       
2643 +       retval = (t <= http_parse_date_ex(modified, 1));
2644 +       efree(modified);
2645 +       return retval;
2646 +}
2647 +/* }}} */
2648 +
2649 +/* {{{ zend_bool http_match_etag(char *, char *) */
2650 +PHP_HTTP_API zend_bool _http_match_etag_ex(const char *entry, const char *etag, zend_bool enforce_presence TSRMLS_DC)
2651 +{
2652 +       zval *zetag;
2653 +       char *quoted_etag;
2654 +       zend_bool result;
2655 +
2656 +       if (!(zetag = http_get_server_var_ex(entry, strlen(entry)+1, 1))) {
2657 +               return !enforce_presence;
2658 +       }
2659 +
2660 +       if (NULL != strchr(Z_STRVAL_P(zetag), '*')) {
2661 +               return 1;
2662 +       }
2663 +
2664 +       spprintf(&quoted_etag, 0, "\"%s\"", etag);
2665 +       if (!strchr(Z_STRVAL_P(zetag), ',')) {
2666 +               result = !strcmp(Z_STRVAL_P(zetag), quoted_etag);
2667 +       } else {
2668 +               result = (NULL != strstr(Z_STRVAL_P(zetag), quoted_etag));
2669 +       }
2670 +       efree(quoted_etag);
2671 +       
2672 +       return result;
2673 +}
2674 +/* }}} */
2675 +
2676 +/* {{{ STATUS http_cache_last_modified(time_t, time_t, char *, size_t) */
2677 +PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified,
2678 +       time_t send_modified, const char *cache_control, size_t cc_len TSRMLS_DC)
2679 +{
2680 +       char *sent_header = NULL;
2681 +       
2682 +       if (SG(headers_sent)) {
2683 +               return FAILURE;
2684 +       }
2685 +       
2686 +       if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) {
2687 +               return FAILURE;
2688 +       }
2689 +
2690 +       if (SUCCESS != http_send_last_modified_ex(send_modified, &sent_header)) {
2691 +               return FAILURE;
2692 +       }
2693 +
2694 +       if (http_match_last_modified("HTTP_IF_MODIFIED_SINCE", last_modified)) {
2695 +               http_exit_ex(304, sent_header, NULL, 0);
2696 +       } else {
2697 +               STR_FREE(sent_header);
2698 +       }
2699 +
2700 +       return SUCCESS;
2701 +}
2702 +/* }}} */
2703 +
2704 +/* {{{ STATUS http_cache_etag(char *, size_t, char *, size_t) */
2705 +PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len,
2706 +       const char *cache_control, size_t cc_len TSRMLS_DC)
2707 +{
2708 +       char *sent_header = NULL;
2709 +       
2710 +       if (SG(headers_sent)) {
2711 +               return FAILURE;
2712 +       }
2713 +       
2714 +       if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) {
2715 +               return FAILURE;
2716 +       }
2717 +
2718 +       if (etag_len) {
2719 +               if (SUCCESS != http_send_etag_ex(etag, etag_len, &sent_header)) {
2720 +                       return FAILURE;
2721 +               }
2722 +               if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
2723 +                       http_exit_ex(304, sent_header, NULL, 0);
2724 +               } else {
2725 +                       STR_FREE(sent_header);
2726 +               }
2727 +               return SUCCESS;
2728 +       }
2729 +       
2730 +       /* start ob_etaghandler */
2731 +       return http_start_ob_etaghandler();
2732 +}
2733 +/* }}} */
2734 +
2735 +PHP_HTTP_API STATUS _http_start_ob_etaghandler(TSRMLS_D)
2736 +{
2737 +       /* already running? */
2738 +       if (php_ob_handler_used("ob_etaghandler" TSRMLS_CC)) {
2739 +               http_error(HE_WARNING, HTTP_E_RUNTIME, "ob_etaghandler can only be used once");
2740 +               return FAILURE;
2741 +       }
2742 +       
2743 +       HTTP_G->etag.started = 1;
2744 +       return php_start_ob_buffer_named("ob_etaghandler", HTTP_G->send.buffer_size, 0 TSRMLS_CC);
2745 +}
2746 +
2747 +PHP_HTTP_API zend_bool _http_interrupt_ob_etaghandler(TSRMLS_D)
2748 +{
2749 +       if (HTTP_G->etag.started) {
2750 +               HTTP_G->etag.started = 0;
2751 +               if (HTTP_G->etag.ctx) {
2752 +                       efree(HTTP_G->etag.ctx);
2753 +                       HTTP_G->etag.ctx = NULL;
2754 +               }
2755 +               return 1;
2756 +       }
2757 +       return 0;
2758 +}
2759 +
2760 +/* {{{ void http_ob_etaghandler(char *, uint, char **, uint *, int) */
2761 +void _http_ob_etaghandler(char *output, uint output_len,
2762 +       char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
2763 +{
2764 +       /* passthru */
2765 +       *handled_output_len = output_len;
2766 +       *handled_output = estrndup(output, output_len);
2767 +       
2768 +       /* are we supposed to run? */
2769 +       if (HTTP_G->etag.started) {
2770 +               /* initialize the etag context */
2771 +               if (mode & PHP_OUTPUT_HANDLER_START) {
2772 +                       HTTP_G->etag.ctx = http_etag_init();
2773 +               }
2774 +               
2775 +               /* update */
2776 +               http_etag_update(HTTP_G->etag.ctx, output, output_len);
2777 +               
2778 +               /* finish */
2779 +               if (mode & PHP_OUTPUT_HANDLER_END) {
2780 +                       char *sent_header = NULL;
2781 +                       char *etag = http_etag_finish(HTTP_G->etag.ctx);
2782 +                       
2783 +                       HTTP_G->etag.ctx = NULL;
2784 +                       
2785 +                       http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL));
2786 +                       http_send_etag_ex(etag, strlen(etag), &sent_header);
2787 +                       
2788 +                       if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
2789 +                               /* force exit; ob within ob does not work */
2790 +                               HTTP_G->force_exit = 1;
2791 +                               http_exit_ex(304, sent_header, etag, 0);
2792 +                       }
2793 +                       
2794 +                       STR_FREE(sent_header);
2795 +                       STR_FREE(etag);
2796 +               }
2797 +       }
2798 +}
2799 +/* }}} */
2800 +
2801 +/*
2802 + * Local variables:
2803 + * tab-width: 4
2804 + * c-basic-offset: 4
2805 + * End:
2806 + * vim600: sw=4 ts=4 fdm=marker
2807 + * vim<600: sw=4 ts=4
2808 + */
2809 +
2810 --- /dev/null
2811 +++ b/ext/http/http_cookie_api.c
2812 @@ -0,0 +1,371 @@
2813 +/*
2814 +    +--------------------------------------------------------------------+
2815 +    | PECL :: http                                                       |
2816 +    +--------------------------------------------------------------------+
2817 +    | Redistribution and use in source and binary forms, with or without |
2818 +    | modification, are permitted provided that the conditions mentioned |
2819 +    | in the accompanying LICENSE file are met.                          |
2820 +    +--------------------------------------------------------------------+
2821 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
2822 +    +--------------------------------------------------------------------+
2823 +*/
2824 +
2825 +/* $Id: http_cookie_api.c 298662 2010-04-27 13:42:32Z mike $ */
2826 +
2827 +#include "php_http.h"
2828 +#include "php_http_api.h"
2829 +#include "php_http_date_api.h"
2830 +#include "php_http_cookie_api.h"
2831 +
2832 +#include "ext/standard/url.h"
2833 +
2834 +/* {{{ PHP_MINIT_FUNCTION(http_cookie) */
2835 +PHP_MINIT_FUNCTION(http_cookie)
2836 +{
2837 +       HTTP_LONG_CONSTANT("HTTP_COOKIE_PARSE_RAW", HTTP_COOKIE_PARSE_RAW);
2838 +       HTTP_LONG_CONSTANT("HTTP_COOKIE_SECURE", HTTP_COOKIE_SECURE);
2839 +       HTTP_LONG_CONSTANT("HTTP_COOKIE_HTTPONLY", HTTP_COOKIE_HTTPONLY);
2840 +       
2841 +       return SUCCESS;
2842 +}
2843 +/* }}} */
2844 +
2845 +/* {{{ http_cookie_list *http_cookie_list_init(http_cookie_list *) */
2846 +PHP_HTTP_API http_cookie_list *_http_cookie_list_init(http_cookie_list *list ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
2847 +{
2848 +       if (!list) {
2849 +               list = emalloc_rel(sizeof(http_cookie_list));
2850 +       }
2851 +       
2852 +       zend_hash_init(&list->cookies, 0, NULL, ZVAL_PTR_DTOR, 0);
2853 +       zend_hash_init(&list->extras, 0, NULL, ZVAL_PTR_DTOR, 0);
2854 +       
2855 +       list->path = NULL;
2856 +       list->domain = NULL;
2857 +       list->expires = 0;
2858 +       list->flags = 0;
2859 +       
2860 +       return list;
2861 +}
2862 +/* }}} */
2863 +
2864 +/* {{{ void http_cookie_list_dtor(http_cookie_list *) */
2865 +PHP_HTTP_API void _http_cookie_list_dtor(http_cookie_list *list TSRMLS_DC)
2866 +{
2867 +       if (list) {
2868 +               zend_hash_destroy(&list->cookies);
2869 +               zend_hash_destroy(&list->extras);
2870 +       
2871 +               STR_SET(list->path, NULL);
2872 +               STR_SET(list->domain, NULL);
2873 +       }
2874 +}
2875 +/* }}} */
2876 +
2877 +/* {{{ void http_cookie_list_free(http_cookie_list **) */
2878 +PHP_HTTP_API void _http_cookie_list_free(http_cookie_list **list TSRMLS_DC)
2879 +{
2880 +       if (list) {
2881 +               http_cookie_list_dtor(*list);
2882 +               efree(*list);
2883 +               *list = NULL;
2884 +       }
2885 +}
2886 +/* }}} */
2887 +
2888 +/* {{{ const char *http_cookie_list_get_cookie(http_cookie_list *, const char*, size_t) */
2889 +PHP_HTTP_API const char *_http_cookie_list_get_cookie(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC)
2890 +{
2891 +       zval **cookie = NULL;
2892 +       if ((SUCCESS != zend_hash_find(&list->cookies, HTTP_ZAPI_CONST_CAST(char *) name, name_len + 1, (void *) &cookie)) || (Z_TYPE_PP(cookie) != IS_STRING)) {
2893 +               return NULL;
2894 +       }
2895 +       return Z_STRVAL_PP(cookie);
2896 +}
2897 +/* }}} */
2898 +
2899 +/* {{{ const char *http_cookie_list_get_extra(http_cookie_list *, const char *, size_t) */
2900 +PHP_HTTP_API const char *_http_cookie_list_get_extra(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC)
2901 +{
2902 +       zval **extra = NULL;
2903 +       if ((SUCCESS != zend_hash_find(&list->extras, HTTP_ZAPI_CONST_CAST(char *) name, name_len + 1, (void *) &extra)) || (Z_TYPE_PP(extra) != IS_STRING)) {
2904 +               return NULL;
2905 +       }
2906 +       return Z_STRVAL_PP(extra);
2907 +}
2908 +/* }}} */
2909 +
2910 +/* {{{ void http_cookie_list_add_cookie(http_cookie_list *, const char *, size_t, const char *, size_t) */
2911 +PHP_HTTP_API void _http_cookie_list_add_cookie(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC)
2912 +{
2913 +       zval *cookie_value;
2914 +       char *key = estrndup(name, name_len);
2915 +       MAKE_STD_ZVAL(cookie_value);
2916 +       ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0);
2917 +       zend_hash_update(&list->cookies, key, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL);
2918 +       efree(key);
2919 +}
2920 +/* }}} */
2921 +
2922 +/* {{{ void http_cookie_list_add_extr(http_cookie_list *, const char *, size_t, const char *, size_t) */
2923 +PHP_HTTP_API void _http_cookie_list_add_extra(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC)
2924 +{
2925 +       zval *cookie_value;
2926 +       char *key = estrndup(name, name_len);
2927 +       MAKE_STD_ZVAL(cookie_value);
2928 +       ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0);
2929 +       zend_hash_update(&list->extras, key, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL);
2930 +       efree(key);
2931 +}
2932 +/* }}} */
2933 +
2934 +typedef struct _http_parse_param_cb_arg_t {
2935 +       http_cookie_list *list;
2936 +       long flags;
2937 +       char **allowed_extras;
2938 +} http_parse_param_cb_arg;
2939 +
2940 +/* {{{ static void http_parse_cookie_callback */
2941 +static void http_parse_cookie_callback(void *ptr, const char *key, int keylen, const char *val, int vallen TSRMLS_DC)
2942 +{
2943 +       http_parse_param_cb_arg *arg = (http_parse_param_cb_arg *) ptr;
2944 +       
2945 +#define _KEY_IS(s) (keylen == lenof(s) && !strncasecmp(key, (s), keylen))
2946 +       if _KEY_IS("path") {
2947 +               STR_SET(arg->list->path, estrndup(val, vallen));
2948 +       } else if _KEY_IS("domain") {
2949 +               STR_SET(arg->list->domain, estrndup(val, vallen));
2950 +       } else if _KEY_IS("expires") {
2951 +               char *date = estrndup(val, vallen);
2952 +               arg->list->expires = http_parse_date(date);
2953 +               efree(date);
2954 +       } else if _KEY_IS("secure") {
2955 +               arg->list->flags |= HTTP_COOKIE_SECURE;
2956 +       } else if _KEY_IS("httpOnly") {
2957 +               arg->list->flags |= HTTP_COOKIE_HTTPONLY;
2958 +       } else {
2959 +               /* check for extra */
2960 +               if (arg->allowed_extras) {
2961 +                       char **ae = arg->allowed_extras;
2962 +                       
2963 +                       for (; *ae; ++ae) {
2964 +                               if ((size_t) keylen == strlen(*ae) && !strncasecmp(key, *ae, keylen)) {
2965 +                                       if (arg->flags & HTTP_COOKIE_PARSE_RAW) {
2966 +                                               http_cookie_list_add_extra(arg->list, key, keylen, val, vallen);
2967 +                                       } else {
2968 +                                               char *dec = estrndup(val, vallen);
2969 +                                               int declen = php_url_decode(dec, vallen);
2970 +                                               
2971 +                                               http_cookie_list_add_extra(arg->list, key, keylen, dec, declen);
2972 +                                               efree(dec);
2973 +                                       }
2974 +                                       return;
2975 +                               }
2976 +                       }
2977 +               }
2978 +               /* new cookie */
2979 +               if (arg->flags & HTTP_COOKIE_PARSE_RAW) {
2980 +                       http_cookie_list_add_cookie(arg->list, key, keylen, val, vallen);
2981 +               } else {
2982 +                       char *dec = estrndup(val, vallen);
2983 +                       int declen = php_url_decode(dec, vallen);
2984 +                       
2985 +                       http_cookie_list_add_cookie(arg->list, key, keylen, dec, declen);
2986 +                       efree(dec);
2987 +               }
2988 +       }
2989 +}
2990 +/* }}} */
2991 +
2992 +/* {{{ http_cookie_list *http_parse_cookie(char *, long) */
2993 +PHP_HTTP_API http_cookie_list *_http_parse_cookie_ex(http_cookie_list *list, const char *string, long flags, char **allowed_extras TSRMLS_DC)
2994 +{
2995 +       int free_list = !list;
2996 +       http_parse_param_cb_arg arg;
2997 +       
2998 +       list = http_cookie_list_init(list);
2999 +       
3000 +       arg.list = list;
3001 +       arg.flags = flags;
3002 +       arg.allowed_extras = allowed_extras;
3003 +       
3004 +       if (SUCCESS != http_parse_params_ex(string, HTTP_PARAMS_RAISE_ERROR, http_parse_cookie_callback, &arg)) {
3005 +               if (free_list) {
3006 +                       http_cookie_list_free(&list);
3007 +               } else {
3008 +                       http_cookie_list_dtor(list);
3009 +               }
3010 +               list = NULL;
3011 +       }
3012 +       
3013 +       return list;
3014 +}
3015 +/* }}} */
3016 +
3017 +/* {{{ void http_cookie_list_tostruct(http_cookie_list *, zval *) */
3018 +PHP_HTTP_API void _http_cookie_list_tostruct(http_cookie_list *list, zval *strct TSRMLS_DC)
3019 +{
3020 +       zval array, *cookies, *extras;
3021 +       
3022 +       INIT_ZARR(array, HASH_OF(strct));
3023 +       
3024 +       MAKE_STD_ZVAL(cookies);
3025 +       array_init(cookies);
3026 +       zend_hash_copy(Z_ARRVAL_P(cookies), &list->cookies, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
3027 +       add_assoc_zval(&array, "cookies", cookies);
3028 +       
3029 +       MAKE_STD_ZVAL(extras);
3030 +       array_init(extras);
3031 +       zend_hash_copy(Z_ARRVAL_P(extras), &list->extras, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
3032 +       add_assoc_zval(&array, "extras", extras);
3033 +       
3034 +       add_assoc_long(&array, "flags", list->flags);
3035 +       add_assoc_long(&array, "expires", (long) list->expires);
3036 +       add_assoc_string(&array, "path", STR_PTR(list->path), 1);
3037 +       add_assoc_string(&array, "domain", STR_PTR(list->domain), 1);
3038 +}
3039 +/* }}} */
3040 +
3041 +/* {{{ http_cookie_list *http_cookie_list_fromstruct(http_cookie_list *, zval *strct) */
3042 +PHP_HTTP_API http_cookie_list *_http_cookie_list_fromstruct(http_cookie_list *list, zval *strct TSRMLS_DC)
3043 +{
3044 +       zval **tmp, *cpy;
3045 +       HashTable *ht = HASH_OF(strct);
3046 +       
3047 +       list = http_cookie_list_init(list);
3048 +       
3049 +       if (SUCCESS == zend_hash_find(ht, "cookies", sizeof("cookies"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) {
3050 +               zend_hash_copy(&list->cookies, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
3051 +       }
3052 +       if (SUCCESS == zend_hash_find(ht, "extras", sizeof("extras"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) {
3053 +               zend_hash_copy(&list->extras, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
3054 +       }
3055 +       if (SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &tmp)) {
3056 +               switch (Z_TYPE_PP(tmp)) {
3057 +                       case IS_LONG:
3058 +                               list->flags = Z_LVAL_PP(tmp);
3059 +                               break;
3060 +                       case IS_DOUBLE:
3061 +                               list->flags = (long) Z_DVAL_PP(tmp);
3062 +                               break;
3063 +                       case IS_STRING:
3064 +                               cpy = http_zsep(IS_LONG, *tmp);
3065 +                               list->flags = Z_LVAL_P(cpy);
3066 +                               zval_ptr_dtor(&cpy);
3067 +                               break;
3068 +                       default:
3069 +                               break;
3070 +               }
3071 +       }
3072 +       if (SUCCESS == zend_hash_find(ht, "expires", sizeof("expires"), (void *) &tmp)) {
3073 +               switch (Z_TYPE_PP(tmp)) {
3074 +                       case IS_LONG:
3075 +                               list->expires = Z_LVAL_PP(tmp);
3076 +                               break;
3077 +                       case IS_DOUBLE:
3078 +                               list->expires = (long) Z_DVAL_PP(tmp);
3079 +                               break;
3080 +                       case IS_STRING:
3081 +                               cpy = http_zsep(IS_LONG, *tmp);
3082 +                               if (Z_LVAL_P(cpy)) {
3083 +                                       list->expires = Z_LVAL_P(cpy);
3084 +                               } else {
3085 +                                       time_t expires = http_parse_date(Z_STRVAL_PP(tmp));
3086 +                                       if (expires > 0) {
3087 +                                               list->expires = expires;
3088 +                                       }
3089 +                               }
3090 +                               zval_ptr_dtor(&cpy);
3091 +                               break;
3092 +                       default:
3093 +                               break;
3094 +               }
3095 +       }
3096 +       if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) {
3097 +               list->path = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
3098 +       }
3099 +       if (SUCCESS == zend_hash_find(ht, "domain", sizeof("domain"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) {
3100 +               list->domain = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
3101 +       }
3102 +       
3103 +       return list;
3104 +}
3105 +/* }}} */
3106 +
3107 +/* {{{ inline append_encoded */
3108 +static inline void append_encoded(phpstr *buf, const char *key, size_t key_len, const char *val, size_t val_len)
3109 +{
3110 +       char *enc_str[2];
3111 +       int enc_len[2];
3112 +       
3113 +       enc_str[0] = php_url_encode(key, key_len, &enc_len[0]);
3114 +       enc_str[1] = php_url_encode(val, val_len, &enc_len[1]);
3115 +       
3116 +       phpstr_append(buf, enc_str[0], enc_len[0]);
3117 +       phpstr_appends(buf, "=");
3118 +       phpstr_append(buf, enc_str[1], enc_len[1]);
3119 +       phpstr_appends(buf, "; ");
3120 +       
3121 +       efree(enc_str[0]);
3122 +       efree(enc_str[1]);
3123 +}
3124 +/* }}} */
3125 +
3126 +/* {{{ void http_cookie_list_tostring(http_cookie_list *, char **, size_t *) */
3127 +PHP_HTTP_API void _http_cookie_list_tostring(http_cookie_list *list, char **str, size_t *len TSRMLS_DC)
3128 +{
3129 +       phpstr buf;
3130 +       zval **val;
3131 +       HashKey key = initHashKey(0);
3132 +       HashPosition pos;
3133 +       
3134 +       phpstr_init(&buf);
3135 +       
3136 +       FOREACH_HASH_KEYVAL(pos, &list->cookies, key, val) {
3137 +               if (key.type == HASH_KEY_IS_STRING && key.len) {
3138 +                       zval *tmp = http_zsep(IS_STRING, *val);
3139 +                       append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
3140 +                       zval_ptr_dtor(&tmp);
3141 +               }
3142 +       }
3143 +       
3144 +       if (list->domain && *list->domain) {
3145 +               phpstr_appendf(&buf, "domain=%s; ", list->domain);
3146 +       }
3147 +       if (list->path && *list->path) {
3148 +               phpstr_appendf(&buf, "path=%s; ", list->path);
3149 +       }
3150 +       if (list->expires) {
3151 +               char *date = http_date(list->expires);
3152 +               phpstr_appendf(&buf, "expires=%s; ", date);
3153 +               efree(date);
3154 +       }
3155 +       
3156 +       FOREACH_HASH_KEYVAL(pos, &list->extras, key, val) {
3157 +               if (key.type == HASH_KEY_IS_STRING && key.len) {
3158 +                       zval *tmp = http_zsep(IS_STRING, *val);
3159 +                       append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
3160 +               }
3161 +       }
3162 +       
3163 +       if (list->flags & HTTP_COOKIE_SECURE) {
3164 +               phpstr_appends(&buf, "secure; ");
3165 +       }
3166 +       if (list->flags & HTTP_COOKIE_HTTPONLY) {
3167 +               phpstr_appends(&buf, "httpOnly; ");
3168 +       }
3169 +       
3170 +       phpstr_fix(&buf);
3171 +       *str = PHPSTR_VAL(&buf);
3172 +       *len = PHPSTR_LEN(&buf);
3173 +}
3174 +/* }}} */
3175 +
3176 +/*
3177 + * Local variables:
3178 + * tab-width: 4
3179 + * c-basic-offset: 4
3180 + * End:
3181 + * vim600: noet sw=4 ts=4 fdm=marker
3182 + * vim<600: noet sw=4 ts=4
3183 + */
3184 --- /dev/null
3185 +++ b/ext/http/http_date_api.c
3186 @@ -0,0 +1,357 @@
3187 +/*
3188 +    +--------------------------------------------------------------------+
3189 +    | PECL :: http                                                       |
3190 +    +--------------------------------------------------------------------+
3191 +    | Redistribution and use in source and binary forms, with or without |
3192 +    | modification, are permitted provided that the conditions mentioned |
3193 +    | in the accompanying LICENSE file are met.                          |
3194 +    +--------------------------------------------------------------------+
3195 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
3196 +    +--------------------------------------------------------------------+
3197 +*/
3198 +
3199 +/* $Id: http_date_api.c 292841 2009-12-31 08:48:57Z mike $ */
3200 +
3201 +#include "php_http.h"
3202 +
3203 +#include "php_http_api.h"
3204 +#include "php_http_date_api.h"
3205 +
3206 +static inline int check_day(const char *day, size_t len);
3207 +static inline int check_month(const char *month);
3208 +static inline int check_tzone(const char *tzone);
3209 +static inline time_t parse_date(const char *month);
3210 +
3211 +/* {{{ day/month names */
3212 +static const char *days[] = {
3213 +       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
3214 +};
3215 +static const char *wkdays[] = {
3216 +       "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
3217 +};
3218 +static const char *weekdays[] = {
3219 +       "Monday", "Tuesday", "Wednesday",
3220 +       "Thursday", "Friday", "Saturday", "Sunday"
3221 +};
3222 +static const char *months[] = {
3223 +       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3224 +       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
3225 +};
3226 +enum assume_next {
3227 +       DATE_MDAY,
3228 +       DATE_YEAR,
3229 +       DATE_TIME
3230 +};
3231 +#define DS -60
3232 +static const struct time_zone {
3233 +       const char *name;
3234 +       const int offset;
3235 +} time_zones[] = {
3236 +    {"GMT", 0},     /* Greenwich Mean */
3237 +    {"UTC", 0},     /* Universal (Coordinated) */
3238 +    {"WET", 0},     /* Western European */
3239 +    {"BST", 0 DS}, /* British Summer */
3240 +    {"WAT", 60},    /* West Africa */
3241 +    {"AST", 240},   /* Atlantic Standard */
3242 +    {"ADT", 240 DS},/* Atlantic Daylight */
3243 +    {"EST", 300},   /* Eastern Standard */
3244 +    {"EDT", 300 DS},/* Eastern Daylight */
3245 +    {"CST", 360},   /* Central Standard */
3246 +    {"CDT", 360 DS},/* Central Daylight */
3247 +    {"MST", 420},   /* Mountain Standard */
3248 +    {"MDT", 420 DS},/* Mountain Daylight */
3249 +    {"PST", 480},   /* Pacific Standard */
3250 +    {"PDT", 480 DS},/* Pacific Daylight */
3251 +    {"YST", 540},   /* Yukon Standard */
3252 +    {"YDT", 540 DS},/* Yukon Daylight */
3253 +    {"HST", 600},   /* Hawaii Standard */
3254 +    {"HDT", 600 DS},/* Hawaii Daylight */
3255 +    {"CAT", 600},   /* Central Alaska */
3256 +    {"AHST", 600},  /* Alaska-Hawaii Standard */
3257 +    {"NT",  660},   /* Nome */
3258 +    {"IDLW", 720},  /* International Date Line West */
3259 +    {"CET", -60},   /* Central European */
3260 +    {"MET", -60},   /* Middle European */
3261 +    {"MEWT", -60},  /* Middle European Winter */
3262 +    {"MEST", -60 DS},/* Middle European Summer */
3263 +    {"CEST", -60 DS},/* Central European Summer */
3264 +    {"MESZ", -60 DS},/* Middle European Summer */
3265 +    {"FWT", -60},   /* French Winter */
3266 +    {"FST", -60 DS},/* French Summer */
3267 +    {"EET", -120},  /* Eastern Europe, USSR Zone 1 */
3268 +    {"WAST", -420}, /* West Australian Standard */
3269 +    {"WADT", -420 DS},/* West Australian Daylight */
3270 +    {"CCT", -480},  /* China Coast, USSR Zone 7 */
3271 +    {"JST", -540},  /* Japan Standard, USSR Zone 8 */
3272 +    {"EAST", -600}, /* Eastern Australian Standard */
3273 +    {"EADT", -600 DS},/* Eastern Australian Daylight */
3274 +    {"GST", -600},  /* Guam Standard, USSR Zone 9 */
3275 +    {"NZT", -720},  /* New Zealand */
3276 +    {"NZST", -720}, /* New Zealand Standard */
3277 +    {"NZDT", -720 DS},/* New Zealand Daylight */
3278 +    {"IDLE", -720}, /* International Date Line East */
3279 +};
3280 +/* }}} */
3281 +
3282 +/* {{{ Day/Month/TZ checks for http_parse_date()
3283 +       Originally by libcurl, Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al. */
3284 +static inline int check_day(const char *day, size_t len)
3285 +{
3286 +       int i;
3287 +       const char * const *check = (len > 3) ? &weekdays[0] : &wkdays[0];
3288 +       for (i = 0; i < 7; i++) {
3289 +           if (!strcmp(day, check[0])) {
3290 +               return i;
3291 +               }
3292 +               check++;
3293 +       }
3294 +       return -1;
3295 +}
3296 +
3297 +static inline int check_month(const char *month)
3298 +{
3299 +       int i;
3300 +       const char * const *check = &months[0];
3301 +       for (i = 0; i < 12; i++) {
3302 +               if (!strcmp(month, check[0])) {
3303 +                       return i;
3304 +               }
3305 +               check++;
3306 +       }
3307 +       return -1;
3308 +}
3309 +
3310 +/* return the time zone offset between GMT and the input one, in number
3311 +   of seconds or -1 if the timezone wasn't found/legal */
3312 +
3313 +static inline int check_tzone(const char *tzone)
3314 +{
3315 +       unsigned i;
3316 +       const struct time_zone *check = time_zones;
3317 +       for (i = 0; i < sizeof(time_zones) / sizeof(time_zones[0]); i++) {
3318 +               if (!strcmp(tzone, check->name)) {
3319 +                       return check->offset * 60;
3320 +               }
3321 +               check++;
3322 +       }
3323 +       return -1;
3324 +}
3325 +/* }}} */
3326 +
3327 +/* {{{ char *http_date(time_t) */
3328 +PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC)
3329 +{
3330 +       char *date = NULL;
3331 +       struct tm *gmtime = NULL, tmbuf;
3332 +
3333 +       memset(&tmbuf, 0, sizeof(tmbuf));
3334 +       if ((gmtime = php_gmtime_r(&t, &tmbuf))) {
3335 +               spprintf(&date, 0,
3336 +                       "%s, %02d %s %04d %02d:%02d:%02d GMT",
3337 +                       days[gmtime->tm_wday], gmtime->tm_mday,
3338 +                       months[gmtime->tm_mon], gmtime->tm_year + 1900,
3339 +                       gmtime->tm_hour, gmtime->tm_min, gmtime->tm_sec
3340 +               );
3341 +       }
3342 +
3343 +       return date;
3344 +}
3345 +/* }}} */
3346 +
3347 +/* {{{ time_t http_parse_date(char *) */
3348 +PHP_HTTP_API time_t _http_parse_date_ex(const char *date, zend_bool silent TSRMLS_DC)
3349 +{
3350 +       time_t t = parse_date(date);
3351 +       
3352 +       if (-1 == t && !silent) {
3353 +               http_error_ex(HE_NOTICE, HTTP_E_RUNTIME, "Could not parse date: %s", date);
3354 +       }
3355 +       
3356 +       return t;
3357 +}
3358 +/* }}} */
3359 +
3360 +/*     time_t parse_date(char *)
3361 +       Originally by libcurl, Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al. */
3362 +static inline time_t parse_date(const char *date)
3363 +{
3364 +       time_t t = 0;
3365 +       int tz_offset = -1, year = -1, month = -1, monthday = -1, weekday = -1,
3366 +               hours = -1, minutes = -1, seconds = -1;
3367 +       struct tm tm;
3368 +       enum assume_next dignext = DATE_MDAY;
3369 +       const char *indate = date;
3370 +
3371 +       int part = 0; /* max 6 parts */
3372 +
3373 +       while (*date && (part < 6)) {
3374 +               int found = 0;
3375 +
3376 +               while (*date && !HTTP_IS_CTYPE(alnum, *date)) {
3377 +                       date++;
3378 +               }
3379 +
3380 +               if (HTTP_IS_CTYPE(alpha, *date)) {
3381 +                       /* a name coming up */
3382 +                       char buf[32] = "";
3383 +                       size_t len;
3384 +                       sscanf(date, "%31[A-Za-z]", buf);
3385 +                       len = strlen(buf);
3386 +
3387 +                       if (weekday == -1) {
3388 +                               weekday = check_day(buf, len);
3389 +                               if (weekday != -1) {
3390 +                                       found = 1;
3391 +                               }
3392 +                       }
3393 +
3394 +                       if (!found && (month == -1)) {
3395 +                               month = check_month(buf);
3396 +                               if (month != -1) {
3397 +                                       found = 1;
3398 +                               }
3399 +                       }
3400 +
3401 +                       if (!found && (tz_offset == -1)) {
3402 +                               /* this just must be a time zone string */
3403 +                               tz_offset = check_tzone(buf);
3404 +                               if (tz_offset != -1) {
3405 +                                       found = 1;
3406 +                               }
3407 +                       }
3408 +
3409 +                       if (!found) {
3410 +                               return -1; /* bad string */
3411 +                       }
3412 +                       date += len;
3413 +               }
3414 +               else if (HTTP_IS_CTYPE(digit, *date)) {
3415 +                       /* a digit */
3416 +                       int val;
3417 +                       char *end;
3418 +                       if ((seconds == -1) &&
3419 +                               (3 == sscanf(date, "%02d:%02d:%02d", &hours, &minutes, &seconds))) {
3420 +                               /* time stamp! */
3421 +                               date += 8;
3422 +                               found = 1;
3423 +                       }
3424 +                       else {
3425 +                               val = (int) strtol(date, &end, 10);
3426 +
3427 +                               if ((tz_offset == -1) && ((end - date) == 4) && (val < 1300) &&
3428 +                                       (indate < date) && ((date[-1] == '+' || date[-1] == '-'))) {
3429 +                                       /* four digits and a value less than 1300 and it is preceeded with
3430 +                                       a plus or minus. This is a time zone indication. */
3431 +                                       found = 1;
3432 +                                       tz_offset = (val / 100 * 60 + val % 100) * 60;
3433 +
3434 +                                       /* the + and - prefix indicates the local time compared to GMT,
3435 +                                       this we need ther reversed math to get what we want */
3436 +                                       tz_offset = date[-1] == '+' ? -tz_offset : tz_offset;
3437 +                               }
3438 +
3439 +                               if (((end - date) == 8) && (year == -1) && (month == -1) && (monthday == -1)) {
3440 +                                       /* 8 digits, no year, month or day yet. This is YYYYMMDD */
3441 +                                       found = 1;
3442 +                                       year = val / 10000;
3443 +                                       month = (val % 10000) / 100 - 1; /* month is 0 - 11 */
3444 +                                       monthday = val % 100;
3445 +                               }
3446 +
3447 +                               if (!found && (dignext == DATE_MDAY) && (monthday == -1)) {
3448 +                                       if ((val > 0) && (val < 32)) {
3449 +                                               monthday = val;
3450 +                                               found = 1;
3451 +                                       }
3452 +                                       dignext = DATE_YEAR;
3453 +                               }
3454 +
3455 +                               if (!found && (dignext == DATE_YEAR) && (year == -1)) {
3456 +                                       year = val;
3457 +                                       found = 1;
3458 +                                       if (year < 1900) {
3459 +                                               year += year > 70 ? 1900 : 2000;
3460 +                                       }
3461 +                                       if(monthday == -1) {
3462 +                                               dignext = DATE_MDAY;
3463 +                                       }
3464 +                               }
3465 +
3466 +                               if (!found) {
3467 +                                       return -1;
3468 +                               }
3469 +
3470 +                               date = end;
3471 +                       }
3472 +               }
3473 +
3474 +               part++;
3475 +       }
3476 +
3477 +       if (-1 == seconds) {
3478 +               seconds = minutes = hours = 0; /* no time, make it zero */
3479 +       }
3480 +
3481 +       if ((-1 == monthday) || (-1 == month) || (-1 == year)) {
3482 +               /* lacks vital info, fail */
3483 +               return -1;
3484 +       }
3485 +
3486 +       if (sizeof(time_t) < 5) {
3487 +               /* 32 bit time_t can only hold dates to the beginning of 2038 */
3488 +               if (year > 2037) {
3489 +                       return 0x7fffffff;
3490 +               }
3491 +       }
3492 +
3493 +       tm.tm_sec = seconds;
3494 +       tm.tm_min = minutes;
3495 +       tm.tm_hour = hours;
3496 +       tm.tm_mday = monthday;
3497 +       tm.tm_mon = month;
3498 +       tm.tm_year = year - 1900;
3499 +       tm.tm_wday = 0;
3500 +       tm.tm_yday = 0;
3501 +       tm.tm_isdst = 0;
3502 +
3503 +       t = mktime(&tm);
3504 +
3505 +       /* time zone adjust */
3506 +       if (t != -1) {
3507 +               struct tm *gmt, keeptime2;
3508 +               long delta;
3509 +               time_t t2;
3510 +
3511 +               if((gmt = php_gmtime_r(&t, &keeptime2))) {
3512 +                       tm = *gmt; /* MSVC quirks */
3513 +               } else {
3514 +                       return -1; /* illegal date/time */
3515 +               }
3516 +
3517 +               t2 = mktime(&tm);
3518 +
3519 +               /* Add the time zone diff (between the given timezone and GMT) and the
3520 +               diff between the local time zone and GMT. */
3521 +               delta = (tz_offset != -1 ? tz_offset : 0) + (t - t2);
3522 +
3523 +               if((delta > 0) && (t + delta < t)) {
3524 +                       return -1; /* time_t overflow */
3525 +               }
3526 +
3527 +               t += delta;
3528 +       }
3529 +
3530 +       return t;
3531 +}
3532 +/* }}} */
3533 +
3534 +
3535 +/*
3536 + * Local variables:
3537 + * tab-width: 4
3538 + * c-basic-offset: 4
3539 + * End:
3540 + * vim600: sw=4 ts=4 fdm=marker
3541 + * vim<600: sw=4 ts=4
3542 + */
3543 +
3544 --- /dev/null
3545 +++ b/ext/http/http_deflatestream_object.c
3546 @@ -0,0 +1,312 @@
3547 +/*
3548 +    +--------------------------------------------------------------------+
3549 +    | PECL :: http                                                       |
3550 +    +--------------------------------------------------------------------+
3551 +    | Redistribution and use in source and binary forms, with or without |
3552 +    | modification, are permitted provided that the conditions mentioned |
3553 +    | in the accompanying LICENSE file are met.                          |
3554 +    +--------------------------------------------------------------------+
3555 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
3556 +    +--------------------------------------------------------------------+
3557 +*/
3558 +
3559 +/* $Id: http_deflatestream_object.c 300299 2010-06-09 06:23:16Z mike $ */
3560 +
3561 +#define HTTP_WANT_ZLIB
3562 +#include "php_http.h"
3563 +
3564 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_ZLIB)
3565 +
3566 +#include "php_http_api.h"
3567 +#include "php_http_encoding_api.h"
3568 +#include "php_http_exception_object.h"
3569 +#include "php_http_deflatestream_object.h"
3570 +
3571 +#define HTTP_BEGIN_ARGS(method, req_args)      HTTP_BEGIN_ARGS_EX(HttpDeflateStream, method, 0, req_args)
3572 +#define HTTP_EMPTY_ARGS(method)                                HTTP_EMPTY_ARGS_EX(HttpDeflateStream, method, 0)
3573 +#define HTTP_DEFLATE_ME(method, visibility)    PHP_ME(HttpDeflateStream, method, HTTP_ARGS(HttpDeflateStream, method), visibility)
3574 +
3575 +HTTP_BEGIN_ARGS(__construct, 0)
3576 +       HTTP_ARG_VAL(flags, 0)
3577 +HTTP_END_ARGS;
3578 +
3579 +HTTP_BEGIN_ARGS(factory, 0)
3580 +       HTTP_ARG_VAL(flags, 0)
3581 +       HTTP_ARG_VAL(class_name, 0)
3582 +HTTP_END_ARGS;
3583 +
3584 +HTTP_BEGIN_ARGS(update, 1)
3585 +       HTTP_ARG_VAL(data, 0)
3586 +HTTP_END_ARGS;
3587 +
3588 +HTTP_BEGIN_ARGS(flush, 0)
3589 +       HTTP_ARG_VAL(data, 0)
3590 +HTTP_END_ARGS;
3591 +
3592 +HTTP_BEGIN_ARGS(finish, 0)
3593 +       HTTP_ARG_VAL(data, 0)
3594 +HTTP_END_ARGS;
3595 +
3596 +#define THIS_CE http_deflatestream_object_ce
3597 +zend_class_entry *http_deflatestream_object_ce;
3598 +zend_function_entry http_deflatestream_object_fe[] = {
3599 +       HTTP_DEFLATE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
3600 +       HTTP_DEFLATE_ME(update, ZEND_ACC_PUBLIC)
3601 +       HTTP_DEFLATE_ME(flush, ZEND_ACC_PUBLIC)
3602 +       HTTP_DEFLATE_ME(finish, ZEND_ACC_PUBLIC)
3603 +       
3604 +       HTTP_DEFLATE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
3605 +       
3606 +       EMPTY_FUNCTION_ENTRY
3607 +};
3608 +static zend_object_handlers http_deflatestream_object_handlers;
3609 +
3610 +PHP_MINIT_FUNCTION(http_deflatestream_object)
3611 +{
3612 +       HTTP_REGISTER_CLASS_EX(HttpDeflateStream, http_deflatestream_object, NULL, 0);
3613 +       http_deflatestream_object_handlers.clone_obj = _http_deflatestream_object_clone_obj;
3614 +       
3615 +#ifndef WONKY
3616 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_GZIP")-1, HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC);
3617 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_ZLIB")-1, HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC);
3618 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_RAW")-1, HTTP_DEFLATE_TYPE_RAW TSRMLS_CC);
3619 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("LEVEL_DEF")-1, HTTP_DEFLATE_LEVEL_DEF TSRMLS_CC);
3620 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("LEVEL_MIN")-1, HTTP_DEFLATE_LEVEL_MIN TSRMLS_CC);
3621 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("LEVEL_MAX")-1, HTTP_DEFLATE_LEVEL_MAX TSRMLS_CC);
3622 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_DEF")-1, HTTP_DEFLATE_STRATEGY_DEF TSRMLS_CC);
3623 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_FILT")-1, HTTP_DEFLATE_STRATEGY_FILT TSRMLS_CC);
3624 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_HUFF")-1, HTTP_DEFLATE_STRATEGY_HUFF TSRMLS_CC);
3625 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_RLE")-1, HTTP_DEFLATE_STRATEGY_RLE TSRMLS_CC);
3626 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_FIXED")-1, HTTP_DEFLATE_STRATEGY_FIXED TSRMLS_CC);
3627 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_NONE")-1, HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC);
3628 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_SYNC")-1, HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC);
3629 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_FULL")-1, HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC);
3630 +#endif
3631 +       
3632 +       return SUCCESS;
3633 +}
3634 +
3635 +zend_object_value _http_deflatestream_object_new(zend_class_entry *ce TSRMLS_DC)
3636 +{
3637 +       return http_deflatestream_object_new_ex(ce, NULL, NULL);
3638 +}
3639 +
3640 +zend_object_value _http_deflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_deflatestream_object **ptr TSRMLS_DC)
3641 +{
3642 +       zend_object_value ov;
3643 +       http_deflatestream_object *o;
3644 +
3645 +       o = ecalloc(1, sizeof(http_deflatestream_object));
3646 +       o->zo.ce = ce;
3647 +       
3648 +       if (ptr) {
3649 +               *ptr = o;
3650 +       }
3651 +
3652 +       if (s) {
3653 +               o->stream = s;
3654 +       }
3655 +
3656 +       ALLOC_HASHTABLE(OBJ_PROP(o));
3657 +       zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
3658 +       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
3659 +
3660 +       ov.handle = putObject(http_deflatestream_object, o);
3661 +       ov.handlers = &http_deflatestream_object_handlers;
3662 +
3663 +       return ov;
3664 +}
3665 +
3666 +zend_object_value _http_deflatestream_object_clone_obj(zval *this_ptr TSRMLS_DC)
3667 +{
3668 +       http_encoding_stream *s;
3669 +       zend_object_value new_ov;
3670 +       http_deflatestream_object *new_obj = NULL;
3671 +       getObject(http_deflatestream_object, old_obj);
3672 +       
3673 +       s = ecalloc(1, sizeof(http_encoding_stream));
3674 +       s->flags = old_obj->stream->flags;
3675 +       deflateCopy(&s->stream, &old_obj->stream->stream);
3676 +       s->stream.opaque = phpstr_dup(s->stream.opaque);
3677 +       
3678 +       new_ov = http_deflatestream_object_new_ex(old_obj->zo.ce, s, &new_obj);
3679 +       zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
3680 +       
3681 +       return new_ov;
3682 +}
3683 +
3684 +void _http_deflatestream_object_free(zend_object *object TSRMLS_DC)
3685 +{
3686 +       http_deflatestream_object *o = (http_deflatestream_object *) object;
3687 +
3688 +       if (o->stream) {
3689 +               http_encoding_deflate_stream_free(&o->stream);
3690 +       }
3691 +       freeObject(o);
3692 +}
3693 +
3694 +/* {{{ proto void HttpDeflateStream::__construct([int flags = 0])
3695 +       Creates a new HttpDeflateStream object instance. */
3696 +PHP_METHOD(HttpDeflateStream, __construct)
3697 +{
3698 +       long flags = 0;
3699 +       
3700 +       SET_EH_THROW_HTTP();
3701 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags)) {
3702 +               getObject(http_deflatestream_object, obj);
3703 +               
3704 +               if (!obj->stream) {
3705 +                       obj->stream = http_encoding_deflate_stream_init(NULL, flags & 0x0fffffff);
3706 +               } else {
3707 +                       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "HttpDeflateStream cannot be initialized twice");
3708 +               }
3709 +       }
3710 +       SET_EH_NORMAL();
3711 +}
3712 +/* }}} */
3713 +
3714 +/* {{{ proto HttpDeflateStream HttpDeflateStream::factory([int flags[, string class = "HttpDeflateStream"]])
3715 +       Creates a new HttpDeflateStream object instance. */
3716 +PHP_METHOD(HttpDeflateStream, factory)
3717 +{
3718 +       long flags = 0;
3719 +       char *cn = NULL;
3720 +       int cl = 0;
3721 +       
3722 +       SET_EH_THROW_HTTP();
3723 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &flags, &cn, &cl)) {
3724 +               zend_object_value ov;
3725 +               http_encoding_stream *s = http_encoding_deflate_stream_init(NULL, flags & 0x0fffffff);
3726 +               
3727 +               if (SUCCESS == http_object_new(&ov, cn, cl, _http_deflatestream_object_new_ex, http_deflatestream_object_ce, s, NULL)) {
3728 +                       RETVAL_OBJVAL(ov, 0);
3729 +               }
3730 +       }
3731 +       SET_EH_NORMAL();
3732 +}
3733 +/* }}} */
3734 +
3735 +/* {{{ proto string HttpDeflateStream::update(string data)
3736 +       Passes more data through the deflate stream. */
3737 +PHP_METHOD(HttpDeflateStream, update)
3738 +{
3739 +       int data_len;
3740 +       size_t encoded_len = 0;
3741 +       char *data, *encoded = NULL;
3742 +       getObject(http_deflatestream_object, obj);
3743 +       
3744 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
3745 +               RETURN_FALSE;
3746 +       }
3747 +       
3748 +       if (!obj->stream && !(obj->stream = http_encoding_deflate_stream_init(NULL, 0))) {
3749 +               RETURN_FALSE;
3750 +       }
3751 +       
3752 +       if (SUCCESS == http_encoding_deflate_stream_update(obj->stream, data, data_len, &encoded, &encoded_len)) {
3753 +               RETURN_STRINGL(encoded, encoded_len, 0);
3754 +       } else {
3755 +               RETURN_FALSE;
3756 +       }
3757 +}
3758 +/* }}} */
3759 +
3760 +/* {{{ proto string HttpDeflateStream::flush([string data])
3761 +       Flushes the deflate stream. */
3762 +PHP_METHOD(HttpDeflateStream, flush)
3763 +{
3764 +       int data_len = 0;
3765 +       size_t updated_len = 0, encoded_len = 0;
3766 +       char *updated = NULL, *encoded = NULL, *data = NULL;
3767 +       getObject(http_deflatestream_object, obj);
3768 +       
3769 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) {
3770 +               RETURN_FALSE;
3771 +       }
3772 +       
3773 +       if (!obj->stream && !(obj->stream = http_encoding_deflate_stream_init(NULL, 0))) {
3774 +               RETURN_FALSE;
3775 +       }
3776 +       
3777 +       if (data_len) {
3778 +               if (SUCCESS != http_encoding_deflate_stream_update(obj->stream, data, data_len, &updated, &updated_len)) {
3779 +                       RETURN_FALSE;
3780 +               }
3781 +       }
3782 +       
3783 +       if (SUCCESS == http_encoding_deflate_stream_flush(obj->stream, &encoded, &encoded_len)) {
3784 +               if (updated_len) {
3785 +                       updated = erealloc(updated, updated_len + encoded_len + 1);
3786 +                       updated[updated_len + encoded_len] = '\0';
3787 +                       memcpy(updated + updated_len, encoded, encoded_len);
3788 +                       STR_FREE(encoded);
3789 +                       updated_len += encoded_len;
3790 +                       RETURN_STRINGL(updated, updated_len, 0);
3791 +               } else if (encoded) {
3792 +                       RETVAL_STRINGL(encoded, encoded_len, 0);
3793 +               } else {
3794 +                       RETVAL_NULL();
3795 +               }
3796 +       } else {
3797 +               RETVAL_FALSE;
3798 +       }
3799 +       STR_FREE(updated);
3800 +}
3801 +/* }}} */
3802 +
3803 +/* {{{ proto string HttpDeflateStream::finish([string data])
3804 +       Finalizes the deflate stream.  The deflate stream can be reused after finalizing. */
3805 +PHP_METHOD(HttpDeflateStream, finish)
3806 +{
3807 +       int data_len = 0;
3808 +       size_t updated_len = 0, encoded_len = 0;
3809 +       char *updated = NULL, *encoded = NULL, *data = NULL;
3810 +       getObject(http_deflatestream_object, obj);
3811 +       
3812 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) {
3813 +               RETURN_FALSE;
3814 +       }
3815 +       
3816 +       if (!obj->stream && !(obj->stream = http_encoding_deflate_stream_init(NULL, 0))) {
3817 +               RETURN_FALSE;
3818 +       }
3819 +       
3820 +       if (data_len) {
3821 +               if (SUCCESS != http_encoding_deflate_stream_update(obj->stream, data, data_len, &updated, &updated_len)) {
3822 +                       RETURN_FALSE;
3823 +               }
3824 +       }
3825 +       
3826 +       if (SUCCESS == http_encoding_deflate_stream_finish(obj->stream, &encoded, &encoded_len)) {
3827 +               if (updated_len) {
3828 +                       updated = erealloc(updated, updated_len + encoded_len + 1);
3829 +                       updated[updated_len + encoded_len] = '\0';
3830 +                       memcpy(updated + updated_len, encoded, encoded_len);
3831 +                       STR_FREE(encoded);
3832 +                       updated_len += encoded_len;
3833 +                       RETVAL_STRINGL(updated, updated_len, 0);
3834 +               } else {
3835 +                       STR_FREE(updated);
3836 +                       RETVAL_STRINGL(encoded, encoded_len, 0);
3837 +               }
3838 +       } else {
3839 +               STR_FREE(updated);
3840 +               RETVAL_FALSE;
3841 +       }
3842 +       
3843 +       http_encoding_deflate_stream_dtor(obj->stream);
3844 +       http_encoding_deflate_stream_init(obj->stream, obj->stream->flags);
3845 +}
3846 +/* }}} */
3847 +
3848 +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_ZLIB*/
3849 +
3850 +/*
3851 + * Local variables:
3852 + * tab-width: 4
3853 + * c-basic-offset: 4
3854 + * End:
3855 + * vim600: noet sw=4 ts=4 fdm=marker
3856 + * vim<600: noet sw=4 ts=4
3857 + */
3858 +
3859 --- /dev/null
3860 +++ b/ext/http/http_encoding_api.c
3861 @@ -0,0 +1,780 @@
3862 +/*
3863 +    +--------------------------------------------------------------------+
3864 +    | PECL :: http                                                       |
3865 +    +--------------------------------------------------------------------+
3866 +    | Redistribution and use in source and binary forms, with or without |
3867 +    | modification, are permitted provided that the conditions mentioned |
3868 +    | in the accompanying LICENSE file are met.                          |
3869 +    +--------------------------------------------------------------------+
3870 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
3871 +    +--------------------------------------------------------------------+
3872 +*/
3873 +
3874 +/* $Id: http_encoding_api.c 305668 2010-11-22 20:17:41Z iliaa $ */
3875 +
3876 +#define HTTP_WANT_ZLIB
3877 +#include "php_http.h"
3878 +
3879 +#include "php_http_api.h"
3880 +#include "php_http_encoding_api.h"
3881 +#include "php_http_send_api.h"
3882 +#include "php_http_headers_api.h"
3883 +
3884 +/* {{{ */
3885 +#ifdef HTTP_HAVE_ZLIB
3886 +PHP_MINIT_FUNCTION(http_encoding)
3887 +{
3888 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_DEF", HTTP_DEFLATE_LEVEL_DEF);
3889 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MIN", HTTP_DEFLATE_LEVEL_MIN);
3890 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MAX", HTTP_DEFLATE_LEVEL_MAX);
3891 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_ZLIB", HTTP_DEFLATE_TYPE_ZLIB);
3892 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_GZIP", HTTP_DEFLATE_TYPE_GZIP);
3893 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_RAW", HTTP_DEFLATE_TYPE_RAW);
3894 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_DEF", HTTP_DEFLATE_STRATEGY_DEF);
3895 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FILT", HTTP_DEFLATE_STRATEGY_FILT);
3896 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_HUFF", HTTP_DEFLATE_STRATEGY_HUFF);
3897 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_RLE", HTTP_DEFLATE_STRATEGY_RLE);
3898 +       HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FIXED", HTTP_DEFLATE_STRATEGY_FIXED);
3899 +       
3900 +       HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_NONE", HTTP_ENCODING_STREAM_FLUSH_NONE);
3901 +       HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_SYNC", HTTP_ENCODING_STREAM_FLUSH_SYNC);
3902 +       HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_FULL", HTTP_ENCODING_STREAM_FLUSH_FULL);
3903 +       
3904 +       return SUCCESS;
3905 +}
3906 +
3907 +PHP_RINIT_FUNCTION(http_encoding)
3908 +{
3909 +       if (HTTP_G->send.inflate.start_auto) {
3910 +               php_ob_set_internal_handler(_http_ob_inflatehandler, HTTP_INFLATE_BUFFER_SIZE, "http inflate", 0 TSRMLS_CC);
3911 +       }
3912 +       if (HTTP_G->send.deflate.start_auto) {
3913 +               php_ob_set_internal_handler(_http_ob_deflatehandler, HTTP_DEFLATE_BUFFER_SIZE, "http deflate", 0 TSRMLS_CC);
3914 +       }
3915 +       return SUCCESS;
3916 +}
3917 +
3918 +PHP_RSHUTDOWN_FUNCTION(http_encoding)
3919 +{
3920 +       if (HTTP_G->send.deflate.stream) {
3921 +               http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream);
3922 +       }
3923 +       if (HTTP_G->send.inflate.stream) {
3924 +               http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream);
3925 +       }
3926 +       return SUCCESS;
3927 +}
3928 +#endif
3929 +/* }}} */
3930 +
3931 +/* {{{ eol_match(char **, int *) */
3932 +static inline int eol_match(char **line, int *eol_len)
3933 +{
3934 +       char *ptr = *line;
3935 +       
3936 +       while (' ' == *ptr) ++ptr;
3937 +
3938 +       if (ptr == http_locate_eol(*line, eol_len)) {
3939 +               *line = ptr;
3940 +               return 1;
3941 +       } else {
3942 +               return 0;
3943 +       }
3944 +}
3945 +/* }}} */
3946 +                       
3947 +/* {{{ char *http_encoding_dechunk(char *, size_t, char **, size_t *) */
3948 +PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC)
3949 +{
3950 +       int eol_len = 0;
3951 +       char *n_ptr = NULL;
3952 +       const char *e_ptr = encoded;
3953 +       
3954 +       *decoded_len = 0;
3955 +       *decoded = ecalloc(1, encoded_len);
3956 +
3957 +       while ((encoded + encoded_len - e_ptr) > 0) {
3958 +               ulong chunk_len = 0, rest;
3959 +
3960 +               chunk_len = strtoul(e_ptr, &n_ptr, 16);
3961 +
3962 +               /* we could not read in chunk size */
3963 +               if (n_ptr == e_ptr) {
3964 +                       /*
3965 +                        * if this is the first turn and there doesn't seem to be a chunk
3966 +                        * size at the begining of the body, do not fail on apparently
3967 +                        * not encoded data and return a copy
3968 +                        */
3969 +                       if (e_ptr == encoded) {
3970 +                               http_error(HE_NOTICE, HTTP_E_ENCODING, "Data does not seem to be chunked encoded");
3971 +                               memcpy(*decoded, encoded, encoded_len);
3972 +                               *decoded_len = encoded_len;
3973 +                               return encoded + encoded_len;
3974 +                       } else {
3975 +                               efree(*decoded);
3976 +                               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len);
3977 +                               return NULL;
3978 +                       }
3979 +               }
3980 +               
3981 +               /* reached the end */
3982 +               if (!chunk_len) {
3983 +                       /* move over '0' chunked encoding terminator */
3984 +                       while (*e_ptr == '0') ++e_ptr;
3985 +                       break;
3986 +               }
3987 +
3988 +               /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
3989 +               if (*n_ptr && !eol_match(&n_ptr, &eol_len)) {
3990 +                       if (eol_len == 2) {
3991 +                               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr - encoded, encoded_len, *n_ptr, *(n_ptr + 1));
3992 +                       } else {
3993 +                               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr);
3994 +                       }
3995 +               }
3996 +               n_ptr += eol_len;
3997 +               
3998 +               /* chunk size pretends more data than we actually got, so it's probably a truncated message */
3999 +               if (chunk_len > (rest = encoded + encoded_len - n_ptr)) {
4000 +                       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len, rest, n_ptr - encoded, encoded_len);
4001 +                       chunk_len = rest;
4002 +               }
4003 +
4004 +               /* copy the chunk */
4005 +               memcpy(*decoded + *decoded_len, n_ptr, chunk_len);
4006 +               *decoded_len += chunk_len;
4007 +               
4008 +               if (chunk_len == rest) {
4009 +                       e_ptr = n_ptr + chunk_len;
4010 +                       break;
4011 +               } else {
4012 +                       /* advance to next chunk */
4013 +                       e_ptr = n_ptr + chunk_len + eol_len;
4014 +               }
4015 +       }
4016 +
4017 +       return e_ptr;
4018 +}
4019 +/* }}} */
4020 +
4021 +/* {{{ int http_encoding_response_start(size_t) */
4022 +PHP_HTTP_API int _http_encoding_response_start(size_t content_length, zend_bool ignore_http_ohandler TSRMLS_DC)
4023 +{
4024 +       int response = HTTP_G->send.deflate.response;
4025 +       int ohandler = php_ob_handler_used("ob_gzhandler" TSRMLS_CC) || php_ob_handler_used("zlib output compression" TSRMLS_CC);
4026 +       
4027 +       if (!ohandler && !ignore_http_ohandler) {
4028 +               ohandler = php_ob_handler_used("ob_deflatehandler" TSRMLS_CC) || php_ob_handler_used("http deflate" TSRMLS_CC);
4029 +       }
4030 +       
4031 +       if (response && !ohandler) {
4032 +#ifdef HTTP_HAVE_ZLIB
4033 +               HashTable *selected;
4034 +               zval zsupported;
4035 +               
4036 +               HTTP_G->send.deflate.encoding = 0;
4037 +               
4038 +               INIT_PZVAL(&zsupported);
4039 +               array_init(&zsupported);
4040 +               add_next_index_stringl(&zsupported, "gzip", lenof("gzip"), 1);
4041 +               add_next_index_stringl(&zsupported, "x-gzip", lenof("x-gzip"), 1);
4042 +               add_next_index_stringl(&zsupported, "deflate", lenof("deflate"), 1);
4043 +               
4044 +               if ((selected = http_negotiate_encoding(&zsupported))) {
4045 +                       STATUS hs = FAILURE;
4046 +                       char *encoding = NULL;
4047 +                       ulong idx;
4048 +                       
4049 +                       if (HASH_KEY_IS_STRING == zend_hash_get_current_key(selected, &encoding, &idx, 0) && encoding) {
4050 +                               if (!strcmp(encoding, "gzip") || !strcmp(encoding, "x-gzip")) {
4051 +                                       if (SUCCESS == (hs = http_send_header_string("Content-Encoding: gzip"))) {
4052 +                                               HTTP_G->send.deflate.encoding = HTTP_ENCODING_GZIP;
4053 +                                       }
4054 +                               } else if (!strcmp(encoding, "deflate")) {
4055 +                                       if (SUCCESS == (hs = http_send_header_string("Content-Encoding: deflate"))) {
4056 +                                               HTTP_G->send.deflate.encoding = HTTP_ENCODING_DEFLATE;
4057 +                                       }
4058 +                               }
4059 +                               if (SUCCESS == hs) {
4060 +                                       http_send_header_string("Vary: Accept-Encoding");
4061 +                               }
4062 +                       }
4063 +                       
4064 +                       zend_hash_destroy(selected);
4065 +                       FREE_HASHTABLE(selected);
4066 +               }
4067 +               
4068 +               zval_dtor(&zsupported);
4069 +#else
4070 +               HTTP_G->send.deflate.encoding = 0;
4071 +               php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC);
4072 +#endif /* HTTP_HAVE_ZLIB */
4073 +       } else if (content_length && !ohandler) {
4074 +               /* emit a content-length header */
4075 +               phpstr header;
4076 +
4077 +               phpstr_init(&header);
4078 +               phpstr_appendf(&header, "Content-Length: %zu", content_length);
4079 +               phpstr_fix(&header);
4080 +               http_send_header_string_ex(PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1);
4081 +               phpstr_dtor(&header);
4082 +       } else {
4083 +               HTTP_G->send.deflate.encoding = 0;
4084 +       }
4085 +       
4086 +       return HTTP_G->send.deflate.encoding;
4087 +}
4088 +/* }}} */
4089 +
4090 +#ifdef HTTP_HAVE_ZLIB
4091 +
4092 +/* {{{ inline int http_inflate_rounds */
4093 +static inline int http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
4094 +{
4095 +       int status = 0, round = 0;
4096 +       phpstr buffer;
4097 +       
4098 +       *buf = NULL;
4099 +       *len = 0;
4100 +       
4101 +       phpstr_init_ex(&buffer, Z->avail_in, PHPSTR_INIT_PREALLOC);
4102 +       
4103 +       do {
4104 +               if (PHPSTR_NOMEM == phpstr_resize_ex(&buffer, buffer.size, 0, 1)) {
4105 +                       status = Z_MEM_ERROR;
4106 +               } else {
4107 +                       Z->avail_out = buffer.free;
4108 +                       Z->next_out = (Bytef *) buffer.data + buffer.used;
4109 +#if 0
4110 +                       fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
4111 +#endif
4112 +                       status = inflate(Z, flush);
4113 +                       
4114 +                       buffer.used += buffer.free - Z->avail_out;
4115 +                       buffer.free = Z->avail_out;
4116 +#if 0
4117 +                       fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
4118 +#endif
4119 +                       HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
4120 +               }
4121 +       } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < HTTP_INFLATE_ROUNDS);
4122 +       
4123 +       if (status == Z_OK || status == Z_STREAM_END) {
4124 +               phpstr_shrink(&buffer);
4125 +               phpstr_fix(&buffer);
4126 +               *buf = buffer.data;
4127 +               *len = buffer.used;
4128 +       } else {
4129 +               phpstr_dtor(&buffer);
4130 +       }
4131 +       
4132 +       return status;
4133 +}
4134 +/* }}} */
4135 +
4136 +/* {{{ STATUS http_encoding_deflate(int, char *, size_t, char **, size_t *) */
4137 +PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4138 +{
4139 +       int status, level, wbits, strategy;
4140 +       z_stream Z;
4141 +       
4142 +       HTTP_DEFLATE_LEVEL_SET(flags, level);
4143 +       HTTP_DEFLATE_WBITS_SET(flags, wbits);
4144 +       HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
4145 +       
4146 +       memset(&Z, 0, sizeof(z_stream));
4147 +       *encoded = NULL;
4148 +       *encoded_len = 0;
4149 +       
4150 +       status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy);
4151 +       if (Z_OK == status) {
4152 +               *encoded_len = HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
4153 +               *encoded = emalloc_rel(*encoded_len);
4154 +               
4155 +               Z.next_in = (Bytef *) data;
4156 +               Z.next_out = (Bytef *) *encoded;
4157 +               Z.avail_in = data_len;
4158 +               Z.avail_out = *encoded_len;
4159 +               
4160 +               status = deflate(&Z, Z_FINISH);
4161 +               deflateEnd(&Z);
4162 +               
4163 +               if (Z_STREAM_END == status) {
4164 +                       /* size buffer down to actual length */
4165 +                       *encoded = erealloc_rel(*encoded, Z.total_out + 1);
4166 +                       (*encoded)[*encoded_len = Z.total_out] = '\0';
4167 +                       return SUCCESS;
4168 +               } else {
4169 +                       STR_SET(*encoded, NULL);
4170 +                       *encoded_len = 0;
4171 +               }
4172 +       }
4173 +       
4174 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not deflate data: %s", zError(status));
4175 +       return FAILURE;
4176 +}
4177 +/* }}} */
4178 +
4179 +/* {{{ STATUS http_encoding_inflate(char *, size_t, char **, size_t) */
4180 +PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4181 +{
4182 +       z_stream Z;
4183 +       int status, wbits = HTTP_WINDOW_BITS_ANY;
4184 +       
4185 +       memset(&Z, 0, sizeof(z_stream));
4186 +       
4187 +retry_raw_inflate:
4188 +       status = inflateInit2(&Z, wbits);
4189 +       if (Z_OK == status) {
4190 +               Z.next_in = (Bytef *) data;
4191 +               Z.avail_in = data_len;
4192 +               
4193 +               switch (status = http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) {
4194 +                       case Z_STREAM_END:
4195 +                               inflateEnd(&Z);
4196 +                               return SUCCESS;
4197 +
4198 +                       case Z_OK:
4199 +                               status = Z_DATA_ERROR;
4200 +                               break;
4201 +                       
4202 +                       case Z_DATA_ERROR:
4203 +                               /* raw deflated data? */
4204 +                               if (HTTP_WINDOW_BITS_ANY == wbits) {
4205 +                                       inflateEnd(&Z);
4206 +                                       wbits = HTTP_WINDOW_BITS_RAW;
4207 +                                       goto retry_raw_inflate;
4208 +                               }
4209 +               }
4210 +               inflateEnd(&Z);
4211 +       }
4212 +       
4213 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not inflate data: %s", zError(status));
4214 +       return FAILURE;
4215 +}
4216 +/* }}} */
4217 +
4218 +/* {{{ http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *, int) */
4219 +PHP_HTTP_API http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4220 +{
4221 +       int status, level, wbits, strategy, free_stream;
4222 +       
4223 +       if ((free_stream = !s)) {
4224 +               s = pemalloc_rel(sizeof(http_encoding_stream), (flags & HTTP_ENCODING_STREAM_PERSISTENT));
4225 +       }
4226 +       memset(s, 0, sizeof(http_encoding_stream));
4227 +       s->flags = flags;
4228 +       
4229 +       HTTP_DEFLATE_LEVEL_SET(flags, level);
4230 +       HTTP_DEFLATE_WBITS_SET(flags, wbits);
4231 +       HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
4232 +       
4233 +       if (Z_OK == (status = deflateInit2(&s->stream, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) {
4234 +               int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0;
4235 +               
4236 +               if ((s->stream.opaque = phpstr_init_ex(NULL, HTTP_DEFLATE_BUFFER_SIZE, p))) {
4237 +                       return s;
4238 +               }
4239 +               deflateEnd(&s->stream);
4240 +               status = Z_MEM_ERROR;
4241 +       }
4242 +       
4243 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize deflate encoding stream: %s", zError(status));
4244 +       if (free_stream) {
4245 +               efree(s);
4246 +       }
4247 +       return NULL;
4248 +}
4249 +/* }}} */
4250 +
4251 +/* {{{ http_encoding_stream *http_encoding_inflate_stream_init(http_encoding_stream *, int) */
4252 +PHP_HTTP_API http_encoding_stream *_http_encoding_inflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4253 +{
4254 +       int status, wbits, free_stream;
4255 +       
4256 +       if ((free_stream = !s)) {
4257 +               s = pemalloc_rel(sizeof(http_encoding_stream), (flags & HTTP_ENCODING_STREAM_PERSISTENT));
4258 +       }
4259 +       memset(s, 0, sizeof(http_encoding_stream));
4260 +       s->flags = flags;
4261 +       
4262 +       HTTP_INFLATE_WBITS_SET(flags, wbits);
4263 +       
4264 +       if (Z_OK == (status = inflateInit2(&s->stream, wbits))) {
4265 +               int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0;
4266 +               
4267 +               if ((s->stream.opaque = phpstr_init_ex(NULL, HTTP_DEFLATE_BUFFER_SIZE, p))) {
4268 +                       return s;
4269 +               }
4270 +               inflateEnd(&s->stream);
4271 +               status = Z_MEM_ERROR;
4272 +       }
4273 +       
4274 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize inflate stream: %s", zError(status));
4275 +       if (free_stream) {
4276 +               efree(s);
4277 +       }
4278 +       return NULL;
4279 +}
4280 +/* }}} */
4281 +
4282 +/* {{{ STATUS http_encoding_deflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */
4283 +PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4284 +{
4285 +       int status;
4286 +       
4287 +       /* append input to our buffer */
4288 +       phpstr_append(PHPSTR(s->stream.opaque), data, data_len);
4289 +       
4290 +       s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
4291 +       s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
4292 +       
4293 +       /* deflate */
4294 +       *encoded_len = HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
4295 +       *encoded = emalloc_rel(*encoded_len);
4296 +       s->stream.avail_out = *encoded_len;
4297 +       s->stream.next_out = (Bytef *) *encoded;
4298 +       
4299 +       switch (status = deflate(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) {
4300 +               case Z_OK:
4301 +               case Z_STREAM_END:
4302 +                       /* cut processed chunk off the buffer */
4303 +                       if (s->stream.avail_in) {
4304 +                               phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
4305 +                       } else {
4306 +                               phpstr_reset(PHPSTR(s->stream.opaque));
4307 +                       }
4308 +                       
4309 +                       /* size buffer down to actual size */
4310 +                       *encoded_len -= s->stream.avail_out;
4311 +                       *encoded = erealloc_rel(*encoded, *encoded_len + 1);
4312 +                       (*encoded)[*encoded_len] = '\0';
4313 +                       return SUCCESS;
4314 +       }
4315 +       
4316 +       STR_SET(*encoded, NULL);
4317 +       *encoded_len = 0;
4318 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update deflate stream: %s", zError(status));
4319 +       return FAILURE;
4320 +}
4321 +/* }}} */
4322 +
4323 +/* {{{ STATUS http_encoding_inflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */
4324 +PHP_HTTP_API STATUS _http_encoding_inflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4325 +{
4326 +       int status;
4327 +       
4328 +       /* append input to buffer */
4329 +       phpstr_append(PHPSTR(s->stream.opaque), data, data_len);
4330 +       
4331 +retry_raw_inflate:
4332 +       s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
4333 +       s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
4334 +       
4335 +       switch (status = http_inflate_rounds(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) {
4336 +               case Z_OK:
4337 +               case Z_STREAM_END:
4338 +                       /* cut off */
4339 +                       if (s->stream.avail_in) {
4340 +                               phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
4341 +                       } else {
4342 +                               phpstr_reset(PHPSTR(s->stream.opaque));
4343 +                       }
4344 +                       return SUCCESS;
4345 +               
4346 +               case Z_DATA_ERROR:
4347 +                       /* raw deflated data ? */
4348 +                       if (!(s->flags & HTTP_INFLATE_TYPE_RAW) && !s->stream.total_out) {
4349 +                               inflateEnd(&s->stream);
4350 +                               s->flags |= HTTP_INFLATE_TYPE_RAW;
4351 +                               inflateInit2(&s->stream, HTTP_WINDOW_BITS_RAW);
4352 +                               goto retry_raw_inflate;
4353 +                       }
4354 +       }
4355 +       
4356 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update inflate stream: %s", zError(status));
4357 +       return FAILURE;
4358 +}
4359 +/* }}} */
4360 +
4361 +/* {{{ STATUS http_encoding_deflate_stream_flush(http_encoding_stream *, char **, size_t *) */
4362 +PHP_HTTP_API STATUS _http_encoding_deflate_stream_flush(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4363 +{
4364 +       int status;
4365 +       
4366 +       *encoded_len = HTTP_DEFLATE_BUFFER_SIZE;
4367 +       *encoded = emalloc_rel(*encoded_len);
4368 +       
4369 +       s->stream.avail_in = 0;
4370 +       s->stream.next_in = NULL;
4371 +       s->stream.avail_out = *encoded_len;
4372 +       s->stream.next_out = (Bytef *) *encoded;
4373 +       
4374 +       switch (status = deflate(&s->stream, Z_FULL_FLUSH)) {
4375 +               case Z_OK:
4376 +               case Z_STREAM_END:
4377 +                       *encoded_len = HTTP_DEFLATE_BUFFER_SIZE - s->stream.avail_out;
4378 +                       *encoded = erealloc_rel(*encoded, *encoded_len + 1);
4379 +                       (*encoded)[*encoded_len] = '\0';
4380 +                       return SUCCESS;
4381 +       }
4382 +       
4383 +       STR_SET(*encoded, NULL);
4384 +       *encoded_len = 0;
4385 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to flush deflate stream: %s", zError(status));
4386 +       return FAILURE;
4387 +}
4388 +/* }}} */
4389 +
4390 +/* {{{ STATUS http_encoding_inflate_straem_flush(http_encoding_stream *, char **, size_t *) */
4391 +PHP_HTTP_API STATUS _http_encoding_inflate_stream_flush(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4392 +{
4393 +       /* noop */
4394 +       *decoded = estrndup("", *decoded_len = 0);
4395 +       return SUCCESS;
4396 +}
4397 +/* }}} */
4398 +
4399 +/* {{{ STATUS http_encoding_deflate_stream_finish(http_encoding_stream *, char **, size_t *) */
4400 +PHP_HTTP_API STATUS _http_encoding_deflate_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4401 +{
4402 +       int status;
4403 +       
4404 +       *encoded_len = HTTP_DEFLATE_BUFFER_SIZE;
4405 +       *encoded = emalloc_rel(*encoded_len);
4406 +       
4407 +       /* deflate remaining input */
4408 +       s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
4409 +       s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
4410 +       
4411 +       s->stream.avail_out = *encoded_len;
4412 +       s->stream.next_out = (Bytef *) *encoded;
4413 +       
4414 +       do {
4415 +               status = deflate(&s->stream, Z_FINISH);
4416 +       } while (Z_OK == status);
4417 +       
4418 +       if (Z_STREAM_END == status) {
4419 +               /* cut processed intp off */
4420 +               phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
4421 +               
4422 +               /* size down */
4423 +               *encoded_len -= s->stream.avail_out;
4424 +               *encoded = erealloc_rel(*encoded, *encoded_len + 1);
4425 +               (*encoded)[*encoded_len] = '\0';
4426 +               return SUCCESS;
4427 +       }
4428 +       
4429 +       STR_SET(*encoded, NULL);
4430 +       *encoded_len = 0;
4431 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish deflate stream: %s", zError(status));
4432 +       return FAILURE;
4433 +}
4434 +/* }}} */
4435 +
4436 +/* {{{ STATUS http_encoding_inflate_stream_finish(http_encoding_stream *, char **, size_t *) */
4437 +PHP_HTTP_API STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
4438 +{
4439 +       int status;
4440 +       
4441 +       if (!PHPSTR_LEN(s->stream.opaque)) {
4442 +               *decoded = NULL;
4443 +               *decoded_len = 0;
4444 +               return SUCCESS;
4445 +       }
4446 +       
4447 +       *decoded_len = (PHPSTR_LEN(s->stream.opaque) + 1) * HTTP_INFLATE_ROUNDS;
4448 +       *decoded = emalloc_rel(*decoded_len);
4449 +       
4450 +       /* inflate remaining input */
4451 +       s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque);
4452 +       s->stream.avail_in = PHPSTR_LEN(s->stream.opaque);
4453 +       
4454 +       s->stream.avail_out = *decoded_len;
4455 +       s->stream.next_out = (Bytef *) *decoded;
4456 +       
4457 +       if (Z_STREAM_END == (status = inflate(&s->stream, Z_FINISH))) {
4458 +               /* cut processed input off */
4459 +               phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in);
4460 +               
4461 +               /* size down */
4462 +               *decoded_len -= s->stream.avail_out;
4463 +               *decoded = erealloc_rel(*decoded, *decoded_len + 1);
4464 +               (*decoded)[*decoded_len] = '\0';
4465 +               return SUCCESS;
4466 +       }
4467 +       
4468 +       STR_SET(*decoded, NULL);
4469 +       *decoded_len = 0;
4470 +       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish inflate stream: %s", zError(status));
4471 +       return FAILURE;
4472 +}
4473 +/* }}} */
4474 +
4475 +/* {{{ void http_encoding_deflate_stream_dtor(http_encoding_stream *) */
4476 +PHP_HTTP_API void _http_encoding_deflate_stream_dtor(http_encoding_stream *s TSRMLS_DC)
4477 +{
4478 +       if (s) {
4479 +               if (s->stream.opaque) {
4480 +                       phpstr_free((phpstr **) &s->stream.opaque);
4481 +               }
4482 +               deflateEnd(&s->stream);
4483 +       }
4484 +}
4485 +/* }}} */
4486 +
4487 +/* {{{ void http_encoding_inflate_stream_dtor(http_encoding_stream *) */
4488 +PHP_HTTP_API void _http_encoding_inflate_stream_dtor(http_encoding_stream *s TSRMLS_DC)
4489 +{
4490 +       if (s) {
4491 +               if (s->stream.opaque) {
4492 +                       phpstr_free((phpstr **) &s->stream.opaque);
4493 +               }
4494 +               inflateEnd(&s->stream);
4495 +       }
4496 +}
4497 +/* }}} */
4498 +
4499 +/* {{{ void http_encoding_deflate_stream_free(http_encoding_stream **) */
4500 +PHP_HTTP_API void _http_encoding_deflate_stream_free(http_encoding_stream **s TSRMLS_DC)
4501 +{
4502 +       if (s) {
4503 +               http_encoding_deflate_stream_dtor(*s);
4504 +               if (*s) {
4505 +                       pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT);
4506 +               }
4507 +               *s = NULL;
4508 +       }
4509 +}
4510 +/* }}} */
4511 +
4512 +/* {{{ void http_encoding_inflate_stream_free(http_encoding_stream **) */
4513 +PHP_HTTP_API void _http_encoding_inflate_stream_free(http_encoding_stream **s TSRMLS_DC)
4514 +{
4515 +       if (s) {
4516 +               http_encoding_inflate_stream_dtor(*s);
4517 +               if (*s) {
4518 +                       pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT);
4519 +               }
4520 +               *s = NULL;
4521 +       }
4522 +}
4523 +/* }}} */
4524 +
4525 +/* {{{ void http_ob_deflatehandler(char *, uint, char **, uint *, int) */
4526 +void _http_ob_deflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
4527 +{
4528 +       int encoding;
4529 +       
4530 +       *handled_output = NULL;
4531 +       *handled_output_len = 0;
4532 +       
4533 +       if (mode & PHP_OUTPUT_HANDLER_START) {
4534 +               int flags;
4535 +               
4536 +               if (HTTP_G->send.deflate.stream) {
4537 +                       zend_error(E_ERROR, "ob_deflatehandler() can only be used once");
4538 +                       return;
4539 +               }
4540 +               
4541 +               HTTP_G->send.deflate.response = 1;
4542 +               encoding = http_encoding_response_start(0, 1);
4543 +               HTTP_G->send.deflate.response = 0;
4544 +               
4545 +               switch (encoding) {
4546 +                       case HTTP_ENCODING_GZIP:
4547 +                               flags = HTTP_DEFLATE_TYPE_GZIP;
4548 +                               break;
4549 +                       
4550 +                       case HTTP_ENCODING_DEFLATE:
4551 +                               flags = HTTP_DEFLATE_TYPE_ZLIB;
4552 +                               break;
4553 +                       
4554 +                       default:
4555 +                               goto deflate_passthru_plain;
4556 +               }
4557 +               
4558 +               flags |= (HTTP_G->send.deflate.start_flags &~ 0xf0);
4559 +               HTTP_G->send.deflate.stream = http_encoding_deflate_stream_init(NULL, flags);
4560 +       }
4561 +       
4562 +       if (HTTP_G->send.deflate.stream) {
4563 +               if (output_len) {
4564 +                       size_t tmp_len;
4565 +                       
4566 +                       http_encoding_deflate_stream_update((http_encoding_stream *) HTTP_G->send.deflate.stream, output, output_len, handled_output, &tmp_len);
4567 +                       *handled_output_len = tmp_len;
4568 +               }
4569 +               
4570 +               if (mode & PHP_OUTPUT_HANDLER_END) {
4571 +                       char *remaining = NULL;
4572 +                       size_t remaining_len = 0;
4573 +                       
4574 +                       http_encoding_deflate_stream_finish((http_encoding_stream *) HTTP_G->send.deflate.stream, &remaining, &remaining_len);
4575 +                       http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream);
4576 +                       if (remaining) {
4577 +                               *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1);
4578 +                               memcpy(*handled_output + *handled_output_len, remaining, remaining_len);
4579 +                               (*handled_output)[*handled_output_len += remaining_len] = '\0';
4580 +                               efree(remaining);
4581 +                       }
4582 +               }
4583 +       } else {
4584 +deflate_passthru_plain:
4585 +               *handled_output = estrndup(output, *handled_output_len = output_len);
4586 +       }
4587 +}
4588 +/* }}} */
4589 +
4590 +/* {{{ void http_ob_inflatehandler(char *, uint, char **, uint *, int) */
4591 +void _http_ob_inflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
4592 +{
4593 +       *handled_output = NULL;
4594 +       *handled_output_len = 0;
4595 +       
4596 +       if (mode & PHP_OUTPUT_HANDLER_START) {
4597 +               if (HTTP_G->send.inflate.stream) {
4598 +                       zend_error(E_ERROR, "ob_inflatehandler() can only be used once");
4599 +                       return;
4600 +               }
4601 +               HTTP_G->send.inflate.stream = http_encoding_inflate_stream_init(NULL, (HTTP_G->send.inflate.start_flags &~ 0xf0));
4602 +       }
4603 +       
4604 +       if (HTTP_G->send.inflate.stream) {
4605 +               if (output_len) {
4606 +                       size_t tmp_len;
4607 +                       
4608 +                       http_encoding_inflate_stream_update((http_encoding_stream *) HTTP_G->send.inflate.stream, output, output_len, handled_output, &tmp_len);
4609 +                       *handled_output_len = tmp_len;
4610 +               }
4611 +               
4612 +               if (mode & PHP_OUTPUT_HANDLER_END) {
4613 +                       char *remaining = NULL;
4614 +                       size_t remaining_len = 0;
4615 +                       
4616 +                       http_encoding_inflate_stream_finish((http_encoding_stream *) HTTP_G->send.inflate.stream, &remaining, &remaining_len);
4617 +                       http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream);
4618 +                       if (remaining) {
4619 +                               *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1);
4620 +                               memcpy(*handled_output + *handled_output_len, remaining, remaining_len);
4621 +                               (*handled_output)[*handled_output_len += remaining_len] = '\0';
4622 +                               efree(remaining);
4623 +                       }
4624 +               }
4625 +       } else {
4626 +               *handled_output = estrndup(output, *handled_output_len = output_len);
4627 +       }
4628 +}
4629 +/* }}} */
4630 +
4631 +#endif /* HTTP_HAVE_ZLIB */
4632 +
4633 +/*
4634 + * Local variables:
4635 + * tab-width: 4
4636 + * c-basic-offset: 4
4637 + * End:
4638 + * vim600: noet sw=4 ts=4 fdm=marker
4639 + * vim<600: noet sw=4 ts=4
4640 + */
4641 +
4642 --- /dev/null
4643 +++ b/ext/http/http_exception_object.c
4644 @@ -0,0 +1,186 @@
4645 +/*
4646 +    +--------------------------------------------------------------------+
4647 +    | PECL :: http                                                       |
4648 +    +--------------------------------------------------------------------+
4649 +    | Redistribution and use in source and binary forms, with or without |
4650 +    | modification, are permitted provided that the conditions mentioned |
4651 +    | in the accompanying LICENSE file are met.                          |
4652 +    +--------------------------------------------------------------------+
4653 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
4654 +    +--------------------------------------------------------------------+
4655 +*/
4656 +
4657 +/* $Id: http_exception_object.c 292841 2009-12-31 08:48:57Z mike $ */
4658 +
4659 +#include "php_http.h"
4660 +
4661 +#ifdef ZEND_ENGINE_2
4662 +
4663 +#ifndef HTTP_DBG_EXCEPTIONS
4664 +#      define HTTP_DBG_EXCEPTIONS 0
4665 +#endif
4666 +
4667 +#include "zend_interfaces.h"
4668 +#include "zend_exceptions.h"
4669 +#include "php_http_exception_object.h"
4670 +
4671 +zend_class_entry *http_exception_object_ce;
4672 +zend_class_entry *HTTP_EX_CE(runtime);
4673 +zend_class_entry *HTTP_EX_CE(header);
4674 +zend_class_entry *HTTP_EX_CE(malformed_headers);
4675 +zend_class_entry *HTTP_EX_CE(request_method);
4676 +zend_class_entry *HTTP_EX_CE(message_type);
4677 +zend_class_entry *HTTP_EX_CE(invalid_param);
4678 +zend_class_entry *HTTP_EX_CE(encoding);
4679 +zend_class_entry *HTTP_EX_CE(request);
4680 +zend_class_entry *HTTP_EX_CE(request_pool);
4681 +zend_class_entry *HTTP_EX_CE(socket);
4682 +zend_class_entry *HTTP_EX_CE(response);
4683 +zend_class_entry *HTTP_EX_CE(url);
4684 +zend_class_entry *HTTP_EX_CE(querystring);
4685 +
4686 +#define HTTP_EMPTY_ARGS(method)                                        HTTP_EMPTY_ARGS_EX(HttpException, method, 0)
4687 +#define HTTP_EXCEPTION_ME(method, visibility)  PHP_ME(HttpException, method, HTTP_ARGS(HttpException, method), visibility)
4688 +
4689 +HTTP_EMPTY_ARGS(__toString);
4690 +
4691 +zend_function_entry http_exception_object_fe[] = {
4692 +       HTTP_EXCEPTION_ME(__toString, ZEND_ACC_PUBLIC)
4693 +       
4694 +       EMPTY_FUNCTION_ENTRY
4695 +};
4696 +
4697 +#if HTTP_DBG_EXCEPTIONS
4698 +static void http_exception_hook(zval *ex TSRMLS_DC)
4699 +{
4700 +       if (ex) {
4701 +               zval *m = zend_read_property(Z_OBJCE_P(ex), ex, "message", lenof("message"), 0 TSRMLS_CC);
4702 +               fprintf(stderr, "*** Threw exception '%s'\n", Z_STRVAL_P(m));
4703 +       } else {
4704 +               fprintf(stderr, "*** Threw NULL exception\n");
4705 +       }
4706 +}
4707 +#endif
4708 +
4709 +PHP_MINIT_FUNCTION(http_exception_object)
4710 +{
4711 +       HTTP_REGISTER_CLASS(HttpException, http_exception_object, ZEND_EXCEPTION_GET_DEFAULT(), 0);
4712 +       
4713 +       zend_declare_property_null(HTTP_EX_DEF_CE, "innerException", lenof("innerException"), ZEND_ACC_PUBLIC TSRMLS_CC);
4714 +       
4715 +       HTTP_REGISTER_EXCEPTION(HttpRuntimeException, HTTP_EX_CE(runtime), HTTP_EX_DEF_CE);
4716 +       HTTP_REGISTER_EXCEPTION(HttpInvalidParamException, HTTP_EX_CE(invalid_param), HTTP_EX_DEF_CE);
4717 +       HTTP_REGISTER_EXCEPTION(HttpHeaderException, HTTP_EX_CE(header), HTTP_EX_DEF_CE);
4718 +       HTTP_REGISTER_EXCEPTION(HttpMalformedHeadersException, HTTP_EX_CE(malformed_headers), HTTP_EX_DEF_CE);
4719 +       HTTP_REGISTER_EXCEPTION(HttpRequestMethodException, HTTP_EX_CE(request_method), HTTP_EX_DEF_CE);
4720 +       HTTP_REGISTER_EXCEPTION(HttpMessageTypeException, HTTP_EX_CE(message_type), HTTP_EX_DEF_CE);
4721 +       HTTP_REGISTER_EXCEPTION(HttpEncodingException, HTTP_EX_CE(encoding), HTTP_EX_DEF_CE);
4722 +       HTTP_REGISTER_EXCEPTION(HttpRequestException, HTTP_EX_CE(request), HTTP_EX_DEF_CE);
4723 +
4724 +       zend_declare_property_long(HTTP_EX_CE(request), "curlCode", lenof("curlCode"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
4725 +
4726 +       HTTP_REGISTER_EXCEPTION(HttpRequestPoolException, HTTP_EX_CE(request_pool), HTTP_EX_DEF_CE);
4727 +       HTTP_REGISTER_EXCEPTION(HttpSocketException, HTTP_EX_CE(socket), HTTP_EX_DEF_CE);
4728 +       HTTP_REGISTER_EXCEPTION(HttpResponseException, HTTP_EX_CE(response), HTTP_EX_DEF_CE);
4729 +       HTTP_REGISTER_EXCEPTION(HttpUrlException, HTTP_EX_CE(url), HTTP_EX_DEF_CE);
4730 +       HTTP_REGISTER_EXCEPTION(HttpQueryStringException, HTTP_EX_CE(querystring), HTTP_EX_DEF_CE);
4731 +       
4732 +       HTTP_LONG_CONSTANT("HTTP_E_RUNTIME", HTTP_E_RUNTIME);
4733 +       HTTP_LONG_CONSTANT("HTTP_E_INVALID_PARAM", HTTP_E_INVALID_PARAM);
4734 +       HTTP_LONG_CONSTANT("HTTP_E_HEADER", HTTP_E_HEADER);
4735 +       HTTP_LONG_CONSTANT("HTTP_E_MALFORMED_HEADERS", HTTP_E_MALFORMED_HEADERS);
4736 +       HTTP_LONG_CONSTANT("HTTP_E_REQUEST_METHOD", HTTP_E_REQUEST_METHOD);
4737 +       HTTP_LONG_CONSTANT("HTTP_E_MESSAGE_TYPE", HTTP_E_MESSAGE_TYPE);
4738 +       HTTP_LONG_CONSTANT("HTTP_E_ENCODING", HTTP_E_ENCODING);
4739 +       HTTP_LONG_CONSTANT("HTTP_E_REQUEST", HTTP_E_REQUEST);
4740 +       HTTP_LONG_CONSTANT("HTTP_E_REQUEST_POOL", HTTP_E_REQUEST_POOL);
4741 +       HTTP_LONG_CONSTANT("HTTP_E_SOCKET", HTTP_E_SOCKET);
4742 +       HTTP_LONG_CONSTANT("HTTP_E_RESPONSE", HTTP_E_RESPONSE);
4743 +       HTTP_LONG_CONSTANT("HTTP_E_URL", HTTP_E_URL);
4744 +       HTTP_LONG_CONSTANT("HTTP_E_QUERYSTRING", HTTP_E_QUERYSTRING);
4745 +       
4746 +#if HTTP_DBG_EXCEPTIONS
4747 +       zend_throw_exception_hook=http_exception_hook;
4748 +#endif
4749 +       
4750 +       return SUCCESS;
4751 +}
4752 +
4753 +zend_class_entry *_http_exception_get_default()
4754 +{
4755 +       return http_exception_object_ce;
4756 +}
4757 +
4758 +zend_class_entry *_http_exception_get_for_code(long code)
4759 +{
4760 +       zend_class_entry *ex = http_exception_object_ce;
4761 +
4762 +       switch (code) {
4763 +               case HTTP_E_RUNTIME:                                    ex = HTTP_EX_CE(runtime);                                       break;
4764 +               case HTTP_E_INVALID_PARAM:                              ex = HTTP_EX_CE(invalid_param);                         break;
4765 +               case HTTP_E_HEADER:                                             ex = HTTP_EX_CE(header);                                        break;
4766 +               case HTTP_E_MALFORMED_HEADERS:                  ex = HTTP_EX_CE(malformed_headers);                     break;
4767 +               case HTTP_E_REQUEST_METHOD:                             ex = HTTP_EX_CE(request_method);                        break;
4768 +               case HTTP_E_MESSAGE_TYPE:                               ex = HTTP_EX_CE(message_type);                          break;
4769 +               case HTTP_E_ENCODING:                                   ex = HTTP_EX_CE(encoding);                                      break;
4770 +               case HTTP_E_REQUEST:                                    ex = HTTP_EX_CE(request);                                       break;
4771 +               case HTTP_E_REQUEST_POOL:                               ex = HTTP_EX_CE(request_pool);                          break;
4772 +               case HTTP_E_SOCKET:                                             ex = HTTP_EX_CE(socket);                                        break;
4773 +               case HTTP_E_RESPONSE:                                   ex = HTTP_EX_CE(response);                                      break;
4774 +               case HTTP_E_URL:                                                ex = HTTP_EX_CE(url);                                           break;
4775 +               case HTTP_E_QUERYSTRING:                                ex = HTTP_EX_CE(querystring);                           break;
4776 +       }
4777 +
4778 +       return ex;
4779 +}
4780 +
4781 +PHP_METHOD(HttpException, __toString)
4782 +{
4783 +       phpstr full_str;
4784 +       zend_class_entry *ce;
4785 +       zval *zobj = getThis(), *retval = NULL, *m, *f, *l;
4786 +       
4787 +       phpstr_init(&full_str);
4788 +       
4789 +       do {
4790 +               ce = Z_OBJCE_P(zobj);
4791 +               
4792 +               m = zend_read_property(ce, zobj, "message", lenof("message"), 0 TSRMLS_CC);
4793 +               f = zend_read_property(ce, zobj, "file", lenof("file"), 0 TSRMLS_CC);
4794 +               l = zend_read_property(ce, zobj, "line", lenof("line"), 0 TSRMLS_CC);
4795 +               
4796 +               if (m && f && l && Z_TYPE_P(m) == IS_STRING && Z_TYPE_P(f) == IS_STRING && Z_TYPE_P(l) == IS_LONG) {
4797 +                       if (zobj != getThis()) {
4798 +                               phpstr_appends(&full_str, " inner ");
4799 +                       }
4800 +               
4801 +                       phpstr_appendf(&full_str, "exception '%.*s' with message '%.*s' in %.*s:%ld" PHP_EOL,
4802 +                               ce->name_length, ce->name, Z_STRLEN_P(m), Z_STRVAL_P(m), Z_STRLEN_P(f), Z_STRVAL_P(f), Z_LVAL_P(l)
4803 +                       );
4804 +               } else {
4805 +                       break;
4806 +               }
4807 +               
4808 +               zobj = zend_read_property(ce, zobj, "innerException", lenof("innerException"), 0 TSRMLS_CC);
4809 +       } while (Z_TYPE_P(zobj) == IS_OBJECT);
4810 +       
4811 +       if (zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "gettraceasstring", &retval) && Z_TYPE_P(retval) == IS_STRING) {
4812 +               phpstr_appends(&full_str, "Stack trace:" PHP_EOL);
4813 +               phpstr_append(&full_str, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
4814 +               zval_ptr_dtor(&retval);
4815 +       }
4816 +       
4817 +       RETURN_PHPSTR_VAL(&full_str);
4818 +}
4819 +
4820 +#endif
4821 +
4822 +/*
4823 + * Local variables:
4824 + * tab-width: 4
4825 + * c-basic-offset: 4
4826 + * End:
4827 + * vim600: noet sw=4 ts=4 fdm=marker
4828 + * vim<600: noet sw=4 ts=4
4829 + */
4830 +
4831 --- /dev/null
4832 +++ b/ext/http/http_filter_api.c
4833 @@ -0,0 +1,534 @@
4834 +/*
4835 +    +--------------------------------------------------------------------+
4836 +    | PECL :: http                                                       |
4837 +    +--------------------------------------------------------------------+
4838 +    | Redistribution and use in source and binary forms, with or without |
4839 +    | modification, are permitted provided that the conditions mentioned |
4840 +    | in the accompanying LICENSE file are met.                          |
4841 +    +--------------------------------------------------------------------+
4842 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
4843 +    +--------------------------------------------------------------------+
4844 +*/
4845 +
4846 +/* $Id: http_filter_api.c 292841 2009-12-31 08:48:57Z mike $ */
4847 +
4848 +#define HTTP_WANT_ZLIB
4849 +#include "php_http.h"
4850 +
4851 +#ifdef ZEND_ENGINE_2
4852 +
4853 +#include "php_streams.h"
4854 +#include "php_http_api.h"
4855 +#include "php_http_encoding_api.h"
4856 +#include "php_http_filter_api.h"
4857 +
4858 +PHP_MINIT_FUNCTION(http_filter)
4859 +{
4860 +       php_stream_filter_register_factory("http.*", &http_filter_factory TSRMLS_CC);
4861 +       return SUCCESS;
4862 +}
4863 +
4864 +/*
4865 +       -
4866 +*/
4867 +
4868 +#define HTTP_FILTER_PARAMS \
4869 +       php_stream *stream, \
4870 +       php_stream_filter *this, \
4871 +       php_stream_bucket_brigade *buckets_in, \
4872 +       php_stream_bucket_brigade *buckets_out, \
4873 +       size_t *bytes_consumed, int flags \
4874 +       TSRMLS_DC
4875 +#define HTTP_FILTER_OP(filter) \
4876 +       http_filter_op_ ##filter
4877 +#define HTTP_FILTER_OPS(filter) \
4878 +       php_stream_filter_ops HTTP_FILTER_OP(filter)
4879 +#define HTTP_FILTER_DTOR(filter) \
4880 +       http_filter_ ##filter## _dtor
4881 +#define HTTP_FILTER_DESTRUCTOR(filter) \
4882 +       void HTTP_FILTER_DTOR(filter)(php_stream_filter *this TSRMLS_DC)
4883 +#define HTTP_FILTER_FUNC(filter) \
4884 +       http_filter_ ##filter
4885 +#define HTTP_FILTER_FUNCTION(filter) \
4886 +       php_stream_filter_status_t HTTP_FILTER_FUNC(filter)(HTTP_FILTER_PARAMS)
4887 +#define HTTP_FILTER_BUFFER(filter) \
4888 +       http_filter_ ##filter## _buffer
4889 +
4890 +#define NEW_BUCKET(data, length) \
4891 +       { \
4892 +               char *__data; \
4893 +               php_stream_bucket *__buck; \
4894 +               \
4895 +               __data = pemalloc(length, this->is_persistent); \
4896 +               if (!__data) { \
4897 +                       return PSFS_ERR_FATAL; \
4898 +               } \
4899 +               memcpy(__data, data, length); \
4900 +               \
4901 +               __buck = php_stream_bucket_new(stream, __data, length, 1, this->is_persistent TSRMLS_CC); \
4902 +               if (!__buck) { \
4903 +                       pefree(__data, this->is_persistent); \
4904 +                       return PSFS_ERR_FATAL; \
4905 +               } \
4906 +               \
4907 +               php_stream_bucket_append(buckets_out, __buck TSRMLS_CC); \
4908 +       }
4909 +
4910 +typedef struct _http_chunked_decode_filter_buffer_t {
4911 +       phpstr  buffer;
4912 +       ulong   hexlen;
4913 +} HTTP_FILTER_BUFFER(chunked_decode);
4914 +
4915 +#ifdef HTTP_HAVE_ZLIB
4916 +typedef http_encoding_stream HTTP_FILTER_BUFFER(deflate);
4917 +typedef http_encoding_stream HTTP_FILTER_BUFFER(inflate);
4918 +#endif /* HTTP_HAVE_ZLIB */
4919 +
4920 +
4921 +static HTTP_FILTER_FUNCTION(chunked_decode)
4922 +{
4923 +       int out_avail = 0;
4924 +       php_stream_bucket *ptr, *nxt;
4925 +       HTTP_FILTER_BUFFER(chunked_decode) *buffer = (HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract);
4926 +       
4927 +       if (bytes_consumed) {
4928 +               *bytes_consumed = 0;
4929 +       }
4930 +       
4931 +       /* new data available? */
4932 +       if (buckets_in->head) {
4933 +               
4934 +               /* fetch available bucket data */
4935 +               for (ptr = buckets_in->head; ptr; ptr = nxt) {
4936 +                       nxt = ptr->next;
4937 +                       if (bytes_consumed) {
4938 +                               *bytes_consumed += ptr->buflen;
4939 +                       }
4940 +               
4941 +                       if (PHPSTR_NOMEM == phpstr_append(PHPSTR(buffer), ptr->buf, ptr->buflen)) {
4942 +                               return PSFS_ERR_FATAL;
4943 +                       }
4944 +                       
4945 +                       php_stream_bucket_unlink(ptr TSRMLS_CC);
4946 +                       php_stream_bucket_delref(ptr TSRMLS_CC);
4947 +               }
4948 +       }
4949 +       if (!phpstr_fix(PHPSTR(buffer))) {
4950 +               return PSFS_ERR_FATAL;
4951 +       }
4952 +
4953 +       /* we have data in our buffer */
4954 +       while (PHPSTR_LEN(buffer)) {
4955 +       
4956 +               /* we already know the size of the chunk and are waiting for data */
4957 +               if (buffer->hexlen) {
4958 +               
4959 +                       /* not enough data buffered */
4960 +                       if (PHPSTR_LEN(buffer) < buffer->hexlen) {
4961 +                       
4962 +                               /* flush anyway? */
4963 +                               if (flags & PSFS_FLAG_FLUSH_INC) {
4964 +                               
4965 +                                       /* flush all data (should only be chunk data) */
4966 +                                       out_avail = 1;
4967 +                                       NEW_BUCKET(PHPSTR_VAL(buffer), PHPSTR_LEN(buffer));
4968 +                                       
4969 +                                       /* waiting for less data now */
4970 +                                       buffer->hexlen -= PHPSTR_LEN(buffer);
4971 +                                       /* no more buffered data */
4972 +                                       phpstr_reset(PHPSTR(buffer));
4973 +                                       /* break */
4974 +                               } 
4975 +                               
4976 +                               /* we have too less data and don't need to flush */
4977 +                               else {
4978 +                                       break;
4979 +                               }
4980 +                       } 
4981 +                       
4982 +                       /* we seem to have all data of the chunk */
4983 +                       else {
4984 +                               out_avail = 1;
4985 +                               NEW_BUCKET(PHPSTR_VAL(buffer), buffer->hexlen);
4986 +                               
4987 +                               /* remove outgoing data from the buffer */
4988 +                               phpstr_cut(PHPSTR(buffer), 0, buffer->hexlen);
4989 +                               /* reset hexlen */
4990 +                               buffer->hexlen = 0;
4991 +                               /* continue */
4992 +                       }
4993 +               } 
4994 +               
4995 +               /* we don't know the length of the chunk yet */
4996 +               else {
4997 +                       size_t off = 0;
4998 +                       
4999 +                       /* ignore preceeding CRLFs (too loose?) */
5000 +                       while (off < PHPSTR_LEN(buffer) && (
5001 +                                       PHPSTR_VAL(buffer)[off] == '\n' || 
5002 +                                       PHPSTR_VAL(buffer)[off] == '\r')) {
5003 +                               ++off;
5004 +                       }
5005 +                       if (off) {
5006 +                               phpstr_cut(PHPSTR(buffer), 0, off);
5007 +                       }
5008 +                       
5009 +                       /* still data there? */
5010 +                       if (PHPSTR_LEN(buffer)) {
5011 +                               int eollen;
5012 +                               const char *eolstr;
5013 +                               
5014 +                               /* we need eol, so we can be sure we have all hex digits */
5015 +                               phpstr_fix(PHPSTR(buffer));
5016 +                               if ((eolstr = http_locate_eol(PHPSTR_VAL(buffer), &eollen))) {
5017 +                                       char *stop = NULL;
5018 +                                       
5019 +                                       /* read in chunk size */
5020 +                                       buffer->hexlen = strtoul(PHPSTR_VAL(buffer), &stop, 16);
5021 +                                       
5022 +                                       /*      if strtoul() stops at the beginning of the buffered data
5023 +                                               there's domething oddly wrong, i.e. bad input */
5024 +                                       if (stop == PHPSTR_VAL(buffer)) {
5025 +                                               return PSFS_ERR_FATAL;
5026 +                                       }
5027 +                                       
5028 +                                       /* cut out <chunk size hex><chunk extension><eol> */
5029 +                                       phpstr_cut(PHPSTR(buffer), 0, eolstr + eollen - PHPSTR_VAL(buffer));
5030 +                                       /* buffer->hexlen is 0 now or contains the size of the next chunk */
5031 +                                       /* continue */
5032 +                               } else {
5033 +                                       /* we have not enough data buffered to read in chunk size */
5034 +                                       break;
5035 +                               }
5036 +                       }
5037 +                       /* break */
5038 +               }
5039 +       }
5040 +       
5041 +       /* flush before close, but only if we are already waiting for more data */
5042 +       if ((flags & PSFS_FLAG_FLUSH_CLOSE) && buffer->hexlen && PHPSTR_LEN(buffer)) {
5043 +               out_avail = 1;
5044 +               NEW_BUCKET(PHPSTR_VAL(buffer), PHPSTR_LEN(buffer));
5045 +               phpstr_reset(PHPSTR(buffer));
5046 +               buffer->hexlen = 0;
5047 +       }
5048 +       
5049 +       return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
5050 +}
5051 +
5052 +static HTTP_FILTER_DESTRUCTOR(chunked_decode)
5053 +{
5054 +       HTTP_FILTER_BUFFER(chunked_decode) *b = (HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract);
5055 +       
5056 +       phpstr_dtor(PHPSTR(b));
5057 +       pefree(b, this->is_persistent);
5058 +}
5059 +
5060 +static HTTP_FILTER_FUNCTION(chunked_encode)
5061 +{
5062 +       int out_avail = 0;
5063 +       php_stream_bucket *ptr, *nxt;
5064 +       
5065 +       if (bytes_consumed) {
5066 +               *bytes_consumed = 0;
5067 +       }
5068 +       
5069 +       /* new data available? */
5070 +       if (buckets_in->head) {
5071 +               phpstr buf;
5072 +               out_avail = 1;
5073 +               
5074 +               phpstr_init(&buf);
5075 +               
5076 +               /* fetch available bucket data */
5077 +               for (ptr = buckets_in->head; ptr; ptr = nxt) {
5078 +                       nxt = ptr->next;
5079 +                       if (bytes_consumed) {
5080 +                               *bytes_consumed += ptr->buflen;
5081 +                       }
5082 +                       
5083 +                       phpstr_appendf(&buf, "%x" HTTP_CRLF, ptr->buflen);
5084 +                       phpstr_append(&buf, ptr->buf, ptr->buflen);
5085 +                       phpstr_appends(&buf, HTTP_CRLF);
5086 +                       
5087 +                       /* pass through */
5088 +                       NEW_BUCKET(PHPSTR_VAL(&buf), PHPSTR_LEN(&buf));
5089 +                       /* reset */
5090 +                       phpstr_reset(&buf);
5091 +                       
5092 +                       php_stream_bucket_unlink(ptr TSRMLS_CC);
5093 +                       php_stream_bucket_delref(ptr TSRMLS_CC);
5094 +               }
5095 +               
5096 +               /* free buffer */
5097 +               phpstr_dtor(&buf);
5098 +       }
5099 +       
5100 +       /* terminate with "0" */
5101 +       if (flags & PSFS_FLAG_FLUSH_CLOSE) {
5102 +               out_avail = 1;
5103 +               NEW_BUCKET("0" HTTP_CRLF, lenof("0" HTTP_CRLF));
5104 +       }
5105 +       
5106 +       return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
5107 +}
5108 +
5109 +static HTTP_FILTER_OPS(chunked_decode) = {
5110 +       HTTP_FILTER_FUNC(chunked_decode),
5111 +       HTTP_FILTER_DTOR(chunked_decode),
5112 +       "http.chunked_decode"
5113 +};
5114 +
5115 +static HTTP_FILTER_OPS(chunked_encode) = {
5116 +       HTTP_FILTER_FUNC(chunked_encode),
5117 +       NULL,
5118 +       "http.chunked_encode"
5119 +};
5120 +
5121 +#ifdef HTTP_HAVE_ZLIB
5122 +
5123 +static HTTP_FILTER_FUNCTION(deflate)
5124 +{
5125 +       int out_avail = 0;
5126 +       php_stream_bucket *ptr, *nxt;
5127 +       HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(deflate) *) this->abstract;
5128 +       
5129 +       if (bytes_consumed) {
5130 +               *bytes_consumed = 0;
5131 +       }
5132 +       
5133 +       /* new data available? */
5134 +       if (buckets_in->head) {
5135 +               
5136 +               /* fetch available bucket data */
5137 +               for (ptr = buckets_in->head; ptr; ptr = nxt) {
5138 +                       char *encoded = NULL;
5139 +                       size_t encoded_len = 0;
5140 +                       
5141 +                       nxt = ptr->next;
5142 +                       if (bytes_consumed) {
5143 +                               *bytes_consumed += ptr->buflen;
5144 +                       }
5145 +                       
5146 +                       if (ptr->buflen) {
5147 +                               http_encoding_deflate_stream_update(buffer, ptr->buf, ptr->buflen, &encoded, &encoded_len);
5148 +                               if (encoded) {
5149 +                                       if (encoded_len) {
5150 +                                               out_avail = 1;
5151 +                                               NEW_BUCKET(encoded, encoded_len);
5152 +                                       }
5153 +                                       efree(encoded);
5154 +                               }
5155 +                       }
5156 +                       
5157 +                       php_stream_bucket_unlink(ptr TSRMLS_CC);
5158 +                       php_stream_bucket_delref(ptr TSRMLS_CC);
5159 +               }
5160 +       }
5161 +       
5162 +       /* flush & close */
5163 +       if (flags & PSFS_FLAG_FLUSH_INC) {
5164 +               char *encoded = NULL;
5165 +               size_t encoded_len = 0;
5166 +               
5167 +               http_encoding_deflate_stream_flush(buffer, &encoded, &encoded_len);
5168 +               if (encoded) {
5169 +                       if (encoded_len) {
5170 +                               out_avail = 1;
5171 +                               NEW_BUCKET(encoded, encoded_len);
5172 +                       }
5173 +                       efree(encoded);
5174 +               }
5175 +       }
5176 +       
5177 +       if (flags & PSFS_FLAG_FLUSH_CLOSE) {
5178 +               char *encoded = NULL;
5179 +               size_t encoded_len = 0;
5180 +               
5181 +               http_encoding_deflate_stream_finish(buffer, &encoded, &encoded_len);
5182 +               if (encoded) {
5183 +                       if (encoded_len) {
5184 +                               out_avail = 1;
5185 +                               NEW_BUCKET(encoded, encoded_len);
5186 +                       }
5187 +                       efree(encoded);
5188 +               }
5189 +       }
5190 +       
5191 +       return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
5192 +}
5193 +
5194 +static HTTP_FILTER_FUNCTION(inflate)
5195 +{
5196 +       int out_avail = 0;
5197 +       php_stream_bucket *ptr, *nxt;
5198 +       HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(inflate) *) this->abstract;
5199 +       
5200 +       if (bytes_consumed) {
5201 +               *bytes_consumed = 0;
5202 +       }
5203 +       
5204 +       /* new data available? */
5205 +       if (buckets_in->head) {
5206 +               
5207 +               /* fetch available bucket data */
5208 +               for (ptr = buckets_in->head; ptr; ptr = nxt) {
5209 +                       char *decoded = NULL;
5210 +                       size_t decoded_len = 0;
5211 +                       
5212 +                       nxt = ptr->next;
5213 +                       if (bytes_consumed) {
5214 +                               *bytes_consumed += ptr->buflen;
5215 +                       }
5216 +                       
5217 +                       if (ptr->buflen) {
5218 +                               http_encoding_inflate_stream_update(buffer, ptr->buf, ptr->buflen, &decoded, &decoded_len);
5219 +                               if (decoded) {
5220 +                                       if (decoded_len) {
5221 +                                               out_avail = 1;
5222 +                                               NEW_BUCKET(decoded, decoded_len);
5223 +                                       }
5224 +                                       efree(decoded);
5225 +                               }
5226 +                       }
5227 +                       
5228 +                       php_stream_bucket_unlink(ptr TSRMLS_CC);
5229 +                       php_stream_bucket_delref(ptr TSRMLS_CC);
5230 +               }
5231 +       }
5232 +       
5233 +       /* flush & close */
5234 +       if (flags & PSFS_FLAG_FLUSH_INC) {
5235 +               char *decoded = NULL;
5236 +               size_t decoded_len = 0;
5237 +               
5238 +               http_encoding_inflate_stream_flush(buffer, &decoded, &decoded_len);
5239 +               if (decoded) {
5240 +                       if (decoded_len) {
5241 +                               out_avail = 1;
5242 +                               NEW_BUCKET(decoded, decoded_len);
5243 +                       }
5244 +                       efree(decoded);
5245 +               }
5246 +       }
5247 +       
5248 +       if (flags & PSFS_FLAG_FLUSH_CLOSE) {
5249 +               char *decoded = NULL;
5250 +               size_t decoded_len = 0;
5251 +               
5252 +               http_encoding_inflate_stream_finish(buffer, &decoded, &decoded_len);
5253 +               if (decoded) {
5254 +                       if (decoded_len) {
5255 +                               out_avail = 1;
5256 +                               NEW_BUCKET(decoded, decoded_len);
5257 +                       }
5258 +                       efree(decoded);
5259 +               }
5260 +       }
5261 +       
5262 +       return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
5263 +}
5264 +
5265 +static HTTP_FILTER_DESTRUCTOR(deflate)
5266 +{
5267 +       HTTP_FILTER_BUFFER(deflate) *buffer = (HTTP_FILTER_BUFFER(deflate) *) this->abstract;
5268 +       http_encoding_deflate_stream_free(&buffer);
5269 +}
5270 +
5271 +static HTTP_FILTER_DESTRUCTOR(inflate)
5272 +{
5273 +       HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(inflate) *) this->abstract;
5274 +       http_encoding_inflate_stream_free(&buffer);
5275 +}
5276 +
5277 +static HTTP_FILTER_OPS(deflate) = {
5278 +       HTTP_FILTER_FUNC(deflate),
5279 +       HTTP_FILTER_DTOR(deflate),
5280 +       "http.deflate"
5281 +};
5282 +
5283 +static HTTP_FILTER_OPS(inflate) = {
5284 +       HTTP_FILTER_FUNC(inflate),
5285 +       HTTP_FILTER_DTOR(inflate),
5286 +       "http.inflate"
5287 +};
5288 +
5289 +#endif /* HTTP_HAVE_ZLIB */
5290 +
5291 +static php_stream_filter *http_filter_create(const char *name, zval *params, int p TSRMLS_DC)
5292 +{
5293 +       zval **tmp = &params;
5294 +       php_stream_filter *f = NULL;
5295 +       
5296 +       if (!strcasecmp(name, "http.chunked_decode")) {
5297 +               HTTP_FILTER_BUFFER(chunked_decode) *b = NULL;
5298 +               
5299 +               if ((b = pecalloc(1, sizeof(HTTP_FILTER_BUFFER(chunked_decode)), p))) {
5300 +                       phpstr_init_ex(PHPSTR(b), 4096, p ? PHPSTR_INIT_PERSISTENT : 0);
5301 +                       if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(chunked_decode), b, p))) {
5302 +                               pefree(b, p);
5303 +                       }
5304 +               }
5305 +       } else
5306 +       
5307 +       if (!strcasecmp(name, "http.chunked_encode")) {
5308 +               f = php_stream_filter_alloc(&HTTP_FILTER_OP(chunked_encode), NULL, p);
5309 +#ifdef HTTP_HAVE_ZLIB
5310 +       } else
5311 +       
5312 +       if (!strcasecmp(name, "http.inflate")) {
5313 +               int flags = p ? HTTP_ENCODING_STREAM_PERSISTENT : 0;
5314 +               HTTP_FILTER_BUFFER(inflate) *b = NULL;
5315 +               
5316 +               if ((b = http_encoding_inflate_stream_init(NULL, flags))) {
5317 +                       if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(inflate), b, p))) {
5318 +                               http_encoding_inflate_stream_free(&b);
5319 +                       }
5320 +               }
5321 +       } else
5322 +       
5323 +       if (!strcasecmp(name, "http.deflate")) {
5324 +               int flags = p ? HTTP_ENCODING_STREAM_PERSISTENT : 0;
5325 +               HTTP_FILTER_BUFFER(deflate) *b = NULL;
5326 +               
5327 +               if (params) {
5328 +                       switch (Z_TYPE_P(params)) {
5329 +                               case IS_ARRAY:
5330 +                               case IS_OBJECT:
5331 +                                       if (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void *) &tmp)) {
5332 +                                               break;
5333 +                                       }
5334 +                               default:
5335 +                               {
5336 +                                       zval *num = http_zsep(IS_LONG, *tmp);
5337 +                                       
5338 +                                       flags |= (Z_LVAL_P(num) & 0x0fffffff);
5339 +                                       zval_ptr_dtor(&num);
5340 +                               }
5341 +                       }
5342 +               }
5343 +               if ((b = http_encoding_deflate_stream_init(NULL, flags))) {
5344 +                       if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(deflate), b, p))) {
5345 +                               http_encoding_deflate_stream_free(&b);
5346 +                       }
5347 +               }
5348 +#endif /* HTTP_HAVE_ZLIB */
5349 +       }
5350 +       
5351 +       return f;
5352 +}
5353 +
5354 +php_stream_filter_factory http_filter_factory = {
5355 +       http_filter_create
5356 +};
5357 +
5358 +#endif /* ZEND_ENGINE_2 */
5359 +
5360 +/*
5361 + * Local variables:
5362 + * tab-width: 4
5363 + * c-basic-offset: 4
5364 + * End:
5365 + * vim600: noet sw=4 ts=4 fdm=marker
5366 + * vim<600: noet sw=4 ts=4
5367 + */
5368 --- /dev/null
5369 +++ b/ext/http/http_functions.c
5370 @@ -0,0 +1,1424 @@
5371 +/*
5372 +    +--------------------------------------------------------------------+
5373 +    | PECL :: http                                                       |
5374 +    +--------------------------------------------------------------------+
5375 +    | Redistribution and use in source and binary forms, with or without |
5376 +    | modification, are permitted provided that the conditions mentioned |
5377 +    | in the accompanying LICENSE file are met.                          |
5378 +    +--------------------------------------------------------------------+
5379 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
5380 +    +--------------------------------------------------------------------+
5381 +*/
5382 +
5383 +/* $Id: http_functions.c 300301 2010-06-09 08:30:34Z mike $ */
5384 +
5385 +#define HTTP_WANT_SAPI
5386 +#define HTTP_WANT_CURL
5387 +#define HTTP_WANT_ZLIB
5388 +#include "php_http.h"
5389 +
5390 +#include "php_ini.h"
5391 +#include "ext/standard/php_string.h"
5392 +#include "zend_operators.h"
5393 +
5394 +#ifdef HTTP_HAVE_SESSION
5395 +#      include "ext/session/php_session.h"
5396 +#endif
5397 +
5398 +#include "php_http_api.h"
5399 +#include "php_http_cache_api.h"
5400 +#include "php_http_cookie_api.h"
5401 +#include "php_http_date_api.h"
5402 +#include "php_http_encoding_api.h"
5403 +#include "php_http_headers_api.h"
5404 +#include "php_http_message_api.h"
5405 +#include "php_http_request_api.h"
5406 +#include "php_http_request_method_api.h"
5407 +#include "php_http_persistent_handle_api.h"
5408 +#include "php_http_send_api.h"
5409 +#include "php_http_url_api.h"
5410 +
5411 +/* {{{ proto string http_date([int timestamp])
5412 +       Compose a valid HTTP date regarding RFC 1123 looking like: "Wed, 22 Dec 2004 11:34:47 GMT" */
5413 +PHP_FUNCTION(http_date)
5414 +{
5415 +       long t = -1;
5416 +       char *date;
5417 +
5418 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
5419 +               RETURN_FALSE;
5420 +       }
5421 +
5422 +       if (t == -1) {
5423 +               t = HTTP_G->request.time;
5424 +       }
5425 +
5426 +       if (!(date = http_date(t))) {
5427 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Could not compose date of timestamp %ld", t);
5428 +               RETURN_FALSE;
5429 +       }
5430 +       
5431 +       RETURN_STRING(date, 0);
5432 +}
5433 +/* }}} */
5434 +
5435 +/* {{{ proto string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE|HTTP_URL_FROM_ENV[, array &new_url]]]])
5436 +       Build an URL. */
5437 +PHP_FUNCTION(http_build_url)
5438 +{
5439 +       char *url_str = NULL;
5440 +       size_t url_len = 0;
5441 +       long flags = HTTP_URL_REPLACE|HTTP_URL_FROM_ENV;
5442 +       zval *z_old_url = NULL, *z_new_url = NULL, *z_composed_url = NULL;
5443 +       php_url *old_url = NULL, *new_url = NULL, *composed_url = NULL;
5444 +
5445 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!/z!/lz", &z_old_url, &z_new_url, &flags, &z_composed_url) != SUCCESS) {
5446 +               RETURN_FALSE;
5447 +       }
5448 +       
5449 +       if (z_new_url) {
5450 +               if (Z_TYPE_P(z_new_url) == IS_ARRAY || Z_TYPE_P(z_new_url) == IS_OBJECT) {
5451 +                       new_url = http_url_from_struct(NULL, HASH_OF(z_new_url));
5452 +               } else {
5453 +                       convert_to_string(z_new_url);
5454 +                       if (!(new_url = php_url_parse_ex(Z_STRVAL_P(z_new_url), Z_STRLEN_P(z_new_url)))) {
5455 +                               http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_new_url));
5456 +                               RETURN_FALSE;
5457 +                       }
5458 +               }
5459 +       }
5460 +       
5461 +       if (z_old_url) {
5462 +               if (Z_TYPE_P(z_old_url) == IS_ARRAY || Z_TYPE_P(z_old_url) == IS_OBJECT) {
5463 +                       old_url = http_url_from_struct(NULL, HASH_OF(z_old_url));
5464 +               } else {
5465 +                       convert_to_string(z_old_url);
5466 +                       if (!(old_url = php_url_parse_ex(Z_STRVAL_P(z_old_url), Z_STRLEN_P(z_old_url)))) {
5467 +                               if (new_url) {
5468 +                                       php_url_free(new_url);
5469 +                               }
5470 +                               http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_old_url));
5471 +                               RETURN_FALSE;
5472 +                       }
5473 +               }
5474 +       }
5475 +       
5476 +       if (z_composed_url) {
5477 +               http_build_url(flags, old_url, new_url, &composed_url, &url_str, &url_len);
5478 +               http_url_tostruct(composed_url, z_composed_url);
5479 +               php_url_free(composed_url);
5480 +       } else {
5481 +               http_build_url(flags, old_url, new_url, NULL, &url_str, &url_len);
5482 +       }
5483 +       
5484 +       if (new_url) {
5485 +               php_url_free(new_url);
5486 +       }
5487 +       if (old_url) {
5488 +               php_url_free(old_url);
5489 +       }
5490 +       
5491 +       RETURN_STRINGL(url_str, url_len, 0);
5492 +}
5493 +/* }}} */
5494 +
5495 +/* {{{ proto string http_build_str(array query [, string prefix[, string arg_separator]])
5496 +       Opponent to parse_str(). */
5497 +PHP_FUNCTION(http_build_str)
5498 +{
5499 +       zval *formdata;
5500 +       char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output");
5501 +       int prefix_len = 0, arg_sep_len = strlen(arg_sep);
5502 +       phpstr formstr;
5503 +
5504 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) {
5505 +               RETURN_FALSE;
5506 +       }
5507 +
5508 +       if (!arg_sep_len) {
5509 +               arg_sep = HTTP_URL_ARGSEP;
5510 +               arg_sep_len = lenof(HTTP_URL_ARGSEP);
5511 +       }
5512 +
5513 +       phpstr_init(&formstr);
5514 +       if (SUCCESS != http_urlencode_hash_recursive(HASH_OF(formdata), &formstr, arg_sep, arg_sep_len, prefix, prefix_len)) {
5515 +               RETURN_FALSE;
5516 +       }
5517 +
5518 +       if (!formstr.used) {
5519 +               phpstr_dtor(&formstr);
5520 +               RETURN_NULL();
5521 +       }
5522 +
5523 +       RETURN_PHPSTR_VAL(&formstr);
5524 +}
5525 +/* }}} */
5526 +
5527 +#define HTTP_DO_NEGOTIATE_DEFAULT(supported) \
5528 +       { \
5529 +               zval **value; \
5530 +                \
5531 +               zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \
5532 +               if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void *) &value)) { \
5533 +                       RETVAL_ZVAL(*value, 1, 0); \
5534 +               } else { \
5535 +                       RETVAL_NULL(); \
5536 +               } \
5537 +       }
5538 +
5539 +#define HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array) \
5540 +       HTTP_DO_NEGOTIATE_DEFAULT(supported); \
5541 +       if (rs_array) { \
5542 +               HashPosition pos; \
5543 +               zval **value_ptr; \
5544 +                \
5545 +               FOREACH_VAL(pos, supported, value_ptr) { \
5546 +                       zval *value = http_zsep(IS_STRING, *value_ptr); \
5547 +                       add_assoc_double(rs_array, Z_STRVAL_P(value), 1.0); \
5548 +                       zval_ptr_dtor(&value); \
5549 +               } \
5550 +       }
5551 +
5552 +#define HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \
5553 +       { \
5554 +               char *key; \
5555 +               uint key_len; \
5556 +               ulong idx; \
5557 +                \
5558 +               if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \
5559 +                       RETVAL_STRINGL(key, key_len-1, 0); \
5560 +               } else { \
5561 +                       HTTP_DO_NEGOTIATE_DEFAULT(supported); \
5562 +               } \
5563 +               \
5564 +               if (rs_array) { \
5565 +                       zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \
5566 +               } \
5567 +               \
5568 +               zend_hash_destroy(result); \
5569 +               FREE_HASHTABLE(result); \
5570 +       }
5571 +
5572 +#define HTTP_DO_NEGOTIATE(type, supported, rs_array) \
5573 +       { \
5574 +               HashTable *result; \
5575 +               if ((result = http_negotiate_ ##type(supported))) { \
5576 +                       HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \
5577 +               } else { \
5578 +                       HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \
5579 +               } \
5580 +       }
5581 +
5582 +/* {{{ proto string http_negotiate_language(array supported[, array &result])
5583 +       Negotiate the clients preferred language. */
5584 +PHP_FUNCTION(http_negotiate_language)
5585 +{
5586 +       zval *supported, *rs_array = NULL;
5587 +
5588 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) {
5589 +               RETURN_FALSE;
5590 +       }
5591 +       
5592 +       if (rs_array) {
5593 +               zval_dtor(rs_array);
5594 +               array_init(rs_array);
5595 +       }
5596 +       
5597 +       HTTP_DO_NEGOTIATE(language, supported, rs_array);
5598 +}
5599 +/* }}} */
5600 +
5601 +/* {{{ proto string http_negotiate_charset(array supported[, array &result])
5602 +       Negotiate the clients preferred charset. */
5603 +PHP_FUNCTION(http_negotiate_charset)
5604 +{
5605 +       zval *supported, *rs_array = NULL;
5606 +
5607 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) {
5608 +               RETURN_FALSE;
5609 +       }
5610 +       
5611 +       if (rs_array) {
5612 +               zval_dtor(rs_array);
5613 +               array_init(rs_array);
5614 +       }
5615 +
5616 +       HTTP_DO_NEGOTIATE(charset, supported, rs_array);
5617 +}
5618 +/* }}} */
5619 +
5620 +/* {{{ proto string http_negotiate_content_type(array supported[, array &result])
5621 +       Negotiate the clients preferred content type. */
5622 +PHP_FUNCTION(http_negotiate_content_type)
5623 +{
5624 +       zval *supported, *rs_array = NULL;
5625 +       
5626 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array)) {
5627 +               RETURN_FALSE;
5628 +       }
5629 +       
5630 +       if (rs_array) {
5631 +               zval_dtor(rs_array);
5632 +               array_init(rs_array);
5633 +       }
5634 +       
5635 +       HTTP_DO_NEGOTIATE(content_type, supported, rs_array);
5636 +}
5637 +/* }}} */
5638 +
5639 +/* {{{ proto string http_negotiate(mixed value, array supported[, array &result])
5640 +       Negotiate the user supplied value. */
5641 +PHP_FUNCTION(http_negotiate)
5642 +{
5643 +       zval *value, *supported, *rs_array = NULL;
5644 +       HashTable *rs;
5645 +
5646 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|z", &value, &supported, &rs_array)) {
5647 +               RETURN_FALSE;
5648 +       }
5649 +
5650 +       if (rs_array) {
5651 +               zval_dtor(rs_array);
5652 +               array_init(rs_array);
5653 +       }
5654 +
5655 +       if ((rs = http_negotiate_z(value, Z_ARRVAL_P(supported), http_negotiate_default_func))) {
5656 +               HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
5657 +       } else {
5658 +               HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
5659 +       }
5660 +}
5661 +/* }}} */
5662 +
5663 +/* {{{ proto bool http_send_status(int status)
5664 +       Send HTTP status code. */
5665 +PHP_FUNCTION(http_send_status)
5666 +{
5667 +       long status = 0;
5668 +
5669 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
5670 +               RETURN_FALSE;
5671 +       }
5672 +       if (status < 100 || status > 510) {
5673 +               http_error_ex(HE_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status);
5674 +               RETURN_FALSE;
5675 +       }
5676 +
5677 +       RETURN_SUCCESS(http_send_status(status));
5678 +}
5679 +/* }}} */
5680 +
5681 +/* {{{ proto bool http_send_last_modified([int timestamp])
5682 +       Send a "Last-Modified" header with a valid HTTP date. */
5683 +PHP_FUNCTION(http_send_last_modified)
5684 +{
5685 +       long t = -1;
5686 +
5687 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
5688 +               RETURN_FALSE;
5689 +       }
5690 +
5691 +       if (t == -1) {
5692 +               t = HTTP_G->request.time;
5693 +       }
5694 +
5695 +       RETURN_SUCCESS(http_send_last_modified(t));
5696 +}
5697 +/* }}} */
5698 +
5699 +/* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
5700 +       Send the Content-Type of the sent entity.  This is particularly important if you use the http_send() API. */
5701 +PHP_FUNCTION(http_send_content_type)
5702 +{
5703 +       char *ct = "application/x-octetstream";
5704 +       int ct_len = lenof("application/x-octetstream");
5705 +
5706 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
5707 +               RETURN_FALSE;
5708 +       }
5709 +
5710 +       RETURN_SUCCESS(http_send_content_type(ct, ct_len));
5711 +}
5712 +/* }}} */
5713 +
5714 +/* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
5715 +       Send the Content-Disposition. */
5716 +PHP_FUNCTION(http_send_content_disposition)
5717 +{
5718 +       char *filename;
5719 +       int f_len;
5720 +       zend_bool send_inline = 0;
5721 +
5722 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
5723 +               RETURN_FALSE;
5724 +       }
5725 +       RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
5726 +}
5727 +/* }}} */
5728 +
5729 +/* {{{ proto bool http_match_modified([int timestamp[, bool for_range = false]])
5730 +       Matches the given unix timestamp against the clients "If-Modified-Since" resp. "If-Unmodified-Since" HTTP headers. */
5731 +PHP_FUNCTION(http_match_modified)
5732 +{
5733 +       long t = -1;
5734 +       zend_bool for_range = 0;
5735 +
5736 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &t, &for_range) != SUCCESS) {
5737 +               RETURN_FALSE;
5738 +       }
5739 +
5740 +       // current time if not supplied (senseless though)
5741 +       if (t == -1) {
5742 +               t = HTTP_G->request.time;
5743 +       }
5744 +
5745 +       if (for_range) {
5746 +               RETURN_BOOL(http_match_last_modified("HTTP_IF_UNMODIFIED_SINCE", t));
5747 +       }
5748 +       RETURN_BOOL(http_match_last_modified("HTTP_IF_MODIFIED_SINCE", t));
5749 +}
5750 +/* }}} */
5751 +
5752 +/* {{{ proto bool http_match_etag(string etag[, bool for_range = false])
5753 +       Matches the given ETag against the clients "If-Match" resp. "If-None-Match" HTTP headers. */
5754 +PHP_FUNCTION(http_match_etag)
5755 +{
5756 +       int etag_len;
5757 +       char *etag;
5758 +       zend_bool for_range = 0;
5759 +
5760 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &etag, &etag_len, &for_range) != SUCCESS) {
5761 +               RETURN_FALSE;
5762 +       }
5763 +
5764 +       if (for_range) {
5765 +               RETURN_BOOL(http_match_etag("HTTP_IF_MATCH", etag));
5766 +       }
5767 +       RETURN_BOOL(http_match_etag("HTTP_IF_NONE_MATCH", etag));
5768 +}
5769 +/* }}} */
5770 +
5771 +/* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
5772 +       Attempts to cache the sent entity by its last modification date. */
5773 +PHP_FUNCTION(http_cache_last_modified)
5774 +{
5775 +       long last_modified = 0, send_modified = 0, t;
5776 +       zval *zlm;
5777 +
5778 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
5779 +               RETURN_FALSE;
5780 +       }
5781 +       
5782 +       HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
5783 +
5784 +       t = HTTP_G->request.time;
5785 +
5786 +       /* 0 or omitted */
5787 +       if (!last_modified) {
5788 +               /* does the client have? (att: caching "forever") */
5789 +               if ((zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE", 1))) {
5790 +                       last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
5791 +               /* send current time */
5792 +               } else {
5793 +                       send_modified = t;
5794 +               }
5795 +       /* negative value is supposed to be expiration time */
5796 +       } else if (last_modified < 0) {
5797 +               last_modified += t;
5798 +               send_modified  = t;
5799 +       /* send supplied time explicitly */
5800 +       } else {
5801 +               send_modified = last_modified;
5802 +       }
5803 +
5804 +       RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
5805 +}
5806 +/* }}} */
5807 +
5808 +/* {{{ proto bool http_cache_etag([string etag])
5809 +       Attempts to cache the sent entity by its ETag, either supplied or generated by the hash algorithm specified by the INI setting "http.etag.mode". */
5810 +PHP_FUNCTION(http_cache_etag)
5811 +{
5812 +       char *etag = NULL;
5813 +       int etag_len = 0;
5814 +
5815 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
5816 +               RETURN_FALSE;
5817 +       }
5818 +       
5819 +       HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
5820 +
5821 +       RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)));
5822 +}
5823 +/* }}} */
5824 +
5825 +/* {{{ proto string ob_etaghandler(string data, int mode)
5826 +       For use with ob_start().  Output buffer handler generating an ETag with the hash algorithm specified with the INI setting "http.etag.mode". */
5827 +PHP_FUNCTION(ob_etaghandler)
5828 +{
5829 +       char *data;
5830 +       int data_len;
5831 +       long mode;
5832 +
5833 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
5834 +               RETURN_FALSE;
5835 +       }
5836 +
5837 +       Z_TYPE_P(return_value) = IS_STRING;
5838 +       http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
5839 +}
5840 +/* }}} */
5841 +
5842 +/* {{{ proto void http_throttle(double sec[, int bytes = 40960])
5843 +       Sets the throttle delay and send buffer size for use with http_send() API. */
5844 +PHP_FUNCTION(http_throttle)
5845 +{
5846 +       long chunk_size = HTTP_SENDBUF_SIZE;
5847 +       double interval;
5848 +
5849 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l", &interval, &chunk_size)) {
5850 +               return;
5851 +       }
5852 +
5853 +       HTTP_G->send.throttle_delay = interval;
5854 +       HTTP_G->send.buffer_size = chunk_size;
5855 +}
5856 +/* }}} */
5857 +
5858 +/* {{{ proto void http_redirect([string url[, array params[, bool session = false[, int status = 302]]]])
5859 +       Redirect to the given url. */
5860 +PHP_FUNCTION(http_redirect)
5861 +{
5862 +       int url_len = 0;
5863 +       size_t query_len = 0;
5864 +       zend_bool session = 0, free_params = 0;
5865 +       zval *params = NULL;
5866 +       long status = HTTP_REDIRECT;
5867 +       char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL;
5868 +
5869 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bl", &url, &url_len, &params, &session, &status) != SUCCESS) {
5870 +               RETURN_FALSE;
5871 +       }
5872 +
5873 +#ifdef HTTP_HAVE_SESSION
5874 +       /* append session info */
5875 +       if (session) {
5876 +               if (!params) {
5877 +                       free_params = 1;
5878 +                       MAKE_STD_ZVAL(params);
5879 +                       array_init(params);
5880 +               }
5881 +               if (PS(session_status) == php_session_active) {
5882 +                       if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
5883 +                               http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information");
5884 +                       }
5885 +               }
5886 +       }
5887 +#endif
5888 +
5889 +       /* treat params array with http_build_query() */
5890 +       if (params) {
5891 +               if (SUCCESS != http_urlencode_hash_ex(Z_ARRVAL_P(params), 0, NULL, 0, &query, &query_len)) {
5892 +                       if (free_params) {
5893 +                               zval_dtor(params);
5894 +                               FREE_ZVAL(params);
5895 +                       }
5896 +                       if (query) {
5897 +                               efree(query);
5898 +                       }
5899 +                       RETURN_FALSE;
5900 +               }
5901 +       }
5902 +
5903 +       URI = http_absolute_url_ex(url, HTTP_URL_FROM_ENV);
5904 +
5905 +       if (query_len) {
5906 +               spprintf(&LOC, 0, "Location: %s?%s", URI, query);
5907 +               if (status != 300) {
5908 +                       spprintf(&RED, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
5909 +               }
5910 +       } else {
5911 +               spprintf(&LOC, 0, "Location: %s", URI);
5912 +               if (status != 300) {
5913 +                       spprintf(&RED, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
5914 +               }
5915 +       }
5916 +       
5917 +       efree(URI);
5918 +       if (query) {
5919 +               efree(query);
5920 +       }
5921 +       if (free_params) {
5922 +               zval_dtor(params);
5923 +               FREE_ZVAL(params);
5924 +       }
5925 +       
5926 +       switch (status) {
5927 +               case 300:
5928 +                       RETVAL_SUCCESS(http_send_status_header(status, LOC));
5929 +                       efree(LOC);
5930 +                       return;
5931 +               
5932 +               case HTTP_REDIRECT_PERM:
5933 +               case HTTP_REDIRECT_FOUND:
5934 +               case HTTP_REDIRECT_POST:
5935 +               case HTTP_REDIRECT_PROXY:
5936 +               case HTTP_REDIRECT_TEMP:
5937 +                       break;
5938 +               
5939 +               case 306:
5940 +               default:
5941 +                       http_error_ex(HE_NOTICE, HTTP_E_RUNTIME, "Unsupported redirection status code: %ld", status);
5942 +               case HTTP_REDIRECT:
5943 +                       if (    SG(request_info).request_method && 
5944 +                                       strcasecmp(SG(request_info).request_method, "HEAD") &&
5945 +                                       strcasecmp(SG(request_info).request_method, "GET")) {
5946 +                               status = HTTP_REDIRECT_POST;
5947 +                       } else {
5948 +                               status = HTTP_REDIRECT_FOUND;
5949 +                       }
5950 +                       break;
5951 +       }
5952 +       
5953 +       RETURN_SUCCESS(http_exit_ex(status, LOC, RED, 1));
5954 +}
5955 +/* }}} */
5956 +
5957 +/* {{{ proto bool http_send_data(string data)
5958 +       Sends raw data with support for (multiple) range requests. */
5959 +PHP_FUNCTION(http_send_data)
5960 +{
5961 +       int data_len;
5962 +       char *data_buf;
5963 +
5964 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_buf, &data_len) != SUCCESS) {
5965 +               RETURN_FALSE;
5966 +       }
5967 +
5968 +       RETURN_SUCCESS(http_send_data(data_buf, data_len));
5969 +}
5970 +/* }}} */
5971 +
5972 +/* {{{ proto bool http_send_file(string file)
5973 +       Sends a file with support for (multiple) range requests. */
5974 +PHP_FUNCTION(http_send_file)
5975 +{
5976 +       char *file;
5977 +       int flen = 0;
5978 +
5979 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &flen) != SUCCESS) {
5980 +               RETURN_FALSE;
5981 +       }
5982 +       if (!flen) {
5983 +               RETURN_FALSE;
5984 +       }
5985 +
5986 +       RETURN_SUCCESS(http_send_file(file));
5987 +}
5988 +/* }}} */
5989 +
5990 +/* {{{ proto bool http_send_stream(resource stream)
5991 +       Sends an already opened stream with support for (multiple) range requests. */
5992 +PHP_FUNCTION(http_send_stream)
5993 +{
5994 +       zval *zstream;
5995 +       php_stream *file;
5996 +
5997 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
5998 +               RETURN_FALSE;
5999 +       }
6000 +
6001 +       php_stream_from_zval(file, &zstream);
6002 +       RETURN_SUCCESS(http_send_stream(file));
6003 +}
6004 +/* }}} */
6005 +
6006 +/* {{{ proto string http_chunked_decode(string encoded)
6007 +       Decodes a string that was HTTP-chunked encoded. */
6008 +PHP_FUNCTION(http_chunked_decode)
6009 +{
6010 +       char *encoded = NULL, *decoded = NULL;
6011 +       size_t decoded_len = 0;
6012 +       int encoded_len = 0;
6013 +
6014 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
6015 +               RETURN_FALSE;
6016 +       }
6017 +
6018 +       if (NULL != http_encoding_dechunk(encoded, encoded_len, &decoded, &decoded_len)) {
6019 +               RETURN_STRINGL(decoded, (int) decoded_len, 0);
6020 +       } else {
6021 +               RETURN_FALSE;
6022 +       }
6023 +}
6024 +/* }}} */
6025 +
6026 +/* {{{ proto object http_parse_message(string message)
6027 +       Parses (a) http_message(s) into a simple recursive object structure. */
6028 +PHP_FUNCTION(http_parse_message)
6029 +{
6030 +       char *message;
6031 +       int message_len;
6032 +       http_message *msg = NULL;
6033 +       
6034 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &message, &message_len)) {
6035 +               RETURN_NULL();
6036 +       }
6037 +       
6038 +       if ((msg = http_message_parse(message, message_len))) {
6039 +               object_init(return_value);
6040 +               http_message_tostruct_recursive(msg, return_value);
6041 +               http_message_free(&msg);
6042 +       } else {
6043 +               RETURN_NULL();
6044 +       }
6045 +}
6046 +/* }}} */
6047 +
6048 +/* {{{ proto array http_parse_headers(string header)
6049 +       Parses HTTP headers into an associative array. */
6050 +PHP_FUNCTION(http_parse_headers)
6051 +{
6052 +       char *header;
6053 +       int header_len;
6054 +
6055 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
6056 +               RETURN_FALSE;
6057 +       }
6058 +
6059 +       array_init(return_value);
6060 +       if (SUCCESS != http_parse_headers(header, return_value)) {
6061 +               zval_dtor(return_value);
6062 +               http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Failed to parse headers");
6063 +               RETURN_FALSE;
6064 +       }
6065 +}
6066 +/* }}}*/
6067 +
6068 +/* {{{ proto object http_parse_cookie(string cookie[, int flags[, array allowed_extras]])
6069 +       Parses HTTP cookies like sent in a response into a struct. */
6070 +PHP_FUNCTION(http_parse_cookie)
6071 +{
6072 +       char *cookie, **allowed_extras = NULL;
6073 +       int i = 0, cookie_len;
6074 +       long flags = 0;
6075 +       zval *allowed_extras_array = NULL, **entry = NULL;
6076 +       HashPosition pos;
6077 +       http_cookie_list list;
6078 +       
6079 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!", &cookie, &cookie_len, &flags, &allowed_extras_array)) {
6080 +               RETURN_FALSE;
6081 +       }
6082 +       
6083 +       if (allowed_extras_array) {
6084 +               allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
6085 +               FOREACH_VAL(pos, allowed_extras_array, entry) {
6086 +                       zval *data = http_zsep(IS_STRING, *entry);
6087 +                       allowed_extras[i++] = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
6088 +                       zval_ptr_dtor(&data);
6089 +               }
6090 +       }
6091 +       
6092 +       if (http_parse_cookie_ex(&list, cookie, flags, allowed_extras)) {
6093 +               object_init(return_value);
6094 +               http_cookie_list_tostruct(&list, return_value);
6095 +               http_cookie_list_dtor(&list);
6096 +       } else {
6097 +               RETVAL_FALSE;
6098 +       }
6099 +       
6100 +       if (allowed_extras) {
6101 +               for (i = 0; allowed_extras[i]; ++i) {
6102 +                       efree(allowed_extras[i]);
6103 +               }
6104 +               efree(allowed_extras);
6105 +       }
6106 +}
6107 +/* }}} */
6108 +
6109 +/* {{{ proto string http_build_cookie(array cookie)
6110 +       Build a cookie string from an array/object like returned by http_parse_cookie(). */
6111 +PHP_FUNCTION(http_build_cookie)
6112 +{
6113 +       char *str = NULL;
6114 +       size_t len = 0;
6115 +       zval *strct;
6116 +       http_cookie_list list;
6117 +       
6118 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &strct)) {
6119 +               RETURN_FALSE;
6120 +       }
6121 +       
6122 +       http_cookie_list_fromstruct(&list, strct);
6123 +       http_cookie_list_tostring(&list, &str, &len);
6124 +       http_cookie_list_dtor(&list);
6125 +       
6126 +       RETURN_STRINGL(str, len, 0);
6127 +}
6128 +/* }}} */
6129 +
6130 +/* {{{ proto object http_parse_params(string param[, int flags = HTTP_PARAMS_DEFAULT])
6131 + Parse parameter list. */
6132 +PHP_FUNCTION(http_parse_params)
6133 +{
6134 +       char *param;
6135 +       int param_len;
6136 +       zval *params;
6137 +       long flags = HTTP_PARAMS_DEFAULT;
6138 +       
6139 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &param, &param_len, &flags)) {
6140 +               RETURN_FALSE;
6141 +       }
6142 +       
6143 +       MAKE_STD_ZVAL(params);
6144 +       array_init(params);
6145 +       if (SUCCESS != http_parse_params(param, flags, Z_ARRVAL_P(params))) {
6146 +               zval_ptr_dtor(&params);
6147 +               RETURN_FALSE;
6148 +       }
6149 +       
6150 +       object_init(return_value);
6151 +       add_property_zval(return_value, "params", params);
6152 +#ifdef ZEND_ENGINE_2
6153 +       zval_ptr_dtor(&params);
6154 +#endif
6155 +}
6156 +/* }}} */
6157 +
6158 +/* {{{ proto array http_get_request_headers(void)
6159 +       Get a list of incoming HTTP headers. */
6160 +PHP_FUNCTION(http_get_request_headers)
6161 +{
6162 +       NO_ARGS;
6163 +
6164 +       array_init(return_value);
6165 +       http_get_request_headers(Z_ARRVAL_P(return_value));
6166 +}
6167 +/* }}} */
6168 +
6169 +/* {{{ proto string http_get_request_body(void)
6170 +       Get the raw request body (e.g. POST or PUT data). */
6171 +PHP_FUNCTION(http_get_request_body)
6172 +{
6173 +       char *body;
6174 +       size_t length;
6175 +
6176 +       NO_ARGS;
6177 +
6178 +       if (SUCCESS == http_get_request_body(&body, &length)) {
6179 +               RETURN_STRINGL(body, (int) length, 0);
6180 +       } else {
6181 +               RETURN_NULL();
6182 +       }
6183 +}
6184 +/* }}} */
6185 +
6186 +/* {{{ proto resource http_get_request_body_stream(void)
6187 +       Create a stream to read the raw request body (e.g. POST or PUT data). This function can only be used once if the request method was another than POST. */
6188 +PHP_FUNCTION(http_get_request_body_stream)
6189 +{
6190 +       php_stream *s;
6191 +       
6192 +       NO_ARGS;
6193 +       
6194 +       if ((s = http_get_request_body_stream())) {
6195 +               php_stream_to_zval(s, return_value);
6196 +       } else {
6197 +               http_error(HE_WARNING, HTTP_E_RUNTIME, "Failed to create request body stream");
6198 +               RETURN_NULL();
6199 +       }
6200 +}
6201 +/* }}} */
6202 +
6203 +/* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false])
6204 +       Match an incoming HTTP header. */
6205 +PHP_FUNCTION(http_match_request_header)
6206 +{
6207 +       char *header, *value;
6208 +       int header_len, value_len;
6209 +       zend_bool match_case = 0;
6210 +
6211 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &header, &header_len, &value, &value_len, &match_case)) {
6212 +               RETURN_FALSE;
6213 +       }
6214 +
6215 +       RETURN_BOOL(http_match_request_header_ex(header, value, match_case));
6216 +}
6217 +/* }}} */
6218 +
6219 +/* {{{ proto object http_persistent_handles_count() */
6220 +PHP_FUNCTION(http_persistent_handles_count)
6221 +{
6222 +       NO_ARGS;
6223 +       object_init(return_value);
6224 +       if (!http_persistent_handle_statall_ex(HASH_OF(return_value))) {
6225 +               zval_dtor(return_value);
6226 +               RETURN_NULL();
6227 +       }
6228 +}
6229 +/* }}} */
6230 +
6231 +/* {{{ proto void http_persistent_handles_clean([string name]) */
6232 +PHP_FUNCTION(http_persistent_handles_clean)
6233 +{
6234 +       char *name_str = NULL;
6235 +       int name_len = 0;
6236 +       
6237 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name_str, &name_len)) {
6238 +               http_persistent_handle_cleanup_ex(name_str, name_len, 1);
6239 +       }
6240 +}
6241 +/* }}} */
6242 +
6243 +/* {{{ proto string http_persistent_handles_ident([string ident]) */
6244 +PHP_FUNCTION(http_persistent_handles_ident)
6245 +{
6246 +       char *ident_str = NULL;
6247 +       int ident_len = 0;
6248 +       
6249 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ident_str, &ident_len)) {
6250 +               RETVAL_STRING(zend_ini_string(ZEND_STRS("http.persistent.handles.ident"), 0), 1);
6251 +               if (ident_str && ident_len) {
6252 +                       zend_alter_ini_entry(ZEND_STRS("http.persistent.handles.ident"), ident_str, ident_len, ZEND_INI_USER, PHP_INI_STAGE_RUNTIME);
6253 +               }
6254 +       }
6255 +}
6256 +/* }}} */
6257 +
6258 +/* {{{ HAVE_CURL */
6259 +#ifdef HTTP_HAVE_CURL
6260 +
6261 +#define RETVAL_RESPONSE_OR_BODY(request) \
6262 +       { \
6263 +               zval **bodyonly; \
6264 +                \
6265 +               /* check if only the body should be returned */ \
6266 +               if (options && (SUCCESS == zend_hash_find(Z_ARRVAL_P(options), "bodyonly", sizeof("bodyonly"), (void *) &bodyonly)) && i_zend_is_true(*bodyonly)) { \
6267 +                       http_message *msg = http_message_parse(PHPSTR_VAL(&request.conv.response), PHPSTR_LEN(&request.conv.response)); \
6268 +                        \
6269 +                       if (msg) { \
6270 +                               RETVAL_STRINGL(PHPSTR_VAL(&msg->body), PHPSTR_LEN(&msg->body), 1); \
6271 +                               http_message_free(&msg); \
6272 +                       } \
6273 +               } else { \
6274 +                       RETVAL_STRINGL(request.conv.response.data, request.conv.response.used, 1); \
6275 +               } \
6276 +       }
6277 +
6278 +/* {{{ proto string http_get(string url[, array options[, array &info]])
6279 +       Performs an HTTP GET request on the supplied url. */
6280 +PHP_FUNCTION(http_get)
6281 +{
6282 +       zval *options = NULL, *info = NULL;
6283 +       char *URL;
6284 +       int URL_len;
6285 +       http_request request;
6286 +
6287 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
6288 +               RETURN_FALSE;
6289 +       }
6290 +
6291 +       if (info) {
6292 +               zval_dtor(info);
6293 +               array_init(info);
6294 +       }
6295 +
6296 +       RETVAL_FALSE;
6297 +
6298 +       http_request_init_ex(&request, NULL, HTTP_GET, URL);
6299 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6300 +               http_request_exec(&request);
6301 +               if (info) {
6302 +                       http_request_info(&request, Z_ARRVAL_P(info));
6303 +               }
6304 +               RETVAL_RESPONSE_OR_BODY(request);
6305 +       }
6306 +       http_request_dtor(&request);
6307 +}
6308 +/* }}} */
6309 +
6310 +/* {{{ proto string http_head(string url[, array options[, array &info]])
6311 +       Performs an HTTP HEAD request on the supplied url. */
6312 +PHP_FUNCTION(http_head)
6313 +{
6314 +       zval *options = NULL, *info = NULL;
6315 +       char *URL;
6316 +       int URL_len;
6317 +       http_request request;
6318 +
6319 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
6320 +               RETURN_FALSE;
6321 +       }
6322 +
6323 +       if (info) {
6324 +               zval_dtor(info);
6325 +               array_init(info);
6326 +       }
6327 +
6328 +       RETVAL_FALSE;
6329 +
6330 +       http_request_init_ex(&request, NULL, HTTP_HEAD, URL);
6331 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6332 +               http_request_exec(&request);
6333 +               if (info) {
6334 +                       http_request_info(&request, Z_ARRVAL_P(info));
6335 +               }
6336 +               RETVAL_RESPONSE_OR_BODY(request);
6337 +       }
6338 +       http_request_dtor(&request);
6339 +}
6340 +/* }}} */
6341 +
6342 +/* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
6343 +       Performs an HTTP POST request on the supplied url. */
6344 +PHP_FUNCTION(http_post_data)
6345 +{
6346 +       zval *options = NULL, *info = NULL;
6347 +       char *URL, *postdata;
6348 +       int postdata_len, URL_len;
6349 +       http_request_body body;
6350 +       http_request request;
6351 +
6352 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
6353 +               RETURN_FALSE;
6354 +       }
6355 +
6356 +       if (info) {
6357 +               zval_dtor(info);
6358 +               array_init(info);
6359 +       }
6360 +
6361 +       RETVAL_FALSE;
6362 +
6363 +       http_request_init_ex(&request, NULL, HTTP_POST, URL);
6364 +       request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, postdata, postdata_len, 0);
6365 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6366 +               http_request_exec(&request);
6367 +               if (info) {
6368 +                       http_request_info(&request, Z_ARRVAL_P(info));
6369 +               }
6370 +               RETVAL_RESPONSE_OR_BODY(request);
6371 +       }
6372 +       http_request_dtor(&request);
6373 +}
6374 +/* }}} */
6375 +
6376 +/* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]])
6377 +       Performs an HTTP POST request on the supplied url. */
6378 +PHP_FUNCTION(http_post_fields)
6379 +{
6380 +       zval *options = NULL, *info = NULL, *fields = NULL, *files = NULL;
6381 +       char *URL;
6382 +       int URL_len;
6383 +       http_request_body body;
6384 +       http_request request;
6385 +
6386 +       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa!|a!a/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) {
6387 +               RETURN_FALSE;
6388 +       }
6389 +
6390 +       if (!http_request_body_fill(&body, fields ? Z_ARRVAL_P(fields) : NULL, files ? Z_ARRVAL_P(files) : NULL)) {
6391 +               RETURN_FALSE;
6392 +       }
6393 +
6394 +       if (info) {
6395 +               zval_dtor(info);
6396 +               array_init(info);
6397 +       }
6398 +
6399 +       RETVAL_FALSE;
6400 +
6401 +       http_request_init_ex(&request, NULL, HTTP_POST, URL);
6402 +       request.body = &body;
6403 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6404 +               http_request_exec(&request);
6405 +               if (info) {
6406 +                       http_request_info(&request, Z_ARRVAL_P(info));
6407 +               }
6408 +               RETVAL_RESPONSE_OR_BODY(request);
6409 +       }
6410 +       http_request_dtor(&request);
6411 +}
6412 +/* }}} */
6413 +
6414 +/* {{{ proto string http_put_file(string url, string file[, array options[, array &info]])
6415 +       Performs an HTTP PUT request on the supplied url. */
6416 +PHP_FUNCTION(http_put_file)
6417 +{
6418 +       char *URL, *file;
6419 +       int URL_len, f_len;
6420 +       zval *options = NULL, *info = NULL;
6421 +       php_stream *stream;
6422 +       php_stream_statbuf ssb;
6423 +       http_request_body body;
6424 +       http_request request;
6425 +
6426 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &file, &f_len, &options, &info)) {
6427 +               RETURN_FALSE;
6428 +       }
6429 +
6430 +       if (!(stream = php_stream_open_wrapper_ex(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT))) {
6431 +               RETURN_FALSE;
6432 +       }
6433 +       if (php_stream_stat(stream, &ssb)) {
6434 +               php_stream_close(stream);
6435 +               RETURN_FALSE;
6436 +       }
6437 +
6438 +       if (info) {
6439 +               zval_dtor(info);
6440 +               array_init(info);
6441 +       }
6442 +
6443 +       RETVAL_FALSE;
6444 +
6445 +       http_request_init_ex(&request, NULL, HTTP_PUT, URL);
6446 +       request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 1);
6447 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6448 +               http_request_exec(&request);
6449 +               if (info) {
6450 +                       http_request_info(&request, Z_ARRVAL_P(info));
6451 +               }
6452 +               RETVAL_RESPONSE_OR_BODY(request);
6453 +       }
6454 +       http_request_dtor(&request);
6455 +}
6456 +/* }}} */
6457 +
6458 +/* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]])
6459 +       Performs an HTTP PUT request on the supplied url. */
6460 +PHP_FUNCTION(http_put_stream)
6461 +{
6462 +       zval *resource, *options = NULL, *info = NULL;
6463 +       char *URL;
6464 +       int URL_len;
6465 +       php_stream *stream;
6466 +       php_stream_statbuf ssb;
6467 +       http_request_body body;
6468 +       http_request request;
6469 +
6470 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr|a/!z", &URL, &URL_len, &resource, &options, &info)) {
6471 +               RETURN_FALSE;
6472 +       }
6473 +
6474 +       php_stream_from_zval(stream, &resource);
6475 +       if (php_stream_stat(stream, &ssb)) {
6476 +               RETURN_FALSE;
6477 +       }
6478 +
6479 +       if (info) {
6480 +               zval_dtor(info);
6481 +               array_init(info);
6482 +       }
6483 +
6484 +       RETVAL_FALSE;
6485 +
6486 +       http_request_init_ex(&request, NULL, HTTP_PUT, URL);
6487 +       request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 0);
6488 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6489 +               http_request_exec(&request);
6490 +               if (info) {
6491 +                       http_request_info(&request, Z_ARRVAL_P(info));
6492 +               }
6493 +               RETVAL_RESPONSE_OR_BODY(request);
6494 +       }
6495 +       http_request_dtor(&request);
6496 +}
6497 +/* }}} */
6498 +
6499 +/* {{{ proto string http_put_data(string url, string data[, array options[, array &info]])
6500 +       Performs an HTTP PUT request on the supplied url. */
6501 +PHP_FUNCTION(http_put_data)
6502 +{
6503 +       char *URL, *data;
6504 +       int URL_len, data_len;
6505 +       zval *options = NULL, *info = NULL;
6506 +       http_request_body body;
6507 +       http_request request;
6508 +       
6509 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &data, &data_len, &options, &info)) {
6510 +               RETURN_FALSE;
6511 +       }
6512 +       
6513 +       if (info) {
6514 +               zval_dtor(info);
6515 +               array_init(info);
6516 +       }
6517 +       
6518 +       RETVAL_FALSE;
6519 +       
6520 +       http_request_init_ex(&request, NULL, HTTP_PUT, URL);
6521 +       request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0);
6522 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6523 +               http_request_exec(&request);
6524 +               if (info) {
6525 +                       http_request_info(&request, Z_ARRVAL_P(info));
6526 +               }
6527 +               RETVAL_RESPONSE_OR_BODY(request);
6528 +       }
6529 +       http_request_dtor(&request);
6530 +}
6531 +/* }}} */
6532 +
6533 +/* {{{ proto string http_request(int method, string url[, string body[, array options[, array &info]]])
6534 +       Performs a custom HTTP request on the supplied url. */
6535 +PHP_FUNCTION(http_request)
6536 +{
6537 +       long meth;
6538 +       char *URL, *data = NULL;
6539 +       int URL_len, data_len = 0;
6540 +       zval *options = NULL, *info = NULL;
6541 +       http_request_body body;
6542 +       http_request request;
6543 +       
6544 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls|sa/!z", &meth, &URL, &URL_len, &data, &data_len, &options, &info)) {
6545 +               RETURN_FALSE;
6546 +       }
6547 +       
6548 +       if (info) {
6549 +               zval_dtor(info);
6550 +               array_init(info);
6551 +       }
6552 +       
6553 +       RETVAL_FALSE;
6554 +       
6555 +       http_request_init_ex(&request, NULL, meth, URL);
6556 +       request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0);
6557 +       if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) {
6558 +               http_request_exec(&request);
6559 +               if (info) {
6560 +                       http_request_info(&request, Z_ARRVAL_P(info));
6561 +               }
6562 +               RETVAL_RESPONSE_OR_BODY(request);
6563 +       }
6564 +       http_request_dtor(&request);
6565 +}
6566 +/* }}} */
6567 +
6568 +/* {{{ proto string http_request_body_encode(array fields, array files)
6569 +       Generate x-www-form-urlencoded resp. form-data encoded request body. */
6570 +PHP_FUNCTION(http_request_body_encode)
6571 +{
6572 +       zval *fields = NULL, *files = NULL;
6573 +       HashTable *fields_ht, *files_ht;
6574 +       http_request_body body;
6575 +       char *buf;
6576 +       size_t len;
6577 +       
6578 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!", &fields, &files)) {
6579 +               RETURN_FALSE;
6580 +       }
6581 +       
6582 +       fields_ht = (fields && Z_TYPE_P(fields) == IS_ARRAY) ? Z_ARRVAL_P(fields) : NULL;
6583 +       files_ht = (files && Z_TYPE_P(files) == IS_ARRAY) ? Z_ARRVAL_P(files) : NULL;
6584 +       if (http_request_body_fill(&body, fields_ht, files_ht) && (SUCCESS == http_request_body_encode(&body, &buf, &len))) {
6585 +               RETVAL_STRINGL(buf, len, 0);
6586 +       } else {
6587 +               http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not encode request body");
6588 +               RETVAL_FALSE;
6589 +       }
6590 +       http_request_body_dtor(&body);
6591 +}
6592 +#endif /* HTTP_HAVE_CURL */
6593 +/* }}} HAVE_CURL */
6594 +
6595 +/* {{{ proto int http_request_method_register(string method)
6596 +       Register a custom request method. */
6597 +PHP_FUNCTION(http_request_method_register)
6598 +{
6599 +       char *method;
6600 +       int method_len;
6601 +       ulong existing;
6602 +
6603 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
6604 +               RETURN_FALSE;
6605 +       }
6606 +       if ((existing = http_request_method_exists(1, 0, method))) {
6607 +               RETURN_LONG((long) existing);
6608 +       }
6609 +
6610 +       RETVAL_LONG((long) http_request_method_register(method, method_len));
6611 +}
6612 +/* }}} */
6613 +
6614 +/* {{{ proto bool http_request_method_unregister(mixed method)
6615 +       Unregister a previously registered custom request method. */
6616 +PHP_FUNCTION(http_request_method_unregister)
6617 +{
6618 +       zval *method;
6619 +
6620 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
6621 +               RETURN_FALSE;
6622 +       }
6623 +
6624 +       switch (Z_TYPE_P(method)) {
6625 +               case IS_OBJECT:
6626 +                       convert_to_string(method);
6627 +               case IS_STRING:
6628 +                       if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
6629 +                               convert_to_long(method);
6630 +                       } else {
6631 +                               int mn;
6632 +                               if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) {
6633 +                                       RETURN_FALSE;
6634 +                               }
6635 +                               zval_dtor(method);
6636 +                               ZVAL_LONG(method, (long)mn);
6637 +                       }
6638 +               case IS_LONG:
6639 +                       RETURN_SUCCESS(http_request_method_unregister(Z_LVAL_P(method)));
6640 +               default:
6641 +                       RETURN_FALSE;
6642 +       }
6643 +}
6644 +/* }}} */
6645 +
6646 +/* {{{ proto int http_request_method_exists(mixed method)
6647 +       Check if a request method is registered (or available by default). */
6648 +PHP_FUNCTION(http_request_method_exists)
6649 +{
6650 +       if (return_value_used) {
6651 +               zval *method;
6652 +
6653 +               if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) {
6654 +                       RETURN_FALSE;
6655 +               }
6656 +
6657 +               switch (Z_TYPE_P(method)) {
6658 +                       case IS_OBJECT:
6659 +                               convert_to_string(method);
6660 +                       case IS_STRING:
6661 +                               if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) {
6662 +                                       convert_to_long(method);
6663 +                               } else {
6664 +                                       RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method)));
6665 +                               }
6666 +                       case IS_LONG:
6667 +                               RETURN_LONG((long) http_request_method_exists(0, (int) Z_LVAL_P(method), NULL));
6668 +                       default:
6669 +                               RETURN_FALSE;
6670 +               }
6671 +       }
6672 +}
6673 +/* }}} */
6674 +
6675 +/* {{{ proto string http_request_method_name(int method)
6676 +       Get the literal string representation of a standard or registered request method. */
6677 +PHP_FUNCTION(http_request_method_name)
6678 +{
6679 +       if (return_value_used) {
6680 +               long method;
6681 +
6682 +               if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) {
6683 +                       RETURN_FALSE;
6684 +               }
6685 +
6686 +               RETURN_STRING(estrdup(http_request_method_name((int) method)), 0);
6687 +       }
6688 +}
6689 +/* }}} */
6690 +
6691 +/* {{{ */
6692 +#ifdef HTTP_HAVE_ZLIB
6693 +
6694 +/* {{{  proto string http_deflate(string data[, int flags = 0])
6695 +       Compress data with gzip, zlib AKA deflate or raw deflate encoding. */
6696 +PHP_FUNCTION(http_deflate)
6697 +{
6698 +       char *data;
6699 +       int data_len;
6700 +       long flags = 0;
6701 +       
6702 +       RETVAL_NULL();
6703 +       
6704 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &flags)) {
6705 +               char *encoded;
6706 +               size_t encoded_len;
6707 +               
6708 +               if (SUCCESS == http_encoding_deflate(flags, data, data_len, &encoded, &encoded_len)) {
6709 +                       RETURN_STRINGL(encoded, (int) encoded_len, 0);
6710 +               }
6711 +       }
6712 +}
6713 +/* }}} */
6714 +
6715 +/* {{{ proto string http_inflate(string data)
6716 +       Decompress data compressed with either gzip, deflate AKA zlib or raw deflate encoding. */
6717 +PHP_FUNCTION(http_inflate)
6718 +{
6719 +       char *data;
6720 +       int data_len;
6721 +       
6722 +       RETVAL_NULL();
6723 +       
6724 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
6725 +               char *decoded;
6726 +               size_t decoded_len;
6727 +               
6728 +               if (SUCCESS == http_encoding_inflate(data, data_len, &decoded, &decoded_len)) {
6729 +                       RETURN_STRINGL(decoded, (int) decoded_len, 0);
6730 +               }
6731 +       }
6732 +}
6733 +/* }}} */
6734 +
6735 +/* {{{ proto string ob_deflatehandler(string data, int mode)
6736 +       For use with ob_start(). The deflate output buffer handler can only be used once. */
6737 +PHP_FUNCTION(ob_deflatehandler)
6738 +{
6739 +       char *data;
6740 +       int data_len;
6741 +       long mode;
6742 +
6743 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
6744 +               RETURN_FALSE;
6745 +       }
6746 +
6747 +       http_ob_deflatehandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
6748 +       Z_TYPE_P(return_value) = Z_STRVAL_P(return_value) ? IS_STRING : IS_NULL;
6749 +}
6750 +/* }}} */
6751 +
6752 +/* {{{ proto string ob_inflatehandler(string data, int mode)
6753 +       For use with ob_start().  Same restrictions as with ob_deflatehandler apply. */
6754 +PHP_FUNCTION(ob_inflatehandler)
6755 +{
6756 +       char *data;
6757 +       int data_len;
6758 +       long mode;
6759 +       
6760 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
6761 +               RETURN_FALSE;
6762 +       }
6763 +       
6764 +       http_ob_inflatehandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode);
6765 +       Z_TYPE_P(return_value) = Z_STRVAL_P(return_value) ? IS_STRING : IS_NULL;
6766 +}
6767 +/* }}} */
6768 +
6769 +#endif /* HTTP_HAVE_ZLIB */
6770 +/* }}} */
6771 +
6772 +/* {{{ proto int http_support([int feature = 0])
6773 +       Check for feature that require external libraries. */
6774 +PHP_FUNCTION(http_support)
6775 +{
6776 +       long feature = 0;
6777 +       
6778 +       RETVAL_LONG(0L);
6779 +       
6780 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &feature)) {
6781 +               RETVAL_LONG(http_support(feature));
6782 +       }
6783 +}
6784 +/* }}} */
6785 +
6786 +/*
6787 + * Local variables:
6788 + * tab-width: 4
6789 + * c-basic-offset: 4
6790 + * End:
6791 + * vim600: noet sw=4 ts=4 fdm=marker
6792 + * vim<600: noet sw=4 ts=4
6793 + */
6794 +
6795 --- /dev/null
6796 +++ b/ext/http/http_headers_api.c
6797 @@ -0,0 +1,534 @@
6798 +/*
6799 +    +--------------------------------------------------------------------+
6800 +    | PECL :: http                                                       |
6801 +    +--------------------------------------------------------------------+
6802 +    | Redistribution and use in source and binary forms, with or without |
6803 +    | modification, are permitted provided that the conditions mentioned |
6804 +    | in the accompanying LICENSE file are met.                          |
6805 +    +--------------------------------------------------------------------+
6806 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
6807 +    +--------------------------------------------------------------------+
6808 +*/
6809 +
6810 +/* $Id: http_headers_api.c 300300 2010-06-09 07:29:35Z mike $ */
6811 +
6812 +#define HTTP_WANT_SAPI
6813 +#include "php_http.h"
6814 +
6815 +#include "ext/standard/url.h"
6816 +#include "ext/standard/php_string.h"
6817 +
6818 +#include "php_http_api.h"
6819 +#include "php_http_headers_api.h"
6820 +
6821 +#ifndef HTTP_DBG_NEG
6822 +#      define HTTP_DBG_NEG 0
6823 +#endif
6824 +
6825 +/* {{{ static void http_grab_response_headers(void *, void *) */
6826 +static void http_grab_response_headers(void *data, void *arg TSRMLS_DC)
6827 +{
6828 +       phpstr_appendl(PHPSTR(arg), ((sapi_header_struct *)data)->header);
6829 +       phpstr_appends(PHPSTR(arg), HTTP_CRLF);
6830 +}
6831 +/* }}} */
6832 +
6833 +/* {{{ static int http_sort_q(const void *, const void *) */
6834 +static int http_sort_q(const void *a, const void *b TSRMLS_DC)
6835 +{
6836 +       Bucket *f, *s;
6837 +       zval result, *first, *second;
6838 +
6839 +       f = *((Bucket **) a);
6840 +       s = *((Bucket **) b);
6841 +
6842 +       first = *((zval **) f->pData);
6843 +       second= *((zval **) s->pData);
6844 +
6845 +       if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
6846 +               return 0;
6847 +       }
6848 +       return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
6849 +}
6850 +/* }}} */
6851 +
6852 +/* {{{ char *http_negotiate_language_func */
6853 +char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
6854 +{
6855 +       zval **value;
6856 +       HashPosition pos;
6857 +       const char *dash_test;
6858 +       
6859 +       FOREACH_HASH_VAL(pos, supported, value) {
6860 +#if HTTP_DBG_NEG
6861 +               fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
6862 +#endif
6863 +               if (!strcasecmp(Z_STRVAL_PP(value), test)) {
6864 +                       return Z_STRVAL_PP(value);
6865 +               }
6866 +       }
6867 +       
6868 +       /* no distinct match found, so try primaries */
6869 +       if ((dash_test = strchr(test, '-'))) {
6870 +               FOREACH_HASH_VAL(pos, supported, value) {
6871 +                       int len = dash_test - test;
6872 +#if HTTP_DBG_NEG
6873 +                       fprintf(stderr, "strncasecmp('%s', '%s', %d)\n", Z_STRVAL_PP(value), test, len);
6874 +#endif
6875 +                       if (    (!strncasecmp(Z_STRVAL_PP(value), test, len)) &&
6876 +                                       (       (Z_STRVAL_PP(value)[len] == '\0') || 
6877 +                                               (Z_STRVAL_PP(value)[len] == '-'))) {
6878 +                               *quality *= .9;
6879 +                               return Z_STRVAL_PP(value);
6880 +                       }
6881 +               }
6882 +       }
6883 +       
6884 +       return NULL;
6885 +}
6886 +/* }}} */
6887 +
6888 +/* {{{ char *http_negotiate_default_func */
6889 +char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
6890 +{
6891 +       zval **value;
6892 +       HashPosition pos;
6893 +       
6894 +       FOREACH_HASH_VAL(pos, supported, value) {
6895 +#if HTTP_DBG_NEG
6896 +               fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
6897 +#endif
6898 +               if (!strcasecmp(Z_STRVAL_PP(value), test)) {
6899 +                       return Z_STRVAL_PP(value);
6900 +               }
6901 +       }
6902 +       
6903 +       return NULL;
6904 +}
6905 +/* }}} */
6906 +
6907 +/* {{{ HashTable *http_negotiate_z(zval *, HashTable *, negotiate_func_t) */
6908 +PHP_HTTP_API HashTable *_http_negotiate_z(zval *value, HashTable *supported, negotiate_func_t neg TSRMLS_DC)
6909 +{
6910 +       zval *accept = http_zsep(IS_STRING, value);
6911 +       HashTable *result = NULL;
6912 +
6913 +       if (Z_STRLEN_P(accept)) {
6914 +               zval ex_arr, ex_del;
6915 +
6916 +               INIT_PZVAL(&ex_del);
6917 +               INIT_PZVAL(&ex_arr);
6918 +               ZVAL_STRINGL(&ex_del, ",", 1, 0);
6919 +               array_init(&ex_arr);
6920 +
6921 +               php_explode(&ex_del, accept, &ex_arr, INT_MAX);
6922 +
6923 +               if (zend_hash_num_elements(Z_ARRVAL(ex_arr)) > 0) {
6924 +                       int i = 0;
6925 +                       HashPosition pos;
6926 +                       zval **entry, array;
6927 +
6928 +                       INIT_PZVAL(&array);
6929 +                       array_init(&array);
6930 +
6931 +                       FOREACH_HASH_VAL(pos, Z_ARRVAL(ex_arr), entry) {
6932 +                               int ident_len;
6933 +                               double quality;
6934 +                               char *selected, *identifier, *freeme;
6935 +                               const char *separator;
6936 +
6937 +#if HTTP_DBG_NEG
6938 +                               fprintf(stderr, "Checking %s\n", Z_STRVAL_PP(entry));
6939 +#endif
6940 +
6941 +                               if ((separator = strchr(Z_STRVAL_PP(entry), ';'))) {
6942 +                                       const char *ptr = separator;
6943 +
6944 +                                       while (*++ptr && !HTTP_IS_CTYPE(digit, *ptr) && '.' != *ptr);
6945 +
6946 +                                       quality = zend_strtod(ptr, NULL);
6947 +                                       identifier = estrndup(Z_STRVAL_PP(entry), ident_len = separator - Z_STRVAL_PP(entry));
6948 +                               } else {
6949 +                                       quality = 1000.0 - i++;
6950 +                                       identifier = estrndup(Z_STRVAL_PP(entry), ident_len = Z_STRLEN_PP(entry));
6951 +                               }
6952 +                               freeme = identifier;
6953 +
6954 +                               while (HTTP_IS_CTYPE(space, *identifier)) {
6955 +                                       ++identifier;
6956 +                                       --ident_len;
6957 +                               }
6958 +                               while (ident_len && HTTP_IS_CTYPE(space, identifier[ident_len - 1])) {
6959 +                                       identifier[--ident_len] = '\0';
6960 +                               }
6961 +
6962 +                               if ((selected = neg(identifier, &quality, supported TSRMLS_CC))) {
6963 +                                       /* don't overwrite previously set with higher quality */
6964 +                                       if (!zend_hash_exists(Z_ARRVAL(array), selected, strlen(selected) + 1)) {
6965 +                                               add_assoc_double(&array, selected, quality);
6966 +                                       }
6967 +                               }
6968 +
6969 +                               efree(freeme);
6970 +                       }
6971 +
6972 +                       result = Z_ARRVAL(array);
6973 +                       zend_hash_sort(result, zend_qsort, http_sort_q, 0 TSRMLS_CC);
6974 +               }
6975 +
6976 +               zval_dtor(&ex_arr);
6977 +       }
6978 +
6979 +       zval_ptr_dtor(&accept);
6980 +
6981 +       return result;
6982 +}
6983 +/* }}} */
6984 +
6985 +/* {{{ HashTable *http_negotiate_q(const char *, HashTable *, negotiate_func_t) */
6986 +PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC)
6987 +{
6988 +       zval *accept;
6989 +       
6990 +#if HTTP_DBG_NEG
6991 +       fprintf(stderr, "Reading header %s: ", header);
6992 +#endif
6993 +       if (!(accept = http_get_server_var(header, 1))) {
6994 +               return NULL;
6995 +       }
6996 +#if HTTP_DBG_NEG
6997 +       fprintf(stderr, "%s\n", Z_STRVAL_P(accept));
6998 +#endif
6999 +       
7000 +       return http_negotiate_z(accept, supported, neg);
7001 +}
7002 +/* }}} */
7003 +
7004 +/* {{{ http_range_status http_get_request_ranges(HashTable *ranges, size_t) */
7005 +PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, size_t length TSRMLS_DC)
7006 +{
7007 +       zval *zrange;
7008 +       char *range, c;
7009 +       long begin = -1, end = -1, *ptr;
7010 +
7011 +       if (    !(zrange = http_get_server_var("HTTP_RANGE", 1)) || 
7012 +                       (size_t) Z_STRLEN_P(zrange) < lenof("bytes=") || strncmp(Z_STRVAL_P(zrange), "bytes=", lenof("bytes="))) {
7013 +               return RANGE_NO;
7014 +       }
7015 +       range = Z_STRVAL_P(zrange) + lenof("bytes=");
7016 +       ptr = &begin;
7017 +
7018 +       do {
7019 +               switch (c = *(range++)) {
7020 +                       case '0':
7021 +                               /* allow 000... - shall we? */
7022 +                               if (*ptr != -10) {
7023 +                                       *ptr *= 10;
7024 +                               }
7025 +                               break;
7026 +
7027 +                       case '1': case '2': case '3':
7028 +                       case '4': case '5': case '6':
7029 +                       case '7': case '8': case '9':
7030 +                               /*
7031 +                                * If the value of the pointer is already set (non-negative)
7032 +                                * then multiply its value by ten and add the current value,
7033 +                                * else initialise the pointers value with the current value
7034 +                                * --
7035 +                                * This let us recognize empty fields when validating the
7036 +                                * ranges, i.e. a "-10" for begin and "12345" for the end
7037 +                                * was the following range request: "Range: bytes=0-12345";
7038 +                                * While a "-1" for begin and "12345" for the end would
7039 +                                * have been: "Range: bytes=-12345".
7040 +                                */
7041 +                               if (*ptr > 0) {
7042 +                                       *ptr *= 10;
7043 +                                       *ptr += c - '0';
7044 +                               } else {
7045 +                                       *ptr = c - '0';
7046 +                               }
7047 +                               break;
7048 +
7049 +                       case '-':
7050 +                               ptr = &end;
7051 +                               break;
7052 +
7053 +                       case ' ':
7054 +                               break;
7055 +
7056 +                       case 0:
7057 +                       case ',':
7058 +
7059 +                               if (length) {
7060 +                                       /* validate ranges */
7061 +                                       switch (begin) {
7062 +                                               /* "0-12345" */
7063 +                                               case -10:
7064 +                                                       switch (end) {
7065 +                                                               /* "0-" */
7066 +                                                               case -1:
7067 +                                                                       return RANGE_NO;
7068 +                                                                       
7069 +                                                               /* "0-0" */
7070 +                                                               case -10:
7071 +                                                                       end = 0;
7072 +                                                                       break;
7073 +                                                                       
7074 +                                                               default:
7075 +                                                                       if (length <= (size_t) end) {
7076 +                                                                               return RANGE_ERR;
7077 +                                                                       }
7078 +                                                                       break;
7079 +                                                       }
7080 +                                                       begin = 0;
7081 +                                                       break;
7082 +
7083 +                                               /* "-12345" */
7084 +                                               case -1:
7085 +                                                       /* "-", "-0" or overflow */
7086 +                                                       if (end == -1 || end == -10 || length <= (size_t) end) {
7087 +                                                               return RANGE_ERR;
7088 +                                                       }
7089 +                                                       begin = length - end;
7090 +                                                       end = length - 1;
7091 +                                                       break;
7092 +
7093 +                                               /* "12345-(xxx)" */
7094 +                                               default:
7095 +                                                       switch (end) {
7096 +                                                               /* "12345-0" */
7097 +                                                               case -10:
7098 +                                                                       return RANGE_ERR;
7099 +
7100 +                                                               /* "12345-" */
7101 +                                                               case -1:
7102 +                                                                       if (length <= (size_t) begin) {
7103 +                                                                               return RANGE_ERR;
7104 +                                                                       }
7105 +                                                                       end = length - 1;
7106 +                                                                       break;
7107 +
7108 +                                                               /* "12345-67890" */
7109 +                                                               default:
7110 +                                                                       if (    (length <= (size_t) begin) ||
7111 +                                                                                       (length <= (size_t) end)   ||
7112 +                                                                                       (end    <  begin)) {
7113 +                                                                               return RANGE_ERR;
7114 +                                                                       }
7115 +                                                                       break;
7116 +                                                       }
7117 +                                                       break;
7118 +                                       }
7119 +                               }
7120 +                               {
7121 +                                       zval *zentry;
7122 +                                       MAKE_STD_ZVAL(zentry);
7123 +                                       array_init(zentry);
7124 +                                       add_index_long(zentry, 0, begin);
7125 +                                       add_index_long(zentry, 1, end);
7126 +                                       zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL);
7127 +
7128 +                                       begin = -1;
7129 +                                       end = -1;
7130 +                                       ptr = &begin;
7131 +                               }
7132 +                               break;
7133 +
7134 +                       default:
7135 +                               return RANGE_NO;
7136 +               }
7137 +       } while (c != 0);
7138 +
7139 +       return RANGE_OK;
7140 +}
7141 +/* }}} */
7142 +
7143 +/* {{{ STATUS http_parse_headers(char *, HashTable *, zend_bool) */
7144 +PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, 
7145 +       http_info_callback callback_func, void **callback_data TSRMLS_DC)
7146 +{
7147 +       const char *colon = NULL, *line = NULL;
7148 +       zval array;
7149 +       
7150 +       INIT_ZARR(array, headers);
7151 +       
7152 +       /* skip leading ws */
7153 +       while (HTTP_IS_CTYPE(space, *header)) ++header;
7154 +       line = header;
7155 +       
7156 +#define MORE_HEADERS (*(line-1) && !(*(line-1) == '\n' && (*line == '\n' || *line == '\r')))
7157 +       do {
7158 +               int value_len = 0;
7159 +               
7160 +               switch (*line++) {
7161 +                       case ':':
7162 +                               if (!colon) {
7163 +                                       colon = line - 1;
7164 +                               }
7165 +                               break;
7166 +                       
7167 +                       case 0:
7168 +                               --value_len; /* we don't have CR so value length is one char less */
7169 +                       case '\n':
7170 +                               if ((!*(line - 1)) || ((*line != ' ') && (*line != '\t'))) {
7171 +                                       http_info i;
7172 +                                       
7173 +                                       if (SUCCESS == http_info_parse(header, &i)) {
7174 +                                               /* response/request line */
7175 +                                               callback_func(callback_data, &headers, &i TSRMLS_CC);
7176 +                                               http_info_dtor(&i);
7177 +                                               Z_ARRVAL(array) = headers;
7178 +                                       } else if (colon) {
7179 +                                               /* "header: value" pair */
7180 +                                               if (header != colon) {
7181 +                                                       int keylen = colon - header;
7182 +                                                       const char *key = header;
7183 +                                                       
7184 +                                                       /* skip leading ws */
7185 +                                                       while (keylen && HTTP_IS_CTYPE(space, *key)) --keylen, ++key;
7186 +                                                       /* skip trailing ws */
7187 +                                                       while (keylen && HTTP_IS_CTYPE(space, key[keylen - 1])) --keylen;
7188 +                                                       
7189 +                                                       if (keylen > 0) {
7190 +                                                               zval **previous = NULL;
7191 +                                                               char *value;
7192 +                                                               char *keydup = estrndup(key, keylen);
7193 +                                                               
7194 +                                                               if (prettify) {
7195 +                                                                       keydup = pretty_key(keydup, keylen, 1, 1);
7196 +                                                               }
7197 +                                                               
7198 +                                                               value_len += line - colon - 1;
7199 +                                                               
7200 +                                                               /* skip leading ws */
7201 +                                                               while (HTTP_IS_CTYPE(space, *(++colon))) --value_len;
7202 +                                                               /* skip trailing ws */
7203 +                                                               while (HTTP_IS_CTYPE(space, colon[value_len - 1])) --value_len;
7204 +                                                               
7205 +                                                               if (value_len > 0) {
7206 +                                                                       value = estrndup(colon, value_len);
7207 +                                                               } else {
7208 +                                                                       value = estrdup("");
7209 +                                                                       value_len = 0;
7210 +                                                               }
7211 +                                                               
7212 +                                                               /* if we already have got such a header make an array of those */
7213 +                                                               if (SUCCESS == zend_hash_find(headers, keydup, keylen + 1, (void *) &previous)) {
7214 +                                                                       /* convert to array */
7215 +                                                                       if (Z_TYPE_PP(previous) != IS_ARRAY) {
7216 +                                                                               convert_to_array(*previous);
7217 +                                                                       }
7218 +                                                                       add_next_index_stringl(*previous, value, value_len, 0);
7219 +                                                               } else {
7220 +                                                                       add_assoc_stringl(&array, keydup, value, value_len, 0);
7221 +                                                               }
7222 +                                                               efree(keydup);
7223 +                                                       } else   {
7224 +                                                               /* empty key ("   : ...") */
7225 +                                                               return FAILURE;
7226 +                                                       }
7227 +                                               } else {
7228 +                                                       /* empty key (": ...") */
7229 +                                                       return FAILURE;
7230 +                                               }
7231 +                                       } else if (MORE_HEADERS) {
7232 +                                               /* a line without a colon */
7233 +                                               return FAILURE;
7234 +                                       }
7235 +                                       colon = NULL;
7236 +                                       value_len = 0;
7237 +                                       header += line - header;
7238 +                               }
7239 +                               break;
7240 +               }
7241 +       } while (MORE_HEADERS);
7242 +
7243 +       return SUCCESS;
7244 +}
7245 +/* }}} */
7246 +
7247 +/* {{{ void http_get_request_headers(HashTable *) */
7248 +PHP_HTTP_API void _http_get_request_headers(HashTable *headers TSRMLS_DC)
7249 +{
7250 +       HashKey key = initHashKey(0);
7251 +       zval **hsv, **header;
7252 +       HashPosition pos;
7253 +       
7254 +       if (!HTTP_G->request.headers) {
7255 +               ALLOC_HASHTABLE(HTTP_G->request.headers);
7256 +               zend_hash_init(HTTP_G->request.headers, 0, NULL, ZVAL_PTR_DTOR, 0);
7257 +               
7258 +#ifdef ZEND_ENGINE_2
7259 +               zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
7260 +#endif
7261 +               
7262 +               if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) {
7263 +                       FOREACH_KEY(pos, *hsv, key) {
7264 +                               if (key.type == HASH_KEY_IS_STRING && key.len > 6 && !strncmp(key.str, "HTTP_", 5)) {
7265 +                                       key.len -= 5;
7266 +                                       key.str = pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1);
7267 +                                       
7268 +                                       zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
7269 +                                       ZVAL_ADDREF(*header);
7270 +                                       zend_hash_add(HTTP_G->request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
7271 +                                       
7272 +                                       efree(key.str);
7273 +                               }
7274 +                       }
7275 +               }
7276 +       }
7277 +       
7278 +       if (headers) {
7279 +               zend_hash_copy(headers, HTTP_G->request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
7280 +       }
7281 +}
7282 +/* }}} */
7283 +
7284 +/* {{{ STATUS http_get_response_headers(HashTable *) */
7285 +PHP_HTTP_API STATUS _http_get_response_headers(HashTable *headers_ht TSRMLS_DC)
7286 +{
7287 +       STATUS status;
7288 +       phpstr headers;
7289 +       
7290 +       phpstr_init(&headers);
7291 +       zend_llist_apply_with_argument(&SG(sapi_headers).headers, http_grab_response_headers, &headers TSRMLS_CC);
7292 +       phpstr_fix(&headers);
7293 +       
7294 +       status = http_parse_headers_ex(PHPSTR_VAL(&headers), headers_ht, 1);
7295 +       phpstr_dtor(&headers);
7296 +       
7297 +       return status;
7298 +}
7299 +/* }}} */
7300 +
7301 +/* {{{ zend_bool http_match_request_header(char *, char *) */
7302 +PHP_HTTP_API zend_bool _http_match_request_header_ex(const char *header, const char *value, zend_bool match_case TSRMLS_DC)
7303 +{
7304 +       char *name;
7305 +       uint name_len = strlen(header);
7306 +       zend_bool result = 0;
7307 +       zval **data, *zvalue;
7308 +
7309 +       http_get_request_headers(NULL);
7310 +       name = pretty_key(estrndup(header, name_len), name_len, 1, 1);
7311 +       if (SUCCESS == zend_hash_find(HTTP_G->request.headers, name, name_len+1, (void *) &data)) {
7312 +               zvalue = http_zsep(IS_STRING, *data);
7313 +               result = (match_case ? strcmp(Z_STRVAL_P(zvalue), value) : strcasecmp(Z_STRVAL_P(zvalue), value)) ? 0 : 1;
7314 +               zval_ptr_dtor(&zvalue);
7315 +       }
7316 +       efree(name);
7317 +
7318 +       return result;
7319 +}
7320 +/* }}} */
7321 +
7322 +
7323 +/*
7324 + * Local variables:
7325 + * tab-width: 4
7326 + * c-basic-offset: 4
7327 + * End:
7328 + * vim600: noet sw=4 ts=4 fdm=marker
7329 + * vim<600: noet sw=4 ts=4
7330 + */
7331 +
7332 --- /dev/null
7333 +++ b/ext/http/http_inflatestream_object.c
7334 @@ -0,0 +1,292 @@
7335 +/*
7336 +    +--------------------------------------------------------------------+
7337 +    | PECL :: http                                                       |
7338 +    +--------------------------------------------------------------------+
7339 +    | Redistribution and use in source and binary forms, with or without |
7340 +    | modification, are permitted provided that the conditions mentioned |
7341 +    | in the accompanying LICENSE file are met.                          |
7342 +    +--------------------------------------------------------------------+
7343 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
7344 +    +--------------------------------------------------------------------+
7345 +*/
7346 +
7347 +/* $Id: http_inflatestream_object.c 300299 2010-06-09 06:23:16Z mike $ */
7348 +
7349 +#define HTTP_WANT_ZLIB
7350 +#include "php_http.h"
7351 +
7352 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_ZLIB)
7353 +
7354 +#include "php_http_api.h"
7355 +#include "php_http_encoding_api.h"
7356 +#include "php_http_exception_object.h"
7357 +#include "php_http_inflatestream_object.h"
7358 +
7359 +#define HTTP_BEGIN_ARGS(method, req_args)      HTTP_BEGIN_ARGS_EX(HttpInflateStream, method, 0, req_args)
7360 +#define HTTP_EMPTY_ARGS(method)                                HTTP_EMPTY_ARGS_EX(HttpInflateStream, method, 0)
7361 +#define HTTP_INFLATE_ME(method, visibility)    PHP_ME(HttpInflateStream, method, HTTP_ARGS(HttpInflateStream, method), visibility)
7362 +
7363 +HTTP_BEGIN_ARGS(__construct, 0)
7364 +       HTTP_ARG_VAL(flags, 0)
7365 +HTTP_END_ARGS;
7366 +
7367 +HTTP_BEGIN_ARGS(factory, 0)
7368 +       HTTP_ARG_VAL(flags, 0)
7369 +       HTTP_ARG_VAL(class_name, 0)
7370 +HTTP_END_ARGS;
7371 +
7372 +HTTP_BEGIN_ARGS(update, 1)
7373 +       HTTP_ARG_VAL(data, 0)
7374 +HTTP_END_ARGS;
7375 +
7376 +HTTP_BEGIN_ARGS(flush, 0)
7377 +       HTTP_ARG_VAL(data, 0)
7378 +HTTP_END_ARGS;
7379 +
7380 +HTTP_BEGIN_ARGS(finish, 0)
7381 +       HTTP_ARG_VAL(data, 0)
7382 +HTTP_END_ARGS;
7383 +
7384 +#define THIS_CE http_inflatestream_object_ce
7385 +zend_class_entry *http_inflatestream_object_ce;
7386 +zend_function_entry http_inflatestream_object_fe[] = {
7387 +       HTTP_INFLATE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
7388 +       HTTP_INFLATE_ME(update, ZEND_ACC_PUBLIC)
7389 +       HTTP_INFLATE_ME(flush, ZEND_ACC_PUBLIC)
7390 +       HTTP_INFLATE_ME(finish, ZEND_ACC_PUBLIC)
7391 +       
7392 +       HTTP_INFLATE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
7393 +       
7394 +       EMPTY_FUNCTION_ENTRY
7395 +};
7396 +static zend_object_handlers http_inflatestream_object_handlers;
7397 +
7398 +PHP_MINIT_FUNCTION(http_inflatestream_object)
7399 +{
7400 +       HTTP_REGISTER_CLASS_EX(HttpInflateStream, http_inflatestream_object, NULL, 0);
7401 +       http_inflatestream_object_handlers.clone_obj = _http_inflatestream_object_clone_obj;
7402 +       
7403 +#ifndef WONKY
7404 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_NONE")-1, HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC);
7405 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_SYNC")-1, HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC);
7406 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_FULL")-1, HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC);
7407 +#endif
7408 +       
7409 +       return SUCCESS;
7410 +}
7411 +
7412 +zend_object_value _http_inflatestream_object_new(zend_class_entry *ce TSRMLS_DC)
7413 +{
7414 +       return http_inflatestream_object_new_ex(ce, NULL, NULL);
7415 +}
7416 +
7417 +zend_object_value _http_inflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_inflatestream_object **ptr TSRMLS_DC)
7418 +{
7419 +       zend_object_value ov;
7420 +       http_inflatestream_object *o;
7421 +
7422 +       o = ecalloc(1, sizeof(http_inflatestream_object));
7423 +       o->zo.ce = ce;
7424 +       
7425 +       if (ptr) {
7426 +               *ptr = o;
7427 +       }
7428 +
7429 +       if (s) {
7430 +               o->stream = s;
7431 +       }
7432 +
7433 +       ALLOC_HASHTABLE(OBJ_PROP(o));
7434 +       zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
7435 +       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
7436 +
7437 +       ov.handle = putObject(http_inflatestream_object, o);
7438 +       ov.handlers = &http_inflatestream_object_handlers;
7439 +
7440 +       return ov;
7441 +}
7442 +
7443 +zend_object_value _http_inflatestream_object_clone_obj(zval *this_ptr TSRMLS_DC)
7444 +{
7445 +       http_encoding_stream *s;
7446 +       zend_object_value new_ov;
7447 +       http_inflatestream_object *new_obj = NULL;
7448 +       getObject(http_inflatestream_object, old_obj);
7449 +       
7450 +       s = ecalloc(1, sizeof(http_encoding_stream));
7451 +       s->flags = old_obj->stream->flags;
7452 +       inflateCopy(&s->stream, &old_obj->stream->stream);
7453 +       s->stream.opaque = phpstr_dup(s->stream.opaque);
7454 +       
7455 +       new_ov = http_inflatestream_object_new_ex(old_obj->zo.ce, s, &new_obj);
7456 +       zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
7457 +       
7458 +       return new_ov;
7459 +}
7460 +
7461 +void _http_inflatestream_object_free(zend_object *object TSRMLS_DC)
7462 +{
7463 +       http_inflatestream_object *o = (http_inflatestream_object *) object;
7464 +
7465 +       if (o->stream) {
7466 +               http_encoding_inflate_stream_free(&o->stream);
7467 +       }
7468 +       freeObject(o);
7469 +}
7470 +
7471 +/* {{{ proto void HttpInflateStream::__construct([int flags = 0])
7472 +       Creates a new HttpInflateStream object instance. */
7473 +PHP_METHOD(HttpInflateStream, __construct)
7474 +{
7475 +       long flags = 0;
7476 +       
7477 +       SET_EH_THROW_HTTP();
7478 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags)) {
7479 +               getObject(http_inflatestream_object, obj);
7480 +               
7481 +               if (!obj->stream) {
7482 +                       obj->stream = http_encoding_inflate_stream_init(NULL, flags & 0x0fffffff);
7483 +               } else {
7484 +                       http_error_ex(HE_WARNING, HTTP_E_ENCODING, "HttpInflateStream cannot be initialized twice");
7485 +               }
7486 +       }
7487 +       SET_EH_NORMAL();
7488 +}
7489 +/* }}} */
7490 +
7491 +/* {{{ proto HttpInflateStream HttpInflateStream::factory([int flags[, string class = "HttpInflateStream"]])
7492 +       Creates a new HttpInflateStream object instance. */
7493 +PHP_METHOD(HttpInflateStream, factory)
7494 +{
7495 +       long flags = 0;
7496 +       char *cn = NULL;
7497 +       int cl = 0;
7498 +       
7499 +       SET_EH_THROW_HTTP();
7500 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &flags, &cn, &cl)) {
7501 +               zend_object_value ov;
7502 +               http_encoding_stream *s = http_encoding_inflate_stream_init(NULL, flags & 0x0fffffff);
7503 +               
7504 +               if (SUCCESS == http_object_new(&ov, cn, cl, _http_inflatestream_object_new_ex, http_inflatestream_object_ce, s, NULL)) {
7505 +                       RETVAL_OBJVAL(ov, 0);
7506 +               }
7507 +       }
7508 +       SET_EH_NORMAL();
7509 +}
7510 +/* }}} */
7511 +
7512 +/* {{{ proto string HttpInflateStream::update(string data)
7513 +       Passes more data through the inflate stream. */
7514 +PHP_METHOD(HttpInflateStream, update)
7515 +{
7516 +       int data_len;
7517 +       size_t decoded_len = 0;
7518 +       char *data, *decoded = NULL;
7519 +       getObject(http_inflatestream_object, obj);
7520 +       
7521 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
7522 +               RETURN_FALSE;
7523 +       }
7524 +       
7525 +       if (!data_len) {
7526 +               RETURN_STRING("", 1);
7527 +       }
7528 +       
7529 +       if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) {
7530 +               RETURN_FALSE;
7531 +       }
7532 +       
7533 +       if (SUCCESS == http_encoding_inflate_stream_update(obj->stream, data, data_len, &decoded, &decoded_len)) {
7534 +               RETURN_STRINGL(decoded, decoded_len, 0);
7535 +       } else {
7536 +               RETURN_FALSE;
7537 +       }
7538 +}
7539 +/* }}} */
7540 +
7541 +/* {{{ proto string HttpInflateStream::flush([string data])
7542 +       Flush the inflate stream. */
7543 +PHP_METHOD(HttpInflateStream, flush)
7544 +{
7545 +       int data_len = 0;
7546 +       size_t decoded_len = 0;
7547 +       char *decoded = NULL, *data = NULL;
7548 +       getObject(http_inflatestream_object, obj);
7549 +       
7550 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) {
7551 +               RETURN_FALSE;
7552 +       }
7553 +       
7554 +       if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) {
7555 +               RETURN_FALSE;
7556 +       }
7557 +       
7558 +       /* flushing the inflate stream is a no-op */
7559 +       if (!data_len) {
7560 +               RETURN_STRINGL("", 0, 1);
7561 +       } else if (SUCCESS == http_encoding_inflate_stream_update(obj->stream, data, data_len, &decoded, &decoded_len)) {
7562 +               RETURN_STRINGL(decoded, decoded_len, 0);
7563 +       } else {
7564 +               RETURN_FALSE;
7565 +       }
7566 +}
7567 +/* }}} */
7568 +
7569 +/* {{{ proto string HttpInflateStream::finish([string data])
7570 +       Finalizes the inflate stream.  The inflate stream can be reused after finalizing. */
7571 +PHP_METHOD(HttpInflateStream, finish)
7572 +{
7573 +       int data_len = 0;
7574 +       size_t updated_len = 0, decoded_len = 0;
7575 +       char *updated = NULL, *decoded = NULL, *data = NULL;
7576 +       getObject(http_inflatestream_object, obj);
7577 +       
7578 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) {
7579 +               RETURN_FALSE;
7580 +       }
7581 +       
7582 +       if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) {
7583 +               RETURN_FALSE;
7584 +       }
7585 +       
7586 +       if (data_len) {
7587 +               if (SUCCESS != http_encoding_inflate_stream_update(obj->stream, data, data_len, &updated, &updated_len)) {
7588 +                       RETURN_FALSE;
7589 +               }
7590 +       }
7591 +       
7592 +       if (SUCCESS == http_encoding_inflate_stream_finish(obj->stream, &decoded, &decoded_len)) {
7593 +               if (updated_len) {
7594 +                       updated = erealloc(updated, updated_len + decoded_len + 1);
7595 +                       updated[updated_len + decoded_len] = '\0';
7596 +                       memcpy(updated + updated_len, decoded, decoded_len);
7597 +                       STR_FREE(decoded);
7598 +                       updated_len += decoded_len;
7599 +                       RETVAL_STRINGL(updated, updated_len, 0);
7600 +               } else if (decoded) {
7601 +                       STR_FREE(updated);
7602 +                       RETVAL_STRINGL(decoded, decoded_len, 0);
7603 +               } else {
7604 +                       RETVAL_NULL();
7605 +               }
7606 +       } else {
7607 +               STR_FREE(updated);
7608 +               RETVAL_FALSE;
7609 +       }
7610 +       
7611 +       http_encoding_inflate_stream_dtor(obj->stream);
7612 +       http_encoding_inflate_stream_init(obj->stream, obj->stream->flags);
7613 +}
7614 +/* }}} */
7615 +
7616 +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_ZLIB*/
7617 +
7618 +/*
7619 + * Local variables:
7620 + * tab-width: 4
7621 + * c-basic-offset: 4
7622 + * End:
7623 + * vim600: noet sw=4 ts=4 fdm=marker
7624 + * vim<600: noet sw=4 ts=4
7625 + */
7626 +
7627 --- /dev/null
7628 +++ b/ext/http/http_info_api.c
7629 @@ -0,0 +1,155 @@
7630 +/*
7631 +    +--------------------------------------------------------------------+
7632 +    | PECL :: http                                                       |
7633 +    +--------------------------------------------------------------------+
7634 +    | Redistribution and use in source and binary forms, with or without |
7635 +    | modification, are permitted provided that the conditions mentioned |
7636 +    | in the accompanying LICENSE file are met.                          |
7637 +    +--------------------------------------------------------------------+
7638 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
7639 +    +--------------------------------------------------------------------+
7640 +*/
7641 +
7642 +/* $Id: http_info_api.c 304921 2010-10-26 15:27:36Z iliaa $ */
7643 +
7644 +#include "php_http.h"
7645 +
7646 +#include "php_http_api.h"
7647 +#include "php_http_info_api.h"
7648 +
7649 +PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC)
7650 +{
7651 +       zval array;
7652 +       
7653 +       INIT_ZARR(array, *headers);
7654 +       
7655 +       switch (info->type) {
7656 +               case IS_HTTP_REQUEST:
7657 +                       add_assoc_string(&array, "Request Method", HTTP_INFO(info).request.method, 1);
7658 +                       add_assoc_string(&array, "Request Url", HTTP_INFO(info).request.url, 1);
7659 +                       break;
7660 +               
7661 +               case IS_HTTP_RESPONSE:
7662 +                       add_assoc_long(&array, "Response Code", (long) HTTP_INFO(info).response.code);
7663 +                       if (HTTP_INFO(info).response.status) {
7664 +                               add_assoc_string(&array, "Response Status", HTTP_INFO(info).response.status, 1);
7665 +                       }
7666 +                       break;
7667 +       }
7668 +}
7669 +
7670 +PHP_HTTP_API void _http_info_dtor(http_info *i)
7671 +{
7672 +       switch (i->type) {
7673 +               case IS_HTTP_REQUEST:
7674 +                       STR_SET(HTTP_INFO(i).request.method, NULL);
7675 +                       STR_SET(HTTP_INFO(i).request.url, NULL);
7676 +                       break;
7677 +               
7678 +               case IS_HTTP_RESPONSE:
7679 +                       STR_SET(HTTP_INFO(i).response.status, NULL);
7680 +                       break;
7681 +               
7682 +               default:
7683 +                       break;
7684 +       }
7685 +}
7686 +
7687 +PHP_HTTP_API STATUS _http_info_parse_ex(const char *pre_header, http_info *info, zend_bool silent TSRMLS_DC)
7688 +{
7689 +       const char *end, *http;
7690 +       
7691 +       /* sane parameter */
7692 +       if ((!pre_header) || (!*pre_header)) {
7693 +               return FAILURE;
7694 +       }
7695 +       
7696 +       /* where's the end of the line */
7697 +       if (!(end = http_locate_eol(pre_header, NULL))) {
7698 +               end = pre_header + strlen(pre_header);
7699 +       }
7700 +       
7701 +       /* there must be HTTP/1.x in the line */
7702 +       if (!(http = http_locate_str(pre_header, end - pre_header, "HTTP/1.", lenof("HTTP/1.")))) {
7703 +               return FAILURE;
7704 +       }
7705 +       
7706 +       /* and nothing than SPACE or NUL after HTTP/1.x */
7707 +       if (    (!HTTP_IS_CTYPE(digit, http[lenof("HTTP/1.")])) ||
7708 +                       (http[lenof("HTTP/1.1")] && (!HTTP_IS_CTYPE(space, http[lenof("HTTP/1.1")])))) {
7709 +               if (!silent) {
7710 +                       http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Invalid HTTP/1.x protocol identification");
7711 +               }
7712 +               return FAILURE;
7713 +       }
7714 +
7715 +#if 0
7716 +       {
7717 +               char *line = estrndup(pre_header, end - pre_header);
7718 +               fprintf(stderr, "http_parse_info('%s')\n", line);
7719 +               efree(line);
7720 +       }
7721 +#endif
7722 +
7723 +       info->http.version = zend_strtod(http + lenof("HTTP/"), NULL);
7724 +       
7725 +       /* is response */
7726 +       if (pre_header == http) {
7727 +               char *status = NULL;
7728 +               const char *code = http + sizeof("HTTP/1.1");
7729 +               
7730 +               info->type = IS_HTTP_RESPONSE;
7731 +               while (' ' == *code) ++code;
7732 +               if (code && end > code) {
7733 +                       HTTP_INFO(info).response.code = strtol(code, &status, 10);
7734 +               } else {
7735 +                       HTTP_INFO(info).response.code = 0;
7736 +               }
7737 +               if (status && end > status) {
7738 +                       while (' ' == *status) ++status;
7739 +                       HTTP_INFO(info).response.status = estrndup(status, end - status);
7740 +               } else {
7741 +                       HTTP_INFO(info).response.status = NULL;
7742 +               }
7743 +               
7744 +               return SUCCESS;
7745 +       }
7746 +       
7747 +       /* is request */
7748 +       else if (!http[lenof("HTTP/1.x")] || http[lenof("HTTP/1.x")] == '\r' || http[lenof("HTTP/1.x")] == '\n') {
7749 +               const char *url = strchr(pre_header, ' ');
7750 +               
7751 +               info->type = IS_HTTP_REQUEST;
7752 +               if (url && http > url) {
7753 +                       HTTP_INFO(info).request.method = estrndup(pre_header, url - pre_header);
7754 +                       while (' ' == *url) ++url;
7755 +                       while (' ' == *(http-1)) --http;
7756 +                       if (http > url) {
7757 +                               HTTP_INFO(info).request.url = estrndup(url, http - url);
7758 +                       } else {
7759 +                               efree(HTTP_INFO(info).request.method);
7760 +                               return FAILURE;
7761 +                       }
7762 +               } else {
7763 +                       HTTP_INFO(info).request.method = NULL;
7764 +                       HTTP_INFO(info).request.url = NULL;
7765 +               }
7766 +               
7767 +               return SUCCESS;
7768 +       }
7769 +
7770 +       /* some darn header containing HTTP/1.x */
7771 +       else {
7772 +               return FAILURE;
7773 +       }
7774 +}
7775 +
7776 +/*
7777 + * Local variables:
7778 + * tab-width: 4
7779 + * c-basic-offset: 4
7780 + * End:
7781 + * vim600: noet sw=4 ts=4 fdm=marker
7782 + * vim<600: noet sw=4 ts=4
7783 + */
7784 +
7785 --- /dev/null
7786 +++ b/ext/http/http_message_api.c
7787 @@ -0,0 +1,735 @@
7788 +/*
7789 +    +--------------------------------------------------------------------+
7790 +    | PECL :: http                                                       |
7791 +    +--------------------------------------------------------------------+
7792 +    | Redistribution and use in source and binary forms, with or without |
7793 +    | modification, are permitted provided that the conditions mentioned |
7794 +    | in the accompanying LICENSE file are met.                          |
7795 +    +--------------------------------------------------------------------+
7796 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
7797 +    +--------------------------------------------------------------------+
7798 +*/
7799 +
7800 +/* $Id: http_message_api.c 298689 2010-04-28 06:50:06Z mike $ */
7801 +
7802 +#define HTTP_WANT_SAPI
7803 +#define HTTP_WANT_CURL
7804 +#define HTTP_WANT_ZLIB
7805 +#include "php_http.h"
7806 +
7807 +#include "php_http_api.h"
7808 +#include "php_http_encoding_api.h"
7809 +#include "php_http_headers_api.h"
7810 +#include "php_http_message_api.h"
7811 +#include "php_http_request_api.h"
7812 +#include "php_http_send_api.h"
7813 +#include "php_http_url_api.h"
7814 +
7815 +#define http_message_info_callback _http_message_info_callback
7816 +static void _http_message_info_callback(http_message **message, HashTable **headers, http_info *info TSRMLS_DC)
7817 +{
7818 +       http_message *old = *message;
7819 +       
7820 +       /* advance message */
7821 +       if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) {
7822 +               (*message) = http_message_new();
7823 +               (*message)->parent = old;
7824 +               (*headers) = &((*message)->hdrs);
7825 +       }
7826 +       
7827 +       http_message_set_info(*message, info);
7828 +}
7829 +
7830 +#define http_message_init_type _http_message_init_type
7831 +static inline void _http_message_init_type(http_message *message, http_message_type type)
7832 +{
7833 +       message->http.version = .0;
7834 +       
7835 +       switch (message->type = type) {
7836 +               case HTTP_MSG_RESPONSE:
7837 +                       message->http.info.response.code = 0;
7838 +                       message->http.info.response.status = NULL;
7839 +                       break;
7840 +
7841 +               case HTTP_MSG_REQUEST:
7842 +                       message->http.info.request.method = NULL;
7843 +                       message->http.info.request.url = NULL;
7844 +                       break;
7845 +
7846 +               case HTTP_MSG_NONE:
7847 +               default:
7848 +                       break;
7849 +       }
7850 +}
7851 +
7852 +PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_message_type type ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
7853 +{
7854 +       if (!message) {
7855 +               message = ecalloc_rel(1, sizeof(http_message));
7856 +       }
7857 +
7858 +       http_message_init_type(message, type);
7859 +       message->parent = NULL;
7860 +       phpstr_init(&message->body);
7861 +       zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0);
7862 +
7863 +       return message;
7864 +}
7865 +
7866 +PHP_HTTP_API http_message *_http_message_init_env(http_message *message, http_message_type type TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
7867 +{
7868 +       int free_msg;
7869 +       http_info inf;
7870 +       zval *sval, tval;
7871 +       char *body_str;
7872 +       size_t body_len;
7873 +       
7874 +       if ((free_msg = !message)) {
7875 +               message = http_message_init_rel(NULL, HTTP_MSG_NONE);
7876 +       }
7877 +       
7878 +       memset(&inf, 0, sizeof(http_info));
7879 +       switch (inf.type = type) {
7880 +               case HTTP_MSG_REQUEST:
7881 +                       if ((sval = http_get_server_var("SERVER_PROTOCOL", 1)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) {
7882 +                               inf.http.version = zend_strtod(Z_STRVAL_P(sval) + lenof("HTTP/"), NULL);
7883 +                       } else {
7884 +                               inf.http.version = 1.1;
7885 +                       }
7886 +                       if ((sval = http_get_server_var("REQUEST_METHOD", 1))) {
7887 +                               inf.http.info.request.method = estrdup(Z_STRVAL_P(sval));
7888 +                       }
7889 +                       if ((sval = http_get_server_var("REQUEST_URI", 1))) {
7890 +                               inf.http.info.request.url = estrdup(Z_STRVAL_P(sval));
7891 +                       }
7892 +                       
7893 +                       http_message_set_info(message, &inf);
7894 +                       http_get_request_headers(&message->hdrs);
7895 +                       if (SUCCESS == http_get_request_body_ex(&body_str, &body_len, 0)) {
7896 +                               phpstr_from_string_ex(&message->body, body_str, body_len);
7897 +                       }
7898 +                       break;
7899 +                       
7900 +               case HTTP_MSG_RESPONSE:
7901 +                       if (!SG(sapi_headers).http_status_line || SUCCESS != http_info_parse_ex(SG(sapi_headers).http_status_line, &inf, 0)) {
7902 +                               inf.http.version = 1.1;
7903 +                               inf.http.info.response.code = 200;
7904 +                               inf.http.info.response.status = estrdup("Ok");
7905 +                       }
7906 +                       
7907 +                       http_message_set_info(message, &inf);
7908 +                       http_get_response_headers(&message->hdrs);
7909 +                       if (SUCCESS == php_ob_get_buffer(&tval TSRMLS_CC)) {
7910 +                               message->body.data = Z_STRVAL(tval);
7911 +                               message->body.used = Z_STRLEN(tval);
7912 +                               message->body.free = 1; /* "\0" */
7913 +                       }
7914 +                       break;
7915 +                       
7916 +               default:
7917 +                       if (free_msg) {
7918 +                               http_message_free(&message);
7919 +                       } else {
7920 +                               message = NULL;
7921 +                       }
7922 +                       break;
7923 +       }
7924 +       http_info_dtor(&inf);
7925 +       
7926 +       return message;
7927 +}
7928 +
7929 +PHP_HTTP_API void _http_message_set_type(http_message *message, http_message_type type)
7930 +{
7931 +       /* just act if different */
7932 +       if (type != message->type) {
7933 +
7934 +               /* free request info */
7935 +               switch (message->type) {
7936 +                       case HTTP_MSG_REQUEST:
7937 +                               STR_FREE(message->http.info.request.method);
7938 +                               STR_FREE(message->http.info.request.url);
7939 +                               break;
7940 +                       
7941 +                       case HTTP_MSG_RESPONSE:
7942 +                               STR_FREE(message->http.info.response.status);
7943 +                               break;
7944 +                       
7945 +                       default:
7946 +                               break;
7947 +               }
7948 +
7949 +               /* init */
7950 +               http_message_init_type(message, type);
7951 +       }
7952 +}
7953 +
7954 +PHP_HTTP_API void _http_message_set_info(http_message *message, http_info *info)
7955 +{
7956 +       http_message_set_type(message, info->type);
7957 +       message->http.version = info->http.version;
7958 +       switch (message->type) {
7959 +               case IS_HTTP_REQUEST:
7960 +                       STR_SET(HTTP_INFO(message).request.url, HTTP_INFO(info).request.url ? estrdup(HTTP_INFO(info).request.url) : NULL);
7961 +                       STR_SET(HTTP_INFO(message).request.method, HTTP_INFO(info).request.method ? estrdup(HTTP_INFO(info).request.method) : NULL);
7962 +                       break;
7963 +               
7964 +               case IS_HTTP_RESPONSE:
7965 +                       HTTP_INFO(message).response.code = HTTP_INFO(info).response.code;
7966 +                       STR_SET(HTTP_INFO(message).response.status, HTTP_INFO(info).response.status ? estrdup(HTTP_INFO(info).response.status) : NULL);
7967 +                       break;
7968 +               
7969 +               default:
7970 +                       break;
7971 +       }
7972 +}
7973 +
7974 +#define http_message_body_parse(m, ms, ml, c) _http_message_body_parse((m), (ms), (ml), (c) TSRMLS_CC)
7975 +static inline void _http_message_body_parse(http_message *msg, const char *message, size_t message_length, const char **continue_at TSRMLS_DC)
7976 +{
7977 +       zval *c;
7978 +       size_t remaining;
7979 +       const char *body;
7980 +       
7981 +       *continue_at = NULL;
7982 +       if ((body = http_locate_body(message))) {
7983 +               remaining = message + message_length - body;
7984 +               
7985 +               if ((c = http_message_header(msg, "Transfer-Encoding"))) {
7986 +                       if (strstr(Z_STRVAL_P(c), "chunked")) {
7987 +                               /* message has chunked transfer encoding */
7988 +                               char *decoded;
7989 +                               size_t decoded_len;
7990 +                               
7991 +                               /* decode and replace Transfer-Encoding with Content-Length header */
7992 +                               if ((*continue_at = http_encoding_dechunk(body, message + message_length - body, &decoded, &decoded_len))) {
7993 +                                       zval *len;
7994 +                                       char *tmp;
7995 +                                       int tmp_len;
7996 +                                       
7997 +                                       tmp_len = (int) spprintf(&tmp, 0, "%zu", decoded_len);
7998 +                                       MAKE_STD_ZVAL(len);
7999 +                                       ZVAL_STRINGL(len, tmp, tmp_len, 0);
8000 +                                       
8001 +                                       ZVAL_ADDREF(c);
8002 +                                       zend_hash_update(&msg->hdrs, "X-Original-Transfer-Encoding", sizeof("X-Original-Transfer-Encoding"), (void *) &c, sizeof(zval *), NULL);
8003 +                                       zend_hash_del(&msg->hdrs, "Transfer-Encoding", sizeof("Transfer-Encoding"));
8004 +                                       zend_hash_del(&msg->hdrs, "Content-Length", sizeof("Content-Length"));
8005 +                                       zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL);
8006 +                                       
8007 +                                       phpstr_from_string_ex(PHPSTR(msg), decoded, decoded_len);
8008 +                                       efree(decoded);
8009 +                               }
8010 +                       }
8011 +                       zval_ptr_dtor(&c);
8012 +               }
8013 +               
8014 +               if (!*continue_at && (c = http_message_header(msg, "Content-Length"))) {
8015 +                       /* message has content-length header */
8016 +                       ulong len = strtoul(Z_STRVAL_P(c), NULL, 10);
8017 +                       if (len > remaining) {
8018 +                               http_error_ex(HE_NOTICE, HTTP_E_MALFORMED_HEADERS, "The Content-Length header pretends a larger body than actually received (expected %lu bytes; got %lu bytes)", len, remaining);
8019 +                               len = remaining;
8020 +                       }
8021 +                       phpstr_from_string_ex(PHPSTR(msg), body, len);
8022 +                       *continue_at = body + len;
8023 +                       zval_ptr_dtor(&c);
8024 +               }
8025 +               
8026 +               if (!*continue_at && (c = http_message_header(msg, "Content-Range"))) {
8027 +                       /* message has content-range header */
8028 +                       ulong total = 0, start = 0, end = 0, len = 0;
8029 +                       
8030 +                       if (!strncasecmp(Z_STRVAL_P(c), "bytes", lenof("bytes")) && 
8031 +                                       (       Z_STRVAL_P(c)[lenof("bytes")] == ':' ||
8032 +                                               Z_STRVAL_P(c)[lenof("bytes")] == ' ' ||
8033 +                                               Z_STRVAL_P(c)[lenof("bytes")] == '=')) {
8034 +                               char *total_at = NULL, *end_at = NULL;
8035 +                               char *start_at = Z_STRVAL_P(c) + sizeof("bytes");
8036 +                               
8037 +                               start = strtoul(start_at, &end_at, 10);
8038 +                               if (end_at) {
8039 +                                       end = strtoul(end_at + 1, &total_at, 10);
8040 +                                       if (total_at && strncmp(total_at + 1, "*", 1)) {
8041 +                                               total = strtoul(total_at + 1, NULL, 10);
8042 +                                       }
8043 +                                       if ((len = (end + 1 - start)) > remaining) {
8044 +                                               http_error_ex(HE_NOTICE, HTTP_E_MALFORMED_HEADERS, "The Content-Range header pretends a larger body than actually received (expected %lu bytes; got %lu bytes)", len, remaining);
8045 +                                               len = remaining;
8046 +                                       }
8047 +                                       if (end >= start && (!total || end < total)) {
8048 +                                               phpstr_from_string_ex(PHPSTR(msg), body, len);
8049 +                                               *continue_at = body + len;
8050 +                                       }
8051 +                               }
8052 +                       }
8053 +                       
8054 +                       if (!*continue_at) {
8055 +                               http_error_ex(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Invalid Content-Range header: %s", Z_STRVAL_P(c));
8056 +                       }
8057 +                       zval_ptr_dtor(&c);
8058 +               }
8059 +               
8060 +               if (!*continue_at) {
8061 +                       /* no headers that indicate content length */
8062 +                       if (HTTP_MSG_TYPE(RESPONSE, msg)) {
8063 +                               phpstr_from_string_ex(PHPSTR(msg), body, remaining);
8064 +                       } else {
8065 +                               *continue_at = body;
8066 +                       }
8067 +               }
8068 +               
8069 +#ifdef HTTP_HAVE_ZLIB
8070 +               /* check for compressed data */
8071 +               if ((c = http_message_header(msg, "Content-Encoding"))) {
8072 +                       char *decoded = NULL;
8073 +                       size_t decoded_len = 0;
8074 +
8075 +                       if (    !strcasecmp(Z_STRVAL_P(c), "gzip") ||
8076 +                                       !strcasecmp(Z_STRVAL_P(c), "x-gzip") ||
8077 +                                       !strcasecmp(Z_STRVAL_P(c), "deflate")) {
8078 +                               http_encoding_inflate(PHPSTR_VAL(msg), PHPSTR_LEN(msg), &decoded, &decoded_len);
8079 +                       }
8080 +
8081 +                       if (decoded) {
8082 +                               zval *len, **original_len;
8083 +                               char *tmp;
8084 +                               int tmp_len;
8085 +
8086 +                               tmp_len = (int) spprintf(&tmp, 0, "%zu", decoded_len);
8087 +                               MAKE_STD_ZVAL(len);
8088 +                               ZVAL_STRINGL(len, tmp, tmp_len, 0);
8089 +
8090 +                               ZVAL_ADDREF(c);
8091 +                               zend_hash_update(&msg->hdrs, "X-Original-Content-Encoding", sizeof("X-Original-Content-Encoding"), (void *) &c, sizeof(zval *), NULL);
8092 +                               zend_hash_del(&msg->hdrs, "Content-Encoding", sizeof("Content-Encoding"));
8093 +                               if (SUCCESS == zend_hash_find(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &original_len)) {
8094 +                                       ZVAL_ADDREF(*original_len);
8095 +                                       zend_hash_update(&msg->hdrs, "X-Original-Content-Length", sizeof("X-Original-Content-Length"), (void *) original_len, sizeof(zval *), NULL);
8096 +                                       zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL);
8097 +                               } else {
8098 +                                       zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL);
8099 +                               }
8100 +
8101 +                               phpstr_dtor(PHPSTR(msg));
8102 +                               PHPSTR(msg)->data = decoded;
8103 +                               PHPSTR(msg)->used = decoded_len;
8104 +                               PHPSTR(msg)->free = 1;
8105 +                       }
8106 +
8107 +                       zval_ptr_dtor(&c);
8108 +               }
8109 +#endif /* HTTP_HAVE_ZLIB */
8110 +       }
8111 +}
8112 +
8113 +PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t message_length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
8114 +{
8115 +       const char *continue_at;
8116 +       zend_bool free_msg = msg ? 0 : 1;
8117 +
8118 +       if ((!message) || (message_length < HTTP_MSG_MIN_SIZE)) {
8119 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Empty or too short HTTP message: '%s'", message);
8120 +               return NULL;
8121 +       }
8122 +
8123 +       msg = http_message_init_rel(msg, 0);
8124 +
8125 +       if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, (http_info_callback) http_message_info_callback, (void *) &msg)) {
8126 +               if (free_msg) {
8127 +                       http_message_free(&msg);
8128 +               }
8129 +               http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Failed to parse message headers");
8130 +               return NULL;
8131 +       }
8132 +       
8133 +       http_message_body_parse(msg, message, message_length, &continue_at);
8134 +       
8135 +       /* check for following messages */
8136 +       if (continue_at && (continue_at < (message + message_length))) {
8137 +               while (HTTP_IS_CTYPE(space, *continue_at)) ++continue_at;
8138 +               if (continue_at < (message + message_length)) {
8139 +                       http_message *next = NULL, *most = NULL;
8140 +
8141 +                       /* set current message to parent of most parent following messages and return deepest */
8142 +                       if ((most = next = http_message_parse_rel(NULL, continue_at, message + message_length - continue_at))) {
8143 +                               while (most->parent) most = most->parent;
8144 +                               most->parent = msg;
8145 +                               msg = next;
8146 +                       }
8147 +               }
8148 +       }
8149 +
8150 +       return msg;
8151 +}
8152 +
8153 +PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length)
8154 +{
8155 +       phpstr str;
8156 +       HashKey key = initHashKey(0);
8157 +       zval **header;
8158 +       char *data;
8159 +       HashPosition pos1;
8160 +
8161 +       phpstr_init_ex(&str, 4096, 0);
8162 +
8163 +       switch (msg->type) {
8164 +               case HTTP_MSG_REQUEST:
8165 +                       phpstr_appendf(&str, HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, HTTP_CRLF));
8166 +                       break;
8167 +
8168 +               case HTTP_MSG_RESPONSE:
8169 +                       phpstr_appendf(&str, HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, HTTP_CRLF));
8170 +                       break;
8171 +
8172 +               case HTTP_MSG_NONE:
8173 +               default:
8174 +                       break;
8175 +       }
8176 +
8177 +       FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, header) {
8178 +               if (key.type == HASH_KEY_IS_STRING) {
8179 +                       HashPosition pos2;
8180 +                       zval **single_header;
8181 +
8182 +                       switch (Z_TYPE_PP(header)) {
8183 +                               case IS_BOOL:
8184 +                                       phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_BVAL_PP(header)?"true":"false");
8185 +                                       break;
8186 +                                       
8187 +                               case IS_LONG:
8188 +                                       phpstr_appendf(&str, "%s: %ld" HTTP_CRLF, key.str, Z_LVAL_PP(header));
8189 +                                       break;
8190 +                                       
8191 +                               case IS_DOUBLE:
8192 +                                       phpstr_appendf(&str, "%s: %f" HTTP_CRLF, key.str, Z_DVAL_PP(header));
8193 +                                       break;
8194 +                                       
8195 +                               case IS_STRING:
8196 +                                       phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(header));
8197 +                                       break;
8198 +
8199 +                               case IS_ARRAY:
8200 +                                       FOREACH_VAL(pos2, *header, single_header) {
8201 +                                               switch (Z_TYPE_PP(single_header)) {
8202 +                                                       case IS_BOOL:
8203 +                                                               phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_BVAL_PP(single_header)?"true":"false");
8204 +                                                               break;
8205 +                                                               
8206 +                                                       case IS_LONG:
8207 +                                                               phpstr_appendf(&str, "%s: %ld" HTTP_CRLF, key.str, Z_LVAL_PP(single_header));
8208 +                                                               break;
8209 +                                                               
8210 +                                                       case IS_DOUBLE:
8211 +                                                               phpstr_appendf(&str, "%s: %f" HTTP_CRLF, key.str, Z_DVAL_PP(single_header));
8212 +                                                               break;
8213 +                                                               
8214 +                                                       case IS_STRING:
8215 +                                                               phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(single_header));
8216 +                                                               break;
8217 +                                               }
8218 +                                       }
8219 +                                       break;
8220 +                       }
8221 +               }
8222 +       }
8223 +
8224 +       if (PHPSTR_LEN(msg)) {
8225 +               phpstr_appends(&str, HTTP_CRLF);
8226 +               phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg));
8227 +               phpstr_appends(&str, HTTP_CRLF);
8228 +       }
8229 +
8230 +       data = phpstr_data(&str, string, length);
8231 +       if (!string) {
8232 +               efree(data);
8233 +       }
8234 +
8235 +       phpstr_dtor(&str);
8236 +}
8237 +
8238 +PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length)
8239 +{
8240 +       char *buf;
8241 +       size_t len;
8242 +       phpstr str;
8243 +
8244 +       phpstr_init(&str);
8245 +
8246 +       do {
8247 +               http_message_tostring(message, &buf, &len);
8248 +               phpstr_prepend(&str, buf, len);
8249 +               efree(buf);
8250 +       } while ((message = message->parent));
8251 +
8252 +       buf = phpstr_data(&str, string, length);
8253 +       if (!string) {
8254 +               efree(buf);
8255 +       }
8256 +
8257 +       phpstr_dtor(&str);
8258 +}
8259 +
8260 +PHP_HTTP_API http_message *_http_message_reverse(http_message *msg)
8261 +{
8262 +       int i, c;
8263 +       
8264 +       http_message_count(c, msg);
8265 +       
8266 +       if (c > 1) {
8267 +               http_message *tmp = msg, **arr = ecalloc(c, sizeof(http_message *));
8268 +               
8269 +               for (i = 0; i < c; ++i) {
8270 +                       arr[i] = tmp;
8271 +                       tmp = tmp->parent;
8272 +               }
8273 +               arr[0]->parent = NULL;
8274 +               for (i = 0; i < c-1; ++i) {
8275 +                       arr[i+1]->parent = arr[i];
8276 +               }
8277 +               
8278 +               msg = arr[c-1];
8279 +               efree(arr);
8280 +       }
8281 +       
8282 +       return msg;
8283 +}
8284 +
8285 +PHP_HTTP_API http_message *_http_message_interconnect(http_message *m1, http_message *m2)
8286 +{
8287 +       if (m1 && m2) {
8288 +               int i = 0, c1, c2;
8289 +               http_message *t1 = m1, *t2 = m2, *p1, *p2;
8290 +               
8291 +               http_message_count(c1, m1);
8292 +               http_message_count(c2, m2);
8293 +               
8294 +               while (i++ < (c1 - c2)) {
8295 +                       t1 = t1->parent;
8296 +               }
8297 +               while (i++ <= c1) {
8298 +                       p1 = t1->parent;
8299 +                       p2 = t2->parent;
8300 +                       t1->parent = t2;
8301 +                       t2->parent = p1;
8302 +                       t1 = p1;
8303 +                       t2 = p2;
8304 +               }
8305 +       } else if (!m1 && m2) {
8306 +               m1 = m2;
8307 +       }
8308 +       return m1;
8309 +}
8310 +
8311 +PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *obj TSRMLS_DC)
8312 +{
8313 +       zval strct;
8314 +       zval *headers;
8315 +       
8316 +       INIT_ZARR(strct, HASH_OF(obj));
8317 +       
8318 +       add_assoc_long(&strct, "type", msg->type);
8319 +       add_assoc_double(&strct, "httpVersion", msg->http.version);
8320 +       switch (msg->type)
8321 +       {
8322 +               case HTTP_MSG_RESPONSE:
8323 +                       add_assoc_long(&strct, "responseCode", msg->http.info.response.code);
8324 +                       add_assoc_string(&strct, "responseStatus", STR_PTR(msg->http.info.response.status), 1);
8325 +               break;
8326 +               
8327 +               case HTTP_MSG_REQUEST:
8328 +                       add_assoc_string(&strct, "requestMethod", STR_PTR(msg->http.info.request.method), 1);
8329 +                       add_assoc_string(&strct, "requestUrl", STR_PTR(msg->http.info.request.url), 1);
8330 +               break;
8331 +               
8332 +               case HTTP_MSG_NONE:
8333 +                       /* avoid compiler warning */
8334 +               break;
8335 +       }
8336 +       
8337 +       MAKE_STD_ZVAL(headers);
8338 +       array_init(headers);
8339 +       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
8340 +       add_assoc_zval(&strct, "headers", headers);
8341 +       
8342 +       add_assoc_stringl(&strct, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1);
8343 +       
8344 +       if (msg->parent) {
8345 +               zval *parent;
8346 +               
8347 +               MAKE_STD_ZVAL(parent);
8348 +               if (Z_TYPE_P(obj) == IS_ARRAY) {
8349 +                       array_init(parent);
8350 +               } else {
8351 +                       object_init(parent);
8352 +               }
8353 +               add_assoc_zval(&strct, "parentMessage", parent);
8354 +               http_message_tostruct_recursive(msg->parent, parent);
8355 +       } else {
8356 +               add_assoc_null(&strct, "parentMessage");
8357 +       }
8358 +}
8359 +
8360 +PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
8361 +{
8362 +       STATUS rs = FAILURE;
8363 +
8364 +       switch (message->type) {
8365 +               case HTTP_MSG_RESPONSE:
8366 +               {
8367 +                       HashKey key = initHashKey(0);
8368 +                       zval **val;
8369 +                       HashPosition pos;
8370 +
8371 +                       FOREACH_HASH_KEYVAL(pos, &message->hdrs, key, val) {
8372 +                               if (key.type == HASH_KEY_IS_STRING) {
8373 +                                       http_send_header_zval_ex(key.str, key.len-1, val, 1);
8374 +                               }
8375 +                       }
8376 +                       rs =    SUCCESS == http_send_status(message->http.info.response.code) &&
8377 +                                       SUCCESS == http_send_data(PHPSTR_VAL(message), PHPSTR_LEN(message)) ?
8378 +                                       SUCCESS : FAILURE;
8379 +                       break;
8380 +               }
8381 +
8382 +               case HTTP_MSG_REQUEST:
8383 +               {
8384 +#ifdef HTTP_HAVE_CURL
8385 +                       char *uri = NULL;
8386 +                       http_request request;
8387 +                       zval **zhost, *options, *headers;
8388 +                       
8389 +                       MAKE_STD_ZVAL(options);
8390 +                       MAKE_STD_ZVAL(headers);
8391 +                       array_init(options);
8392 +                       array_init(headers);
8393 +                       zend_hash_copy(Z_ARRVAL_P(headers), &message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
8394 +                       add_assoc_zval(options, "headers", headers);
8395 +
8396 +                       /* check host header */
8397 +                       if (SUCCESS == zend_hash_find(&message->hdrs, "Host", sizeof("Host"), (void *) &zhost) && Z_TYPE_PP(zhost) == IS_STRING) {
8398 +                               char *colon = NULL;
8399 +                               php_url parts, *url = php_url_parse(message->http.info.request.url);
8400 +                               
8401 +                               memset(&parts, 0, sizeof(php_url));
8402 +
8403 +                               /* check for port */
8404 +                               if ((colon = strchr(Z_STRVAL_PP(zhost), ':'))) {
8405 +                                       parts.port = atoi(colon + 1);
8406 +                                       parts.host = estrndup(Z_STRVAL_PP(zhost), (Z_STRVAL_PP(zhost) - colon - 1));
8407 +                               } else {
8408 +                                       parts.host = estrndup(Z_STRVAL_PP(zhost), Z_STRLEN_PP(zhost));
8409 +                               }
8410 +                               
8411 +                               http_build_url(HTTP_URL_REPLACE, url, &parts, NULL, &uri, NULL);
8412 +                               php_url_free(url);
8413 +                               efree(parts.host);
8414 +                       } else {
8415 +                               uri = http_absolute_url(message->http.info.request.url);
8416 +                       }
8417 +
8418 +                       if ((request.meth = http_request_method_exists(1, 0, message->http.info.request.method))) {
8419 +                               http_request_body body;
8420 +                               
8421 +                               http_request_init_ex(&request, NULL, request.meth, uri);
8422 +                               request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, PHPSTR_VAL(message), PHPSTR_LEN(message), 0);
8423 +                               if (SUCCESS == (rs = http_request_prepare(&request, Z_ARRVAL_P(options)))) {
8424 +                                       http_request_exec(&request);
8425 +                               }
8426 +                               http_request_dtor(&request);
8427 +                       } else {
8428 +                               http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD,
8429 +                                       "Cannot send HttpMessage. Request method %s not supported",
8430 +                                       message->http.info.request.method);
8431 +                       }
8432 +                       efree(uri);
8433 +                       zval_ptr_dtor(&options);
8434 +#else
8435 +                       http_error(HE_WARNING, HTTP_E_RUNTIME, "HTTP requests not supported - ext/http was not linked against libcurl.");
8436 +#endif
8437 +               break;
8438 +               }
8439 +
8440 +               case HTTP_MSG_NONE:
8441 +               default:
8442 +                       http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is neither of type HTTP_MSG_REQUEST nor HTTP_MSG_RESPONSE");
8443 +                       break;
8444 +       }
8445 +
8446 +       return rs;
8447 +}
8448 +
8449 +PHP_HTTP_API http_message *_http_message_dup(http_message *orig TSRMLS_DC)
8450 +{
8451 +       http_message *temp, *copy = NULL;
8452 +       http_info info;
8453 +       
8454 +       if (orig) {
8455 +               info.type = orig->type;
8456 +               info.http = orig->http;
8457 +               
8458 +               copy = temp = http_message_new();
8459 +               http_message_set_info(temp, &info);
8460 +               zend_hash_copy(&temp->hdrs, &orig->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
8461 +               phpstr_append(&temp->body, orig->body.data, orig->body.used);
8462 +       
8463 +               while (orig->parent) {
8464 +                       info.type = orig->parent->type;
8465 +                       info.http = orig->parent->http;
8466 +               
8467 +                       temp->parent = http_message_new();
8468 +                       http_message_set_info(temp->parent, &info);
8469 +                       zend_hash_copy(&temp->parent->hdrs, &orig->parent->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
8470 +                       phpstr_append(&temp->parent->body, orig->parent->body.data, orig->parent->body.used);
8471 +               
8472 +                       temp = temp->parent;
8473 +                       orig = orig->parent;
8474 +               }
8475 +       }
8476 +       
8477 +       return copy;
8478 +}
8479 +
8480 +PHP_HTTP_API void _http_message_dtor(http_message *message)
8481 +{
8482 +       if (message) {
8483 +               zend_hash_destroy(&message->hdrs);
8484 +               phpstr_dtor(PHPSTR(message));
8485 +               
8486 +               switch (message->type) {
8487 +                       case HTTP_MSG_REQUEST:
8488 +                               STR_SET(message->http.info.request.method, NULL);
8489 +                               STR_SET(message->http.info.request.url, NULL);
8490 +                               break;
8491 +                       
8492 +                       case HTTP_MSG_RESPONSE:
8493 +                               STR_SET(message->http.info.response.status, NULL);
8494 +                               break;
8495 +                       
8496 +                       default:
8497 +                               break;
8498 +               }
8499 +       }
8500 +}
8501 +
8502 +PHP_HTTP_API void _http_message_free(http_message **message)
8503 +{
8504 +       if (*message) {
8505 +               if ((*message)->parent) {
8506 +                       http_message_free(&(*message)->parent);
8507 +               }
8508 +               http_message_dtor(*message);
8509 +               efree(*message);
8510 +               *message = NULL;
8511 +       }
8512 +}
8513 +
8514 +/*
8515 + * Local variables:
8516 + * tab-width: 4
8517 + * c-basic-offset: 4
8518 + * End:
8519 + * vim600: noet sw=4 ts=4 fdm=marker
8520 + * vim<600: noet sw=4 ts=4
8521 + */
8522 +
8523 --- /dev/null
8524 +++ b/ext/http/http_message_object.c
8525 @@ -0,0 +1,1546 @@
8526 +/*
8527 +    +--------------------------------------------------------------------+
8528 +    | PECL :: http                                                       |
8529 +    +--------------------------------------------------------------------+
8530 +    | Redistribution and use in source and binary forms, with or without |
8531 +    | modification, are permitted provided that the conditions mentioned |
8532 +    | in the accompanying LICENSE file are met.                          |
8533 +    +--------------------------------------------------------------------+
8534 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
8535 +    +--------------------------------------------------------------------+
8536 +*/
8537 +
8538 +/* $Id: http_message_object.c 309640 2011-03-24 09:26:11Z mike $ */
8539 +
8540 +#define HTTP_WANT_SAPI
8541 +#define HTTP_WANT_CURL
8542 +#define HTTP_WANT_MAGIC
8543 +#include "php_http.h"
8544 +
8545 +#ifdef ZEND_ENGINE_2
8546 +
8547 +#include "zend_interfaces.h"
8548 +#include "ext/standard/url.h"
8549 +#include "php_variables.h"
8550 +
8551 +#include "php_http_api.h"
8552 +#include "php_http_send_api.h"
8553 +#include "php_http_url_api.h"
8554 +#include "php_http_message_api.h"
8555 +#include "php_http_message_object.h"
8556 +#include "php_http_exception_object.h"
8557 +#include "php_http_response_object.h"
8558 +#include "php_http_request_method_api.h"
8559 +#include "php_http_request_api.h"
8560 +#include "php_http_request_object.h"
8561 +#include "php_http_headers_api.h"
8562 +
8563 +#if defined(HTTP_HAVE_SPL) && !defined(WONKY)
8564 +/* SPL doesn't install its headers */
8565 +extern PHPAPI zend_class_entry *spl_ce_Countable;
8566 +#endif
8567 +
8568 +#define HTTP_BEGIN_ARGS(method, req_args)      HTTP_BEGIN_ARGS_EX(HttpMessage, method, 0, req_args)
8569 +#define HTTP_EMPTY_ARGS(method)                                HTTP_EMPTY_ARGS_EX(HttpMessage, method, 0)
8570 +#define HTTP_MESSAGE_ME(method, visibility)    PHP_ME(HttpMessage, method, HTTP_ARGS(HttpMessage, method), visibility)
8571 +
8572 +HTTP_BEGIN_ARGS(__construct, 0)
8573 +       HTTP_ARG_VAL(message, 0)
8574 +HTTP_END_ARGS;
8575 +
8576 +HTTP_BEGIN_ARGS(factory, 0)
8577 +       HTTP_ARG_VAL(message, 0)
8578 +       HTTP_ARG_VAL(class_name, 0)
8579 +HTTP_END_ARGS;
8580 +
8581 +HTTP_BEGIN_ARGS(fromEnv, 1)
8582 +       HTTP_ARG_VAL(type, 0)
8583 +       HTTP_ARG_VAL(class_name, 0)
8584 +HTTP_END_ARGS;
8585 +
8586 +HTTP_EMPTY_ARGS(getBody);
8587 +HTTP_BEGIN_ARGS(setBody, 1)
8588 +       HTTP_ARG_VAL(body, 0)
8589 +HTTP_END_ARGS;
8590 +
8591 +HTTP_BEGIN_ARGS(getHeader, 1)
8592 +       HTTP_ARG_VAL(header, 0)
8593 +HTTP_END_ARGS;
8594 +
8595 +HTTP_EMPTY_ARGS(getHeaders);
8596 +HTTP_BEGIN_ARGS(setHeaders, 1)
8597 +       HTTP_ARG_VAL(headers, 0)
8598 +HTTP_END_ARGS;
8599 +
8600 +HTTP_BEGIN_ARGS(addHeaders, 1)
8601 +       HTTP_ARG_VAL(headers, 0)
8602 +       HTTP_ARG_VAL(append, 0)
8603 +HTTP_END_ARGS;
8604 +
8605 +HTTP_EMPTY_ARGS(getType);
8606 +HTTP_BEGIN_ARGS(setType, 1)
8607 +       HTTP_ARG_VAL(type, 0)
8608 +HTTP_END_ARGS;
8609 +
8610 +HTTP_EMPTY_ARGS(getInfo);
8611 +HTTP_BEGIN_ARGS(setInfo, 1)
8612 +       HTTP_ARG_VAL(http_info, 0)
8613 +HTTP_END_ARGS;
8614 +
8615 +HTTP_EMPTY_ARGS(getResponseCode);
8616 +HTTP_BEGIN_ARGS(setResponseCode, 1)
8617 +       HTTP_ARG_VAL(response_code, 0)
8618 +HTTP_END_ARGS;
8619 +
8620 +HTTP_EMPTY_ARGS(getResponseStatus);
8621 +HTTP_BEGIN_ARGS(setResponseStatus, 1)
8622 +       HTTP_ARG_VAL(response_status, 0)
8623 +HTTP_END_ARGS;
8624 +
8625 +HTTP_EMPTY_ARGS(getRequestMethod);
8626 +HTTP_BEGIN_ARGS(setRequestMethod, 1)
8627 +       HTTP_ARG_VAL(request_method, 0)
8628 +HTTP_END_ARGS;
8629 +
8630 +HTTP_EMPTY_ARGS(getRequestUrl);
8631 +HTTP_BEGIN_ARGS(setRequestUrl, 1)
8632 +       HTTP_ARG_VAL(url, 0)
8633 +HTTP_END_ARGS;
8634 +
8635 +HTTP_EMPTY_ARGS(getHttpVersion);
8636 +HTTP_BEGIN_ARGS(setHttpVersion, 1)
8637 +       HTTP_ARG_VAL(http_version, 0)
8638 +HTTP_END_ARGS;
8639 +
8640 +HTTP_BEGIN_ARGS(guessContentType, 1)
8641 +       HTTP_ARG_VAL(magic_file, 0)
8642 +       HTTP_ARG_VAL(magic_mode, 0)
8643 +HTTP_END_ARGS;
8644 +
8645 +HTTP_EMPTY_ARGS(getParentMessage);
8646 +HTTP_EMPTY_ARGS(send);
8647 +HTTP_EMPTY_ARGS(__toString);
8648 +HTTP_BEGIN_ARGS(toString, 0)
8649 +       HTTP_ARG_VAL(include_parent, 0)
8650 +HTTP_END_ARGS;
8651 +
8652 +HTTP_EMPTY_ARGS(toMessageTypeObject);
8653 +
8654 +HTTP_EMPTY_ARGS(count);
8655 +
8656 +HTTP_EMPTY_ARGS(serialize);
8657 +HTTP_BEGIN_ARGS(unserialize, 1)
8658 +       HTTP_ARG_VAL(serialized, 0)
8659 +HTTP_END_ARGS;
8660 +
8661 +HTTP_EMPTY_ARGS(rewind);
8662 +HTTP_EMPTY_ARGS(valid);
8663 +HTTP_EMPTY_ARGS(key);
8664 +HTTP_EMPTY_ARGS(current);
8665 +HTTP_EMPTY_ARGS(next);
8666 +
8667 +HTTP_EMPTY_ARGS(detach);
8668 +HTTP_BEGIN_ARGS(prepend, 1)
8669 +       HTTP_ARG_OBJ(HttpMessage, message, 0)
8670 +HTTP_END_ARGS;
8671 +HTTP_EMPTY_ARGS(reverse);
8672 +
8673 +#define http_message_object_read_prop _http_message_object_read_prop
8674 +static zval *_http_message_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC);
8675 +#define http_message_object_write_prop _http_message_object_write_prop
8676 +static void _http_message_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC);
8677 +#define http_message_object_get_prop_ptr _http_message_object_get_prop_ptr
8678 +static zval **_http_message_object_get_prop_ptr(zval *object, zval *member ZEND_LITERAL_KEY_DC TSRMLS_DC);
8679 +#define http_message_object_get_props _http_message_object_get_props
8680 +static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC);
8681 +
8682 +#define THIS_CE http_message_object_ce
8683 +zend_class_entry *http_message_object_ce;
8684 +zend_function_entry http_message_object_fe[] = {
8685 +       HTTP_MESSAGE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
8686 +       HTTP_MESSAGE_ME(getBody, ZEND_ACC_PUBLIC)
8687 +       HTTP_MESSAGE_ME(setBody, ZEND_ACC_PUBLIC)
8688 +       HTTP_MESSAGE_ME(getHeader, ZEND_ACC_PUBLIC)
8689 +       HTTP_MESSAGE_ME(getHeaders, ZEND_ACC_PUBLIC)
8690 +       HTTP_MESSAGE_ME(setHeaders, ZEND_ACC_PUBLIC)
8691 +       HTTP_MESSAGE_ME(addHeaders, ZEND_ACC_PUBLIC)
8692 +       HTTP_MESSAGE_ME(getType, ZEND_ACC_PUBLIC)
8693 +       HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC)
8694 +       HTTP_MESSAGE_ME(getInfo, ZEND_ACC_PUBLIC)
8695 +       HTTP_MESSAGE_ME(setInfo, ZEND_ACC_PUBLIC)
8696 +       HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC)
8697 +       HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC)
8698 +       HTTP_MESSAGE_ME(getResponseStatus, ZEND_ACC_PUBLIC)
8699 +       HTTP_MESSAGE_ME(setResponseStatus, ZEND_ACC_PUBLIC)
8700 +       HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC)
8701 +       HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC)
8702 +       HTTP_MESSAGE_ME(getRequestUrl, ZEND_ACC_PUBLIC)
8703 +       HTTP_MESSAGE_ME(setRequestUrl, ZEND_ACC_PUBLIC)
8704 +       HTTP_MESSAGE_ME(getHttpVersion, ZEND_ACC_PUBLIC)
8705 +       HTTP_MESSAGE_ME(setHttpVersion, ZEND_ACC_PUBLIC)
8706 +       HTTP_MESSAGE_ME(guessContentType, ZEND_ACC_PUBLIC)
8707 +       HTTP_MESSAGE_ME(getParentMessage, ZEND_ACC_PUBLIC)
8708 +       HTTP_MESSAGE_ME(send, ZEND_ACC_PUBLIC)
8709 +       HTTP_MESSAGE_ME(toString, ZEND_ACC_PUBLIC)
8710 +       HTTP_MESSAGE_ME(toMessageTypeObject, ZEND_ACC_PUBLIC)
8711 +
8712 +       /* implements Countable */
8713 +       HTTP_MESSAGE_ME(count, ZEND_ACC_PUBLIC)
8714 +       
8715 +       /* implements Serializable */
8716 +       HTTP_MESSAGE_ME(serialize, ZEND_ACC_PUBLIC)
8717 +       HTTP_MESSAGE_ME(unserialize, ZEND_ACC_PUBLIC)
8718 +       
8719 +       /* implements Iterator */
8720 +       HTTP_MESSAGE_ME(rewind, ZEND_ACC_PUBLIC)
8721 +       HTTP_MESSAGE_ME(valid, ZEND_ACC_PUBLIC)
8722 +       HTTP_MESSAGE_ME(current, ZEND_ACC_PUBLIC)
8723 +       HTTP_MESSAGE_ME(key, ZEND_ACC_PUBLIC)
8724 +       HTTP_MESSAGE_ME(next, ZEND_ACC_PUBLIC)
8725 +
8726 +       ZEND_MALIAS(HttpMessage, __toString, toString, HTTP_ARGS(HttpMessage, __toString), ZEND_ACC_PUBLIC)
8727 +
8728 +       HTTP_MESSAGE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
8729 +       ZEND_MALIAS(HttpMessage, fromString, factory, HTTP_ARGS(HttpMessage, factory), ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
8730 +       HTTP_MESSAGE_ME(fromEnv, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
8731 +       
8732 +       HTTP_MESSAGE_ME(detach, ZEND_ACC_PUBLIC)
8733 +       HTTP_MESSAGE_ME(prepend, ZEND_ACC_PUBLIC)
8734 +       HTTP_MESSAGE_ME(reverse, ZEND_ACC_PUBLIC)
8735 +
8736 +       EMPTY_FUNCTION_ENTRY
8737 +};
8738 +static zend_object_handlers http_message_object_handlers;
8739 +
8740 +static HashTable http_message_object_prophandlers;
8741 +
8742 +typedef void (*http_message_object_prophandler_func)(http_message_object *o, zval *v TSRMLS_DC);
8743 +
8744 +typedef struct _http_message_object_prophandler {
8745 +       http_message_object_prophandler_func read;
8746 +       http_message_object_prophandler_func write;
8747 +} http_message_object_prophandler;
8748 +
8749 +static STATUS http_message_object_add_prophandler(const char *prop_str, size_t prop_len, http_message_object_prophandler_func read, http_message_object_prophandler_func write) {
8750 +       http_message_object_prophandler h = { read, write };
8751 +       return zend_hash_add(&http_message_object_prophandlers, prop_str, prop_len, (void *) &h, sizeof(h), NULL);
8752 +}
8753 +static STATUS http_message_object_get_prophandler(const char *prop_str, size_t prop_len, http_message_object_prophandler **handler) {
8754 +       return zend_hash_find(&http_message_object_prophandlers, prop_str, prop_len, (void *) handler);
8755 +}
8756 +static void http_message_object_prophandler_get_type(http_message_object *obj, zval *return_value TSRMLS_DC) {
8757 +       RETVAL_LONG(obj->message->type);
8758 +}
8759 +static void http_message_object_prophandler_set_type(http_message_object *obj, zval *value TSRMLS_DC) {
8760 +       zval *cpy = http_zsep(IS_LONG, value);
8761 +       http_message_set_type(obj->message, Z_LVAL_P(cpy));
8762 +       zval_ptr_dtor(&cpy);
8763 +}
8764 +static void http_message_object_prophandler_get_body(http_message_object *obj, zval *return_value TSRMLS_DC) {
8765 +       phpstr_fix(PHPSTR(obj->message));
8766 +       RETVAL_PHPSTR(PHPSTR(obj->message), 0, 1);
8767 +}
8768 +static void http_message_object_prophandler_set_body(http_message_object *obj, zval *value TSRMLS_DC) {
8769 +       zval *cpy = http_zsep(IS_STRING, value);
8770 +       phpstr_dtor(PHPSTR(obj->message));
8771 +       phpstr_from_string_ex(PHPSTR(obj->message), Z_STRVAL_P(cpy), Z_STRLEN_P(cpy));
8772 +       zval_ptr_dtor(&cpy);
8773 +}
8774 +static void http_message_object_prophandler_get_request_method(http_message_object *obj, zval *return_value TSRMLS_DC) {
8775 +       if (HTTP_MSG_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) {
8776 +               RETVAL_STRING(obj->message->http.info.request.method, 1);
8777 +       } else {
8778 +               RETVAL_NULL();
8779 +       }
8780 +}
8781 +static void http_message_object_prophandler_set_request_method(http_message_object *obj, zval *value TSRMLS_DC) {
8782 +       if (HTTP_MSG_TYPE(REQUEST, obj->message)) {
8783 +               zval *cpy = http_zsep(IS_STRING, value);
8784 +               STR_SET(obj->message->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
8785 +               zval_ptr_dtor(&cpy);
8786 +       }
8787 +}
8788 +static void http_message_object_prophandler_get_request_url(http_message_object *obj, zval *return_value TSRMLS_DC) {
8789 +       if (HTTP_MSG_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url) {
8790 +               RETVAL_STRING(obj->message->http.info.request.url, 1);
8791 +       } else {
8792 +               RETVAL_NULL();
8793 +       }
8794 +}
8795 +static void http_message_object_prophandler_set_request_url(http_message_object *obj, zval *value TSRMLS_DC) {
8796 +       if (HTTP_MSG_TYPE(REQUEST, obj->message)) {
8797 +               zval *cpy = http_zsep(IS_STRING, value);
8798 +               STR_SET(obj->message->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
8799 +               zval_ptr_dtor(&cpy);
8800 +       }
8801 +}
8802 +static void http_message_object_prophandler_get_response_status(http_message_object *obj, zval *return_value TSRMLS_DC) {
8803 +       if (HTTP_MSG_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) {
8804 +               RETVAL_STRING(obj->message->http.info.response.status, 1);
8805 +       } else {
8806 +               RETVAL_NULL();
8807 +       }
8808 +}
8809 +static void http_message_object_prophandler_set_response_status(http_message_object *obj, zval *value TSRMLS_DC) {
8810 +       if (HTTP_MSG_TYPE(RESPONSE, obj->message)) {
8811 +               zval *cpy = http_zsep(IS_STRING, value);
8812 +               STR_SET(obj->message->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
8813 +               zval_ptr_dtor(&cpy);
8814 +       }
8815 +}
8816 +static void http_message_object_prophandler_get_response_code(http_message_object *obj, zval *return_value TSRMLS_DC) {
8817 +       if (HTTP_MSG_TYPE(RESPONSE, obj->message)) {
8818 +               RETVAL_LONG(obj->message->http.info.response.code);
8819 +       } else {
8820 +               RETVAL_NULL();
8821 +       }
8822 +}
8823 +static void http_message_object_prophandler_set_response_code(http_message_object *obj, zval *value TSRMLS_DC) {
8824 +       if (HTTP_MSG_TYPE(RESPONSE, obj->message)) {
8825 +               zval *cpy = http_zsep(IS_LONG, value);
8826 +               obj->message->http.info.response.code = Z_LVAL_P(cpy);
8827 +               zval_ptr_dtor(&cpy);
8828 +       }
8829 +}
8830 +static void http_message_object_prophandler_get_http_version(http_message_object *obj, zval *return_value TSRMLS_DC) {
8831 +       RETVAL_DOUBLE(obj->message->http.version);
8832 +}
8833 +static void http_message_object_prophandler_set_http_version(http_message_object *obj, zval *value TSRMLS_DC) {
8834 +       zval *cpy = http_zsep(IS_DOUBLE, value);
8835 +       obj->message->http.version = Z_DVAL_P(cpy);
8836 +       zval_ptr_dtor(&cpy);
8837 +}
8838 +static void http_message_object_prophandler_get_headers(http_message_object *obj, zval *return_value TSRMLS_DC) {
8839 +       array_init(return_value);
8840 +       zend_hash_copy(Z_ARRVAL_P(return_value), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
8841 +}
8842 +static void http_message_object_prophandler_set_headers(http_message_object *obj, zval *value TSRMLS_DC) {
8843 +       zval *cpy = http_zsep(IS_ARRAY, value);
8844 +       zend_hash_clean(&obj->message->hdrs);
8845 +       zend_hash_copy(&obj->message->hdrs, Z_ARRVAL_P(cpy), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
8846 +       zval_ptr_dtor(&cpy);
8847 +}
8848 +static void http_message_object_prophandler_get_parent_message(http_message_object *obj, zval *return_value TSRMLS_DC) {
8849 +       if (obj->message->parent) {
8850 +               RETVAL_OBJVAL(obj->parent, 1);
8851 +       } else {
8852 +               RETVAL_NULL();
8853 +       }
8854 +}
8855 +static void http_message_object_prophandler_set_parent_message(http_message_object *obj, zval *value TSRMLS_DC) {
8856 +       if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), http_message_object_ce TSRMLS_CC)) {
8857 +               if (obj->message->parent) {
8858 +                       zval tmp;
8859 +                       tmp.value.obj = obj->parent;
8860 +                       Z_OBJ_DELREF(tmp);
8861 +               }
8862 +               Z_OBJ_ADDREF_P(value);
8863 +               obj->parent = value->value.obj;
8864 +       }
8865 +}
8866 +
8867 +PHP_MINIT_FUNCTION(http_message_object)
8868 +{
8869 +       HTTP_REGISTER_CLASS_EX(HttpMessage, http_message_object, NULL, 0);
8870 +       
8871 +#ifndef WONKY
8872 +#      ifdef HTTP_HAVE_SPL
8873 +       zend_class_implements(http_message_object_ce TSRMLS_CC, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator);
8874 +#      else
8875 +       zend_class_implements(http_message_object_ce TSRMLS_CC, 2, zend_ce_serializable, zend_ce_iterator);
8876 +#      endif
8877 +#else
8878 +       zend_class_implements(http_message_object_ce TSRMLS_CC, 1, zend_ce_iterator);
8879 +#endif
8880 +       
8881 +       http_message_object_handlers.clone_obj = _http_message_object_clone_obj;
8882 +       http_message_object_handlers.read_property = http_message_object_read_prop;
8883 +       http_message_object_handlers.write_property = http_message_object_write_prop;
8884 +       http_message_object_handlers.get_properties = http_message_object_get_props;
8885 +       http_message_object_handlers.get_property_ptr_ptr = http_message_object_get_prop_ptr;
8886 +
8887 +       zend_hash_init(&http_message_object_prophandlers, 9, NULL, NULL, 1);
8888 +       zend_declare_property_long(THIS_CE, ZEND_STRS("type")-1, HTTP_MSG_NONE, ZEND_ACC_PROTECTED TSRMLS_CC);
8889 +       http_message_object_add_prophandler(ZEND_STRS("type")-1, http_message_object_prophandler_get_type, http_message_object_prophandler_set_type);
8890 +       zend_declare_property_string(THIS_CE, ZEND_STRS("body")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC);
8891 +       http_message_object_add_prophandler(ZEND_STRS("body")-1, http_message_object_prophandler_get_body, http_message_object_prophandler_set_body);
8892 +       zend_declare_property_string(THIS_CE, ZEND_STRS("requestMethod")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC);
8893 +       http_message_object_add_prophandler(ZEND_STRS("requestMethod")-1, http_message_object_prophandler_get_request_method, http_message_object_prophandler_set_request_method);
8894 +       zend_declare_property_string(THIS_CE, ZEND_STRS("requestUrl")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC);
8895 +       http_message_object_add_prophandler(ZEND_STRS("requestUrl")-1, http_message_object_prophandler_get_request_url, http_message_object_prophandler_set_request_url);
8896 +       zend_declare_property_string(THIS_CE, ZEND_STRS("responseStatus")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC);
8897 +       http_message_object_add_prophandler(ZEND_STRS("responseStatus")-1, http_message_object_prophandler_get_response_status, http_message_object_prophandler_set_response_status);
8898 +       zend_declare_property_long(THIS_CE, ZEND_STRS("responseCode")-1, 0, ZEND_ACC_PROTECTED TSRMLS_CC);
8899 +       http_message_object_add_prophandler(ZEND_STRS("responseCode")-1, http_message_object_prophandler_get_response_code, http_message_object_prophandler_set_response_code);
8900 +       zend_declare_property_null(THIS_CE, ZEND_STRS("httpVersion")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
8901 +       http_message_object_add_prophandler(ZEND_STRS("httpVersion")-1, http_message_object_prophandler_get_http_version, http_message_object_prophandler_set_http_version);
8902 +       zend_declare_property_null(THIS_CE, ZEND_STRS("headers")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
8903 +       http_message_object_add_prophandler(ZEND_STRS("headers")-1, http_message_object_prophandler_get_headers, http_message_object_prophandler_set_headers);
8904 +       zend_declare_property_null(THIS_CE, ZEND_STRS("parentMessage")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
8905 +       http_message_object_add_prophandler(ZEND_STRS("parentMessage")-1, http_message_object_prophandler_get_parent_message, http_message_object_prophandler_set_parent_message);
8906 +       
8907 +#ifndef WONKY
8908 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_NONE")-1, HTTP_MSG_NONE TSRMLS_CC);
8909 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_REQUEST")-1, HTTP_MSG_REQUEST TSRMLS_CC);
8910 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_RESPONSE")-1, HTTP_MSG_RESPONSE TSRMLS_CC);
8911 +#endif
8912 +       
8913 +       HTTP_LONG_CONSTANT("HTTP_MSG_NONE", HTTP_MSG_NONE);
8914 +       HTTP_LONG_CONSTANT("HTTP_MSG_REQUEST", HTTP_MSG_REQUEST);
8915 +       HTTP_LONG_CONSTANT("HTTP_MSG_RESPONSE", HTTP_MSG_RESPONSE);
8916 +       
8917 +       return SUCCESS;
8918 +}
8919 +
8920 +PHP_MSHUTDOWN_FUNCTION(http_message_object)
8921 +{
8922 +       zend_hash_destroy(&http_message_object_prophandlers);
8923 +
8924 +       return SUCCESS;
8925 +}
8926 +
8927 +void _http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC)
8928 +{
8929 +       int i;
8930 +       getObject(http_message_object, obj);
8931 +       
8932 +       /* count */
8933 +       http_message_count(i, obj->message);
8934 +       
8935 +       if (i > 1) {
8936 +               zval o;
8937 +               zend_object_value *ovalues = NULL;
8938 +               http_message_object **objects = NULL;
8939 +               int last = i - 1;
8940 +               
8941 +               objects = ecalloc(i, sizeof(http_message_object *));
8942 +               ovalues = ecalloc(i, sizeof(zend_object_value));
8943 +       
8944 +               /* we are the first message */
8945 +               objects[0] = obj;
8946 +               ovalues[0] = getThis()->value.obj;
8947 +       
8948 +               /* fetch parents */
8949 +               INIT_PZVAL(&o);
8950 +               o.type = IS_OBJECT;
8951 +               for (i = 1; obj->parent.handle; ++i) {
8952 +                       o.value.obj = obj->parent;
8953 +                       ovalues[i] = o.value.obj;
8954 +                       objects[i] = obj = zend_object_store_get_object(&o TSRMLS_CC);
8955 +               }
8956 +               
8957 +               /* reorder parents */
8958 +               for (last = --i; i; --i) {
8959 +                       objects[i]->message->parent = objects[i-1]->message;
8960 +                       objects[i]->parent = ovalues[i-1];
8961 +               }
8962 +               objects[0]->message->parent = NULL;
8963 +               objects[0]->parent.handle = 0;
8964 +               objects[0]->parent.handlers = NULL;
8965 +               
8966 +               /* add ref (why?) */
8967 +               Z_OBJ_ADDREF_P(getThis());
8968 +               RETVAL_OBJVAL(ovalues[last], 1);
8969 +               
8970 +               efree(objects);
8971 +               efree(ovalues);
8972 +       } else {
8973 +               RETURN_ZVAL(getThis(), 1, 0);
8974 +       }
8975 +}
8976 +
8977 +void _http_message_object_prepend_ex(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC)
8978 +{
8979 +       zval m;
8980 +       http_message *save_parent_msg = NULL;
8981 +       zend_object_value save_parent_obj = {0, NULL};
8982 +       getObject(http_message_object, obj);
8983 +       getObjectEx(http_message_object, prepend_obj, prepend);
8984 +               
8985 +       INIT_PZVAL(&m);
8986 +       m.type = IS_OBJECT;
8987 +               
8988 +       if (!top) {
8989 +               save_parent_obj = obj->parent;
8990 +               save_parent_msg = obj->message->parent;
8991 +       } else {
8992 +               /* iterate to the most parent object */
8993 +               while (obj->parent.handle) {
8994 +                       m.value.obj = obj->parent;
8995 +                       obj = zend_object_store_get_object(&m TSRMLS_CC);
8996 +               }
8997 +       }
8998 +               
8999 +       /* prepend */
9000 +       obj->parent = prepend->value.obj;
9001 +       obj->message->parent = prepend_obj->message;
9002 +               
9003 +       /* add ref */
9004 +       zend_objects_store_add_ref(prepend TSRMLS_CC);
9005 +       while (prepend_obj->parent.handle) {
9006 +               m.value.obj = prepend_obj->parent;
9007 +               zend_objects_store_add_ref(&m TSRMLS_CC);
9008 +               prepend_obj = zend_object_store_get_object(&m TSRMLS_CC);
9009 +       }
9010 +               
9011 +       if (!top) {
9012 +               prepend_obj->parent = save_parent_obj;
9013 +               prepend_obj->message->parent = save_parent_msg;
9014 +       }
9015 +}
9016 +
9017 +zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC)
9018 +{
9019 +       return http_message_object_new_ex(ce, NULL, NULL);
9020 +}
9021 +
9022 +zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC)
9023 +{
9024 +       zend_object_value ov;
9025 +       http_message_object *o;
9026 +
9027 +       o = ecalloc(1, sizeof(http_message_object));
9028 +       o->zo.ce = ce;
9029 +       
9030 +       if (ptr) {
9031 +               *ptr = o;
9032 +       }
9033 +
9034 +       if (msg) {
9035 +               o->message = msg;
9036 +               if (msg->parent) {
9037 +                       o->parent = http_message_object_new_ex(ce, msg->parent, NULL);
9038 +               }
9039 +       }
9040 +
9041 +       ALLOC_HASHTABLE(OBJ_PROP(o));
9042 +       zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
9043 +       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
9044 +
9045 +       ov.handle = putObject(http_message_object, o);
9046 +       ov.handlers = &http_message_object_handlers;
9047 +
9048 +       return ov;
9049 +}
9050 +
9051 +zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC)
9052 +{
9053 +       zend_object_value new_ov;
9054 +       http_message_object *new_obj = NULL;
9055 +       getObject(http_message_object, old_obj);
9056 +       
9057 +       new_ov = http_message_object_new_ex(old_obj->zo.ce, http_message_dup(old_obj->message), &new_obj);
9058 +       zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
9059 +       
9060 +       return new_ov;
9061 +}
9062 +
9063 +void _http_message_object_free(zend_object *object TSRMLS_DC)
9064 +{
9065 +       http_message_object *o = (http_message_object *) object;
9066 +
9067 +       if (o->iterator) {
9068 +               zval_ptr_dtor(&o->iterator);
9069 +               o->iterator = NULL;
9070 +       }
9071 +       if (o->message) {
9072 +               http_message_dtor(o->message);
9073 +               efree(o->message);
9074 +       }
9075 +       if (o->parent.handle) {
9076 +               zval p;
9077 +               
9078 +               INIT_PZVAL(&p);
9079 +               p.type = IS_OBJECT;
9080 +               p.value.obj = o->parent;
9081 +               zend_objects_store_del_ref(&p TSRMLS_CC);
9082 +       }
9083 +       freeObject(o);
9084 +}
9085 +
9086 +static zval **_http_message_object_get_prop_ptr(zval *object, zval *member ZEND_LITERAL_KEY_DC TSRMLS_DC) {
9087 +       getObjectEx(http_message_object, obj, object);
9088 +       http_message_object_prophandler *handler;
9089 +       
9090 +       if (SUCCESS == http_message_object_get_prophandler(Z_STRVAL_P(member), Z_STRLEN_P(member), &handler)) {
9091 +               zend_error(E_ERROR, "Cannot access HttpMessage properties by reference or array key/index");
9092 +               return NULL;
9093 +       }
9094 +
9095 +       return zend_get_std_object_handlers()->get_property_ptr_ptr(object, member ZEND_LITERAL_KEY_CC TSRMLS_CC);
9096 +}
9097 +
9098 +static zval *_http_message_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC)
9099 +{
9100 +       getObjectEx(http_message_object, obj, object);
9101 +       http_message_object_prophandler *handler;
9102 +       zval *return_value;
9103 +
9104 +       if (SUCCESS == http_message_object_get_prophandler(Z_STRVAL_P(member), Z_STRLEN_P(member), &handler)) {
9105 +               if (type == BP_VAR_W) {
9106 +                       zend_error(E_ERROR, "Cannot access HttpMessage properties by reference or array key/index");
9107 +                       return NULL;
9108 +               }
9109 +
9110 +               ALLOC_ZVAL(return_value);
9111 +#ifdef Z_SET_REFCOUNT
9112 +               Z_SET_REFCOUNT_P(return_value, 0);
9113 +               Z_UNSET_ISREF_P(return_value);
9114 +#else
9115 +               return_value->refcount = 0;
9116 +               return_value->is_ref = 0;
9117 +#endif
9118 +
9119 +               handler->read(obj, return_value TSRMLS_CC);
9120 +
9121 +       } else {
9122 +               return_value = zend_get_std_object_handlers()->read_property(object, member, type ZEND_LITERAL_KEY_CC TSRMLS_CC);
9123 +       }
9124 +       
9125 +       return return_value;
9126 +}
9127 +
9128 +static void _http_message_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC)
9129 +{
9130 +       getObjectEx(http_message_object, obj, object);
9131 +       http_message_object_prophandler *handler;
9132 +       
9133 +       if (SUCCESS == http_message_object_get_prophandler(Z_STRVAL_P(member), Z_STRLEN_P(member), &handler)) {
9134 +               handler->write(obj, value TSRMLS_CC);
9135 +       } else {
9136 +               zend_get_std_object_handlers()->write_property(object, member, value ZEND_LITERAL_KEY_CC TSRMLS_CC);
9137 +       }
9138 +}
9139 +
9140 +static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC)
9141 +{
9142 +       zval *headers;
9143 +       getObjectEx(http_message_object, obj, object);
9144 +       http_message *msg = obj->message;
9145 +       HashTable *props = OBJ_PROP(obj);
9146 +       zval array, *parent;
9147 +       
9148 +       INIT_ZARR(array, props);
9149 +
9150 +#define ASSOC_PROP(array, ptype, name, val) \
9151 +       { \
9152 +               char *m_prop_name; \
9153 +               int m_prop_len; \
9154 +               zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
9155 +               add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+3, val); \
9156 +               efree(m_prop_name); \
9157 +       }
9158 +#define ASSOC_STRING(array, name, val) ASSOC_STRINGL(array, name, val, strlen(val))
9159 +#define ASSOC_STRINGL(array, name, val, len) \
9160 +       { \
9161 +               char *m_prop_name; \
9162 +               int m_prop_len; \
9163 +               zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \
9164 +               add_assoc_stringl_ex(&array, m_prop_name, sizeof(name)+3, val, len, 1); \
9165 +               efree(m_prop_name); \
9166 +       }
9167 +
9168 +       ASSOC_PROP(array, long, "type", msg->type);
9169 +       ASSOC_PROP(array, double, "httpVersion", msg->http.version);
9170 +
9171 +       switch (msg->type) {
9172 +               case HTTP_MSG_REQUEST:
9173 +                       ASSOC_PROP(array, long, "responseCode", 0);
9174 +                       ASSOC_STRINGL(array, "responseStatus", "", 0);
9175 +                       ASSOC_STRING(array, "requestMethod", STR_PTR(msg->http.info.request.method));
9176 +                       ASSOC_STRING(array, "requestUrl", STR_PTR(msg->http.info.request.url));
9177 +                       break;
9178 +
9179 +               case HTTP_MSG_RESPONSE:
9180 +                       ASSOC_PROP(array, long, "responseCode", msg->http.info.response.code);
9181 +                       ASSOC_STRING(array, "responseStatus", STR_PTR(msg->http.info.response.status));
9182 +                       ASSOC_STRINGL(array, "requestMethod", "", 0);
9183 +                       ASSOC_STRINGL(array, "requestUrl", "", 0);
9184 +                       break;
9185 +
9186 +               case HTTP_MSG_NONE:
9187 +               default:
9188 +                       ASSOC_PROP(array, long, "responseCode", 0);
9189 +                       ASSOC_STRINGL(array, "responseStatus", "", 0);
9190 +                       ASSOC_STRINGL(array, "requestMethod", "", 0);
9191 +                       ASSOC_STRINGL(array, "requestUrl", "", 0);
9192 +                       break;
9193 +       }
9194 +
9195 +       MAKE_STD_ZVAL(headers);
9196 +       array_init(headers);
9197 +       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
9198 +       ASSOC_PROP(array, zval, "headers", headers);
9199 +       ASSOC_STRINGL(array, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
9200 +       
9201 +       MAKE_STD_ZVAL(parent);
9202 +       if (msg->parent) {
9203 +               ZVAL_OBJVAL(parent, obj->parent, 1);
9204 +       } else {
9205 +               ZVAL_NULL(parent);
9206 +       }
9207 +       ASSOC_PROP(array, zval, "parentMessage", parent);
9208 +
9209 +       return OBJ_PROP(obj);
9210 +}
9211 +
9212 +/* ### USERLAND ### */
9213 +
9214 +/* {{{ proto void HttpMessage::__construct([string message])
9215 +       Create a new HttpMessage object instance. */
9216 +PHP_METHOD(HttpMessage, __construct)
9217 +{
9218 +       int length = 0;
9219 +       char *message = NULL;
9220 +       
9221 +       getObject(http_message_object, obj);
9222 +       
9223 +       SET_EH_THROW_HTTP();
9224 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
9225 +               http_message *msg = obj->message;
9226 +               
9227 +               http_message_dtor(msg);
9228 +               if ((obj->message = http_message_parse_ex(msg, message, length))) {
9229 +                       if (obj->message->parent) {
9230 +                               obj->parent = http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL);
9231 +                       }
9232 +               } else {
9233 +                       obj->message = http_message_init(msg);
9234 +               }
9235 +       }
9236 +       if (!obj->message) {
9237 +               obj->message = http_message_new();
9238 +       }
9239 +       SET_EH_NORMAL();
9240 +}
9241 +/* }}} */
9242 +
9243 +/* {{{ proto static HttpMessage HttpMessage::factory([string raw_message[, string class_name = "HttpMessage"]])
9244 +       Create a new HttpMessage object instance. */
9245 +PHP_METHOD(HttpMessage, factory)
9246 +{
9247 +       char *string = NULL, *cn = NULL;
9248 +       int length = 0, cl = 0;
9249 +       http_message *msg = NULL;
9250 +       zend_object_value ov;
9251 +       http_message_object *obj = NULL;
9252 +
9253 +       RETVAL_NULL();
9254 +       
9255 +       SET_EH_THROW_HTTP();
9256 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &string, &length, &cn, &cl)) {
9257 +               if (length) {
9258 +                       msg = http_message_parse(string, length);
9259 +               }
9260 +               if ((msg || !length) && SUCCESS == http_object_new(&ov, cn, cl, _http_message_object_new_ex, http_message_object_ce, msg, &obj)) {
9261 +                       RETVAL_OBJVAL(ov, 0);
9262 +               }
9263 +               if (obj && !obj->message) {
9264 +                       obj->message = http_message_new();
9265 +               }
9266 +       }
9267 +       SET_EH_NORMAL();
9268 +}
9269 +/* }}} */
9270 +
9271 +/* {{{ proto static HttpMessage HttpMessage::fromEnv(int type[, string class_name = "HttpMessage"])
9272 +       Create a new HttpMessage object from environment representing either current request or response */
9273 +PHP_METHOD(HttpMessage, fromEnv)
9274 +{
9275 +       char *cn = NULL;
9276 +       int cl = 0;
9277 +       long type;
9278 +       http_message_object *obj = NULL;
9279 +       zend_object_value ov;
9280 +       
9281 +       RETVAL_NULL();
9282 +       SET_EH_THROW_HTTP();
9283 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &type, &cn, &cl)) {
9284 +               if (SUCCESS == http_object_new(&ov, cn, cl, _http_message_object_new_ex, http_message_object_ce, http_message_init_env(NULL, type), &obj)) {
9285 +                       RETVAL_OBJVAL(ov, 0);
9286 +               }
9287 +               if (obj && !obj->message) {
9288 +                       obj->message = http_message_new();
9289 +               }
9290 +       }
9291 +       SET_EH_NORMAL();
9292 +}
9293 +/* }}} */
9294 +
9295 +/* {{{ proto string HttpMessage::getBody()
9296 +       Get the body of the parsed HttpMessage. */
9297 +PHP_METHOD(HttpMessage, getBody)
9298 +{
9299 +       NO_ARGS;
9300 +
9301 +       if (return_value_used) {
9302 +               getObject(http_message_object, obj);
9303 +               RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1);
9304 +       }
9305 +}
9306 +/* }}} */
9307 +
9308 +/* {{{ proto void HttpMessage::setBody(string body)
9309 +       Set the body of the HttpMessage. NOTE: Don't forget to update any headers accordingly. */
9310 +PHP_METHOD(HttpMessage, setBody)
9311 +{
9312 +       char *body;
9313 +       int len;
9314 +       getObject(http_message_object, obj);
9315 +       
9316 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &body, &len)) {
9317 +               phpstr_dtor(PHPSTR(obj->message));
9318 +               phpstr_from_string_ex(PHPSTR(obj->message), body, len);
9319 +       }
9320 +}
9321 +/* }}} */
9322 +
9323 +/* {{{ proto string HttpMessage::getHeader(string header)
9324 +       Get message header. */
9325 +PHP_METHOD(HttpMessage, getHeader)
9326 +{
9327 +       zval *header;
9328 +       char *orig_header, *nice_header;
9329 +       int header_len;
9330 +       getObject(http_message_object, obj);
9331 +       
9332 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &orig_header, &header_len)) {
9333 +               RETURN_FALSE;
9334 +       }
9335 +       
9336 +       nice_header = pretty_key(estrndup(orig_header, header_len), header_len, 1, 1);
9337 +       if ((header = http_message_header_ex(obj->message, nice_header, header_len + 1, 0))) {
9338 +               RETVAL_ZVAL(header, 1, 1);
9339 +       }
9340 +       efree(nice_header);
9341 +}
9342 +/* }}} */
9343 +
9344 +/* {{{ proto array HttpMessage::getHeaders()
9345 +       Get Message Headers. */
9346 +PHP_METHOD(HttpMessage, getHeaders)
9347 +{
9348 +       NO_ARGS;
9349 +
9350 +       if (return_value_used) {
9351 +               getObject(http_message_object, obj);
9352 +
9353 +               array_init(return_value);
9354 +               array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
9355 +       }
9356 +}
9357 +/* }}} */
9358 +
9359 +/* {{{ proto void HttpMessage::setHeaders(array headers)
9360 +       Sets new headers. */
9361 +PHP_METHOD(HttpMessage, setHeaders)
9362 +{
9363 +       zval *new_headers = NULL;
9364 +       getObject(http_message_object, obj);
9365 +
9366 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &new_headers)) {
9367 +               return;
9368 +       }
9369 +
9370 +       zend_hash_clean(&obj->message->hdrs);
9371 +       if (new_headers) {
9372 +               array_copy(Z_ARRVAL_P(new_headers), &obj->message->hdrs);
9373 +       }
9374 +}
9375 +/* }}} */
9376 +
9377 +/* {{{ proto void HttpMessage::addHeaders(array headers[, bool append = false])
9378 +       Add headers. If append is true, headers with the same name will be separated, else overwritten. */
9379 +PHP_METHOD(HttpMessage, addHeaders)
9380 +{
9381 +       zval *new_headers;
9382 +       zend_bool append = 0;
9383 +       getObject(http_message_object, obj);
9384 +
9385 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
9386 +               return;
9387 +       }
9388 +
9389 +       array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY);
9390 +}
9391 +/* }}} */
9392 +
9393 +/* {{{ proto int HttpMessage::getType()
9394 +       Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE) */
9395 +PHP_METHOD(HttpMessage, getType)
9396 +{
9397 +       NO_ARGS;
9398 +
9399 +       if (return_value_used) {
9400 +               getObject(http_message_object, obj);
9401 +               RETURN_LONG(obj->message->type);
9402 +       }
9403 +}
9404 +/* }}} */
9405 +
9406 +/* {{{ proto void HttpMessage::setType(int type)
9407 +       Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE) */
9408 +PHP_METHOD(HttpMessage, setType)
9409 +{
9410 +       long type;
9411 +       getObject(http_message_object, obj);
9412 +
9413 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
9414 +               return;
9415 +       }
9416 +       http_message_set_type(obj->message, type);
9417 +}
9418 +/* }}} */
9419 +
9420 +/* {{{ proto string HttpMessage::getInfo(void)
9421 +       Get the HTTP request/response line */
9422 +PHP_METHOD(HttpMessage, getInfo)
9423 +{
9424 +       NO_ARGS;
9425 +       
9426 +       if (return_value_used) {
9427 +               getObject(http_message_object, obj);
9428 +               
9429 +               switch (obj->message->type) {
9430 +                       case HTTP_MSG_REQUEST:
9431 +                               Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, ""));
9432 +                               break;
9433 +                       case HTTP_MSG_RESPONSE:
9434 +                               Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, ""));
9435 +                               break;
9436 +                       default:
9437 +                               RETURN_NULL();
9438 +                               break;
9439 +               }
9440 +               Z_TYPE_P(return_value) = IS_STRING;
9441 +       }
9442 +}
9443 +/* }}} */
9444 +
9445 +/* {{{ proto bool HttpMessage::setInfo(string http_info)
9446 +       Set type and request or response info with a standard HTTP request or response line */
9447 +PHP_METHOD(HttpMessage, setInfo)
9448 +{
9449 +       char *str;
9450 +       int len;
9451 +       http_info inf;
9452 +       
9453 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) && SUCCESS == http_info_parse_ex(str, &inf, 0)) {
9454 +               getObject(http_message_object, obj);
9455 +               
9456 +               http_message_set_info(obj->message, &inf);
9457 +               http_info_dtor(&inf);
9458 +               RETURN_TRUE;
9459 +       }
9460 +       RETURN_FALSE;
9461 +}
9462 +/* }}} */
9463 +
9464 +/* {{{ proto int HttpMessage::getResponseCode()
9465 +       Get the Response Code of the Message. */
9466 +PHP_METHOD(HttpMessage, getResponseCode)
9467 +{
9468 +       NO_ARGS;
9469 +
9470 +       if (return_value_used) {
9471 +               getObject(http_message_object, obj);
9472 +               HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
9473 +               RETURN_LONG(obj->message->http.info.response.code);
9474 +       }
9475 +}
9476 +/* }}} */
9477 +
9478 +/* {{{ proto bool HttpMessage::setResponseCode(int code)
9479 +       Set the response code of an HTTP Response Message. */
9480 +PHP_METHOD(HttpMessage, setResponseCode)
9481 +{
9482 +       long code;
9483 +       getObject(http_message_object, obj);
9484 +
9485 +       HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
9486 +
9487 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
9488 +               RETURN_FALSE;
9489 +       }
9490 +       if (code < 100 || code > 599) {
9491 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid response code (100-599): %ld", code);
9492 +               RETURN_FALSE;
9493 +       }
9494 +
9495 +       obj->message->http.info.response.code = code;
9496 +       RETURN_TRUE;
9497 +}
9498 +/* }}} */
9499 +
9500 +/* {{{ proto string HttpMessage::getResponseStatus()
9501 +       Get the Response Status of the message (i.e. the string following the response code). */
9502 +PHP_METHOD(HttpMessage, getResponseStatus)
9503 +{
9504 +       NO_ARGS;
9505 +       
9506 +       if (return_value_used) {
9507 +               getObject(http_message_object, obj);
9508 +               HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
9509 +               if (obj->message->http.info.response.status) {
9510 +                       RETURN_STRING(obj->message->http.info.response.status, 1);
9511 +               } else {
9512 +                       RETURN_EMPTY_STRING();
9513 +               }
9514 +       }
9515 +}
9516 +/* }}} */
9517 +
9518 +/* {{{ proto bool HttpMessage::setResponseStatus(string status)
9519 +       Set the Response Status of the HTTP message (i.e. the string following the response code). */
9520 +PHP_METHOD(HttpMessage, setResponseStatus)
9521 +{
9522 +       char *status;
9523 +       int status_len;
9524 +       getObject(http_message_object, obj);
9525 +       
9526 +       HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE);
9527 +       
9528 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len)) {
9529 +               RETURN_FALSE;
9530 +       }
9531 +       STR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
9532 +       RETURN_TRUE;
9533 +}
9534 +/* }}} */
9535 +
9536 +/* {{{ proto string HttpMessage::getRequestMethod()
9537 +       Get the Request Method of the Message. */
9538 +PHP_METHOD(HttpMessage, getRequestMethod)
9539 +{
9540 +       NO_ARGS;
9541 +
9542 +       if (return_value_used) {
9543 +               getObject(http_message_object, obj);
9544 +               HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
9545 +               if (obj->message->http.info.request.method) {
9546 +                       RETURN_STRING(obj->message->http.info.request.method, 1);
9547 +               } else {
9548 +                       RETURN_EMPTY_STRING();
9549 +               }
9550 +       }
9551 +}
9552 +/* }}} */
9553 +
9554 +/* {{{ proto bool HttpMessage::setRequestMethod(string method)
9555 +       Set the Request Method of the HTTP Message. */
9556 +PHP_METHOD(HttpMessage, setRequestMethod)
9557 +{
9558 +       char *method;
9559 +       int method_len;
9560 +       getObject(http_message_object, obj);
9561 +
9562 +       HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
9563 +
9564 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
9565 +               RETURN_FALSE;
9566 +       }
9567 +       if (method_len < 1) {
9568 +               http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
9569 +               RETURN_FALSE;
9570 +       }
9571 +       if (!http_request_method_exists(1, 0, method)) {
9572 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unknown request method: %s", method);
9573 +               RETURN_FALSE;
9574 +       }
9575 +
9576 +       STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
9577 +       RETURN_TRUE;
9578 +}
9579 +/* }}} */
9580 +
9581 +/* {{{ proto string HttpMessage::getRequestUrl()
9582 +       Get the Request URL of the Message. */
9583 +PHP_METHOD(HttpMessage, getRequestUrl)
9584 +{
9585 +       NO_ARGS;
9586 +
9587 +       if (return_value_used) {
9588 +               getObject(http_message_object, obj);
9589 +               HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
9590 +               if (obj->message->http.info.request.url) {
9591 +                       RETURN_STRING(obj->message->http.info.request.url, 1);
9592 +               } else {
9593 +                       RETURN_EMPTY_STRING();
9594 +               }
9595 +       }
9596 +}
9597 +/* }}} */
9598 +
9599 +/* {{{ proto bool HttpMessage::setRequestUrl(string url)
9600 +       Set the Request URL of the HTTP Message. */
9601 +PHP_METHOD(HttpMessage, setRequestUrl)
9602 +{
9603 +       char *URI;
9604 +       int URIlen;
9605 +       getObject(http_message_object, obj);
9606 +
9607 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) {
9608 +               RETURN_FALSE;
9609 +       }
9610 +       HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE);
9611 +       if (URIlen < 1) {
9612 +               http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUrl to an empty string");
9613 +               RETURN_FALSE;
9614 +       }
9615 +
9616 +       STR_SET(obj->message->http.info.request.url, estrndup(URI, URIlen));
9617 +       RETURN_TRUE;
9618 +}
9619 +/* }}} */
9620 +
9621 +/* {{{ proto string HttpMessage::getHttpVersion()
9622 +       Get the HTTP Protocol Version of the Message. */
9623 +PHP_METHOD(HttpMessage, getHttpVersion)
9624 +{
9625 +       NO_ARGS;
9626 +
9627 +       if (return_value_used) {
9628 +               char *version;
9629 +               getObject(http_message_object, obj);
9630 +
9631 +               spprintf(&version, 0, "%1.1F", obj->message->http.version);
9632 +               RETURN_STRING(version, 0);
9633 +       }
9634 +}
9635 +/* }}} */
9636 +
9637 +/* {{{ proto bool HttpMessage::setHttpVersion(string version)
9638 +       Set the HTTP Protocol version of the Message. */
9639 +PHP_METHOD(HttpMessage, setHttpVersion)
9640 +{
9641 +       zval *zv;
9642 +       char *version;
9643 +       getObject(http_message_object, obj);
9644 +
9645 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &zv)) {
9646 +               return;
9647 +       }
9648 +
9649 +       convert_to_double(zv);
9650 +       spprintf(&version, 0, "%1.1F", Z_DVAL_P(zv));
9651 +       if (strcmp(version, "1.0") && strcmp(version, "1.1")) {
9652 +               efree(version);
9653 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %g", Z_DVAL_P(zv));
9654 +               RETURN_FALSE;
9655 +       }
9656 +       efree(version);
9657 +       obj->message->http.version = Z_DVAL_P(zv);
9658 +       RETURN_TRUE;
9659 +}
9660 +/* }}} */
9661 +
9662 +/* {{{ proto string HttpMessage::guessContentType(string magic_file[, int magic_mode = MAGIC_MIME])
9663 +       Attempts to guess the content type of supplied payload through libmagic. */
9664 +PHP_METHOD(HttpMessage, guessContentType)
9665 +{
9666 +#ifdef HTTP_HAVE_MAGIC
9667 +       char *magic_file, *ct = NULL;
9668 +       int magic_file_len;
9669 +       long magic_mode = MAGIC_MIME;
9670 +       
9671 +       RETVAL_FALSE;
9672 +       SET_EH_THROW_HTTP();
9673 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &magic_file, &magic_file_len, &magic_mode)) {
9674 +               getObject(http_message_object, obj);
9675 +               if ((ct = http_guess_content_type(magic_file, magic_mode, PHPSTR_VAL(&obj->message->body), PHPSTR_LEN(&obj->message->body), SEND_DATA))) {
9676 +                       RETVAL_STRING(ct, 0);
9677 +               }
9678 +       }
9679 +       SET_EH_NORMAL();
9680 +#else
9681 +       http_error(HE_THROW, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available");
9682 +       RETURN_FALSE;
9683 +#endif
9684 +}
9685 +/* }}} */
9686 +
9687 +/* {{{ proto HttpMessage HttpMessage::getParentMessage()
9688 +       Get parent Message. */
9689 +PHP_METHOD(HttpMessage, getParentMessage)
9690 +{
9691 +       SET_EH_THROW_HTTP();
9692 +       NO_ARGS {
9693 +               getObject(http_message_object, obj);
9694 +
9695 +               if (obj->message->parent) {
9696 +                       RETVAL_OBJVAL(obj->parent, 1);
9697 +               } else {
9698 +                       http_error(HE_WARNING, HTTP_E_RUNTIME, "HttpMessage does not have a parent message");
9699 +               }
9700 +       }
9701 +       SET_EH_NORMAL();
9702 +}
9703 +/* }}} */
9704 +
9705 +/* {{{ proto bool HttpMessage::send()
9706 +       Send the Message according to its type as Response or Request. */
9707 +PHP_METHOD(HttpMessage, send)
9708 +{
9709 +       getObject(http_message_object, obj);
9710 +
9711 +       NO_ARGS;
9712 +
9713 +       RETURN_SUCCESS(http_message_send(obj->message));
9714 +}
9715 +/* }}} */
9716 +
9717 +/* {{{ proto string HttpMessage::toString([bool include_parent = false])
9718 +       Get the string representation of the Message. */
9719 +PHP_METHOD(HttpMessage, toString)
9720 +{
9721 +       if (return_value_used) {
9722 +               char *string;
9723 +               size_t length;
9724 +               zend_bool include_parent = 0;
9725 +               getObject(http_message_object, obj);
9726 +
9727 +               if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) {
9728 +                       RETURN_FALSE;
9729 +               }
9730 +
9731 +               if (include_parent) {
9732 +                       http_message_serialize(obj->message, &string, &length);
9733 +               } else {
9734 +                       http_message_tostring(obj->message, &string, &length);
9735 +               }
9736 +               RETURN_STRINGL(string, length, 0);
9737 +       }
9738 +}
9739 +/* }}} */
9740 +
9741 +/* {{{ proto HttpRequest|HttpResponse HttpMessage::toMessageTypeObject(void)
9742 +       Creates an object regarding to the type of the message. Returns either an HttpRequest or HttpResponse object on success, or NULL on failure. */
9743 +PHP_METHOD(HttpMessage, toMessageTypeObject)
9744 +{
9745 +       SET_EH_THROW_HTTP();
9746 +       
9747 +       NO_ARGS;
9748 +       
9749 +       if (return_value_used) {
9750 +               getObject(http_message_object, obj);
9751 +               
9752 +               switch (obj->message->type) {
9753 +                       case HTTP_MSG_REQUEST:
9754 +                       {
9755 +#ifdef HTTP_HAVE_CURL
9756 +                               int method;
9757 +                               char *url;
9758 +                               zval post, body, *array, *headers, *host = http_message_header(obj->message, "Host");
9759 +                               php_url hurl, *purl = php_url_parse(STR_PTR(obj->message->http.info.request.url));
9760 +                               
9761 +                               MAKE_STD_ZVAL(array);
9762 +                               array_init(array);
9763 +                               
9764 +                               memset(&hurl, 0, sizeof(php_url));
9765 +                               if (host) {
9766 +                                       hurl.host = Z_STRVAL_P(host);
9767 +                                       zval_ptr_dtor(&host);
9768 +                               }
9769 +                               http_build_url(HTTP_URL_REPLACE, purl, &hurl, NULL, &url, NULL);
9770 +                               php_url_free(purl);
9771 +                               add_assoc_string(array, "url", url, 0);
9772 +                               
9773 +                               if (    obj->message->http.info.request.method &&
9774 +                                                       ((method = http_request_method_exists(1, 0, obj->message->http.info.request.method)) ||
9775 +                                                       (method = http_request_method_register(obj->message->http.info.request.method, strlen(obj->message->http.info.request.method))))) {
9776 +                                       add_assoc_long(array, "method", method);
9777 +                               }
9778 +                               
9779 +                               if (10 == (int) (obj->message->http.version * 10)) {
9780 +                                       add_assoc_long(array, "protocol", CURL_HTTP_VERSION_1_0);
9781 +                               }
9782 +                               
9783 +                               MAKE_STD_ZVAL(headers);
9784 +                               array_init(headers);
9785 +                               array_copy(&obj->message->hdrs, Z_ARRVAL_P(headers));
9786 +                               add_assoc_zval(array, "headers", headers);
9787 +                               
9788 +                               object_init_ex(return_value, http_request_object_ce);
9789 +                               zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setoptions", NULL, array);
9790 +                               zval_ptr_dtor(&array);
9791 +                               
9792 +                               if (PHPSTR_VAL(obj->message) && PHPSTR_LEN(obj->message)) {
9793 +                                       phpstr_fix(PHPSTR(obj->message));
9794 +                                       INIT_PZVAL(&body);
9795 +                                       ZVAL_STRINGL(&body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message), 0);
9796 +                                       if (method != HTTP_POST) {
9797 +                                               zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setbody", NULL, &body);
9798 +                                       } else {
9799 +                                               INIT_PZVAL(&post);
9800 +                                               array_init(&post);
9801 +                                               
9802 +                                               zval_copy_ctor(&body);
9803 +                                               sapi_module.treat_data(PARSE_STRING, Z_STRVAL(body), &post TSRMLS_CC);
9804 +                                               zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setpostfields", NULL, &post);
9805 +                                               zval_dtor(&post);
9806 +                                       }
9807 +                               }
9808 +#else
9809 +                               http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot transform HttpMessage to HttpRequest (missing curl support)");
9810 +#endif
9811 +                               break;
9812 +                       }
9813 +                       
9814 +                       case HTTP_MSG_RESPONSE:
9815 +                       {
9816 +#ifndef WONKY
9817 +                               HashPosition pos1, pos2;
9818 +                               HashKey key = initHashKey(0);
9819 +                               zval **header, **h, *body;
9820 +                               
9821 +                               if (obj->message->http.info.response.code) {
9822 +                                       http_send_status(obj->message->http.info.response.code);
9823 +                               }
9824 +                               
9825 +                               object_init_ex(return_value, http_response_object_ce);
9826 +                               
9827 +                               FOREACH_HASH_KEYVAL(pos1, &obj->message->hdrs, key, header) {
9828 +                                       if (key.type == HASH_KEY_IS_STRING) {
9829 +                                               zval *zkey;
9830 +                                               
9831 +                                               MAKE_STD_ZVAL(zkey);
9832 +                                               ZVAL_STRINGL(zkey, key.str, key.len - 1, 1);
9833 +                                               
9834 +                                               switch (Z_TYPE_PP(header)) {
9835 +                                                       case IS_ARRAY:
9836 +                                                       case IS_OBJECT:
9837 +                                                               FOREACH_HASH_VAL(pos2, HASH_OF(*header), h) {
9838 +                                                                       ZVAL_ADDREF(*h);
9839 +                                                                       zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *h);
9840 +                                                                       zval_ptr_dtor(h);
9841 +                                                               }
9842 +                                                               break;
9843 +                                                       
9844 +                                                       default:
9845 +                                                               ZVAL_ADDREF(*header);
9846 +                                                               zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *header);
9847 +                                                               zval_ptr_dtor(header);
9848 +                                                               break;
9849 +                                               }
9850 +                                               zval_ptr_dtor(&zkey);
9851 +                                       }
9852 +                               }
9853 +                               
9854 +                               MAKE_STD_ZVAL(body);
9855 +                               ZVAL_STRINGL(body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message), 1);
9856 +                               zend_call_method_with_1_params(&return_value, http_response_object_ce, NULL, "setdata", NULL, body);
9857 +                               zval_ptr_dtor(&body);
9858 +#else
9859 +                               http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot transform HttpMessage to HttpResponse (need PHP 5.1+)");
9860 +#endif
9861 +                               break;
9862 +                       }
9863 +                       
9864 +                       default:
9865 +                               http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is neither of type HttpMessage::TYPE_REQUEST nor HttpMessage::TYPE_RESPONSE");
9866 +                               break;
9867 +               }
9868 +       }
9869 +       SET_EH_NORMAL();
9870 +}
9871 +/* }}} */
9872 +
9873 +/* {{{ proto int HttpMessage::count()
9874 +       Implements Countable::count(). Returns the number of parent messages + 1. */
9875 +PHP_METHOD(HttpMessage, count)
9876 +{
9877 +       NO_ARGS {
9878 +               long i;
9879 +               getObject(http_message_object, obj);
9880 +               
9881 +               http_message_count(i, obj->message);
9882 +               RETURN_LONG(i);
9883 +       }
9884 +}
9885 +/* }}} */
9886 +
9887 +/* {{{ proto string HttpMessage::serialize()
9888 +       Implements Serializable::serialize(). Returns the serialized representation of the HttpMessage. */
9889 +PHP_METHOD(HttpMessage, serialize)
9890 +{
9891 +       NO_ARGS {
9892 +               char *string;
9893 +               size_t length;
9894 +               getObject(http_message_object, obj);
9895 +               
9896 +               http_message_serialize(obj->message, &string, &length);
9897 +               RETURN_STRINGL(string, length, 0);
9898 +       }
9899 +}
9900 +/* }}} */
9901 +
9902 +/* {{{ proto void HttpMessage::unserialize(string serialized)
9903 +       Implements Serializable::unserialize(). Re-constructs the HttpMessage based upon the serialized string. */
9904 +PHP_METHOD(HttpMessage, unserialize)
9905 +{
9906 +       int length;
9907 +       char *serialized;
9908 +       getObject(http_message_object, obj);
9909 +       
9910 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized, &length)) {
9911 +               http_message *msg;
9912 +               
9913 +               http_message_dtor(obj->message);
9914 +               if ((msg = http_message_parse_ex(obj->message, serialized, (size_t) length))) {
9915 +                       obj->message = msg;
9916 +               } else {
9917 +                       http_message_init(obj->message);
9918 +                       http_error(HE_ERROR, HTTP_E_RUNTIME, "Could not unserialize HttpMessage");
9919 +               }
9920 +       }
9921 +}
9922 +/* }}} */
9923 +
9924 +/* {{{ proto HttpMessage HttpMessage::detach(void)
9925 +       Returns a clone of an HttpMessage object detached from any parent messages. */
9926 +PHP_METHOD(HttpMessage, detach)
9927 +{
9928 +       http_info info;
9929 +       http_message *msg;
9930 +       getObject(http_message_object, obj);
9931 +       
9932 +       NO_ARGS;
9933 +       
9934 +       info.type = obj->message->type;
9935 +       memcpy(&HTTP_INFO(&info), &HTTP_INFO(obj->message), sizeof(struct http_info));
9936 +       
9937 +       msg = http_message_new();
9938 +       http_message_set_info(msg, &info);
9939 +       
9940 +       zend_hash_copy(&msg->hdrs, &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
9941 +       phpstr_append(&msg->body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message));
9942 +       
9943 +       RETVAL_OBJVAL(http_message_object_new_ex(Z_OBJCE_P(getThis()), msg, NULL), 0);
9944 +}
9945 +/* }}} */
9946 +
9947 +/* {{{ proto void HttpMessage::prepend(HttpMessage message[, bool top = true])
9948 +       Prepends message(s) to the HTTP message. Throws HttpInvalidParamException if the message is located within the same message chain. */
9949 +PHP_METHOD(HttpMessage, prepend)
9950 +{
9951 +       zval *prepend;
9952 +       zend_bool top = 1;
9953 +       
9954 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, http_message_object_ce, &top)) {
9955 +               http_message *msg[2];
9956 +               getObject(http_message_object, obj);
9957 +               getObjectEx(http_message_object, prepend_obj, prepend);
9958 +               
9959 +               /* safety check */
9960 +               for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
9961 +                       for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
9962 +                               if (msg[0] == msg[1]) {
9963 +                                       http_error(HE_THROW, HTTP_E_INVALID_PARAM, "Cannot prepend a message located within the same message chain");
9964 +                                       return;
9965 +                               }
9966 +                       }
9967 +               }
9968 +               
9969 +               http_message_object_prepend_ex(getThis(), prepend, top);
9970 +       }
9971 +}
9972 +/* }}} */
9973 +
9974 +/* {{{ proto HttpMessage HttpMessage::reverse()
9975 +       Reorders the message chain in reverse order. Returns the most parent HttpMessage object. */
9976 +PHP_METHOD(HttpMessage, reverse)
9977 +{
9978 +       NO_ARGS {
9979 +               http_message_object_reverse(getThis(), return_value);
9980 +       }
9981 +}
9982 +/* }}} */
9983 +
9984 +/* {{{ proto void HttpMessage::rewind(void)
9985 +       Implements Iterator::rewind(). */
9986 +PHP_METHOD(HttpMessage, rewind)
9987 +{
9988 +       NO_ARGS {
9989 +               getObject(http_message_object, obj);
9990 +               
9991 +               if (obj->iterator) {
9992 +                       zval_ptr_dtor(&obj->iterator);
9993 +               }
9994 +               ZVAL_ADDREF(getThis());
9995 +               obj->iterator = getThis();
9996 +       }
9997 +}
9998 +/* }}} */
9999 +
10000 +/* {{{ proto bool HttpMessage::valid(void)
10001 +       Implements Iterator::valid(). */
10002 +PHP_METHOD(HttpMessage, valid)
10003 +{
10004 +       NO_ARGS {
10005 +               getObject(http_message_object, obj);
10006 +               
10007 +               RETURN_BOOL(obj->iterator != NULL);
10008 +       }
10009 +}
10010 +/* }}} */
10011 +
10012 +/* {{{ proto void HttpMessage::next(void)
10013 +       Implements Iterator::next(). */
10014 +PHP_METHOD(HttpMessage, next)
10015 +{
10016 +       NO_ARGS {
10017 +               getObject(http_message_object, obj);
10018 +               if (obj->iterator) {
10019 +                       getObjectEx(http_message_object, itr, obj->iterator);
10020 +                       
10021 +                       if (itr && itr->parent.handle) {
10022 +                               zval *old = obj->iterator;
10023 +                               MAKE_STD_ZVAL(obj->iterator);
10024 +                               ZVAL_OBJVAL(obj->iterator, itr->parent, 1);
10025 +                               zval_ptr_dtor(&old);
10026 +                       } else {
10027 +                               zval_ptr_dtor(&obj->iterator);
10028 +                               obj->iterator = NULL;
10029 +                       }
10030 +               }
10031 +       }
10032 +}
10033 +/* }}} */
10034 +
10035 +/* {{{ proto int HttpMessage::key(void)
10036 +       Implements Iterator::key(). */
10037 +PHP_METHOD(HttpMessage, key)
10038 +{
10039 +       NO_ARGS {
10040 +               getObject(http_message_object, obj);
10041 +               
10042 +               RETURN_LONG(obj->iterator ? obj->iterator->value.obj.handle:0);
10043 +       }
10044 +}
10045 +/* }}} */
10046 +
10047 +/* {{{ proto HttpMessage HttpMessage::current(void)
10048 +       Implements Iterator::current(). */
10049 +PHP_METHOD(HttpMessage, current)
10050 +{
10051 +       NO_ARGS {
10052 +               getObject(http_message_object, obj);
10053 +               
10054 +               if (obj->iterator) {
10055 +                       RETURN_ZVAL(obj->iterator, 1, 0);
10056 +               }
10057 +       }
10058 +}
10059 +/* }}} */
10060 +
10061 +#endif /* ZEND_ENGINE_2 */
10062 +
10063 +/*
10064 + * Local variables:
10065 + * tab-width: 4
10066 + * c-basic-offset: 4
10067 + * End:
10068 + * vim600: noet sw=4 ts=4 fdm=marker
10069 + * vim<600: noet sw=4 ts=4
10070 + */
10071 +
10072 --- /dev/null
10073 +++ b/ext/http/http_persistent_handle_api.c
10074 @@ -0,0 +1,388 @@
10075 +/*
10076 +    +--------------------------------------------------------------------+
10077 +    | PECL :: http                                                       |
10078 +    +--------------------------------------------------------------------+
10079 +    | Redistribution and use in source and binary forms, with or without |
10080 +    | modification, are permitted provided that the conditions mentioned |
10081 +    | in the accompanying LICENSE file are met.                          |
10082 +    +--------------------------------------------------------------------+
10083 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
10084 +    +--------------------------------------------------------------------+
10085 +*/
10086 +
10087 +/* $Id: http_persistent_handle_api.c 292841 2009-12-31 08:48:57Z mike $ */
10088 +
10089 +#include "php_http.h"
10090 +#include "php_http_api.h"
10091 +
10092 +#include "php_http_persistent_handle_api.h"
10093 +
10094 +#ifndef HTTP_DEBUG_PHANDLES
10095 +#      define HTTP_DEBUG_PHANDLES 0
10096 +#endif
10097 +#if HTTP_DEBUG_PHANDLES
10098 +#      undef inline
10099 +#      define inline
10100 +#endif
10101 +
10102 +static HashTable http_persistent_handles_hash;
10103 +#ifdef ZTS
10104 +#      define LOCK() tsrm_mutex_lock(http_persistent_handles_lock)
10105 +#      define UNLOCK() tsrm_mutex_unlock(http_persistent_handles_lock)
10106 +static MUTEX_T http_persistent_handles_lock;
10107 +#else
10108 +#      define LOCK()
10109 +#      define UNLOCK()
10110 +#endif
10111 +
10112 +typedef struct _http_persistent_handle_list_t {
10113 +       HashTable free;
10114 +       ulong used;
10115 +} http_persistent_handle_list;
10116 +
10117 +typedef struct _http_persistent_handle_provider_t {
10118 +       http_persistent_handle_list list; /* "ident" => array(handles) entries */
10119 +       http_persistent_handle_ctor ctor;
10120 +       http_persistent_handle_dtor dtor;
10121 +       http_persistent_handle_copy copy;
10122 +} http_persistent_handle_provider;
10123 +
10124 +static inline http_persistent_handle_list *http_persistent_handle_list_init(http_persistent_handle_list *list)
10125 +{
10126 +       int free_list;
10127 +       
10128 +       if ((free_list = !list)) {
10129 +               list = pemalloc(sizeof(http_persistent_handle_list), 1);
10130 +       }
10131 +       
10132 +       list->used = 0;
10133 +       
10134 +       if (SUCCESS != zend_hash_init(&list->free, 0, NULL, NULL, 1)) {
10135 +               if (free_list) {
10136 +                       pefree(list, 1);
10137 +               }
10138 +               list = NULL;
10139 +       }
10140 +       
10141 +       return list;
10142 +}
10143 +
10144 +static inline void http_persistent_handle_list_dtor(http_persistent_handle_list *list, http_persistent_handle_dtor dtor)
10145 +{
10146 +       HashPosition pos;
10147 +       void **handle;
10148 +       
10149 +#if HTTP_DEBUG_PHANDLES
10150 +       fprintf(stderr, "LSTDTOR: %p\n", list);
10151 +#endif
10152 +       FOREACH_HASH_VAL(pos, &list->free, handle) {
10153 +#if HTTP_DEBUG_PHANDLES
10154 +               fprintf(stderr, "DESTROY: %p\n", *handle);
10155 +#endif
10156 +               
10157 +               dtor(*handle);
10158 +       }
10159 +       zend_hash_destroy(&list->free);
10160 +}
10161 +
10162 +static inline void http_persistent_handle_list_free(http_persistent_handle_list **list, http_persistent_handle_dtor dtor)
10163 +{
10164 +       http_persistent_handle_list_dtor(*list, dtor);
10165 +#if HTTP_DEBUG_PHANDLES
10166 +       fprintf(stderr, "LSTFREE: %p\n", *list);
10167 +#endif
10168 +       pefree(*list, 1);
10169 +       *list = NULL;
10170 +}
10171 +
10172 +static inline http_persistent_handle_list *http_persistent_handle_list_find(http_persistent_handle_provider *provider TSRMLS_DC)
10173 +{
10174 +       http_persistent_handle_list **list, *new_list;
10175 +       
10176 +       if (SUCCESS == zend_hash_quick_find(&provider->list.free, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &list)) {
10177 +#if HTTP_DEBUG_PHANDLES
10178 +               fprintf(stderr, "LSTFIND: %p\n", *list);
10179 +#endif
10180 +               return *list;
10181 +       }
10182 +       
10183 +       if ((new_list = http_persistent_handle_list_init(NULL))) {
10184 +               if (SUCCESS == zend_hash_quick_add(&provider->list.free, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &new_list, sizeof(http_persistent_handle_list *), (void *) &list)) {
10185 +#if HTTP_DEBUG_PHANDLES
10186 +                       fprintf(stderr, "LSTFIND: %p (new)\n", *list);
10187 +#endif
10188 +                       return *list;
10189 +               }
10190 +               http_persistent_handle_list_free(&new_list, provider->dtor);
10191 +       }
10192 +       
10193 +       return NULL;
10194 +}
10195 +
10196 +static inline STATUS http_persistent_handle_do_acquire(http_persistent_handle_provider *provider, void **handle TSRMLS_DC)
10197 +{
10198 +       ulong index;
10199 +       void **handle_ptr;
10200 +       http_persistent_handle_list *list;
10201 +       
10202 +       if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
10203 +               zend_hash_internal_pointer_end(&list->free);
10204 +               if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&list->free, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(&list->free, (void *) &handle_ptr)) {
10205 +                       *handle = *handle_ptr;
10206 +                       zend_hash_index_del(&list->free, index);
10207 +               } else {
10208 +                       *handle = provider->ctor();
10209 +               }
10210 +               
10211 +               if (*handle) {
10212 +                       ++provider->list.used;
10213 +                       ++list->used;
10214 +                       return SUCCESS;
10215 +               }
10216 +       } else {
10217 +               *handle = NULL;
10218 +       }
10219 +       
10220 +       return FAILURE;
10221 +}
10222 +
10223 +static inline STATUS http_persistent_handle_do_release(http_persistent_handle_provider *provider, void **handle TSRMLS_DC)
10224 +{
10225 +       http_persistent_handle_list *list;
10226 +       
10227 +       if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
10228 +               if (provider->list.used >= HTTP_G->persistent.handles.limit) {
10229 +                       provider->dtor(*handle);
10230 +               } else {
10231 +                       if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) handle, sizeof(void *), NULL)) {
10232 +                               return FAILURE;
10233 +                       }
10234 +               }
10235 +               
10236 +               *handle = NULL;
10237 +               --provider->list.used;
10238 +               --list->used;
10239 +               return SUCCESS;
10240 +       }
10241 +       
10242 +       return FAILURE;
10243 +}
10244 +
10245 +static inline STATUS http_persistent_handle_do_accrete(http_persistent_handle_provider *provider, void *old_handle, void **new_handle TSRMLS_DC)
10246 +{
10247 +       http_persistent_handle_list *list;
10248 +       
10249 +       if (provider->copy && (*new_handle = provider->copy(old_handle))) {
10250 +               if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
10251 +                       ++list->used;
10252 +               }
10253 +               ++provider->list.used;
10254 +               return SUCCESS;
10255 +       }
10256 +       return FAILURE;
10257 +}
10258 +
10259 +static void http_persistent_handles_hash_dtor(void *p)
10260 +{
10261 +       http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p;
10262 +       http_persistent_handle_list **list, *list_tmp;
10263 +       HashPosition pos;
10264 +       
10265 +       FOREACH_HASH_VAL(pos, &provider->list.free, list) {
10266 +               /* fix shutdown crash in PHP4 */
10267 +               list_tmp = *list;
10268 +               http_persistent_handle_list_free(&list_tmp, provider->dtor);
10269 +       }
10270 +       
10271 +       zend_hash_destroy(&provider->list.free);
10272 +}
10273 +
10274 +PHP_MINIT_FUNCTION(http_persistent_handle)
10275 +{
10276 +       zend_hash_init(&http_persistent_handles_hash, 0, NULL, http_persistent_handles_hash_dtor, 1);
10277 +#ifdef ZTS
10278 +       http_persistent_handles_lock = tsrm_mutex_alloc();
10279 +#endif
10280 +       return SUCCESS;
10281 +}
10282 +
10283 +PHP_MSHUTDOWN_FUNCTION(http_persistent_handle)
10284 +{
10285 +       zend_hash_destroy(&http_persistent_handles_hash);
10286 +#ifdef ZTS
10287 +       tsrm_mutex_free(http_persistent_handles_lock);
10288 +#endif
10289 +       return SUCCESS;
10290 +}
10291 +
10292 +PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor, http_persistent_handle_copy copy)
10293 +{
10294 +       STATUS status = FAILURE;
10295 +       http_persistent_handle_provider provider;
10296 +       
10297 +       LOCK();
10298 +       if (http_persistent_handle_list_init(&provider.list)) {
10299 +               provider.ctor = ctor;
10300 +               provider.dtor = dtor;
10301 +               provider.copy = copy;
10302 +               
10303 +#if HTTP_DEBUG_PHANDLES
10304 +               fprintf(stderr, "PROVIDE: %s\n", name_str);
10305 +#endif
10306 +               
10307 +               if (SUCCESS == zend_hash_add(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider, sizeof(http_persistent_handle_provider), NULL)) {
10308 +                       status = SUCCESS;
10309 +               }
10310 +       }
10311 +       UNLOCK();
10312 +       
10313 +       return status;
10314 +}
10315 +
10316 +PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC)
10317 +{
10318 +       STATUS status = FAILURE;
10319 +       http_persistent_handle_provider *provider;
10320 +       
10321 +       *handle = NULL;
10322 +       LOCK();
10323 +       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) {
10324 +               status = http_persistent_handle_do_acquire(provider, handle TSRMLS_CC);
10325 +       }
10326 +       UNLOCK();
10327 +       
10328 +#if HTTP_DEBUG_PHANDLES
10329 +       fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle, name_str);
10330 +#endif
10331 +       
10332 +       return status;
10333 +}
10334 +
10335 +PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC)
10336 +{
10337 +       STATUS status = FAILURE;
10338 +       http_persistent_handle_provider *provider;
10339 +#if HTTP_DEBUG_PHANDLES
10340 +       void *handle_tmp = *handle;
10341 +#endif
10342 +       
10343 +       LOCK();
10344 +       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) {
10345 +               status = http_persistent_handle_do_release(provider, handle TSRMLS_CC);
10346 +       }
10347 +       UNLOCK();
10348 +       
10349 +#if HTTP_DEBUG_PHANDLES
10350 +       fprintf(stderr, "RELEASE: %p (%s)\n", handle_tmp, name_str);
10351 +#endif
10352 +       
10353 +       return status;
10354 +}
10355 +
10356 +PHP_HTTP_API STATUS _http_persistent_handle_accrete_ex(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC)
10357 +{
10358 +       STATUS status = FAILURE;
10359 +       http_persistent_handle_provider *provider;
10360 +       
10361 +       *new_handle = NULL;
10362 +       LOCK();
10363 +       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) {
10364 +               status = http_persistent_handle_do_accrete(provider, old_handle, new_handle TSRMLS_CC);
10365 +       }
10366 +       UNLOCK();
10367 +       
10368 +#if HTTP_DEBUG_PHANDLES
10369 +       fprintf(stderr, "ACCRETE: %p > %p (%s)\n", old_handle, *new_handle, name_str);
10370 +#endif
10371 +       
10372 +       return status;
10373 +}
10374 +
10375 +PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC)
10376 +{
10377 +       http_persistent_handle_provider *provider;
10378 +       http_persistent_handle_list *list, **listp;
10379 +       HashPosition pos1, pos2;
10380 +       
10381 +       LOCK();
10382 +       if (name_str && name_len) {
10383 +               if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) {
10384 +                       if (current_ident_only) {
10385 +                               if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
10386 +                                       http_persistent_handle_list_dtor(list, provider->dtor);
10387 +                                       http_persistent_handle_list_init(list);
10388 +                               }
10389 +                       } else {
10390 +                               FOREACH_HASH_VAL(pos1, &provider->list.free, listp) {
10391 +                                       http_persistent_handle_list_dtor(*listp, provider->dtor);
10392 +                                       http_persistent_handle_list_init(*listp);
10393 +                               }
10394 +                       }
10395 +               }
10396 +       } else {
10397 +               FOREACH_HASH_VAL(pos1, &http_persistent_handles_hash, provider) {
10398 +                       if (current_ident_only) {
10399 +                               if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
10400 +                                       http_persistent_handle_list_dtor(list, provider->dtor);
10401 +                                       http_persistent_handle_list_init(list);
10402 +                               }
10403 +                       } else {
10404 +                               FOREACH_HASH_VAL(pos2, &provider->list.free, listp) {
10405 +                                       http_persistent_handle_list_dtor(*listp, provider->dtor);
10406 +                                       http_persistent_handle_list_init(*listp);
10407 +                               }
10408 +                       }
10409 +               }
10410 +       }
10411 +       UNLOCK();
10412 +}
10413 +
10414 +PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht TSRMLS_DC)
10415 +{
10416 +       zval *zentry[2];
10417 +       HashPosition pos1, pos2;
10418 +       HashKey key1 = initHashKey(0), key2 = initHashKey(0);
10419 +       http_persistent_handle_provider *provider;
10420 +       http_persistent_handle_list **list;
10421 +       
10422 +       LOCK();
10423 +       if (zend_hash_num_elements(&http_persistent_handles_hash)) {
10424 +               if (!ht) {
10425 +                       ALLOC_HASHTABLE(ht);
10426 +                       zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
10427 +               }
10428 +               
10429 +               FOREACH_HASH_KEYVAL(pos1, &http_persistent_handles_hash, key1, provider) {
10430 +                       MAKE_STD_ZVAL(zentry[0]);
10431 +                       array_init(zentry[0]);
10432 +                       
10433 +                       FOREACH_HASH_KEYVAL(pos2, &provider->list.free, key2, list) {
10434 +                               MAKE_STD_ZVAL(zentry[1]);
10435 +                               array_init(zentry[1]);
10436 +                               add_assoc_long_ex(zentry[1], ZEND_STRS("used"), (*list)->used);
10437 +                               add_assoc_long_ex(zentry[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list)->free));
10438 +                               
10439 +                               /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */
10440 +                               zend_hash_add(Z_ARRVAL_P(zentry[0]), key2.str, key2.len, &zentry[1], sizeof(zval *), NULL);
10441 +                       }
10442 +                       
10443 +                       zend_hash_add(ht, key1.str, key1.len, &zentry[0], sizeof(zval *), NULL);
10444 +               }
10445 +       } else if (ht) {
10446 +               ht = NULL;
10447 +       }
10448 +       UNLOCK();
10449 +       
10450 +       return ht;
10451 +}
10452 +
10453 +
10454 +/*
10455 + * Local variables:
10456 + * tab-width: 4
10457 + * c-basic-offset: 4
10458 + * End:
10459 + * vim600: noet sw=4 ts=4 fdm=marker
10460 + * vim<600: noet sw=4 ts=4
10461 + */
10462 +
10463 --- /dev/null
10464 +++ b/ext/http/http_querystring_api.c
10465 @@ -0,0 +1,220 @@
10466 +/*
10467 +    +--------------------------------------------------------------------+
10468 +    | PECL :: http                                                       |
10469 +    +--------------------------------------------------------------------+
10470 +    | Redistribution and use in source and binary forms, with or without |
10471 +    | modification, are permitted provided that the conditions mentioned |
10472 +    | in the accompanying LICENSE file are met.                          |
10473 +    +--------------------------------------------------------------------+
10474 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
10475 +    +--------------------------------------------------------------------+
10476 +*/
10477 +
10478 +/* $Id: http_querystring_api.c 292841 2009-12-31 08:48:57Z mike $ */
10479 +
10480 +#define HTTP_WANT_SAPI
10481 +#include "php_http.h"
10482 +
10483 +#include "php_variables.h"
10484 +#ifdef HTTP_HAVE_ICONV
10485 +#      undef PHP_ATOM_INC
10486 +#      include "ext/iconv/php_iconv.h"
10487 +#      include "ext/standard/url.h"
10488 +#endif
10489 +
10490 +#include "php_http_api.h"
10491 +#include "php_http_url_api.h"
10492 +#include "php_http_querystring_api.h"
10493 +
10494 +#ifdef ZEND_ENGINE_2
10495 +#define THIS_CE http_querystring_object_ce
10496 +extern zend_class_entry *http_querystring_object_ce;
10497 +#endif
10498 +
10499 +
10500 +#define http_querystring_modify_array_ex(q, t, k, kl, i, pe) _http_querystring_modify_array_ex((q), (t), (k), (kl), (i), (pe) TSRMLS_CC)
10501 +static inline int _http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC);
10502 +#define http_querystring_modify_array(q, p) _http_querystring_modify_array((q), (p) TSRMLS_CC)
10503 +static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC);
10504 +
10505 +
10506 +#ifdef HTTP_HAVE_ICONV
10507 +PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC)
10508 +{
10509 +       HashPosition pos;
10510 +       zval **entry = NULL;
10511 +       char *xlate_str = NULL, *xkey;
10512 +       size_t xlate_len = 0, xlen;
10513 +       HashKey key = initHashKey(0);
10514 +       
10515 +       FOREACH_KEYVAL(pos, param, key, entry) {
10516 +               if (key.type == HASH_KEY_IS_STRING) {
10517 +                       if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.str, key.len-1, &xkey, &xlen, oe, ie)) {
10518 +                               http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", key.len-1, key.str, ie, oe);
10519 +                               return FAILURE;
10520 +                       }
10521 +               }
10522 +               
10523 +               if (Z_TYPE_PP(entry) == IS_STRING) {
10524 +                       if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) {
10525 +                               if (key.type == HASH_KEY_IS_STRING) {
10526 +                                       efree(xkey);
10527 +                               }
10528 +                               http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe);
10529 +                               return FAILURE;
10530 +                       }
10531 +                       if (key.type == HASH_KEY_IS_STRING) {
10532 +                               add_assoc_stringl_ex(array, xkey, xlen+1, xlate_str, xlate_len, 0);
10533 +                       } else {
10534 +                               add_index_stringl(array, key.num, xlate_str, xlate_len, 0);
10535 +                       }
10536 +               } else if (Z_TYPE_PP(entry) == IS_ARRAY) {
10537 +                       zval *subarray;
10538 +                       
10539 +                       MAKE_STD_ZVAL(subarray);
10540 +                       array_init(subarray);
10541 +                       if (key.type == HASH_KEY_IS_STRING) {
10542 +                               add_assoc_zval_ex(array, xkey, xlen+1, subarray);
10543 +                       } else {
10544 +                               add_index_zval(array, key.num, subarray);
10545 +                       }
10546 +                       if (SUCCESS != http_querystring_xlate(subarray, *entry, ie, oe)) {
10547 +                               if (key.type == HASH_KEY_IS_STRING) {
10548 +                                       efree(xkey);
10549 +                               }
10550 +                               return FAILURE;
10551 +                       }
10552 +               }
10553 +               
10554 +               if (key.type == HASH_KEY_IS_STRING) {
10555 +                       efree(xkey);
10556 +               }
10557 +       }
10558 +       return SUCCESS;
10559 +}
10560 +#endif /* HAVE_ICONV */
10561 +
10562 +PHP_HTTP_API void _http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC)
10563 +{
10564 +       char *s = NULL;
10565 +       size_t l = 0;
10566 +       
10567 +       if (Z_TYPE_P(qarray) != IS_ARRAY) {
10568 +               convert_to_array(qarray);
10569 +       }
10570 +       if (SUCCESS == http_urlencode_hash_ex(Z_ARRVAL_P(qarray), 0, NULL, 0, &s, &l)) {
10571 +               zval_dtor(qstring);
10572 +               ZVAL_STRINGL(qstring, s, l, 0);
10573 +       } else {
10574 +               http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to update query string");
10575 +       }
10576 +}
10577 +
10578 +PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC)
10579 +{
10580 +       if (Z_TYPE_P(params) == IS_ARRAY) {
10581 +               return http_querystring_modify_array(qarray, params);
10582 +       } else if (Z_TYPE_P(params) == IS_OBJECT) {
10583 +#ifdef ZEND_ENGINE_2
10584 +               if (instanceof_function(Z_OBJCE_P(params), http_querystring_object_ce TSRMLS_CC)) {
10585 +                       return http_querystring_modify_array(qarray, zend_read_property(THIS_CE, params, ZEND_STRS("queryArray")-1, 0 TSRMLS_CC));
10586 +               } else {
10587 +#endif
10588 +               return  http_querystring_modify_array(qarray, params);
10589 +#ifdef ZEND_ENGINE_2
10590 +               }
10591 +#endif
10592 +       } else {
10593 +               int rv;
10594 +               zval array;
10595 +               zval *qstring = http_zsep(IS_STRING, params);
10596 +               
10597 +               INIT_PZVAL(&array);
10598 +               array_init(&array);
10599 +               
10600 +               sapi_module.treat_data(PARSE_STRING, estrdup(Z_STRVAL_P(qstring)), &array TSRMLS_CC);
10601 +               zval_ptr_dtor(&qstring);
10602 +               
10603 +               rv = http_querystring_modify_array(qarray, &array);
10604 +               zval_dtor(&array);
10605 +               return rv;
10606 +       }
10607 +}
10608 +
10609 +static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC)
10610 +{
10611 +       int rv = 0;
10612 +       HashKey key = initHashKey(0);
10613 +       HashPosition pos;
10614 +       zval **params_entry = NULL;
10615 +       
10616 +       FOREACH_HASH_KEYVAL(pos, HASH_OF(params), key, params_entry) {
10617 +               /* only public properties */
10618 +               if ((key.type != HASH_KEY_IS_STRING || *key.str) && http_querystring_modify_array_ex(qarray, key.type, key.str, key.len, key.num, *params_entry)) {
10619 +                       rv = 1;
10620 +               }
10621 +       }
10622 +       
10623 +       return rv;
10624 +}
10625 +
10626 +static inline int _http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC)
10627 +{
10628 +       zval **qarray_entry;
10629 +
10630 +       /* ensure array type */
10631 +       if (Z_TYPE_P(qarray) != IS_ARRAY) {
10632 +               convert_to_array(qarray);
10633 +       }
10634 +       
10635 +       /* delete */
10636 +       if (Z_TYPE_P(params_entry) == IS_NULL) {
10637 +               if (key_type == HASH_KEY_IS_STRING) {
10638 +                       return (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), key, keylen));
10639 +               } else {
10640 +                       return (SUCCESS == zend_hash_index_del(Z_ARRVAL_P(qarray), idx));
10641 +               }
10642 +       }
10643 +       
10644 +       /* update */
10645 +       if (    ((key_type == HASH_KEY_IS_STRING) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), key, keylen, (void *) &qarray_entry))) ||
10646 +                       ((key_type == HASH_KEY_IS_LONG) && (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(qarray), idx, (void *) &qarray_entry)))) {
10647 +               zval equal;
10648 +               
10649 +               /* recursive */
10650 +               if (Z_TYPE_P(params_entry) == IS_ARRAY || Z_TYPE_P(params_entry) == IS_OBJECT) {
10651 +                       return http_querystring_modify(*qarray_entry, params_entry);
10652 +               }
10653 +               /* equal */
10654 +               if ((SUCCESS == is_equal_function(&equal, *qarray_entry, params_entry TSRMLS_CC)) && Z_BVAL(equal)) {
10655 +                       return 0;
10656 +               }
10657 +       }
10658 +       
10659 +       /* add */
10660 +       if (Z_TYPE_P(params_entry) == IS_OBJECT) {
10661 +               zval *new_array;
10662 +               
10663 +               MAKE_STD_ZVAL(new_array);
10664 +               array_init(new_array);
10665 +               http_querystring_modify_array(new_array, params_entry);
10666 +               params_entry = new_array;
10667 +       } else {
10668 +               ZVAL_ADDREF(params_entry);
10669 +       }
10670 +       if (key_type == HASH_KEY_IS_STRING) {
10671 +               add_assoc_zval_ex(qarray, key, keylen, params_entry);
10672 +       } else {
10673 +               add_index_zval(qarray, idx, params_entry);
10674 +       }
10675 +       return 1;
10676 +}
10677 +
10678 +/*
10679 + * Local variables:
10680 + * tab-width: 4
10681 + * c-basic-offset: 4
10682 + * End:
10683 + * vim600: noet sw=4 ts=4 fdm=marker
10684 + * vim<600: noet sw=4 ts=4
10685 + */
10686 --- /dev/null
10687 +++ b/ext/http/http_querystring_object.c
10688 @@ -0,0 +1,628 @@
10689 +/*
10690 +    +--------------------------------------------------------------------+
10691 +    | PECL :: http                                                       |
10692 +    +--------------------------------------------------------------------+
10693 +    | Redistribution and use in source and binary forms, with or without |
10694 +    | modification, are permitted provided that the conditions mentioned |
10695 +    | in the accompanying LICENSE file are met.                          |
10696 +    +--------------------------------------------------------------------+
10697 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
10698 +    +--------------------------------------------------------------------+
10699 +*/
10700 +
10701 +/* $Id: http_querystring_object.c 300299 2010-06-09 06:23:16Z mike $ */
10702 +
10703 +#define HTTP_WANT_SAPI
10704 +#include "php_http.h"
10705 +
10706 +#ifdef ZEND_ENGINE_2
10707 +
10708 +#include "php_variables.h"
10709 +#include "zend_interfaces.h"
10710 +
10711 +#include "php_http_api.h"
10712 +#include "php_http_querystring_api.h"
10713 +#include "php_http_querystring_object.h"
10714 +#include "php_http_exception_object.h"
10715 +
10716 +#define HTTP_BEGIN_ARGS(method, req_args)                      HTTP_BEGIN_ARGS_EX(HttpQueryString, method, 0, req_args)
10717 +#define HTTP_EMPTY_ARGS(method)                                                HTTP_EMPTY_ARGS_EX(HttpQueryString, method, 0)
10718 +#define HTTP_QUERYSTRING_ME(method, visibility)                PHP_ME(HttpQueryString, method, HTTP_ARGS(HttpQueryString, method), visibility)
10719 +#define HTTP_QUERYSTRING_GME(method, visibility)       PHP_ME(HttpQueryString, method, HTTP_ARGS(HttpQueryString, __getter), visibility)
10720 +
10721 +HTTP_BEGIN_ARGS(__construct, 0)
10722 +       HTTP_ARG_VAL(global, 0)
10723 +       HTTP_ARG_VAL(params, 0)
10724 +HTTP_END_ARGS;
10725 +
10726 +#ifndef WONKY
10727 +HTTP_BEGIN_ARGS(singleton, 0)
10728 +       HTTP_ARG_VAL(global, 0)
10729 +HTTP_END_ARGS;
10730 +#endif
10731 +
10732 +HTTP_BEGIN_ARGS(factory, 0)
10733 +       HTTP_ARG_VAL(global, 0)
10734 +       HTTP_ARG_VAL(params, 0)
10735 +       HTTP_ARG_VAL(class_name, 0)
10736 +HTTP_END_ARGS;
10737 +
10738 +HTTP_EMPTY_ARGS(toArray);
10739 +HTTP_EMPTY_ARGS(toString);
10740 +
10741 +HTTP_BEGIN_ARGS(get, 0)
10742 +       HTTP_ARG_VAL(name, 0)
10743 +       HTTP_ARG_VAL(type, 0)
10744 +       HTTP_ARG_VAL(defval, 0)
10745 +       HTTP_ARG_VAL(delete, 0)
10746 +HTTP_END_ARGS;
10747 +
10748 +HTTP_BEGIN_ARGS(set, 1)
10749 +       HTTP_ARG_VAL(params, 0)
10750 +HTTP_END_ARGS;
10751 +
10752 +HTTP_BEGIN_ARGS(mod, 0)
10753 +       HTTP_ARG_VAL(params, 0)
10754 +HTTP_END_ARGS;
10755 +
10756 +HTTP_BEGIN_ARGS(__getter, 1)
10757 +       HTTP_ARG_VAL(name, 0)
10758 +       HTTP_ARG_VAL(defval, 0)
10759 +       HTTP_ARG_VAL(delete, 0)
10760 +HTTP_END_ARGS;
10761 +
10762 +#ifdef HTTP_HAVE_ICONV
10763 +HTTP_BEGIN_ARGS(xlate, 2)
10764 +       HTTP_ARG_VAL(from_encoding, 0)
10765 +       HTTP_ARG_VAL(to_encoding, 0)
10766 +HTTP_END_ARGS;
10767 +#endif
10768 +
10769 +HTTP_EMPTY_ARGS(serialize);
10770 +HTTP_BEGIN_ARGS(unserialize, 1)
10771 +       HTTP_ARG_VAL(serialized, 0)
10772 +HTTP_END_ARGS;
10773 +
10774 +HTTP_BEGIN_ARGS(offsetGet, 1)
10775 +       HTTP_ARG_VAL(offset, 0)
10776 +HTTP_END_ARGS;
10777 +
10778 +HTTP_BEGIN_ARGS(offsetSet, 2)
10779 +       HTTP_ARG_VAL(offset, 0)
10780 +       HTTP_ARG_VAL(value, 0)
10781 +HTTP_END_ARGS;
10782 +
10783 +HTTP_BEGIN_ARGS(offsetExists, 1)
10784 +       HTTP_ARG_VAL(offset, 0)
10785 +HTTP_END_ARGS;
10786 +
10787 +HTTP_BEGIN_ARGS(offsetUnset, 1)
10788 +       HTTP_ARG_VAL(offset, 0)
10789 +HTTP_END_ARGS;
10790 +
10791 +
10792 +#define THIS_CE http_querystring_object_ce
10793 +zend_class_entry *http_querystring_object_ce;
10794 +zend_function_entry http_querystring_object_fe[] = {
10795 +       HTTP_QUERYSTRING_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
10796 +       
10797 +       HTTP_QUERYSTRING_ME(toArray, ZEND_ACC_PUBLIC)
10798 +       HTTP_QUERYSTRING_ME(toString, ZEND_ACC_PUBLIC)
10799 +       ZEND_MALIAS(HttpQueryString, __toString, toString, HTTP_ARGS(HttpQueryString, toString), ZEND_ACC_PUBLIC)
10800 +       
10801 +       HTTP_QUERYSTRING_ME(get, ZEND_ACC_PUBLIC)
10802 +       HTTP_QUERYSTRING_ME(set, ZEND_ACC_PUBLIC)
10803 +       HTTP_QUERYSTRING_ME(mod, ZEND_ACC_PUBLIC)
10804 +       
10805 +       HTTP_QUERYSTRING_GME(getBool, ZEND_ACC_PUBLIC)
10806 +       HTTP_QUERYSTRING_GME(getInt, ZEND_ACC_PUBLIC)
10807 +       HTTP_QUERYSTRING_GME(getFloat, ZEND_ACC_PUBLIC)
10808 +       HTTP_QUERYSTRING_GME(getString, ZEND_ACC_PUBLIC)
10809 +       HTTP_QUERYSTRING_GME(getArray, ZEND_ACC_PUBLIC)
10810 +       HTTP_QUERYSTRING_GME(getObject, ZEND_ACC_PUBLIC)
10811 +       
10812 +       HTTP_QUERYSTRING_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
10813 +#ifndef WONKY
10814 +       HTTP_QUERYSTRING_ME(singleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
10815 +#endif
10816 +#ifdef HTTP_HAVE_ICONV
10817 +       HTTP_QUERYSTRING_ME(xlate, ZEND_ACC_PUBLIC)
10818 +#endif
10819 +       
10820 +       /* Implements Serializable */
10821 +       HTTP_QUERYSTRING_ME(serialize, ZEND_ACC_PUBLIC)
10822 +       HTTP_QUERYSTRING_ME(unserialize, ZEND_ACC_PUBLIC)
10823 +       
10824 +       /* Implements ArrayAccess */
10825 +       HTTP_QUERYSTRING_ME(offsetGet, ZEND_ACC_PUBLIC)
10826 +       HTTP_QUERYSTRING_ME(offsetSet, ZEND_ACC_PUBLIC)
10827 +       HTTP_QUERYSTRING_ME(offsetExists, ZEND_ACC_PUBLIC)
10828 +       HTTP_QUERYSTRING_ME(offsetUnset, ZEND_ACC_PUBLIC)
10829 +       
10830 +       EMPTY_FUNCTION_ENTRY
10831 +};
10832 +static zend_object_handlers http_querystring_object_handlers;
10833 +
10834 +PHP_MINIT_FUNCTION(http_querystring_object)
10835 +{
10836 +       HTTP_REGISTER_CLASS_EX(HttpQueryString, http_querystring_object, NULL, 0);
10837 +       
10838 +#ifndef WONKY
10839 +       zend_class_implements(http_querystring_object_ce TSRMLS_CC, 2, zend_ce_serializable, zend_ce_arrayaccess);
10840 +#endif
10841 +       
10842 +       zend_declare_property_null(THIS_CE, ZEND_STRS("instance")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
10843 +       zend_declare_property_null(THIS_CE, ZEND_STRS("queryArray")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
10844 +       zend_declare_property_string(THIS_CE, ZEND_STRS("queryString")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
10845 +       
10846 +#ifndef WONKY
10847 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_BOOL")-1, HTTP_QUERYSTRING_TYPE_BOOL TSRMLS_CC);
10848 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_INT")-1, HTTP_QUERYSTRING_TYPE_INT TSRMLS_CC);
10849 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_FLOAT")-1, HTTP_QUERYSTRING_TYPE_FLOAT TSRMLS_CC);
10850 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_STRING")-1, HTTP_QUERYSTRING_TYPE_STRING TSRMLS_CC);
10851 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_ARRAY")-1, HTTP_QUERYSTRING_TYPE_ARRAY TSRMLS_CC);
10852 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_OBJECT")-1, HTTP_QUERYSTRING_TYPE_OBJECT TSRMLS_CC);
10853 +#endif
10854 +       
10855 +       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_BOOL", HTTP_QUERYSTRING_TYPE_BOOL);
10856 +       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_INT", HTTP_QUERYSTRING_TYPE_INT);
10857 +       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_FLOAT", HTTP_QUERYSTRING_TYPE_FLOAT);
10858 +       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_STRING", HTTP_QUERYSTRING_TYPE_STRING);
10859 +       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_ARRAY", HTTP_QUERYSTRING_TYPE_ARRAY);
10860 +       HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_OBJECT", HTTP_QUERYSTRING_TYPE_OBJECT);
10861 +       
10862 +       return SUCCESS;
10863 +}
10864 +
10865 +zend_object_value _http_querystring_object_new(zend_class_entry *ce TSRMLS_DC)
10866 +{
10867 +       return http_querystring_object_new_ex(ce, NULL, NULL);
10868 +}
10869 +
10870 +zend_object_value _http_querystring_object_new_ex(zend_class_entry *ce, void *nothing, http_querystring_object **ptr TSRMLS_DC)
10871 +{
10872 +       zend_object_value ov;
10873 +       http_querystring_object *o;
10874 +
10875 +       o = ecalloc(1, sizeof(http_querystring_object));
10876 +       o->zo.ce = ce;
10877 +       
10878 +       if (ptr) {
10879 +               *ptr = o;
10880 +       }
10881 +
10882 +       ALLOC_HASHTABLE(OBJ_PROP(o));
10883 +       zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
10884 +       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
10885 +
10886 +       ov.handle = putObject(http_querystring_object, o);
10887 +       ov.handlers = &http_querystring_object_handlers;
10888 +
10889 +       return ov;
10890 +}
10891 +
10892 +void _http_querystring_object_free(zend_object *object TSRMLS_DC)
10893 +{
10894 +       http_querystring_object *o = (http_querystring_object *) object;
10895 +
10896 +       freeObject(o);
10897 +}
10898 +
10899 +/* {{{ querystring helpers */
10900 +#define http_querystring_instantiate(t, g, p, u) _http_querystring_instantiate((t), (g), (p), (u) TSRMLS_CC)
10901 +static inline zval *_http_querystring_instantiate(zval *this_ptr, zend_bool global, zval *params, zend_bool defer_update TSRMLS_DC)
10902 +{
10903 +       zval *qarray = NULL, *qstring = NULL, **_SERVER = NULL, **_GET = NULL, **QUERY_STRING = NULL;;
10904 +       
10905 +       if (!this_ptr) {
10906 +               MAKE_STD_ZVAL(this_ptr);
10907 +               Z_TYPE_P(this_ptr) = IS_OBJECT;
10908 +               this_ptr->value.obj = http_querystring_object_new(http_querystring_object_ce);
10909 +       }
10910 +       if (global) {
10911 +#ifdef ZEND_ENGINE_2
10912 +               zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
10913 +#endif
10914 +               if (    (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &_SERVER)) &&
10915 +                               (Z_TYPE_PP(_SERVER) == IS_ARRAY) &&
10916 +                               (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "QUERY_STRING", sizeof("QUERY_STRING"), (void *) &QUERY_STRING))) {
10917 +                       
10918 +                       qstring = *QUERY_STRING;
10919 +#ifdef ZEND_ENGINE_2
10920 +                       zend_is_auto_global("_GET", lenof("_GET") TSRMLS_CC);
10921 +#endif
10922 +                       if ((SUCCESS == zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void *) &_GET)) && (Z_TYPE_PP(_GET) == IS_ARRAY)) {
10923 +                               qarray = *_GET;
10924 +                       } else {
10925 +                               http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Could not acquire reference to superglobal GET array");
10926 +                       }
10927 +               } else {
10928 +                       http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Could not acquire reference to QUERY_STRING");
10929 +               }
10930 +               
10931 +               if (qarray && qstring) {
10932 +                       if (Z_TYPE_P(qstring) != IS_STRING) {
10933 +                               convert_to_string(qstring);
10934 +                       }
10935 +                       
10936 +                       zend_update_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, qarray TSRMLS_CC);
10937 +                       zend_update_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, qstring TSRMLS_CC);
10938 +#ifdef Z_SET_ISREF
10939 +                       Z_SET_ISREF_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC));
10940 +                       Z_SET_ISREF_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC));
10941 +#else
10942 +                       zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)->is_ref = 1;
10943 +                       zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)->is_ref = 1;
10944 +#endif
10945 +       
10946 +                       if (params) {
10947 +                               http_querystring_modify(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), params);
10948 +                       }
10949 +                       if (!defer_update) {
10950 +                               http_querystring_update(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC));
10951 +                       }
10952 +               }
10953 +       } else {
10954 +               MAKE_STD_ZVAL(qarray);
10955 +               array_init(qarray);
10956 +               
10957 +               zend_update_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, qarray TSRMLS_CC);
10958 +               zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryString")-1, "", 0 TSRMLS_CC);
10959 +               
10960 +               if (params && http_querystring_modify(qarray, params) && !defer_update) {
10961 +                       http_querystring_update(qarray, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC));
10962 +               }
10963 +               
10964 +               zval_ptr_dtor(&qarray);
10965 +       }
10966 +       
10967 +       return this_ptr;
10968 +}
10969 +
10970 +#define http_querystring_get(o, t, n, l, def, del, r) _http_querystring_get((o), (t), (n), (l), (def), (del), (r) TSRMLS_CC)
10971 +static inline void _http_querystring_get(zval *this_ptr, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value TSRMLS_DC)
10972 +{
10973 +       zval **arrval, *qarray = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC);
10974 +               
10975 +       if ((Z_TYPE_P(qarray) == IS_ARRAY) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), name, name_len + 1, (void *) &arrval))) {
10976 +               if (type) {
10977 +                       zval *value = http_zsep(type, *arrval);
10978 +                       RETVAL_ZVAL(value, 1, 1);
10979 +               } else {
10980 +                       RETVAL_ZVAL(*arrval, 1, 0);
10981 +               }
10982 +                       
10983 +               if (del && (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), name, name_len + 1))) {
10984 +                       http_querystring_update(qarray, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC));
10985 +               }
10986 +       } else if(defval) {
10987 +               RETURN_ZVAL(defval, 1, 0);
10988 +       }
10989 +}
10990 +/* }}} */
10991 +
10992 +/* {{{ proto final void HttpQueryString::__construct([bool global = true[, mixed add])
10993 +       Creates a new HttpQueryString object instance. Operates on and modifies $_GET and $_SERVER['QUERY_STRING'] if global is TRUE. */
10994 +PHP_METHOD(HttpQueryString, __construct)
10995 +{
10996 +       zend_bool global = 1;
10997 +       zval *params = NULL;
10998 +       
10999 +       SET_EH_THROW_HTTP();
11000 +       if (!sapi_module.treat_data) {
11001 +               http_error(HE_ERROR, HTTP_E_QUERYSTRING, "The SAPI does not have a treat_data function registered");
11002 +       } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bz", &global, &params)) {
11003 +               http_querystring_instantiate(getThis(), global, params, 0);
11004 +       }
11005 +       SET_EH_NORMAL();
11006 +}
11007 +/* }}} */
11008 +
11009 +/* {{{ proto HttpQueryString HttpQueryString::factory([bool global = TRUE[, mixed params[, string class_name = "HttpQueryString"])
11010 +       Creates a new HttpQueryString object instance. */
11011 +PHP_METHOD(HttpQueryString, factory)
11012 +{
11013 +       zend_bool global = 1;
11014 +       zval *params = NULL;
11015 +       char *cn = NULL;
11016 +       int cl = 0;
11017 +       zend_object_value ov;
11018 +       
11019 +       SET_EH_THROW_HTTP();
11020 +       if (!sapi_module.treat_data) {
11021 +               http_error(HE_ERROR, HTTP_E_QUERYSTRING, "The SAPI does not have a treat_data function registered");
11022 +       } else if (     SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bzs", &global, &params, &cn, &cl) &&
11023 +                               SUCCESS == http_object_new(&ov, cn, cl, _http_querystring_object_new_ex, http_querystring_object_ce, NULL, NULL)) {
11024 +               RETVAL_OBJVAL(ov, 0);
11025 +               http_querystring_instantiate(return_value, global, params, 0);
11026 +       }
11027 +       SET_EH_NORMAL();
11028 +}
11029 +/* }}} */
11030 +
11031 +/* {{{ proto string HttpQueryString::toString()
11032 +       Returns the string representation. */
11033 +PHP_METHOD(HttpQueryString, toString)
11034 +{
11035 +       NO_ARGS;
11036 +       RETURN_PROP(queryString);
11037 +}
11038 +/* }}} */
11039 +
11040 +/* {{{ proto array HttpQueryString::toArray()
11041 +       Returns the array representation. */
11042 +PHP_METHOD(HttpQueryString, toArray)
11043 +{
11044 +       NO_ARGS;
11045 +       RETURN_PROP(queryArray);
11046 +}
11047 +/* }}} */
11048 +
11049 +/* {{{ proto mixed HttpQueryString::get([string key[, mixed type = 0[, mixed defval = NULL[, bool delete = false]]]])
11050 +       Get (part of) the query string. The type parameter is either one of the HttpQueryString::TYPE_* constants or a type abbreviation like "b" for bool, "i" for int, "f" for float, "s" for string, "a" for array and "o" for a stdClass object. */
11051 +PHP_METHOD(HttpQueryString, get)
11052 +{
11053 +       char *name = NULL;
11054 +       int name_len = 0;
11055 +       long type = 0;
11056 +       zend_bool del = 0;
11057 +       zval *ztype = NULL, *defval = NULL;
11058 +       
11059 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|szzb", &name, &name_len, &ztype, &defval, &del)) {
11060 +               if (name && name_len) {
11061 +                       if (ztype) {
11062 +                               if (Z_TYPE_P(ztype) == IS_LONG) {
11063 +                                       type = Z_LVAL_P(ztype);
11064 +                               } else if(Z_TYPE_P(ztype) == IS_STRING) {
11065 +                                       switch (Z_STRVAL_P(ztype)[0]) {
11066 +                                               case 'B': 
11067 +                                               case 'b':       type = HTTP_QUERYSTRING_TYPE_BOOL;              break;
11068 +                                               case 'I':
11069 +                                               case 'i':       type = HTTP_QUERYSTRING_TYPE_INT;               break;
11070 +                                               case 'F':
11071 +                                               case 'f':       type = HTTP_QUERYSTRING_TYPE_FLOAT;             break;  
11072 +                                               case 'S':
11073 +                                               case 's':       type = HTTP_QUERYSTRING_TYPE_STRING;    break;
11074 +                                               case 'A':
11075 +                                               case 'a':       type = HTTP_QUERYSTRING_TYPE_ARRAY;             break;
11076 +                                               case 'O':
11077 +                                               case 'o':       type = HTTP_QUERYSTRING_TYPE_OBJECT;    break;
11078 +                                       }
11079 +                               }
11080 +                       }
11081 +                       http_querystring_get(getThis(), type, name, name_len, defval, del, return_value);
11082 +               } else {
11083 +                       RETURN_PROP(queryString);
11084 +               }
11085 +       }
11086 +}
11087 +/* }}} */
11088 +
11089 +/* {{{ proto string HttpQueryString::set(mixed params)
11090 +       Set query string entry/entries. NULL values will unset the variable. */
11091 +PHP_METHOD(HttpQueryString, set)
11092 +{
11093 +       zval *params;
11094 +       
11095 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &params)) {
11096 +               zval *qarray = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC);
11097 +               if (http_querystring_modify(qarray, params)) {
11098 +                       http_querystring_update(qarray, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC));
11099 +               }
11100 +       }
11101 +       
11102 +       if (return_value_used) {
11103 +               RETURN_PROP(queryString);
11104 +       }
11105 +}
11106 +/* }}} */
11107 +
11108 +/* {{{ proto HttpQueryString HttpQueryString::mod(mixed params)
11109 +       Copies the query string object and sets provided params at the clone. */
11110 +PHP_METHOD(HttpQueryString, mod)
11111 +{
11112 +       zval *zobj, *qarr, *qstr, *params;
11113 +       
11114 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &params)) {
11115 +               zobj = http_querystring_instantiate(NULL, 0, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), 1);
11116 +               qarr = zend_read_property(THIS_CE, zobj, ZEND_STRS("queryArray")-1, 0 TSRMLS_CC);
11117 +               qstr = zend_read_property(THIS_CE, zobj, ZEND_STRS("queryString")-1, 0 TSRMLS_CC);
11118 +               
11119 +               http_querystring_modify(qarr, params);
11120 +               http_querystring_update(qarr, qstr);
11121 +               
11122 +               RETURN_ZVAL(zobj, 1, 1);
11123 +       }
11124 +}
11125 +/* }}} */
11126 +
11127 +#ifndef WONKY
11128 +/* {{{ proto static HttpQueryString HttpQueryString::singleton([bool global = true])
11129 +       Get a single instance (differentiates between the global setting). */
11130 +PHP_METHOD(HttpQueryString, singleton)
11131 +{
11132 +       zend_bool global = 1;
11133 +       zval *instance = *zend_std_get_static_property(THIS_CE, ZEND_STRS("instance")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC);
11134 +       
11135 +       SET_EH_THROW_HTTP();
11136 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &global)) {
11137 +               zval **zobj_ptr = NULL, *zobj = NULL;
11138 +               
11139 +               if (Z_TYPE_P(instance) == IS_ARRAY) {
11140 +                       if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(instance), global, (void *) &zobj_ptr)) {
11141 +                               RETVAL_ZVAL(*zobj_ptr, 1, 0);
11142 +                       } else {
11143 +                               zobj = http_querystring_instantiate(NULL, global, NULL, (zend_bool) !global);
11144 +                               add_index_zval(instance, global, zobj);
11145 +                               RETVAL_OBJECT(zobj, 1);
11146 +                       }
11147 +               } else {
11148 +                       MAKE_STD_ZVAL(instance);
11149 +                       array_init(instance);
11150 +                       
11151 +                       zobj = http_querystring_instantiate(NULL, global, NULL, (zend_bool) !global);
11152 +                       add_index_zval(instance, global, zobj);
11153 +                       RETVAL_OBJECT(zobj, 1);
11154 +                       
11155 +                       zend_update_static_property(THIS_CE, ZEND_STRS("instance")-1, instance TSRMLS_CC);
11156 +                       zval_ptr_dtor(&instance);
11157 +               }
11158 +       }
11159 +       SET_EH_NORMAL();
11160 +}
11161 +/* }}} */
11162 +#endif
11163 +
11164 +/* {{{ Getters by type */
11165 +#define HTTP_QUERYSTRING_GETTER(method, TYPE) \
11166 +PHP_METHOD(HttpQueryString, method) \
11167 +{ \
11168 +       char *name; \
11169 +       int name_len; \
11170 +       zval *defval = NULL; \
11171 +       zend_bool del = 0; \
11172 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zb", &name, &name_len, &defval, &del)) { \
11173 +               http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value); \
11174 +       } \
11175 +}
11176 +HTTP_QUERYSTRING_GETTER(getBool, IS_BOOL);
11177 +HTTP_QUERYSTRING_GETTER(getInt, IS_LONG);
11178 +HTTP_QUERYSTRING_GETTER(getFloat, IS_DOUBLE);
11179 +HTTP_QUERYSTRING_GETTER(getString, IS_STRING);
11180 +HTTP_QUERYSTRING_GETTER(getArray, IS_ARRAY);
11181 +HTTP_QUERYSTRING_GETTER(getObject, IS_OBJECT);
11182 +/* }}} */
11183 +
11184 +#ifdef HTTP_HAVE_ICONV
11185 +/* {{{ proto bool HttpQueryString::xlate(string ie, string oe)
11186 +       Converts the query string from the source encoding ie to the target encoding oe. WARNING: Don't use any character set that can contain NUL bytes like UTF-16. */
11187 +PHP_METHOD(HttpQueryString, xlate)
11188 +{
11189 +       char *ie, *oe;
11190 +       int ie_len, oe_len;
11191 +       zval xa, *qa, *qs;
11192 +       STATUS rs;
11193 +       
11194 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &ie, &ie_len, &oe, &oe_len)) {
11195 +               RETURN_FALSE;
11196 +       }
11197 +       
11198 +       qa = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC);
11199 +       qs = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC);
11200 +       INIT_PZVAL(&xa);
11201 +       array_init(&xa);
11202 +       
11203 +       if (SUCCESS == (rs = http_querystring_xlate(&xa, qa, ie, oe))) {
11204 +               zend_hash_clean(Z_ARRVAL_P(qa));
11205 +               zend_hash_copy(Z_ARRVAL_P(qa), Z_ARRVAL(xa), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
11206 +               http_querystring_update(qa, qs);
11207 +       }
11208 +       zval_dtor(&xa);
11209 +       
11210 +       RETURN_SUCCESS(rs);
11211 +}
11212 +/* }}} */
11213 +#endif /* HAVE_ICONV */
11214 +
11215 +/* {{{ proto string HttpQueryString::serialize()
11216 +       Implements Serializable::serialize(). */
11217 +PHP_METHOD(HttpQueryString, serialize)
11218 +{
11219 +       NO_ARGS;
11220 +       RETURN_PROP(queryString);
11221 +}
11222 +/* }}} */
11223 +
11224 +/* {{{ proto void HttpQueryString::unserialize(string serialized)
11225 +       Implements Serializable::unserialize(). */
11226 +PHP_METHOD(HttpQueryString, unserialize)
11227 +{
11228 +       zval *serialized;
11229 +       
11230 +       SET_EH_THROW_HTTP();
11231 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &serialized)) {
11232 +               if (Z_TYPE_P(serialized) == IS_STRING) {
11233 +                       http_querystring_instantiate(getThis(), 0, serialized, 0);
11234 +               } else {
11235 +                       http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Expected a string as parameter");
11236 +               }
11237 +       }
11238 +       SET_EH_NORMAL();
11239 +}
11240 +/* }}} */
11241 +
11242 +/* {{{ proto mixed HttpQueryString::offsetGet(string offset)
11243 +       Implements ArrayAccess::offsetGet(). */
11244 +PHP_METHOD(HttpQueryString, offsetGet)
11245 +{
11246 +       char *offset_str;
11247 +       int offset_len;
11248 +       zval **value;
11249 +       
11250 +       if (    (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) &&
11251 +                       (SUCCESS == zend_hash_find(Z_ARRVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)), offset_str, offset_len + 1, (void *) &value))) {
11252 +               RETVAL_ZVAL(*value, 1, 0);
11253 +       }
11254 +}
11255 +/* }}} */
11256 +
11257 +/* {{{ proto void HttpQueryString::offsetSet(string offset, mixed value)
11258 +       Implements ArrayAccess::offsetGet(). */
11259 +PHP_METHOD(HttpQueryString, offsetSet)
11260 +{
11261 +       char *offset_str;
11262 +       int offset_len;
11263 +       zval *value;
11264 +       
11265 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &offset_str, &offset_len, &value)) {
11266 +               zval *qarr = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), *qstr = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC);
11267 +               
11268 +               ZVAL_ADDREF(value);
11269 +               add_assoc_zval_ex(qarr, offset_str, offset_len + 1, value);
11270 +               http_querystring_update(qarr, qstr);
11271 +       }
11272 +}
11273 +/* }}} */
11274 +
11275 +/* {{{ proto bool HttpQueryString::offsetExists(string offset)
11276 +       Implements ArrayAccess::offsetExists(). */
11277 +PHP_METHOD(HttpQueryString, offsetExists)
11278 +{
11279 +       char *offset_str;
11280 +       int offset_len;
11281 +       zval **value;
11282 +       
11283 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) {
11284 +               RETURN_BOOL((SUCCESS == zend_hash_find(Z_ARRVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)), offset_str, offset_len + 1, (void *) &value)) && (Z_TYPE_PP(value) != IS_NULL));
11285 +       }
11286 +}
11287 +/* }}} */
11288 +
11289 +/* {{{ proto void HttpQueryString::offsetUnset(string offset)
11290 +       Implements ArrayAccess::offsetUnset(). */
11291 +PHP_METHOD(HttpQueryString, offsetUnset)
11292 +{
11293 +       char *offset_str;
11294 +       int offset_len;
11295 +       
11296 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) {
11297 +               zval *qarr = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC);
11298 +               
11299 +               if (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarr), offset_str, offset_len + 1)) {
11300 +                       http_querystring_update(qarr, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC));
11301 +               }
11302 +       }
11303 +}
11304 +/* }}} */
11305 +
11306 +#endif /* ZEND_ENGINE_2 */
11307 +
11308 +/*
11309 + * Local variables:
11310 + * tab-width: 4
11311 + * c-basic-offset: 4
11312 + * End:
11313 + * vim600: noet sw=4 ts=4 fdm=marker
11314 + * vim<600: noet sw=4 ts=4
11315 + */
11316 +
11317 --- /dev/null
11318 +++ b/ext/http/http_request_api.c
11319 @@ -0,0 +1,1326 @@
11320 +/*
11321 +    +--------------------------------------------------------------------+
11322 +    | PECL :: http                                                       |
11323 +    +--------------------------------------------------------------------+
11324 +    | Redistribution and use in source and binary forms, with or without |
11325 +    | modification, are permitted provided that the conditions mentioned |
11326 +    | in the accompanying LICENSE file are met.                          |
11327 +    +--------------------------------------------------------------------+
11328 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
11329 +    +--------------------------------------------------------------------+
11330 +*/
11331 +
11332 +/* $Id: http_request_api.c 310775 2011-05-05 06:02:50Z mike $ */
11333 +
11334 +#define HTTP_WANT_SAPI
11335 +#define HTTP_WANT_CURL
11336 +#include "php_http.h"
11337 +
11338 +#ifdef HTTP_HAVE_CURL
11339 +
11340 +#include "php_http_api.h"
11341 +#include "php_http_persistent_handle_api.h"
11342 +#include "php_http_request_api.h"
11343 +#include "php_http_url_api.h"
11344 +
11345 +#ifdef ZEND_ENGINE_2
11346 +#      include "php_http_request_object.h"
11347 +#endif
11348 +
11349 +#include "php_http_request_int.h"
11350 +
11351 +/* {{{ cruft for thread safe SSL crypto locks */
11352 +#ifdef HTTP_NEED_OPENSSL_TSL
11353 +static MUTEX_T *http_openssl_tsl = NULL;
11354 +
11355 +static void http_openssl_thread_lock(int mode, int n, const char * file, int line)
11356 +{
11357 +       if (mode & CRYPTO_LOCK) {
11358 +               tsrm_mutex_lock(http_openssl_tsl[n]);
11359 +       } else {
11360 +               tsrm_mutex_unlock(http_openssl_tsl[n]);
11361 +       }
11362 +}
11363 +
11364 +static ulong http_openssl_thread_id(void)
11365 +{
11366 +       return (ulong) tsrm_thread_id();
11367 +}
11368 +#endif
11369 +#ifdef HTTP_NEED_GNUTLS_TSL
11370 +static int http_gnutls_mutex_create(void **m)
11371 +{
11372 +       if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) {
11373 +               return SUCCESS;
11374 +       } else {
11375 +               return FAILURE;
11376 +       }
11377 +}
11378 +
11379 +static int http_gnutls_mutex_destroy(void **m)
11380 +{
11381 +       tsrm_mutex_free(*((MUTEX_T *) m));
11382 +       return SUCCESS;
11383 +}
11384 +
11385 +static int http_gnutls_mutex_lock(void **m)
11386 +{
11387 +       return tsrm_mutex_lock(*((MUTEX_T *) m));
11388 +}
11389 +
11390 +static int http_gnutls_mutex_unlock(void **m)
11391 +{
11392 +       return tsrm_mutex_unlock(*((MUTEX_T *) m));
11393 +}
11394 +
11395 +static struct gcry_thread_cbs http_gnutls_tsl = {
11396 +       GCRY_THREAD_OPTION_USER,
11397 +       NULL,
11398 +       http_gnutls_mutex_create,
11399 +       http_gnutls_mutex_destroy,
11400 +       http_gnutls_mutex_lock,
11401 +       http_gnutls_mutex_unlock
11402 +};
11403 +#endif
11404 +/* }}} */
11405 +
11406 +/* safe curl wrappers */
11407 +#define init_curl_storage(ch) \
11408 +       {\
11409 +               http_request_storage *st = pecalloc(1, sizeof(http_request_storage), 1); \
11410 +               curl_easy_setopt(ch, CURLOPT_PRIVATE, st); \
11411 +               curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); \
11412 +       }
11413 +
11414 +static void *safe_curl_init(void)
11415 +{
11416 +       CURL *ch;
11417 +       
11418 +       if ((ch = curl_easy_init())) {
11419 +               init_curl_storage(ch);
11420 +               return ch;
11421 +       }
11422 +       return NULL;
11423 +}
11424 +static void *safe_curl_copy(void *p)
11425 +{
11426 +       CURL *ch;
11427 +       
11428 +       if ((ch = curl_easy_duphandle(p))) {
11429 +               init_curl_storage(ch);
11430 +               return ch;
11431 +       }
11432 +       return NULL;
11433 +}
11434 +static void safe_curl_dtor(void *p) {
11435 +       http_request_storage *st = http_request_storage_get(p);
11436 +       
11437 +       curl_easy_cleanup(p);
11438 +       
11439 +       if (st) {
11440 +               if (st->url) {
11441 +                       pefree(st->url, 1);
11442 +               }
11443 +               if (st->cookiestore) {
11444 +                       pefree(st->cookiestore, 1);
11445 +               }
11446 +               pefree(st, 1);
11447 +       }
11448 +}
11449 +/* }}} */
11450 +
11451 +/* {{{ MINIT */
11452 +PHP_MINIT_FUNCTION(http_request)
11453 +{
11454 +#ifdef HTTP_NEED_OPENSSL_TSL
11455 +       /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */
11456 +       if (!CRYPTO_get_id_callback()) {
11457 +               int i, c = CRYPTO_num_locks();
11458 +               
11459 +               http_openssl_tsl = malloc(c * sizeof(MUTEX_T));
11460 +               
11461 +               for (i = 0; i < c; ++i) {
11462 +                       http_openssl_tsl[i] = tsrm_mutex_alloc();
11463 +               }
11464 +               
11465 +               CRYPTO_set_id_callback(http_openssl_thread_id);
11466 +               CRYPTO_set_locking_callback(http_openssl_thread_lock);
11467 +       }
11468 +#endif
11469 +#ifdef HTTP_NEED_GNUTLS_TSL
11470 +       gcry_control(GCRYCTL_SET_THREAD_CBS, &http_gnutls_tsl);
11471 +#endif
11472 +
11473 +       if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) {
11474 +               return FAILURE;
11475 +       }
11476 +       
11477 +       if (SUCCESS != http_persistent_handle_provide("http_request", safe_curl_init, safe_curl_dtor, safe_curl_copy)) {
11478 +               return FAILURE;
11479 +       }
11480 +       
11481 +       HTTP_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC);
11482 +       HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST);
11483 +#if HTTP_CURL_VERSION(7,19,3)
11484 +       HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST_IE", CURLAUTH_DIGEST_IE);
11485 +#endif
11486 +       HTTP_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM);
11487 +       HTTP_LONG_CONSTANT("HTTP_AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE);
11488 +       HTTP_LONG_CONSTANT("HTTP_AUTH_ANY", CURLAUTH_ANY);
11489 +       
11490 +       HTTP_LONG_CONSTANT("HTTP_VERSION_NONE", CURL_HTTP_VERSION_NONE); /* to be removed */
11491 +       HTTP_LONG_CONSTANT("HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0);
11492 +       HTTP_LONG_CONSTANT("HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1);
11493 +       HTTP_LONG_CONSTANT("HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE);
11494 +       
11495 +       HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1);
11496 +       HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2);
11497 +       HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3);
11498 +       HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT);
11499 +       
11500 +       HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_V4", CURL_IPRESOLVE_V4);
11501 +       HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_V6", CURL_IPRESOLVE_V6);
11502 +       HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER);
11503 +
11504 +#if HTTP_CURL_VERSION(7,15,2)
11505 +       HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS4", CURLPROXY_SOCKS4);
11506 +#endif
11507 +#if HTTP_CURL_VERSION(7,18,0)
11508 +       HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS4A", CURLPROXY_SOCKS4A);
11509 +       HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5_HOSTNAME);
11510 +#endif
11511 +       HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS5", CURLPROXY_SOCKS5);
11512 +       HTTP_LONG_CONSTANT("HTTP_PROXY_HTTP", CURLPROXY_HTTP);
11513 +#if HTTP_CURL_VERSION(7,19,4)
11514 +       HTTP_LONG_CONSTANT("HTTP_PROXY_HTTP_1_0", CURLPROXY_HTTP_1_0);
11515 +#endif
11516 +
11517 +#if HTTP_CURL_VERSION(7,19,1)
11518 +       HTTP_LONG_CONSTANT("HTTP_POSTREDIR_301", CURL_REDIR_POST_301);
11519 +       HTTP_LONG_CONSTANT("HTTP_POSTREDIR_302", CURL_REDIR_POST_302);
11520 +       HTTP_LONG_CONSTANT("HTTP_POSTREDIR_ALL", CURL_REDIR_POST_ALL);
11521 +#endif
11522 +       return SUCCESS;
11523 +}
11524 +/* }}} */
11525 +
11526 +/* {{{ MSHUTDOWN */
11527 +PHP_MSHUTDOWN_FUNCTION(http_request)
11528 +{
11529 +       curl_global_cleanup();
11530 +#ifdef HTTP_NEED_OPENSSL_TSL
11531 +       if (http_openssl_tsl) {
11532 +               int i, c = CRYPTO_num_locks();
11533 +                       
11534 +               CRYPTO_set_id_callback(NULL);
11535 +               CRYPTO_set_locking_callback(NULL);
11536 +                       
11537 +               for (i = 0; i < c; ++i) {
11538 +                       tsrm_mutex_free(http_openssl_tsl[i]);
11539 +               }
11540 +                       
11541 +               free(http_openssl_tsl);
11542 +               http_openssl_tsl = NULL;
11543 +       }
11544 +#endif
11545 +       return SUCCESS;
11546 +}
11547 +/* }}} */
11548 +
11549 +/* {{{ forward declarations */
11550 +#define http_request_option(r, o, k, t) _http_request_option_ex((r), (o), (k), sizeof(k), (t) TSRMLS_CC)
11551 +#define http_request_option_ex(r, o, k, l, t) _http_request_option_ex((r), (o), (k), (l), (t) TSRMLS_CC)
11552 +static inline zval *_http_request_option_ex(http_request *request, HashTable *options, char *key, size_t keylen, int type TSRMLS_DC);
11553 +#define http_request_option_cache(r, k, z) _http_request_option_cache_ex((r), (k), sizeof(k), 0, (z) TSRMLS_CC)
11554 +#define http_request_option_cache_ex(r, k, kl, h, z) _http_request_option_cache_ex((r), (k), (kl), (h), (z) TSRMLS_CC)
11555 +static inline zval *_http_request_option_cache_ex(http_request *r, char *key, size_t keylen, ulong h, zval *opt TSRMLS_DC);
11556 +
11557 +#define http_request_cookies_enabled(r) _http_request_cookies_enabled((r))
11558 +static inline int _http_request_cookies_enabled(http_request *r);
11559 +
11560 +static size_t http_curl_read_callback(void *, size_t, size_t, void *);
11561 +static int http_curl_progress_callback(void *, double, double, double, double);
11562 +static int http_curl_raw_callback(CURL *, curl_infotype, char *, size_t, void *);
11563 +static int http_curl_dummy_callback(char *data, size_t n, size_t l, void *s) { return n*l; }
11564 +static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *);
11565 +/* }}} */
11566 +
11567 +/* {{{ CURL *http_curl_init(http_request *) */
11568 +PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC)
11569 +{
11570 +       if (ch || (SUCCESS == http_persistent_handle_acquire("http_request", &ch))) {
11571 +#if defined(ZTS)
11572 +               curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L);
11573 +#endif
11574 +               curl_easy_setopt(ch, CURLOPT_HEADER, 0L);
11575 +               curl_easy_setopt(ch, CURLOPT_FILETIME, 1L);
11576 +               curl_easy_setopt(ch, CURLOPT_AUTOREFERER, 1L);
11577 +               curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L);
11578 +               curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, NULL);
11579 +               curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, http_curl_raw_callback);
11580 +               curl_easy_setopt(ch, CURLOPT_READFUNCTION, http_curl_read_callback);
11581 +               curl_easy_setopt(ch, CURLOPT_IOCTLFUNCTION, http_curl_ioctl_callback);
11582 +               curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, http_curl_dummy_callback);
11583 +               
11584 +               /* set context */
11585 +               if (request) {
11586 +                       curl_easy_setopt(ch, CURLOPT_DEBUGDATA, request);
11587 +                       
11588 +                       /* attach curl handle */
11589 +                       request->ch = ch;
11590 +                       /* set defaults (also in http_request_reset()) */
11591 +                       http_request_defaults(request);
11592 +               }
11593 +       }
11594 +       
11595 +       return ch;
11596 +}
11597 +/* }}} */
11598 +
11599 +/* {{{ CURL *http_curl_copy(CURL *) */
11600 +PHP_HTTP_API CURL *_http_curl_copy(CURL *ch TSRMLS_DC)
11601 +{
11602 +       CURL *copy;
11603 +       
11604 +       if (SUCCESS == http_persistent_handle_accrete("http_request", ch, &copy)) {
11605 +               return copy;
11606 +       }
11607 +       return NULL;
11608 +}
11609 +/* }}} */
11610 +
11611 +/* {{{ void http_curl_free(CURL **) */
11612 +PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC)
11613 +{
11614 +       if (*ch) {
11615 +               curl_easy_setopt(*ch, CURLOPT_NOPROGRESS, 1L);
11616 +               curl_easy_setopt(*ch, CURLOPT_PROGRESSFUNCTION, NULL);
11617 +               curl_easy_setopt(*ch, CURLOPT_VERBOSE, 0L);
11618 +               curl_easy_setopt(*ch, CURLOPT_DEBUGFUNCTION, NULL);
11619 +               
11620 +               http_persistent_handle_release("http_request", ch);
11621 +       }
11622 +}
11623 +/* }}} */
11624 +
11625 +/* {{{ http_request *http_request_init(http_request *) */
11626 +PHP_HTTP_API http_request *_http_request_init_ex(http_request *request, CURL *ch, http_request_method meth, const char *url ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
11627 +{
11628 +       http_request *r;
11629 +       
11630 +       if (request) {
11631 +               r = request;
11632 +       } else {
11633 +               r = emalloc_rel(sizeof(http_request));
11634 +       }
11635 +       memset(r, 0, sizeof(http_request));
11636 +       
11637 +       r->ch = ch;
11638 +       r->url = (url) ? http_absolute_url(url) : NULL;
11639 +       r->meth = (meth > 0) ? meth : HTTP_GET;
11640 +       
11641 +       phpstr_init(&r->conv.request);
11642 +       phpstr_init_ex(&r->conv.response, HTTP_CURLBUF_SIZE, 0);
11643 +       phpstr_init(&r->_cache.cookies);
11644 +       zend_hash_init(&r->_cache.options, 0, NULL, ZVAL_PTR_DTOR, 0);
11645 +       
11646 +       TSRMLS_SET_CTX(r->tsrm_ls);
11647 +       
11648 +       return r;
11649 +}
11650 +/* }}} */
11651 +
11652 +/* {{{ void http_request_dtor(http_request *) */
11653 +PHP_HTTP_API void _http_request_dtor(http_request *request)
11654 +{
11655 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
11656 +       
11657 +       http_request_reset(request);
11658 +       http_curl_free(&request->ch);
11659 +       
11660 +       phpstr_dtor(&request->_cache.cookies);
11661 +       zend_hash_destroy(&request->_cache.options);
11662 +       if (request->_cache.headers) {
11663 +               curl_slist_free_all(request->_cache.headers);
11664 +               request->_cache.headers = NULL;
11665 +       }
11666 +       if (request->_progress_callback) {
11667 +               zval_ptr_dtor(&request->_progress_callback);
11668 +               request->_progress_callback = NULL;
11669 +       }
11670 +}
11671 +/* }}} */
11672 +
11673 +/* {{{ void http_request_free(http_request **) */
11674 +PHP_HTTP_API void _http_request_free(http_request **request)
11675 +{
11676 +       if (*request) {
11677 +               TSRMLS_FETCH_FROM_CTX((*request)->tsrm_ls);
11678 +               http_request_body_free(&(*request)->body);
11679 +               http_request_dtor(*request);
11680 +               efree(*request);
11681 +               *request = NULL;
11682 +       }
11683 +}
11684 +/* }}} */
11685 +
11686 +/* {{{ void http_request_reset(http_request *) */
11687 +PHP_HTTP_API void _http_request_reset(http_request *request)
11688 +{
11689 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
11690 +       STR_SET(request->url, NULL);
11691 +       request->conv.last_type = 0;
11692 +       phpstr_dtor(&request->conv.request);
11693 +       phpstr_dtor(&request->conv.response);
11694 +       http_request_body_dtor(request->body);
11695 +       http_request_defaults(request);
11696 +       
11697 +       if (request->ch) {
11698 +               http_request_storage *st = http_request_storage_get(request->ch);
11699 +               
11700 +               if (st) {
11701 +                       if (st->url) {
11702 +                               pefree(st->url, 1);
11703 +                               st->url = NULL;
11704 +                       }
11705 +                       if (st->cookiestore) {
11706 +                               pefree(st->cookiestore, 1);
11707 +                               st->cookiestore = NULL;
11708 +                       }
11709 +                       st->errorbuffer[0] = '\0';
11710 +               }
11711 +       }
11712 +}
11713 +/* }}} */
11714 +
11715 +/* {{{ STATUS http_request_enable_cookies(http_request *) */
11716 +PHP_HTTP_API STATUS _http_request_enable_cookies(http_request *request)
11717 +{
11718 +       int initialized = 1;
11719 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
11720 +       
11721 +       HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0);
11722 +       if (initialized && (http_request_cookies_enabled(request) || (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, "")))) {
11723 +               return SUCCESS;
11724 +       }
11725 +       http_error(HE_WARNING, HTTP_E_REQUEST, "Could not enable cookies for this session");
11726 +       return FAILURE;
11727 +}
11728 +/* }}} */
11729 +
11730 +/* {{{ STATUS http_request_reset_cookies(http_request *, int) */
11731 +PHP_HTTP_API STATUS _http_request_reset_cookies(http_request *request, int session_only)
11732 +{
11733 +       int initialized = 1;
11734 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
11735 +       
11736 +       HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0);
11737 +       if (initialized) {
11738 +               if (!http_request_cookies_enabled(request)) {
11739 +                       if (SUCCESS != http_request_enable_cookies(request)) {
11740 +                               return FAILURE;
11741 +                       }
11742 +               }
11743 +               if (session_only) {
11744 +#if HTTP_CURL_VERSION(7,15,4)
11745 +                       if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS")) {
11746 +                               return SUCCESS;
11747 +                       }
11748 +#else
11749 +                       http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset session cookies (need libcurl >= v7.15.4)");
11750 +#endif
11751 +               } else {
11752 +#if HTTP_CURL_VERSION(7,14,1)
11753 +                       if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL")) {
11754 +                               return SUCCESS;
11755 +                       }
11756 +#else
11757 +                       http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset cookies (need libcurl >= v7.14.1)");
11758 +#endif
11759 +               }
11760 +       }
11761 +       return FAILURE;
11762 +}
11763 +/* }}} */
11764 +
11765 +PHP_HTTP_API STATUS _http_request_flush_cookies(http_request *request)
11766 +{
11767 +       int initialized = 1;
11768 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
11769 +       
11770 +       HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0);
11771 +       if (initialized) {
11772 +               if (!http_request_cookies_enabled(request)) {
11773 +                       return FAILURE;
11774 +               }
11775 +#if HTTP_CURL_VERSION(7,17,1)
11776 +               if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "FLUSH")) {
11777 +                       return SUCCESS;
11778 +               }
11779 +#else
11780 +               http_error(HE_WARNING, HTTP_E_REQUEST, "Could not flush cookies (need libcurl >= v7.17.1)");
11781 +#endif
11782 +       }
11783 +       return FAILURE;
11784 +}
11785 +
11786 +/* {{{ void http_request_defaults(http_request *) */
11787 +PHP_HTTP_API void _http_request_defaults(http_request *request)
11788 +{
11789 +       if (request->ch) {
11790 +               HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, NULL);
11791 +               HTTP_CURL_OPT(CURLOPT_URL, NULL);
11792 +               HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 1L);
11793 +#if HTTP_CURL_VERSION(7,19,4)
11794 +               HTTP_CURL_OPT(CURLOPT_NOPROXY, NULL);
11795 +#endif
11796 +               HTTP_CURL_OPT(CURLOPT_PROXY, NULL);
11797 +               HTTP_CURL_OPT(CURLOPT_PROXYPORT, 0L);
11798 +               HTTP_CURL_OPT(CURLOPT_PROXYTYPE, 0L);
11799 +               /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
11800 +#if HTTP_CURL_VERSION(7,19,1)          
11801 +               HTTP_CURL_OPT(CURLOPT_PROXYUSERNAME, NULL);
11802 +               HTTP_CURL_OPT(CURLOPT_PROXYPASSWORD, NULL);
11803 +#endif
11804 +               HTTP_CURL_OPT(CURLOPT_PROXYAUTH, 0L);
11805 +               HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL, 0L);
11806 +               HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, 60L);
11807 +               HTTP_CURL_OPT(CURLOPT_IPRESOLVE, 0);
11808 +               HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, 0L);
11809 +               HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, 0L);
11810 +#if HTTP_CURL_VERSION(7,15,5)
11811 +               /* LFS weirdance
11812 +               HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) 0);
11813 +               HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) 0);
11814 +               */
11815 +#endif
11816 +               /* crashes
11817 +               HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, 5L); */
11818 +               HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 0L);
11819 +               HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 0L);
11820 +               HTTP_CURL_OPT(CURLOPT_INTERFACE, NULL);
11821 +               HTTP_CURL_OPT(CURLOPT_PORT, 0L);
11822 +#if HTTP_CURL_VERSION(7,19,0)
11823 +               HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE, 0L);
11824 +#endif
11825 +#if HTTP_CURL_VERSION(7,15,2)
11826 +               HTTP_CURL_OPT(CURLOPT_LOCALPORT, 0L);
11827 +               HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, 0L);
11828 +#endif
11829 +               /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
11830 +#if HTTP_CURL_VERSION(7,19,1)
11831 +               HTTP_CURL_OPT(CURLOPT_USERNAME, NULL);
11832 +               HTTP_CURL_OPT(CURLOPT_PASSWORD, NULL);
11833 +#endif
11834 +               HTTP_CURL_OPT(CURLOPT_HTTPAUTH, 0L);
11835 +               HTTP_CURL_OPT(CURLOPT_ENCODING, NULL);
11836 +#if HTTP_CURL_VERSION(7,16,2)
11837 +               /* we do this ourself anyway */
11838 +               HTTP_CURL_OPT(CURLOPT_HTTP_CONTENT_DECODING, 0L);
11839 +               HTTP_CURL_OPT(CURLOPT_HTTP_TRANSFER_DECODING, 0L);
11840 +#endif
11841 +               HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, 0L);
11842 +#if HTTP_CURL_VERSION(7,19,1)
11843 +               HTTP_CURL_OPT(CURLOPT_POSTREDIR, 0L);
11844 +#elif HTTP_CURL_VERSION(7,17,1)
11845 +               HTTP_CURL_OPT(CURLOPT_POST301, 0L);
11846 +#endif
11847 +               HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, 0L);
11848 +               HTTP_CURL_OPT(CURLOPT_REFERER, NULL);
11849 +               HTTP_CURL_OPT(CURLOPT_USERAGENT, "PECL::HTTP/" PHP_HTTP_VERSION " (PHP/" PHP_VERSION ")");
11850 +               HTTP_CURL_OPT(CURLOPT_HTTPHEADER, NULL);
11851 +               HTTP_CURL_OPT(CURLOPT_COOKIE, NULL);
11852 +               HTTP_CURL_OPT(CURLOPT_COOKIESESSION, 0L);
11853 +               /* these options would enable curl's cookie engine by default which we don't want
11854 +               HTTP_CURL_OPT(CURLOPT_COOKIEFILE, NULL);
11855 +               HTTP_CURL_OPT(CURLOPT_COOKIEJAR, NULL); */
11856 +#if HTTP_CURL_VERSION(7,14,1)
11857 +               HTTP_CURL_OPT(CURLOPT_COOKIELIST, NULL);
11858 +#endif
11859 +               HTTP_CURL_OPT(CURLOPT_RANGE, NULL);
11860 +               HTTP_CURL_OPT(CURLOPT_RESUME_FROM, 0L);
11861 +               HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, 0L);
11862 +               HTTP_CURL_OPT(CURLOPT_TIMECONDITION, 0L);
11863 +               HTTP_CURL_OPT(CURLOPT_TIMEVALUE, 0L);
11864 +               HTTP_CURL_OPT(CURLOPT_TIMEOUT, 0L);
11865 +               HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, 3);
11866 +               HTTP_CURL_OPT(CURLOPT_SSLCERT, NULL);
11867 +               HTTP_CURL_OPT(CURLOPT_SSLCERTTYPE, NULL);
11868 +               HTTP_CURL_OPT(CURLOPT_SSLCERTPASSWD, NULL);
11869 +               HTTP_CURL_OPT(CURLOPT_SSLKEY, NULL);
11870 +               HTTP_CURL_OPT(CURLOPT_SSLKEYTYPE, NULL);
11871 +               HTTP_CURL_OPT(CURLOPT_SSLKEYPASSWD, NULL);
11872 +               HTTP_CURL_OPT(CURLOPT_SSLENGINE, NULL);
11873 +               HTTP_CURL_OPT(CURLOPT_SSLVERSION, 0L);
11874 +               HTTP_CURL_OPT(CURLOPT_SSL_VERIFYPEER, 0L);
11875 +               HTTP_CURL_OPT(CURLOPT_SSL_VERIFYHOST, 0L);
11876 +               HTTP_CURL_OPT(CURLOPT_SSL_CIPHER_LIST, NULL);
11877 +#if HTTP_CURL_VERSION(7,19,0)
11878 +               HTTP_CURL_OPT(CURLOPT_ISSUERCERT, NULL);
11879 +       #if defined(HTTP_HAVE_OPENSSL)
11880 +               HTTP_CURL_OPT(CURLOPT_CRLFILE, NULL);
11881 +       #endif
11882 +#endif
11883 +#if HTTP_CURL_VERSION(7,19,1) && defined(HTTP_HAVE_OPENSSL)
11884 +               HTTP_CURL_OPT(CURLOPT_CERTINFO, NULL);
11885 +#endif
11886 +#ifdef HTTP_CURL_CAINFO
11887 +               HTTP_CURL_OPT(CURLOPT_CAINFO, HTTP_CURL_CAINFO);
11888 +#else
11889 +               HTTP_CURL_OPT(CURLOPT_CAINFO, NULL);
11890 +#endif
11891 +               HTTP_CURL_OPT(CURLOPT_CAPATH, NULL);
11892 +               HTTP_CURL_OPT(CURLOPT_RANDOM_FILE, NULL);
11893 +               HTTP_CURL_OPT(CURLOPT_EGDSOCKET, NULL);
11894 +               HTTP_CURL_OPT(CURLOPT_POSTFIELDS, NULL);
11895 +               HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, 0L);
11896 +               HTTP_CURL_OPT(CURLOPT_HTTPPOST, NULL);
11897 +               HTTP_CURL_OPT(CURLOPT_IOCTLDATA, NULL);
11898 +               HTTP_CURL_OPT(CURLOPT_READDATA, NULL);
11899 +               HTTP_CURL_OPT(CURLOPT_INFILESIZE, 0L);
11900 +               HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
11901 +               HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, NULL);
11902 +               HTTP_CURL_OPT(CURLOPT_NOBODY, 0L);
11903 +               HTTP_CURL_OPT(CURLOPT_POST, 0L);
11904 +               HTTP_CURL_OPT(CURLOPT_UPLOAD, 0L);
11905 +               HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L);
11906 +       }
11907 +}
11908 +/* }}} */
11909 +
11910 +PHP_HTTP_API void _http_request_set_progress_callback(http_request *request, zval *cb)
11911 +{
11912 +       if (request->_progress_callback) {
11913 +               zval_ptr_dtor(&request->_progress_callback);
11914 +       }
11915 +       if ((request->_progress_callback = cb)) {
11916 +               ZVAL_ADDREF(cb);
11917 +               HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 0);
11918 +               HTTP_CURL_OPT(CURLOPT_PROGRESSDATA, request);
11919 +               HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, http_curl_progress_callback);
11920 +       } else {
11921 +               HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 1);
11922 +               HTTP_CURL_OPT(CURLOPT_PROGRESSDATA, NULL);
11923 +               HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, NULL);
11924 +       }
11925 +}
11926 +
11927 +/* {{{ STATUS http_request_prepare(http_request *, HashTable *) */
11928 +PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *options)
11929 +{
11930 +       zval *zoption;
11931 +       zend_bool range_req = 0;
11932 +       http_request_storage *storage;
11933 +
11934 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
11935 +       
11936 +       HTTP_CHECK_CURL_INIT(request->ch, http_curl_init(request), return FAILURE);
11937 +
11938 +       if (!request->url) {
11939 +               return FAILURE;
11940 +       }
11941 +       if (!(storage = http_request_storage_get(request->ch))) {
11942 +               return FAILURE;
11943 +       }
11944 +       storage->errorbuffer[0] = '\0';
11945 +       /* set options */
11946 +       if (storage->url) {
11947 +               pefree(storage->url, 1);
11948 +       }
11949 +       storage->url = pestrdup(request->url, 1);
11950 +       HTTP_CURL_OPT(CURLOPT_URL, storage->url);
11951 +
11952 +       /* progress callback */
11953 +       if ((zoption = http_request_option(request, options, "onprogress", -1))) {
11954 +               http_request_set_progress_callback(request, zoption);
11955 +       }
11956 +
11957 +       /* proxy */
11958 +       if ((zoption = http_request_option(request, options, "proxyhost", IS_STRING))) {
11959 +               HTTP_CURL_OPT(CURLOPT_PROXY, Z_STRVAL_P(zoption));
11960 +               /* type */
11961 +               if ((zoption = http_request_option(request, options, "proxytype", IS_LONG))) {
11962 +                       HTTP_CURL_OPT(CURLOPT_PROXYTYPE, Z_LVAL_P(zoption));
11963 +               }
11964 +               /* port */
11965 +               if ((zoption = http_request_option(request, options, "proxyport", IS_LONG))) {
11966 +                       HTTP_CURL_OPT(CURLOPT_PROXYPORT, Z_LVAL_P(zoption));
11967 +               }
11968 +               /* user:pass */
11969 +               if ((zoption = http_request_option(request, options, "proxyauth", IS_STRING)) && Z_STRLEN_P(zoption)) {
11970 +                       HTTP_CURL_OPT(CURLOPT_PROXYUSERPWD, Z_STRVAL_P(zoption));
11971 +               }
11972 +               /* auth method */
11973 +               if ((zoption = http_request_option(request, options, "proxyauthtype", IS_LONG))) {
11974 +                       HTTP_CURL_OPT(CURLOPT_PROXYAUTH, Z_LVAL_P(zoption));
11975 +               }
11976 +               /* tunnel */
11977 +               if ((zoption = http_request_option(request, options, "proxytunnel", IS_BOOL)) && Z_BVAL_P(zoption)) {
11978 +                       HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL, 1L);
11979 +               }
11980 +       }
11981 +#if HTTP_CURL_VERSION(7,19,4)
11982 +       if ((zoption = http_request_option(request, options, "noproxy", IS_STRING))) {
11983 +               HTTP_CURL_OPT(CURLOPT_NOPROXY, Z_STRVAL_P(zoption));
11984 +       }
11985 +#endif
11986 +
11987 +       /* dns */
11988 +       if ((zoption = http_request_option(request, options, "dns_cache_timeout", IS_LONG))) {
11989 +               HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, Z_LVAL_P(zoption));
11990 +       }
11991 +       if ((zoption = http_request_option(request, options, "ipresolve", IS_LONG)) && Z_LVAL_P(zoption)) {
11992 +               HTTP_CURL_OPT(CURLOPT_IPRESOLVE, Z_LVAL_P(zoption));
11993 +       }
11994 +       
11995 +       /* limits */
11996 +       if ((zoption = http_request_option(request, options, "low_speed_limit", IS_LONG))) {
11997 +               HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, Z_LVAL_P(zoption));
11998 +       }
11999 +       if ((zoption = http_request_option(request, options, "low_speed_time", IS_LONG))) {
12000 +               HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, Z_LVAL_P(zoption));
12001 +       }
12002 +#if HTTP_CURL_VERSION(7,15,5)
12003 +       /* LSF weirdance
12004 +       if ((zoption = http_request_option(request, options, "max_send_speed", IS_LONG))) {
12005 +               HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
12006 +       }
12007 +       if ((zoption = http_request_option(request, options, "max_recv_speed", IS_LONG))) {
12008 +               HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
12009 +       }
12010 +       */
12011 +#endif
12012 +       /* crashes
12013 +       if ((zoption = http_request_option(request, options, "maxconnects", IS_LONG))) {
12014 +               HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, Z_LVAL_P(zoption));
12015 +       } */
12016 +       if ((zoption = http_request_option(request, options, "fresh_connect", IS_BOOL)) && Z_BVAL_P(zoption)) {
12017 +               HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 1L);
12018 +       }
12019 +       if ((zoption = http_request_option(request, options, "forbid_reuse", IS_BOOL)) && Z_BVAL_P(zoption)) {
12020 +               HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 1L);
12021 +       }
12022 +       
12023 +       /* outgoing interface */
12024 +       if ((zoption = http_request_option(request, options, "interface", IS_STRING))) {
12025 +               HTTP_CURL_OPT(CURLOPT_INTERFACE, Z_STRVAL_P(zoption));
12026 +               
12027 +#if HTTP_CURL_VERSION(7,15,2)
12028 +               if ((zoption = http_request_option(request, options, "portrange", IS_ARRAY))) {
12029 +                       zval **prs, **pre;
12030 +                       
12031 +                       zend_hash_internal_pointer_reset(Z_ARRVAL_P(zoption));
12032 +                       if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &prs)) {
12033 +                               zend_hash_move_forward(Z_ARRVAL_P(zoption));
12034 +                               if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &pre)) {
12035 +                                       zval *prs_cpy = http_zsep(IS_LONG, *prs);
12036 +                                       zval *pre_cpy = http_zsep(IS_LONG, *pre);
12037 +                                       
12038 +                                       if (Z_LVAL_P(prs_cpy) && Z_LVAL_P(pre_cpy)) {
12039 +                                               HTTP_CURL_OPT(CURLOPT_LOCALPORT, MIN(Z_LVAL_P(prs_cpy), Z_LVAL_P(pre_cpy)));
12040 +                                               HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, labs(Z_LVAL_P(prs_cpy)-Z_LVAL_P(pre_cpy))+1L);
12041 +                                       }
12042 +                                       zval_ptr_dtor(&prs_cpy);
12043 +                                       zval_ptr_dtor(&pre_cpy);
12044 +                               }
12045 +                       }
12046 +               }
12047 +#endif
12048 +       }
12049 +
12050 +       /* another port */
12051 +       if ((zoption = http_request_option(request, options, "port", IS_LONG))) {
12052 +               HTTP_CURL_OPT(CURLOPT_PORT, Z_LVAL_P(zoption));
12053 +       }
12054 +       
12055 +       /* RFC4007 zone_id */
12056 +#if HTTP_CURL_VERSION(7,19,0)
12057 +       if ((zoption = http_request_option(request, options, "address_scope", IS_LONG))) {
12058 +               HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE, Z_LVAL_P(zoption));
12059 +       }
12060 +#endif
12061 +
12062 +       /* auth */
12063 +       if ((zoption = http_request_option(request, options, "httpauth", IS_STRING)) && Z_STRLEN_P(zoption)) {
12064 +               HTTP_CURL_OPT(CURLOPT_USERPWD, Z_STRVAL_P(zoption));
12065 +       }
12066 +       if ((zoption = http_request_option(request, options, "httpauthtype", IS_LONG))) {
12067 +               HTTP_CURL_OPT(CURLOPT_HTTPAUTH, Z_LVAL_P(zoption));
12068 +       }
12069 +
12070 +       /* redirects, defaults to 0 */
12071 +       if ((zoption = http_request_option(request, options, "redirect", IS_LONG))) {
12072 +               HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, Z_LVAL_P(zoption) ? 1L : 0L);
12073 +               HTTP_CURL_OPT(CURLOPT_MAXREDIRS, Z_LVAL_P(zoption));
12074 +               if ((zoption = http_request_option(request, options, "unrestrictedauth", IS_BOOL))) {
12075 +                       HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, Z_LVAL_P(zoption));
12076 +               }
12077 +#if HTTP_CURL_VERSION(7,17,1)
12078 +               if ((zoption = http_request_option(request, options, "postredir", IS_BOOL))) {
12079 +#      if HTTP_CURL_VERSION(7,19,1)
12080 +                       HTTP_CURL_OPT(CURLOPT_POSTREDIR, Z_BVAL_P(zoption) ? 1L : 0L);
12081 +#      else
12082 +                       HTTP_CURL_OPT(CURLOPT_POST301, Z_BVAL_P(zoption) ? 1L : 0L);
12083 +#      endif
12084 +               }
12085 +#endif
12086 +       }
12087 +       
12088 +       /* retries, defaults to 0 */
12089 +       if ((zoption = http_request_option(request, options, "retrycount", IS_LONG))) {
12090 +               request->_retry.count = Z_LVAL_P(zoption);
12091 +               if ((zoption = http_request_option(request, options, "retrydelay", IS_DOUBLE))) {
12092 +                       request->_retry.delay = Z_DVAL_P(zoption);
12093 +               } else {
12094 +                       request->_retry.delay = 0;
12095 +               }
12096 +       } else {
12097 +               request->_retry.count = 0;
12098 +       }
12099 +
12100 +       /* referer */
12101 +       if ((zoption = http_request_option(request, options, "referer", IS_STRING)) && Z_STRLEN_P(zoption)) {
12102 +               HTTP_CURL_OPT(CURLOPT_REFERER, Z_STRVAL_P(zoption));
12103 +       }
12104 +
12105 +       /* useragent, default "PECL::HTTP/version (PHP/version)" */
12106 +       if ((zoption = http_request_option(request, options, "useragent", IS_STRING))) {
12107 +               /* allow to send no user agent, not even default one */
12108 +               if (Z_STRLEN_P(zoption)) {
12109 +                       HTTP_CURL_OPT(CURLOPT_USERAGENT, Z_STRVAL_P(zoption));
12110 +               } else {
12111 +                       HTTP_CURL_OPT(CURLOPT_USERAGENT, NULL);
12112 +               }
12113 +       }
12114 +
12115 +       /* resume */
12116 +       if ((zoption = http_request_option(request, options, "resume", IS_LONG)) && (Z_LVAL_P(zoption) > 0)) {
12117 +               range_req = 1;
12118 +               HTTP_CURL_OPT(CURLOPT_RESUME_FROM, Z_LVAL_P(zoption));
12119 +       }
12120 +       /* or range of kind array(array(0,499), array(100,1499)) */
12121 +       else if ((zoption = http_request_option(request, options, "range", IS_ARRAY)) && zend_hash_num_elements(Z_ARRVAL_P(zoption))) {
12122 +               HashPosition pos1, pos2;
12123 +               zval **rr, **rb, **re;
12124 +               phpstr rs;
12125 +               
12126 +               phpstr_init(&rs);
12127 +               FOREACH_VAL(pos1, zoption, rr) {
12128 +                       if (Z_TYPE_PP(rr) == IS_ARRAY) {
12129 +                               zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(rr), &pos2);
12130 +                               if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &rb, &pos2)) {
12131 +                                       zend_hash_move_forward_ex(Z_ARRVAL_PP(rr), &pos2);
12132 +                                       if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &re, &pos2)) {
12133 +                                               if (    ((Z_TYPE_PP(rb) == IS_LONG) || ((Z_TYPE_PP(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(rb), Z_STRLEN_PP(rb), NULL, NULL, 1))) &&
12134 +                                                               ((Z_TYPE_PP(re) == IS_LONG) || ((Z_TYPE_PP(re) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(re), Z_STRLEN_PP(re), NULL, NULL, 1)))) {
12135 +                                                       zval *rbl = http_zsep(IS_LONG, *rb);
12136 +                                                       zval *rel = http_zsep(IS_LONG, *re);
12137 +                                                       
12138 +                                                       if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) {
12139 +                                                               phpstr_appendf(&rs, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel));
12140 +                                                       }
12141 +                                                       zval_ptr_dtor(&rbl);
12142 +                                                       zval_ptr_dtor(&rel);
12143 +                                               }
12144 +                                       }
12145 +                               }
12146 +                       }
12147 +               }
12148 +               
12149 +               if (PHPSTR_LEN(&rs)) {
12150 +                       zval *cached_range;
12151 +                       
12152 +                       /* ditch last comma */
12153 +                       PHPSTR_VAL(&rs)[PHPSTR_LEN(&rs)-- -1] = '\0';
12154 +                       /* cache string */
12155 +                       MAKE_STD_ZVAL(cached_range);
12156 +                       ZVAL_STRINGL(cached_range, PHPSTR_VAL(&rs), PHPSTR_LEN(&rs), 0);
12157 +                       HTTP_CURL_OPT(CURLOPT_RANGE, Z_STRVAL_P(http_request_option_cache(request, "range", cached_range)));
12158 +                       zval_ptr_dtor(&cached_range);
12159 +               }
12160 +       }
12161 +
12162 +       /* additional headers, array('name' => 'value') */
12163 +       if (request->_cache.headers) {
12164 +               curl_slist_free_all(request->_cache.headers);
12165 +               request->_cache.headers = NULL;
12166 +       }
12167 +       if ((zoption = http_request_option(request, options, "headers", IS_ARRAY))) {
12168 +               HashKey header_key = initHashKey(0);
12169 +               zval **header_val;
12170 +               HashPosition pos;
12171 +               phpstr header;
12172 +               
12173 +               phpstr_init(&header);
12174 +               FOREACH_KEYVAL(pos, zoption, header_key, header_val) {
12175 +                       if (header_key.type == HASH_KEY_IS_STRING) {
12176 +                               zval *header_cpy = http_zsep(IS_STRING, *header_val);
12177 +                               
12178 +                               if (!strcasecmp(header_key.str, "range")) {
12179 +                                       range_req = 1;
12180 +                               }
12181 +
12182 +                               phpstr_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy));
12183 +                               phpstr_fix(&header);
12184 +                               request->_cache.headers = curl_slist_append(request->_cache.headers, PHPSTR_VAL(&header));
12185 +                               phpstr_reset(&header);
12186 +                               
12187 +                               zval_ptr_dtor(&header_cpy);
12188 +                       }
12189 +               }
12190 +               phpstr_dtor(&header);
12191 +       }
12192 +       /* etag */
12193 +       if ((zoption = http_request_option(request, options, "etag", IS_STRING)) && Z_STRLEN_P(zoption)) {
12194 +               zend_bool is_quoted = !((Z_STRVAL_P(zoption)[0] != '"') || (Z_STRVAL_P(zoption)[Z_STRLEN_P(zoption)-1] != '"'));
12195 +               phpstr header;
12196 +               
12197 +               phpstr_init(&header);
12198 +               phpstr_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", range_req?"If-Match":"If-None-Match", Z_STRVAL_P(zoption));
12199 +               phpstr_fix(&header);
12200 +               request->_cache.headers = curl_slist_append(request->_cache.headers, PHPSTR_VAL(&header));
12201 +               phpstr_dtor(&header);
12202 +       }
12203 +       /* compression */
12204 +       if ((zoption = http_request_option(request, options, "compress", IS_BOOL)) && Z_LVAL_P(zoption)) {
12205 +               request->_cache.headers = curl_slist_append(request->_cache.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5");
12206 +       }
12207 +       HTTP_CURL_OPT(CURLOPT_HTTPHEADER, request->_cache.headers);
12208 +
12209 +       /* lastmodified */
12210 +       if ((zoption = http_request_option(request, options, "lastmodified", IS_LONG))) {
12211 +               if (Z_LVAL_P(zoption)) {
12212 +                       if (Z_LVAL_P(zoption) > 0) {
12213 +                               HTTP_CURL_OPT(CURLOPT_TIMEVALUE, Z_LVAL_P(zoption));
12214 +                       } else {
12215 +                               HTTP_CURL_OPT(CURLOPT_TIMEVALUE, (long) HTTP_G->request.time + Z_LVAL_P(zoption));
12216 +                       }
12217 +                       HTTP_CURL_OPT(CURLOPT_TIMECONDITION, (long) (range_req ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE));
12218 +               } else {
12219 +                       HTTP_CURL_OPT(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
12220 +               }
12221 +       }
12222 +
12223 +       /* cookies, array('name' => 'value') */
12224 +       if ((zoption = http_request_option(request, options, "cookies", IS_ARRAY))) {
12225 +               phpstr_dtor(&request->_cache.cookies);
12226 +               if (zend_hash_num_elements(Z_ARRVAL_P(zoption))) {
12227 +                       zval *urlenc_cookies = NULL;
12228 +                       /* check whether cookies should not be urlencoded; default is to urlencode them */
12229 +                       if ((!(urlenc_cookies = http_request_option(request, options, "encodecookies", IS_BOOL))) || Z_BVAL_P(urlenc_cookies)) {
12230 +                               if (SUCCESS == http_urlencode_hash_recursive(HASH_OF(zoption), &request->_cache.cookies, "; ", lenof("; "), NULL, 0)) {
12231 +                                       phpstr_fix(&request->_cache.cookies);
12232 +                                       HTTP_CURL_OPT(CURLOPT_COOKIE, request->_cache.cookies.data);
12233 +                               }
12234 +                       } else {
12235 +                               HashPosition pos;
12236 +                               HashKey cookie_key = initHashKey(0);
12237 +                               zval **cookie_val;
12238 +                               
12239 +                               FOREACH_KEYVAL(pos, zoption, cookie_key, cookie_val) {
12240 +                                       if (cookie_key.type == HASH_KEY_IS_STRING) {
12241 +                                               zval *val = http_zsep(IS_STRING, *cookie_val);
12242 +                                               phpstr_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(val));
12243 +                                               zval_ptr_dtor(&val);
12244 +                                       }
12245 +                               }
12246 +                               
12247 +                               phpstr_fix(&request->_cache.cookies);
12248 +                               if (PHPSTR_LEN(&request->_cache.cookies)) {
12249 +                                       HTTP_CURL_OPT(CURLOPT_COOKIE, PHPSTR_VAL(&request->_cache.cookies));
12250 +                               }
12251 +                       }
12252 +               }
12253 +       }
12254 +
12255 +       /* don't load session cookies from cookiestore */
12256 +       if ((zoption = http_request_option(request, options, "cookiesession", IS_BOOL)) && Z_BVAL_P(zoption)) {
12257 +               HTTP_CURL_OPT(CURLOPT_COOKIESESSION, 1L);
12258 +       }
12259 +
12260 +       /* cookiestore, read initial cookies from that file and store cookies back into that file */
12261 +       if ((zoption = http_request_option(request, options, "cookiestore", IS_STRING))) {
12262 +               if (Z_STRLEN_P(zoption)) {
12263 +                       HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(zoption), return FAILURE);
12264 +               }
12265 +               if (storage->cookiestore) {
12266 +                       pefree(storage->cookiestore, 1);
12267 +               }
12268 +               storage->cookiestore = pestrndup(Z_STRVAL_P(zoption), Z_STRLEN_P(zoption), 1);
12269 +               HTTP_CURL_OPT(CURLOPT_COOKIEFILE, storage->cookiestore);
12270 +               HTTP_CURL_OPT(CURLOPT_COOKIEJAR, storage->cookiestore);
12271 +       }
12272 +
12273 +       /* maxfilesize */
12274 +       if ((zoption = http_request_option(request, options, "maxfilesize", IS_LONG))) {
12275 +               HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, Z_LVAL_P(zoption));
12276 +       }
12277 +
12278 +       /* http protocol */
12279 +       if ((zoption = http_request_option(request, options, "protocol", IS_LONG))) {
12280 +               HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, Z_LVAL_P(zoption));
12281 +       }
12282 +
12283 +#if HTTP_CURL_VERSION(7,16,2)
12284 +       /* timeout, defaults to 0 */
12285 +       if ((zoption = http_request_option(request, options, "timeout", IS_DOUBLE))) {
12286 +               HTTP_CURL_OPT(CURLOPT_TIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000));
12287 +       }
12288 +       /* connecttimeout, defaults to 0 */
12289 +       if ((zoption = http_request_option(request, options, "connecttimeout", IS_DOUBLE))) {
12290 +               HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000));
12291 +       }
12292 +#else
12293 +       /* timeout, defaults to 0 */
12294 +       if ((zoption = http_request_option(request, options, "timeout", IS_LONG))) {
12295 +               HTTP_CURL_OPT(CURLOPT_TIMEOUT, Z_LVAL_P(zoption));
12296 +       }
12297 +       /* connecttimeout, defaults to 0 */
12298 +       if ((zoption = http_request_option(request, options, "connecttimeout", IS_LONG))) {
12299 +               HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, Z_LVAL_P(zoption));
12300 +       }
12301 +#endif
12302 +
12303 +       /* ssl */
12304 +       if ((zoption = http_request_option(request, options, "ssl", IS_ARRAY))) {
12305 +               HashKey key = initHashKey(0);
12306 +               zval **param;
12307 +               HashPosition pos;
12308 +
12309 +               FOREACH_KEYVAL(pos, zoption, key, param) {
12310 +                       if (key.type == HASH_KEY_IS_STRING) {
12311 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSLCERT, 0, 1);
12312 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTTYPE, 0, 0);
12313 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTPASSWD, 0, 0);
12314 +
12315 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSLKEY, 0, 0);
12316 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYTYPE, 0, 0);
12317 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYPASSWD, 0, 0);
12318 +
12319 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSLENGINE, 0, 0);
12320 +                               HTTP_CURL_OPT_LONG(CURLOPT_SSLVERSION, 0);
12321 +
12322 +                               HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYPEER, 1);
12323 +                               HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYHOST, 1);
12324 +                               HTTP_CURL_OPT_STRING(CURLOPT_SSL_CIPHER_LIST, 1, 0);
12325 +
12326 +                               HTTP_CURL_OPT_STRING(CURLOPT_CAINFO, -3, 1);
12327 +                               HTTP_CURL_OPT_STRING(CURLOPT_CAPATH, -3, 1);
12328 +                               HTTP_CURL_OPT_STRING(CURLOPT_RANDOM_FILE, -3, 1);
12329 +                               HTTP_CURL_OPT_STRING(CURLOPT_EGDSOCKET, -3, 1);
12330 +#if HTTP_CURL_VERSION(7,19,0)
12331 +                               HTTP_CURL_OPT_STRING(CURLOPT_ISSUERCERT, -3, 1);
12332 +       #if defined(HTTP_HAVE_OPENSSL)
12333 +                               HTTP_CURL_OPT_STRING(CURLOPT_CRLFILE, -3, 1);
12334 +       #endif
12335 +#endif
12336 +#if HTTP_CURL_VERSION(7,19,1) && defined(HTTP_HAVE_OPENSSL)
12337 +                               HTTP_CURL_OPT_LONG(CURLOPT_CERTINFO, -3);
12338 +#endif
12339 +                       }
12340 +               }
12341 +       }
12342 +
12343 +       /* request method */
12344 +       switch (request->meth) {
12345 +               case HTTP_GET:
12346 +                       HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L);
12347 +                       break;
12348 +
12349 +               case HTTP_HEAD:
12350 +                       HTTP_CURL_OPT(CURLOPT_NOBODY, 1L);
12351 +                       break;
12352 +
12353 +               case HTTP_POST:
12354 +                       HTTP_CURL_OPT(CURLOPT_POST, 1L);
12355 +                       break;
12356 +
12357 +               case HTTP_PUT:
12358 +                       HTTP_CURL_OPT(CURLOPT_UPLOAD, 1L);
12359 +                       break;
12360 +
12361 +               default:
12362 +                       if (http_request_method_exists(0, request->meth, NULL)) {
12363 +                               HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, http_request_method_name(request->meth));
12364 +                       } else {
12365 +                               http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unsupported request method: %d (%s)", request->meth, request->url);
12366 +                               return FAILURE;
12367 +                       }
12368 +                       break;
12369 +       }
12370 +
12371 +       /* attach request body */
12372 +       if (request->body && (request->meth != HTTP_GET) && (request->meth != HTTP_HEAD) && (request->meth != HTTP_OPTIONS)) {
12373 +               switch (request->body->type) {
12374 +                       case HTTP_REQUEST_BODY_EMPTY:
12375 +                               /* nothing */
12376 +                               break;
12377 +                       
12378 +                       case HTTP_REQUEST_BODY_CURLPOST:
12379 +                               HTTP_CURL_OPT(CURLOPT_HTTPPOST, (struct curl_httppost *) request->body->data);
12380 +                               break;
12381 +
12382 +                       case HTTP_REQUEST_BODY_CSTRING:
12383 +                               if (request->meth != HTTP_PUT) {
12384 +                                       HTTP_CURL_OPT(CURLOPT_POSTFIELDS, request->body->data);
12385 +                                       HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, request->body->size);
12386 +                                       break;
12387 +                               }
12388 +                               /* fallthrough, PUT/UPLOAD _needs_ READDATA */
12389 +                       case HTTP_REQUEST_BODY_UPLOADFILE:
12390 +                               HTTP_CURL_OPT(CURLOPT_IOCTLDATA, request);
12391 +                               HTTP_CURL_OPT(CURLOPT_READDATA, request);
12392 +                               HTTP_CURL_OPT(CURLOPT_INFILESIZE, request->body->size);
12393 +                               break;
12394 +
12395 +                       default:
12396 +                               /* shouldn't ever happen */
12397 +                               http_error_ex(HE_ERROR, 0, "Unknown request body type: %d (%s)", request->body->type, request->url);
12398 +                               return FAILURE;
12399 +               }
12400 +       }
12401 +
12402 +       return SUCCESS;
12403 +}
12404 +/* }}} */
12405 +
12406 +/* {{{ void http_request_exec(http_request *) */
12407 +PHP_HTTP_API void _http_request_exec(http_request *request)
12408 +{
12409 +       uint tries = 0;
12410 +       CURLcode result;
12411 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
12412 +       
12413 +retry:
12414 +       if (CURLE_OK != (result = curl_easy_perform(request->ch))) {
12415 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(result), http_request_storage_get(request->ch)->errorbuffer, request->url);
12416 +#ifdef ZEND_ENGINE_2
12417 +               if ((HTTP_G->only_exceptions || GLOBAL_ERROR_HANDLING == EH_THROW) && EG(exception)) {
12418 +                       add_property_long(EG(exception), "curlCode", result);
12419 +               }
12420 +#endif
12421 +               
12422 +               if (request->_retry.count > tries++) {
12423 +                       switch (result) {
12424 +                               case CURLE_COULDNT_RESOLVE_PROXY:
12425 +                               case CURLE_COULDNT_RESOLVE_HOST:
12426 +                               case CURLE_COULDNT_CONNECT:
12427 +                               case CURLE_WRITE_ERROR:
12428 +                               case CURLE_READ_ERROR:
12429 +                               case CURLE_OPERATION_TIMEDOUT:
12430 +                               case CURLE_SSL_CONNECT_ERROR:
12431 +                               case CURLE_GOT_NOTHING:
12432 +                               case CURLE_SSL_ENGINE_SETFAILED:
12433 +                               case CURLE_SEND_ERROR:
12434 +                               case CURLE_RECV_ERROR:
12435 +                               case CURLE_SSL_ENGINE_INITFAILED:
12436 +                               case CURLE_LOGIN_DENIED:
12437 +                                       if (request->_retry.delay >= HTTP_DIFFSEC) {
12438 +                                               http_sleep(request->_retry.delay);
12439 +                                       }
12440 +                                       goto retry;
12441 +                               default:
12442 +                                       break;
12443 +                       }
12444 +               }
12445 +       }
12446 +}
12447 +/* }}} */
12448 +
12449 +/* {{{ static size_t http_curl_read_callback(void *, size_t, size_t, void *) */
12450 +static size_t http_curl_read_callback(void *data, size_t len, size_t n, void *ctx)
12451 +{
12452 +       http_request *request = (http_request *) ctx;
12453 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
12454 +       
12455 +       if (request->body) {
12456 +               switch (request->body->type) {
12457 +                       case HTTP_REQUEST_BODY_CSTRING:
12458 +                       {
12459 +                               size_t out = MIN(len * n, request->body->size - request->body->priv);
12460 +                               
12461 +                               if (out) {
12462 +                                       memcpy(data, ((char *) request->body->data) + request->body->priv, out);
12463 +                                       request->body->priv += out;
12464 +                                       return out;
12465 +                               }
12466 +                               break;
12467 +                       }
12468 +                       
12469 +                       case HTTP_REQUEST_BODY_UPLOADFILE:
12470 +                               return php_stream_read((php_stream *) request->body->data, data, len * n);
12471 +               }
12472 +       }
12473 +       return 0;
12474 +}
12475 +/* }}} */
12476 +
12477 +/* {{{ static int http_curl_progress_callback(void *, double, double, double, double) */
12478 +static int http_curl_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow)
12479 +{
12480 +       zval *param, retval;
12481 +       http_request *request = (http_request *) ctx;
12482 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
12483 +
12484 +       INIT_PZVAL(&retval);
12485 +       ZVAL_NULL(&retval);
12486 +
12487 +       MAKE_STD_ZVAL(param);
12488 +       array_init(param);
12489 +       add_assoc_double(param, "dltotal", dltotal);
12490 +       add_assoc_double(param, "dlnow", dlnow);
12491 +       add_assoc_double(param, "ultotal", ultotal);
12492 +       add_assoc_double(param, "ulnow", ulnow);
12493 +       
12494 +       with_error_handling(EH_NORMAL, NULL) {
12495 +               request->_in_progress_cb = 1;
12496 +               call_user_function(EG(function_table), NULL, request->_progress_callback, &retval, 1, &param TSRMLS_CC);
12497 +               request->_in_progress_cb = 0;
12498 +       } end_error_handling();
12499 +       
12500 +       zval_ptr_dtor(&param);
12501 +       zval_dtor(&retval);
12502 +       
12503 +       return 0;
12504 +}
12505 +/* }}} */
12506 +
12507 +/* {{{ static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *) */
12508 +static curlioerr http_curl_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx)
12509 +{
12510 +       http_request *request = (http_request *) ctx;
12511 +       TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
12512 +       
12513 +       if (cmd != CURLIOCMD_RESTARTREAD) {
12514 +               return CURLIOE_UNKNOWNCMD;
12515 +       }
12516 +       
12517 +       if (request->body) {
12518 +               switch (request->body->type) {
12519 +                       case HTTP_REQUEST_BODY_CSTRING:
12520 +                               request->body->priv = 0;
12521 +                               return CURLIOE_OK;
12522 +                               break;
12523 +                               
12524 +                       case HTTP_REQUEST_BODY_UPLOADFILE:
12525 +                               if (SUCCESS == php_stream_rewind((php_stream *) request->body->data)) {
12526 +                                       return CURLIOE_OK;
12527 +                               }
12528 +                               break;
12529 +               }
12530 +       }
12531 +       
12532 +       return CURLIOE_FAILRESTART;
12533 +}
12534 +/* }}} */
12535 +
12536 +/* {{{ static int http_curl_raw_callback(CURL *, curl_infotype, char *, size_t, void *) */
12537 +static int http_curl_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx)
12538 +{
12539 +       http_request *request = (http_request *) ctx;
12540 +
12541 +#define EMPTY_HEADER(d, l) (!l || (l == 1 && d[0] == '\n') || (l == 2 && d[0] == '\r' && d[1] == '\n'))
12542 +       switch (type) {
12543 +               case CURLINFO_DATA_IN:
12544 +                       if (request->conv.last_type == CURLINFO_HEADER_IN) {
12545 +                               phpstr_appends(&request->conv.response, HTTP_CRLF);
12546 +                       }
12547 +                       phpstr_append(&request->conv.response, data, length);
12548 +                       break;
12549 +               case CURLINFO_HEADER_IN:
12550 +                       if (!EMPTY_HEADER(data, length)) {
12551 +                               phpstr_append(&request->conv.response, data, length);
12552 +                       }
12553 +                       break;
12554 +               case CURLINFO_DATA_OUT:
12555 +               case CURLINFO_HEADER_OUT:
12556 +                       phpstr_append(&request->conv.request, data, length);
12557 +                       break;
12558 +               default:
12559 +                       break;
12560 +       }
12561 +
12562 +#if 0
12563 +       {
12564 +               const char _sym[] = "><><><";
12565 +               if (type) {
12566 +                       for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) {
12567 +                               fprintf(stderr, HTTP_IS_CTYPE(print, *data)?"%c":"\\x%02X", (int) *data);
12568 +                               if (*data == '\n' && length) {
12569 +                                       fprintf(stderr, "\n%c ", _sym[type-1]);
12570 +                               }
12571 +                       }
12572 +                       fprintf(stderr, "\n");
12573 +               } else {
12574 +                       fprintf(stderr, "# %s", data);
12575 +               }
12576 +       }
12577 +#endif
12578 +       
12579 +       if (type) {
12580 +               request->conv.last_type = type;
12581 +       }
12582 +       return 0;
12583 +}
12584 +/* }}} */
12585 +
12586 +/* {{{ static inline zval *http_request_option(http_request *, HashTable *, char *, size_t, int) */
12587 +static inline zval *_http_request_option_ex(http_request *r, HashTable *options, char *key, size_t keylen, int type TSRMLS_DC)
12588 +{
12589 +       if (options) {
12590 +               zval **zoption;
12591 +               ulong h = zend_hash_func(key, keylen);
12592 +               
12593 +               if (SUCCESS == zend_hash_quick_find(options, key, keylen, h, (void *) &zoption)) {
12594 +                       zval *option, *cached;
12595 +                       
12596 +                       option = http_zsep(type, *zoption);
12597 +                       cached = http_request_option_cache_ex(r, key, keylen, h, option);
12598 +                       
12599 +                       zval_ptr_dtor(&option);
12600 +                       return cached;
12601 +               }
12602 +       }
12603 +       
12604 +       return NULL;
12605 +}
12606 +/* }}} */
12607 +
12608 +/* {{{ static inline zval *http_request_option_cache(http_request *, char *key, zval *) */
12609 +static inline zval *_http_request_option_cache_ex(http_request *r, char *key, size_t keylen, ulong h, zval *opt TSRMLS_DC)
12610 +{
12611 +       ZVAL_ADDREF(opt);
12612 +       
12613 +       if (h) {
12614 +               zend_hash_quick_update(&r->_cache.options, key, keylen, h, &opt, sizeof(zval *), NULL);
12615 +       } else {
12616 +               zend_hash_update(&r->_cache.options, key, keylen, &opt, sizeof(zval *), NULL);
12617 +       }
12618 +       
12619 +       return opt;
12620 +}
12621 +/* }}} */
12622 +
12623 +/* {{{ static inline int http_request_cookies_enabled(http_request *) */
12624 +static inline int _http_request_cookies_enabled(http_request *request) {
12625 +       http_request_storage *st;
12626 +       
12627 +       if (request->ch && (st = http_request_storage_get(request->ch)) && st->cookiestore) {
12628 +               /* cookies are enabled */
12629 +               return 1;
12630 +       }
12631 +       return 0;
12632 +}
12633 +/* }}} */
12634 +
12635 +#endif /* HTTP_HAVE_CURL */
12636 +
12637 +/*
12638 + * Local variables:
12639 + * tab-width: 4
12640 + * c-basic-offset: 4
12641 + * End:
12642 + * vim600: noet sw=4 ts=4 fdm=marker
12643 + * vim<600: noet sw=4 ts=4
12644 + */
12645 +
12646 --- /dev/null
12647 +++ b/ext/http/http_request_body_api.c
12648 @@ -0,0 +1,332 @@
12649 +/*
12650 +    +--------------------------------------------------------------------+
12651 +    | PECL :: http                                                       |
12652 +    +--------------------------------------------------------------------+
12653 +    | Redistribution and use in source and binary forms, with or without |
12654 +    | modification, are permitted provided that the conditions mentioned |
12655 +    | in the accompanying LICENSE file are met.                          |
12656 +    +--------------------------------------------------------------------+
12657 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
12658 +    +--------------------------------------------------------------------+
12659 +*/
12660 +
12661 +/* $Id: http_request_body_api.c 292841 2009-12-31 08:48:57Z mike $ */
12662 +
12663 +#define HTTP_WANT_CURL
12664 +#include "php_http.h"
12665 +
12666 +#ifdef HTTP_HAVE_CURL
12667 +
12668 +#include "php_http_api.h"
12669 +#include "php_http_url_api.h"
12670 +#include "php_http_request_body_api.h"
12671 +
12672 +/* {{{ */
12673 +typedef struct curl_httppost *post_data[2];
12674 +static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC);
12675 +static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC);
12676 +/* }}} */
12677 +
12678 +/* {{{ http_request_body *http_request_body_new() */
12679 +PHP_HTTP_API http_request_body *_http_request_body_init_ex(http_request_body *body, int type, void *data, size_t size, zend_bool free ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
12680 +{
12681 +       if (!body) {
12682 +               body = emalloc_rel(sizeof(http_request_body));
12683 +       }
12684 +       
12685 +       body->type = type;
12686 +       body->free = free;
12687 +       body->priv = 0;
12688 +       body->data = data;
12689 +       body->size = size;
12690 +       
12691 +       return body;
12692 +}
12693 +/* }}} */
12694 +
12695 +/* {{{ http_request_body *http_request_body_fill(http_request_body *body, HashTable *, HashTable *) */
12696 +PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
12697 +{
12698 +       if (files && (zend_hash_num_elements(files) > 0)) {
12699 +               struct curl_httppost *http_post_data[2] = {NULL, NULL};
12700 +
12701 +               if (fields && SUCCESS != recursive_fields(http_post_data, fields, NULL TSRMLS_CC)) {
12702 +                       return NULL;
12703 +               }
12704 +               if (SUCCESS != recursive_files(http_post_data, files, NULL TSRMLS_CC)) {
12705 +                       return NULL;
12706 +               }
12707 +               return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CURLPOST, http_post_data[0], 0, 1);
12708 +       } else if (fields) {
12709 +               char *encoded;
12710 +               size_t encoded_len;
12711 +
12712 +               if (SUCCESS != http_urlencode_hash_ex(fields, 1, NULL, 0, &encoded, &encoded_len)) {
12713 +                       http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post data");
12714 +                       return NULL;
12715 +               }
12716 +               
12717 +               return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, encoded, encoded_len, 1);
12718 +       } else {
12719 +               return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, estrndup("", 0), 0, 1);
12720 +       }
12721 +}
12722 +
12723 +/* STATUS http_request_body_encode(http_request_body *, char**, size_t *) */
12724 +PHP_HTTP_API STATUS _http_request_body_encode(http_request_body *body, char **buf, size_t *len TSRMLS_DC)
12725 +{
12726 +       switch (body->type) {
12727 +               case HTTP_REQUEST_BODY_CURLPOST:
12728 +               {
12729 +#ifdef HAVE_CURL_FORMGET
12730 +                       phpstr str;
12731 +                       
12732 +                       phpstr_init_ex(&str, 0x8000, 0);
12733 +                       if (curl_formget(body->data, &str, (curl_formget_callback) phpstr_append)) {
12734 +                               phpstr_dtor(&str);
12735 +                       } else {
12736 +                               phpstr_fix(&str);
12737 +                               *buf = PHPSTR_VAL(&str);
12738 +                               *len = PHPSTR_LEN(&str);
12739 +                               return SUCCESS;
12740 +                       }
12741 +#endif
12742 +                       break;
12743 +               }
12744 +               
12745 +               case HTTP_REQUEST_BODY_CSTRING:
12746 +                       *buf = estrndup(body->data, *len = body->size);
12747 +                       return SUCCESS;
12748 +               
12749 +               default:
12750 +                       break;
12751 +       }
12752 +       return FAILURE;
12753 +}
12754 +/* }}} */
12755 +
12756 +/* {{{ void http_request_body_dtor(http_request_body *) */
12757 +PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC)
12758 +{
12759 +       if (body) {
12760 +               if (body->free) {
12761 +                       switch (body->type) {
12762 +                               case HTTP_REQUEST_BODY_CSTRING:
12763 +                                       if (body->data) {
12764 +                                               efree(body->data);
12765 +                                       }
12766 +                                       break;
12767 +       
12768 +                               case HTTP_REQUEST_BODY_CURLPOST:
12769 +                                       curl_formfree(body->data);
12770 +                                       break;
12771 +       
12772 +                               case HTTP_REQUEST_BODY_UPLOADFILE:
12773 +                                       php_stream_close(body->data);
12774 +                                       break;
12775 +                       }
12776 +               }
12777 +               memset(body, 0, sizeof(http_request_body));
12778 +       }
12779 +}
12780 +/* }}} */
12781 +
12782 +/* {{{ void http_request_body_free(http_request_body *) */
12783 +PHP_HTTP_API void _http_request_body_free(http_request_body **body TSRMLS_DC)
12784 +{
12785 +       if (*body) {
12786 +               http_request_body_dtor(*body);
12787 +               efree(*body);
12788 +               *body = NULL;
12789 +       }
12790 +}
12791 +/* }}} */
12792 +
12793 +static inline char *format_key(uint type, char *str, ulong num, const char *prefix, int numeric_key_for_empty_prefix) {
12794 +       char *new_key = NULL;
12795 +       
12796 +       if (prefix && *prefix) {
12797 +               if (type == HASH_KEY_IS_STRING) {
12798 +                       spprintf(&new_key, 0, "%s[%s]", prefix, str);
12799 +               } else {
12800 +                       spprintf(&new_key, 0, "%s[%lu]", prefix, num);
12801 +               }
12802 +       } else if (type == HASH_KEY_IS_STRING) {
12803 +               new_key = estrdup(str);
12804 +       } else if (numeric_key_for_empty_prefix) {
12805 +               spprintf(&new_key, 0, "%lu", num);
12806 +       }
12807 +       
12808 +       return new_key;
12809 +}
12810 +
12811 +/* {{{ static STATUS recursive_fields(post_data d, HashTable *f, const char *p TSRMLS_DC) */
12812 +static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC) {
12813 +       HashKey key = initHashKey(0);
12814 +       zval **data_ptr;
12815 +       HashPosition pos;
12816 +       char *new_key = NULL;
12817 +       CURLcode err = 0;
12818 +       
12819 +       if (fields && !fields->nApplyCount) {
12820 +               FOREACH_HASH_KEYVAL(pos, fields, key, data_ptr) {
12821 +                       if (key.type != HASH_KEY_IS_STRING || *key.str) {
12822 +                               new_key = format_key(key.type, key.str, key.num, prefix, 1);
12823 +                               
12824 +                               switch (Z_TYPE_PP(data_ptr)) {
12825 +                                       case IS_ARRAY:
12826 +                                       case IS_OBJECT: {
12827 +                                               STATUS status;
12828 +                                               
12829 +                                               ++fields->nApplyCount;
12830 +                                               status = recursive_fields(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
12831 +                                               --fields->nApplyCount;
12832 +                                               
12833 +                                               if (SUCCESS != status) {
12834 +                                                       goto error;
12835 +                                               }
12836 +                                               break;
12837 +                                       }
12838 +                                               
12839 +                                       default: {
12840 +                                               zval *data = http_zsep(IS_STRING, *data_ptr);
12841 +                                               
12842 +                                               err = curl_formadd(&http_post_data[0], &http_post_data[1],
12843 +                                                       CURLFORM_COPYNAME,                      new_key,
12844 +                                                       CURLFORM_COPYCONTENTS,          Z_STRVAL_P(data),
12845 +                                                       CURLFORM_CONTENTSLENGTH,        (long) Z_STRLEN_P(data),
12846 +                                                       CURLFORM_END
12847 +                                               );
12848 +                                               
12849 +                                               zval_ptr_dtor(&data);
12850 +                                               
12851 +                                               if (CURLE_OK != err) {
12852 +                                                       goto error;
12853 +                                               }
12854 +                                               break;
12855 +                                       }
12856 +                               }
12857 +                               STR_FREE(new_key);
12858 +                       }
12859 +               }
12860 +       }
12861 +       
12862 +       return SUCCESS;
12863 +       
12864 +error:
12865 +       if (new_key) {
12866 +               efree(new_key);
12867 +       }
12868 +       if (http_post_data[0]) {
12869 +               curl_formfree(http_post_data[0]);
12870 +       }
12871 +       if (err) {
12872 +               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
12873 +       } else {
12874 +               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: unknown error");
12875 +       }
12876 +       return FAILURE;
12877 +}
12878 +/* }}} */
12879 +
12880 +/* {{{ static STATUS recursive_files(post_data d, HashTable *f, const char *p TSRMLS_DC) */
12881 +static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC) {
12882 +       HashKey key = initHashKey(0);
12883 +       zval **data_ptr;
12884 +       HashPosition pos;
12885 +       char *new_key = NULL;
12886 +       CURLcode err = 0;
12887 +       
12888 +       if (files && !files->nApplyCount) {
12889 +               FOREACH_HASH_KEYVAL(pos, files, key, data_ptr) {
12890 +                       zval **file_ptr, **type_ptr, **name_ptr;
12891 +                       
12892 +                       if (key.type != HASH_KEY_IS_STRING || *key.str) {
12893 +                               new_key = format_key(key.type, key.str, key.num, prefix, 0);
12894 +                               
12895 +                               if (Z_TYPE_PP(data_ptr) != IS_ARRAY && Z_TYPE_PP(data_ptr) != IS_OBJECT) {
12896 +                                       if (new_key || key.type == HASH_KEY_IS_STRING) {
12897 +                                               http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%s'", new_key ? new_key : key.str);
12898 +                                       } else {
12899 +                                               http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%lu'", key.num);
12900 +                                       }
12901 +                               } else if (     SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "name", sizeof("name"), (void *) &name_ptr) ||
12902 +                                                       SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "type", sizeof("type"), (void *) &type_ptr) ||
12903 +                                                       SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "file", sizeof("file"), (void *) &file_ptr)) {
12904 +                                       STATUS status;
12905 +                                       
12906 +                                       ++files->nApplyCount;
12907 +                                       status = recursive_files(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
12908 +                                       --files->nApplyCount;
12909 +                                       
12910 +                                       if (SUCCESS != status) {
12911 +                                               goto error;
12912 +                                       }
12913 +                               } else {
12914 +                                       const char *path;
12915 +                                       zval *file = http_zsep(IS_STRING, *file_ptr);
12916 +                                       zval *type = http_zsep(IS_STRING, *type_ptr);
12917 +                                       zval *name = http_zsep(IS_STRING, *name_ptr);
12918 +                                       
12919 +                                       HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(file), goto error);
12920 +                                       
12921 +                                       /* this is blatant but should be sufficient for most cases */
12922 +                                       if (strncasecmp(Z_STRVAL_P(file), "file://", lenof("file://"))) {
12923 +                                               path = Z_STRVAL_P(file);
12924 +                                       } else {
12925 +                                               path = Z_STRVAL_P(file) + lenof("file://");
12926 +                                       }
12927 +                                       
12928 +                                       if (new_key) {
12929 +                                               char *tmp_key = format_key(HASH_KEY_IS_STRING, Z_STRVAL_P(name), 0, new_key, 0);
12930 +                                               STR_SET(new_key, tmp_key);
12931 +                                       }
12932 +                                       
12933 +                                       err = curl_formadd(&http_post_data[0], &http_post_data[1],
12934 +                                               CURLFORM_COPYNAME,              new_key ? new_key : Z_STRVAL_P(name),
12935 +                                               CURLFORM_FILE,                  path,
12936 +                                               CURLFORM_CONTENTTYPE,   Z_STRVAL_P(type),
12937 +                                               CURLFORM_END
12938 +                                       );
12939 +                                       
12940 +                                       zval_ptr_dtor(&file);
12941 +                                       zval_ptr_dtor(&type);
12942 +                                       zval_ptr_dtor(&name);
12943 +                                       
12944 +                                       if (CURLE_OK != err) {
12945 +                                               goto error;
12946 +                                       }
12947 +                               }
12948 +                               STR_FREE(new_key);
12949 +                       }
12950 +               }
12951 +       }
12952 +       
12953 +       return SUCCESS;
12954 +       
12955 +error:
12956 +       if (new_key) {
12957 +               efree(new_key);
12958 +       }
12959 +       if (http_post_data[0]) {
12960 +               curl_formfree(http_post_data[0]);
12961 +       }
12962 +       if (err) {
12963 +               http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
12964 +       } else {
12965 +               http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: unknown error");
12966 +       }
12967 +       return FAILURE;
12968 +}
12969 +/* }}} */
12970 +
12971 +#endif /* HTTP_HAVE_CURL */
12972 +
12973 +/*
12974 + * Local variables:
12975 + * tab-width: 4
12976 + * c-basic-offset: 4
12977 + * End:
12978 + * vim600: noet sw=4 ts=4 fdm=marker
12979 + * vim<600: noet sw=4 ts=4
12980 + */
12981 --- /dev/null
12982 +++ b/ext/http/http_request_datashare_api.c
12983 @@ -0,0 +1,288 @@
12984 +/*
12985 +    +--------------------------------------------------------------------+
12986 +    | PECL :: http                                                       |
12987 +    +--------------------------------------------------------------------+
12988 +    | Redistribution and use in source and binary forms, with or without |
12989 +    | modification, are permitted provided that the conditions mentioned |
12990 +    | in the accompanying LICENSE file are met.                          |
12991 +    +--------------------------------------------------------------------+
12992 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
12993 +    +--------------------------------------------------------------------+
12994 +*/
12995 +
12996 +/* $Id: http_request_datashare_api.c 292841 2009-12-31 08:48:57Z mike $ */
12997 +
12998 +#define HTTP_WANT_CURL
12999 +#include "php_http.h"
13000 +
13001 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
13002 +
13003 +#include "php_http_api.h"
13004 +#include "php_http_persistent_handle_api.h"
13005 +#include "php_http_request_datashare_api.h"
13006 +#include "php_http_request_api.h"
13007 +#include "php_http_request_object.h"
13008 +
13009 +static HashTable http_request_datashare_options;
13010 +static http_request_datashare http_request_datashare_global;
13011 +static int http_request_datashare_compare_handles(void *h1, void *h2);
13012 +static void http_request_datashare_destroy_handles(void *el);
13013 +#ifdef ZTS
13014 +static void *http_request_datashare_locks_init(void);
13015 +static void http_request_datashare_locks_dtor(void *l);
13016 +static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr);
13017 +static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr);
13018 +#endif
13019 +
13020 +http_request_datashare *_http_request_datashare_global_get(void)
13021 +{
13022 +       return &http_request_datashare_global;
13023 +}
13024 +
13025 +PHP_MINIT_FUNCTION(http_request_datashare)
13026 +{
13027 +       curl_lock_data val;
13028 +       
13029 +       if (SUCCESS != http_persistent_handle_provide("http_request_datashare", curl_share_init, (http_persistent_handle_dtor) curl_share_cleanup, NULL)) {
13030 +               return FAILURE;
13031 +       }
13032 +#ifdef ZTS
13033 +       if (SUCCESS != http_persistent_handle_provide("http_request_datashare_lock", http_request_datashare_locks_init, http_request_datashare_locks_dtor, NULL)) {
13034 +               return FAILURE;
13035 +       }
13036 +#endif
13037 +       
13038 +       if (!http_request_datashare_init_ex(&http_request_datashare_global, 1)) {
13039 +               return FAILURE;
13040 +       }
13041 +       
13042 +       zend_hash_init(&http_request_datashare_options, 4, NULL, NULL, 1);
13043 +#define ADD_DATASHARE_OPT(name, opt) \
13044 +       val = opt; \
13045 +       zend_hash_add(&http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
13046 +       ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE);
13047 +       ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS);
13048 +       ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION);
13049 +       ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT);
13050 +       
13051 +       return SUCCESS;
13052 +}
13053 +
13054 +PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
13055 +{
13056 +       http_request_datashare_dtor(&http_request_datashare_global);
13057 +       zend_hash_destroy(&http_request_datashare_options);
13058 +       
13059 +       return SUCCESS;
13060 +}
13061 +
13062 +PHP_RINIT_FUNCTION(http_request_datashare)
13063 +{
13064 +       zend_llist_init(&HTTP_G->request.datashare.handles, sizeof(zval *), http_request_datashare_destroy_handles, 0);
13065 +       
13066 +       return SUCCESS;
13067 +}
13068 +
13069 +PHP_RSHUTDOWN_FUNCTION(http_request_datashare)
13070 +{
13071 +       zend_llist_destroy(&HTTP_G->request.datashare.handles);
13072 +       
13073 +       return SUCCESS;
13074 +}
13075 +
13076 +PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC)
13077 +{
13078 +       zend_bool free_share;
13079 +       
13080 +       if ((free_share = !share)) {
13081 +               share = pemalloc(sizeof(http_request_datashare), persistent);
13082 +       }
13083 +       memset(share, 0, sizeof(http_request_datashare));
13084 +       
13085 +       if (SUCCESS != http_persistent_handle_acquire("http_request_datashare", &share->ch)) {
13086 +               if (free_share) {
13087 +                       pefree(share, persistent);
13088 +               }
13089 +               return NULL;
13090 +       }
13091 +       
13092 +       if (!(share->persistent = persistent)) {
13093 +               share->handle.list = emalloc(sizeof(zend_llist));
13094 +               zend_llist_init(share->handle.list, sizeof(zval *), ZVAL_PTR_DTOR, 0);
13095 +#ifdef ZTS
13096 +       } else {
13097 +               if (SUCCESS == http_persistent_handle_acquire("http_request_datashare_lock", (void *) &share->handle.locks)) {
13098 +                       curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, http_request_datashare_lock_func);
13099 +                       curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, http_request_datashare_unlock_func);
13100 +                       curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share->handle.locks);
13101 +               }
13102 +#endif
13103 +       }
13104 +       
13105 +       return share;
13106 +}
13107 +
13108 +PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC)
13109 +{
13110 +       CURLcode rc;
13111 +       getObjectEx(http_request_object, obj, request);
13112 +       
13113 +       if (obj->share) {
13114 +               if (obj->share == share)  {
13115 +                       return SUCCESS;
13116 +               } else if (SUCCESS != http_request_datashare_detach(obj->share, request)) {
13117 +                       return FAILURE;
13118 +               }
13119 +       }
13120 +       
13121 +       HTTP_CHECK_CURL_INIT(obj->request->ch, http_curl_init_ex(obj->request->ch, obj->request), return FAILURE);
13122 +       if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) {
13123 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_easy_strerror(rc));
13124 +               return FAILURE;
13125 +       }
13126 +       
13127 +       obj->share = share;
13128 +       ZVAL_ADDREF(request);
13129 +       zend_llist_add_element(HTTP_RSHARE_HANDLES(share), (void *) &request);
13130 +       
13131 +       return SUCCESS;
13132 +}
13133 +
13134 +PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC)
13135 +{
13136 +       CURLcode rc;
13137 +       getObjectEx(http_request_object, obj, request);
13138 +       
13139 +       if (!obj->share) {
13140 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
13141 +       } else if (obj->share != share) {
13142 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
13143 +       } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) {
13144 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
13145 +       } else {
13146 +               obj->share = NULL;
13147 +               zend_llist_del_element(HTTP_RSHARE_HANDLES(share), request, http_request_datashare_compare_handles);
13148 +               return SUCCESS;
13149 +       }
13150 +       return FAILURE;
13151 +}
13152 +
13153 +PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC)
13154 +{
13155 +       zval **r;
13156 +       
13157 +       while ((r = zend_llist_get_first(HTTP_RSHARE_HANDLES(share)))) {
13158 +               http_request_datashare_detach(share, *r);
13159 +       }
13160 +}
13161 +
13162 +PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC)
13163 +{
13164 +       if (!share->persistent) {
13165 +               zend_llist_destroy(share->handle.list);
13166 +               efree(share->handle.list);
13167 +       }
13168 +       http_persistent_handle_release("http_request_datashare", &share->ch);
13169 +#ifdef ZTS
13170 +       if (share->persistent) {
13171 +               http_persistent_handle_release("http_request_datashare_lock", (void *) &share->handle.locks);
13172 +       }
13173 +#endif
13174 +}
13175 +
13176 +PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC)
13177 +{
13178 +       http_request_datashare_dtor(*share);
13179 +       pefree(*share, (*share)->persistent);
13180 +       *share = NULL;
13181 +}
13182 +
13183 +PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC)
13184 +{
13185 +       curl_lock_data *opt;
13186 +       CURLSHcode rc;
13187 +       
13188 +       if (SUCCESS == zend_hash_find(&http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) {
13189 +               if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) {
13190 +                       return SUCCESS;
13191 +               }
13192 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not %s sharing of %s data: %s",  enable ? "enable" : "disable", option, curl_share_strerror(rc));
13193 +       }
13194 +       return FAILURE;
13195 +}
13196 +
13197 +static int http_request_datashare_compare_handles(void *h1, void *h2)
13198 +{
13199 +       return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
13200 +}
13201 +
13202 +static void http_request_datashare_destroy_handles(void *el)
13203 +{
13204 +       zval **r = (zval **) el;
13205 +       TSRMLS_FETCH();
13206 +       
13207 +       { /* gcc 2.95 needs these braces */
13208 +               getObjectEx(http_request_object, obj, *r);
13209 +               
13210 +               curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL);
13211 +               zval_ptr_dtor(r);
13212 +       }
13213 +}
13214 +
13215 +#ifdef ZTS
13216 +static void *http_request_datashare_locks_init(void)
13217 +{
13218 +       int i;
13219 +       http_request_datashare_lock *locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(http_request_datashare_lock), 1);
13220 +       
13221 +       if (locks) {
13222 +               for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
13223 +                       locks[i].mx = tsrm_mutex_alloc();
13224 +               }
13225 +       }
13226 +       
13227 +       return locks;
13228 +}
13229 +
13230 +static void http_request_datashare_locks_dtor(void *l)
13231 +{
13232 +       int i;
13233 +       http_request_datashare_lock *locks = (http_request_datashare_lock *) l;
13234 +       
13235 +       for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
13236 +               tsrm_mutex_free(locks[i].mx);
13237 +       }
13238 +       pefree(locks, 1);
13239 +}
13240 +
13241 +static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
13242 +{
13243 +       http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr;
13244 +       
13245 +       /* TSRM can't distinguish shared/exclusive locks */
13246 +       tsrm_mutex_lock(locks[data].mx);
13247 +       locks[data].ch = handle;
13248 +}
13249 +
13250 +static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
13251 +{
13252 +       http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr;
13253 +       
13254 +       if (locks[data].ch == handle) {
13255 +               tsrm_mutex_unlock(locks[data].mx);
13256 +       }
13257 +}
13258 +#endif
13259 +
13260 +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
13261 +
13262 +
13263 +/*
13264 + * Local variables:
13265 + * tab-width: 4
13266 + * c-basic-offset: 4
13267 + * End:
13268 + * vim600: noet sw=4 ts=4 fdm=marker
13269 + * vim<600: noet sw=4 ts=4
13270 + */
13271 +
13272 --- /dev/null
13273 +++ b/ext/http/http_request_info.c
13274 @@ -0,0 +1,198 @@
13275 +/*
13276 +    +--------------------------------------------------------------------+
13277 +    | PECL :: http                                                       |
13278 +    +--------------------------------------------------------------------+
13279 +    | Redistribution and use in source and binary forms, with or without |
13280 +    | modification, are permitted provided that the conditions mentioned |
13281 +    | in the accompanying LICENSE file are met.                          |
13282 +    +--------------------------------------------------------------------+
13283 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
13284 +    +--------------------------------------------------------------------+
13285 +*/
13286 +
13287 +/* $Id: http_request_info.c 293136 2010-01-05 08:48:52Z mike $ */
13288 +
13289 +#define HTTP_WANT_CURL
13290 +#include "php_http.h"
13291 +
13292 +#ifdef HTTP_HAVE_CURL
13293 +#include "php_http_request_api.h"
13294 +
13295 +/* {{{ void http_request_info(http_request *, HashTable *) */
13296 +PHP_HTTP_API void _http_request_info(http_request *request, HashTable *info)
13297 +{
13298 +       char *c;
13299 +       long l;
13300 +       double d;
13301 +       struct curl_slist *s, *p;
13302 +       zval *subarray, array;
13303 +       INIT_ZARR(array, info);
13304 +       
13305 +       /* BEGIN */
13306 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_EFFECTIVE_URL, &c)) {
13307 +               add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1);
13308 +       }
13309 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_RESPONSE_CODE, &l)) {
13310 +               add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l);
13311 +       }
13312 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_TOTAL_TIME, &d)) {
13313 +               add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d);
13314 +       }
13315 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_NAMELOOKUP_TIME, &d)) {
13316 +               add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d);
13317 +       }
13318 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONNECT_TIME, &d)) {
13319 +               add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d);
13320 +       }
13321 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PRETRANSFER_TIME, &d)) {
13322 +               add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d);
13323 +       }
13324 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SIZE_UPLOAD, &d)) {
13325 +               add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d);
13326 +       }
13327 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SIZE_DOWNLOAD, &d)) {
13328 +               add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d);
13329 +       }
13330 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SPEED_DOWNLOAD, &d)) {
13331 +               add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d);
13332 +       }
13333 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SPEED_UPLOAD, &d)) {
13334 +               add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d);
13335 +       }
13336 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HEADER_SIZE, &l)) {
13337 +               add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l);
13338 +       }
13339 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REQUEST_SIZE, &l)) {
13340 +               add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l);
13341 +       }
13342 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SSL_VERIFYRESULT, &l)) {
13343 +               add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l);
13344 +       }
13345 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_FILETIME, &l)) {
13346 +               add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l);
13347 +       }
13348 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
13349 +               add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d);
13350 +       }
13351 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) {
13352 +               add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d);
13353 +       }
13354 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_STARTTRANSFER_TIME, &d)) {
13355 +               add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d);
13356 +       }
13357 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_TYPE, &c)) {
13358 +               add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1);
13359 +       }
13360 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_TIME, &d)) {
13361 +               add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d);
13362 +       }
13363 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_COUNT, &l)) {
13364 +               add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l);
13365 +       }
13366 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HTTP_CONNECTCODE, &l)) {
13367 +               add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l);
13368 +       }
13369 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HTTPAUTH_AVAIL, &l)) {
13370 +               add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l);
13371 +       }
13372 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PROXYAUTH_AVAIL, &l)) {
13373 +               add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l);
13374 +       }
13375 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_OS_ERRNO, &l)) {
13376 +               add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l);
13377 +       }
13378 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_NUM_CONNECTS, &l)) {
13379 +               add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l);
13380 +       }
13381 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SSL_ENGINES, &s)) {
13382 +               MAKE_STD_ZVAL(subarray);
13383 +               array_init(subarray);
13384 +               for (p = s; p; p = p->next) {
13385 +                       if (p->data) {
13386 +                               add_next_index_string(subarray, p->data, 1);
13387 +                       }
13388 +               }
13389 +               add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray);
13390 +               curl_slist_free_all(s);
13391 +       }
13392 +#if HTTP_CURL_VERSION(7,14,1)
13393 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_COOKIELIST, &s)) {
13394 +               MAKE_STD_ZVAL(subarray);
13395 +               array_init(subarray);
13396 +               for (p = s; p; p = p->next) {
13397 +                       if (p->data) {
13398 +                               add_next_index_string(subarray, p->data, 1);
13399 +                       }
13400 +               }
13401 +               add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray);
13402 +               curl_slist_free_all(s);
13403 +       }
13404 +#endif
13405 +#if HTTP_CURL_VERSION(7,18,2)
13406 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_URL, &c)) {
13407 +               add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1);
13408 +       }
13409 +#endif
13410 +#if HTTP_CURL_VERSION(7,19,0)
13411 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PRIMARY_IP, &c)) {
13412 +               add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1);
13413 +       }
13414 +#endif
13415 +#if HTTP_CURL_VERSION(7,19,0)
13416 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_APPCONNECT_TIME, &d)) {
13417 +               add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d);
13418 +       }
13419 +#endif
13420 +#if HTTP_CURL_VERSION(7,19,4)
13421 +       if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONDITION_UNMET, &l)) {
13422 +               add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l);
13423 +       }
13424 +#endif
13425 +/* END */
13426 +#if HTTP_CURL_VERSION(7,19,1) && defined(HTTP_HAVE_OPENSSL)
13427 +       {
13428 +               int i;
13429 +               zval *ci_array;
13430 +               struct curl_certinfo *ci;
13431 +               char *colon, *keyname;
13432 +               
13433 +               if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CERTINFO, &ci)) {
13434 +                       MAKE_STD_ZVAL(ci_array);
13435 +                       array_init(ci_array);
13436 +                       
13437 +                       for (i = 0; i < ci->num_of_certs; ++i) {
13438 +                               s = ci->certinfo[i];
13439 +                               
13440 +                               MAKE_STD_ZVAL(subarray);
13441 +                               array_init(subarray);
13442 +                               for (p = s; p; p = p->next) {
13443 +                                       if (p->data) {
13444 +                                               if ((colon = strchr(p->data, ':'))) {
13445 +                                                       keyname = estrndup(p->data, colon - p->data);
13446 +                                                       add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1);
13447 +                                                       efree(keyname);
13448 +                                               } else {
13449 +                                                       add_next_index_string(subarray, p->data, 1);
13450 +                                               }
13451 +                                       }
13452 +                               }
13453 +                               add_next_index_zval(ci_array, subarray);
13454 +                       }
13455 +                       add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array);
13456 +               }
13457 +       }
13458 +#endif
13459 +       add_assoc_string_ex(&array, "error", sizeof("error"), http_request_storage_get(request->ch)->errorbuffer, 1);
13460 +}
13461 +/* }}} */
13462 +
13463 +#endif /* HTTP_HAVE_CURL */
13464 +
13465 +/*
13466 + * Local variables:
13467 + * tab-width: 4
13468 + * c-basic-offset: 4
13469 + * End:
13470 + * vim600: noet sw=4 ts=4 fdm=marker
13471 + * vim<600: noet sw=4 ts=4
13472 + */
13473 --- /dev/null
13474 +++ b/ext/http/http_request_method_api.c
13475 @@ -0,0 +1,321 @@
13476 +/*
13477 +    +--------------------------------------------------------------------+
13478 +    | PECL :: http                                                       |
13479 +    +--------------------------------------------------------------------+
13480 +    | Redistribution and use in source and binary forms, with or without |
13481 +    | modification, are permitted provided that the conditions mentioned |
13482 +    | in the accompanying LICENSE file are met.                          |
13483 +    +--------------------------------------------------------------------+
13484 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
13485 +    +--------------------------------------------------------------------+
13486 +*/
13487 +
13488 +/* $Id: http_request_method_api.c 292841 2009-12-31 08:48:57Z mike $ */
13489 +
13490 +#define HTTP_WANT_CURL
13491 +#include "php_http.h"
13492 +
13493 +#include "php_http_api.h"
13494 +#include "php_http_request_api.h"
13495 +#include "php_http_request_method_api.h"
13496 +
13497 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY)
13498 +#      include "php_http_request_object.h"
13499 +#endif
13500 +
13501 +/* {{{ char *http_request_methods[] */
13502 +static const char *const http_request_methods[] = {
13503 +       "UNKNOWN",
13504 +       /* HTTP/1.1 */
13505 +       "GET",
13506 +       "HEAD",
13507 +       "POST",
13508 +       "PUT",
13509 +       "DELETE",
13510 +       "OPTIONS",
13511 +       "TRACE",
13512 +       "CONNECT",
13513 +       /* WebDAV - RFC 2518 */
13514 +       "PROPFIND",
13515 +       "PROPPATCH",
13516 +       "MKCOL",
13517 +       "COPY",
13518 +       "MOVE",
13519 +       "LOCK",
13520 +       "UNLOCK",
13521 +       /* WebDAV Versioning - RFC 3253 */
13522 +       "VERSION-CONTROL",
13523 +       "REPORT",
13524 +       "CHECKOUT",
13525 +       "CHECKIN",
13526 +       "UNCHECKOUT",
13527 +       "MKWORKSPACE",
13528 +       "UPDATE",
13529 +       "LABEL",
13530 +       "MERGE",
13531 +       "BASELINE-CONTROL",
13532 +       "MKACTIVITY",
13533 +       /* WebDAV Access Control - RFC 3744 */
13534 +       "ACL",
13535 +       NULL
13536 +};
13537 +/* }}} */
13538 +
13539 +/* {{{ */
13540 +PHP_MINIT_FUNCTION(http_request_method)
13541 +{
13542 +       /* HTTP/1.1 */
13543 +       HTTP_LONG_CONSTANT("HTTP_METH_GET", HTTP_GET);
13544 +       HTTP_LONG_CONSTANT("HTTP_METH_HEAD", HTTP_HEAD);
13545 +       HTTP_LONG_CONSTANT("HTTP_METH_POST", HTTP_POST);
13546 +       HTTP_LONG_CONSTANT("HTTP_METH_PUT", HTTP_PUT);
13547 +       HTTP_LONG_CONSTANT("HTTP_METH_DELETE", HTTP_DELETE);
13548 +       HTTP_LONG_CONSTANT("HTTP_METH_OPTIONS", HTTP_OPTIONS);
13549 +       HTTP_LONG_CONSTANT("HTTP_METH_TRACE", HTTP_TRACE);
13550 +       HTTP_LONG_CONSTANT("HTTP_METH_CONNECT", HTTP_CONNECT);
13551 +       /* WebDAV - RFC 2518 */
13552 +       HTTP_LONG_CONSTANT("HTTP_METH_PROPFIND", HTTP_PROPFIND);
13553 +       HTTP_LONG_CONSTANT("HTTP_METH_PROPPATCH", HTTP_PROPPATCH);
13554 +       HTTP_LONG_CONSTANT("HTTP_METH_MKCOL", HTTP_MKCOL);
13555 +       HTTP_LONG_CONSTANT("HTTP_METH_COPY", HTTP_COPY);
13556 +       HTTP_LONG_CONSTANT("HTTP_METH_MOVE", HTTP_MOVE);
13557 +       HTTP_LONG_CONSTANT("HTTP_METH_LOCK", HTTP_LOCK);
13558 +       HTTP_LONG_CONSTANT("HTTP_METH_UNLOCK", HTTP_UNLOCK);
13559 +       /* WebDAV Versioning - RFC 3253 */
13560 +       HTTP_LONG_CONSTANT("HTTP_METH_VERSION_CONTROL", HTTP_VERSION_CONTROL);
13561 +       HTTP_LONG_CONSTANT("HTTP_METH_REPORT", HTTP_REPORT);
13562 +       HTTP_LONG_CONSTANT("HTTP_METH_CHECKOUT", HTTP_CHECKOUT);
13563 +       HTTP_LONG_CONSTANT("HTTP_METH_CHECKIN", HTTP_CHECKIN);
13564 +       HTTP_LONG_CONSTANT("HTTP_METH_UNCHECKOUT", HTTP_UNCHECKOUT);
13565 +       HTTP_LONG_CONSTANT("HTTP_METH_MKWORKSPACE", HTTP_MKWORKSPACE);
13566 +       HTTP_LONG_CONSTANT("HTTP_METH_UPDATE", HTTP_UPDATE);
13567 +       HTTP_LONG_CONSTANT("HTTP_METH_LABEL", HTTP_LABEL);
13568 +       HTTP_LONG_CONSTANT("HTTP_METH_MERGE", HTTP_MERGE);
13569 +       HTTP_LONG_CONSTANT("HTTP_METH_BASELINE_CONTROL", HTTP_BASELINE_CONTROL);
13570 +       HTTP_LONG_CONSTANT("HTTP_METH_MKACTIVITY", HTTP_MKACTIVITY);
13571 +       /* WebDAV Access Control - RFC 3744 */
13572 +       HTTP_LONG_CONSTANT("HTTP_METH_ACL", HTTP_ACL);
13573 +       
13574 +       return SUCCESS;
13575 +}
13576 +
13577 +static void free_method(void *el)
13578 +{
13579 +       efree(*(char **)el);
13580 +}
13581 +
13582 +static void unregister_method(const char *name TSRMLS_DC)
13583 +{
13584 +       char *ptr, tmp[sizeof("HTTP_METH_") + HTTP_REQUEST_METHOD_MAXLEN] = "HTTP_METH_";
13585 +       
13586 +       strlcpy(tmp + lenof("HTTP_METH_"), name, HTTP_REQUEST_METHOD_MAXLEN);
13587 +       for (ptr = tmp + lenof("HTTP_METH_"); *ptr; ++ptr) {
13588 +               if (*ptr == '-') {
13589 +                       *ptr = '_';
13590 +               }
13591 +       }
13592 +       
13593 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY)
13594 +       if (SUCCESS != zend_hash_del(&http_request_object_ce->constants_table, tmp + lenof("HTTP_"), strlen(tmp + lenof("HTTP_")) + 1)) {
13595 +               http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: HttpRequest::%s", tmp + lenof("HTTP_"));
13596 +       }
13597 +#endif
13598 +       if (SUCCESS != zend_hash_del(EG(zend_constants), tmp, strlen(tmp) + 1)) {
13599 +               http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: %s", tmp);
13600 +       }
13601 +}
13602 +
13603 +PHP_RINIT_FUNCTION(http_request_method)
13604 +{
13605 +       HashTable ht;
13606 +       
13607 +       zend_hash_init(&HTTP_G->request.methods.registered, 0, NULL, free_method, 0);
13608 +#define HTTP_METH_REG(m) \
13609 +       { \
13610 +               char *_m=estrdup(m); \
13611 +               zend_hash_next_index_insert(&HTTP_G->request.methods.registered, (void *) &_m, sizeof(char *), NULL); \
13612 +       }
13613 +       HTTP_METH_REG("UNKNOWN");
13614 +       /* HTTP/1.1 */
13615 +       HTTP_METH_REG("GET");
13616 +       HTTP_METH_REG("HEAD");
13617 +       HTTP_METH_REG("POST");
13618 +       HTTP_METH_REG("PUT");
13619 +       HTTP_METH_REG("DELETE");
13620 +       HTTP_METH_REG("OPTIONS");
13621 +       HTTP_METH_REG("TRACE");
13622 +       HTTP_METH_REG("CONNECT");
13623 +       /* WebDAV - RFC 2518 */
13624 +       HTTP_METH_REG("PROPFIND");
13625 +       HTTP_METH_REG("PROPPATCH");
13626 +       HTTP_METH_REG("MKCOL");
13627 +       HTTP_METH_REG("COPY");
13628 +       HTTP_METH_REG("MOVE");
13629 +       HTTP_METH_REG("LOCK");
13630 +       HTTP_METH_REG("UNLOCK");
13631 +       /* WebDAV Versioning - RFC 3253 */
13632 +       HTTP_METH_REG("VERSION-CONTROL");
13633 +       HTTP_METH_REG("REPORT");
13634 +       HTTP_METH_REG("CHECKOUT");
13635 +       HTTP_METH_REG("CHECKIN");
13636 +       HTTP_METH_REG("UNCHECKOUT");
13637 +       HTTP_METH_REG("MKWORKSPACE");
13638 +       HTTP_METH_REG("UPDATE");
13639 +       HTTP_METH_REG("LABEL");
13640 +       HTTP_METH_REG("MERGE");
13641 +       HTTP_METH_REG("BASELINE-CONTROL");
13642 +       HTTP_METH_REG("MKACTIVITY");
13643 +       /* WebDAV Access Control - RFC 3744 */
13644 +       HTTP_METH_REG("ACL");
13645 +       
13646 +       zend_hash_init(&ht, 0, NULL, ZVAL_PTR_DTOR, 0);
13647 +       if (*HTTP_G->request.methods.custom && SUCCESS == http_parse_params(HTTP_G->request.methods.custom, HTTP_PARAMS_DEFAULT, &ht)) {
13648 +               HashPosition pos;
13649 +               zval **val;
13650 +               
13651 +               FOREACH_HASH_VAL(pos, &ht, val) {
13652 +                       if (Z_TYPE_PP(val) == IS_STRING) {
13653 +                               http_request_method_register(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
13654 +                       }
13655 +               }
13656 +       }
13657 +       zend_hash_destroy(&ht);
13658 +       
13659 +       return SUCCESS;
13660 +}
13661 +
13662 +PHP_RSHUTDOWN_FUNCTION(http_request_method)
13663 +{
13664 +       char **name;
13665 +       int i, c = zend_hash_next_free_element(&HTTP_G->request.methods.registered);
13666 +       
13667 +       for (i = HTTP_MAX_REQUEST_METHOD; i < c; ++i) {
13668 +               if (SUCCESS == zend_hash_index_find(&HTTP_G->request.methods.registered, i, (void *) &name)) {
13669 +                       unregister_method(*name TSRMLS_CC);
13670 +               }
13671 +       }
13672 +       
13673 +       zend_hash_destroy(&HTTP_G->request.methods.registered);
13674 +       return SUCCESS;
13675 +}
13676 +
13677 +#define http_request_method_cncl(m, c) _http_request_method_cncl_ex((m), strlen(m), (c) TSRMLS_CC)
13678 +#define http_request_method_cncl_ex(m, l, c) _http_request_method_cncl_ex((m), (l), (c) TSRMLS_CC)
13679 +static STATUS _http_request_method_cncl_ex(const char *method_name, int method_name_len, char **cnst TSRMLS_DC)
13680 +{
13681 +       int i;
13682 +       char *cncl;
13683 +       
13684 +       if (method_name_len >= HTTP_REQUEST_METHOD_MAXLEN) {
13685 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method too long (%s)", method_name);
13686 +       }
13687 +       cncl = emalloc(method_name_len + 1);
13688 +       
13689 +       for (i = 0; i < method_name_len; ++i) {
13690 +               switch (method_name[i]) {
13691 +                       case '-':
13692 +                               cncl[i] = '-';
13693 +                               break;
13694 +                       
13695 +                       default:
13696 +                               if (!HTTP_IS_CTYPE(alnum, method_name[i])) {
13697 +                                       efree(cncl);
13698 +                                       http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method contains illegal characters (%s)", method_name);
13699 +                                       return FAILURE;
13700 +                               }
13701 +                               cncl[i] = HTTP_TO_CTYPE(upper, method_name[i]);
13702 +                               break;
13703 +               }
13704 +       }
13705 +       cncl[method_name_len] = '\0';
13706 +       
13707 +       *cnst = cncl;
13708 +       return SUCCESS;
13709 +}
13710 +
13711 +PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC)
13712 +{
13713 +       char **name;
13714 +       
13715 +       if (SUCCESS == zend_hash_index_find(&HTTP_G->request.methods.registered, m, (void *) &name)) {
13716 +               return *name;
13717 +       }
13718 +       return "UNKNOWN";
13719 +}
13720 +
13721 +PHP_HTTP_API int _http_request_method_exists(int by_name, http_request_method id_num, const char *id_str TSRMLS_DC)
13722 +{
13723 +       char *id_dup;
13724 +       
13725 +       if (by_name && (SUCCESS == http_request_method_cncl(id_str, &id_dup))) {
13726 +               char **name;
13727 +               HashPosition pos;
13728 +               HashKey key = initHashKey(0);
13729 +               
13730 +               FOREACH_HASH_KEYVAL(pos, &HTTP_G->request.methods.registered, key, name) {
13731 +                       if (key.type == HASH_KEY_IS_LONG && !strcmp(*name, id_dup)) {
13732 +                               efree(id_dup);
13733 +                               return key.num;
13734 +                       }
13735 +               }
13736 +               efree(id_dup);
13737 +       } else if (zend_hash_index_exists(&HTTP_G->request.methods.registered, id_num)){
13738 +               return id_num;
13739 +       }
13740 +       return 0;
13741 +}
13742 +
13743 +PHP_HTTP_API int _http_request_method_register(const char *method_str, int method_len TSRMLS_DC)
13744 +{
13745 +       char *method_dup, *ptr, tmp[sizeof("HTTP_METH_") + HTTP_REQUEST_METHOD_MAXLEN] = "HTTP_METH_";
13746 +       int method_num = http_request_method_exists(1, 0, method_str);
13747 +       
13748 +       if (!method_num && (SUCCESS == http_request_method_cncl_ex(method_str, method_len, &method_dup))) {
13749 +               method_num = zend_hash_next_free_element(&HTTP_G->request.methods.registered);
13750 +               zend_hash_index_update(&HTTP_G->request.methods.registered, method_num, (void *) &method_dup, sizeof(char *), NULL);
13751 +               
13752 +               strlcpy(tmp + lenof("HTTP_METH_"), method_dup, HTTP_REQUEST_METHOD_MAXLEN);
13753 +               for (ptr = tmp + lenof("HTTP_METH_"); *ptr; ++ptr) {
13754 +                       if (*ptr == '-') {
13755 +                               *ptr = '_';
13756 +                       }
13757 +               }
13758 +               
13759 +               zend_register_long_constant(tmp, strlen(tmp) + 1, method_num, CONST_CS, http_module_number TSRMLS_CC);
13760 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY)
13761 +               zend_declare_class_constant_long(http_request_object_ce, tmp + lenof("HTTP_"), strlen(tmp + lenof("HTTP_")), method_num TSRMLS_CC);
13762 +#endif
13763 +       }
13764 +       
13765 +       return method_num;
13766 +}
13767 +
13768 +PHP_HTTP_API STATUS _http_request_method_unregister(int method TSRMLS_DC)
13769 +{
13770 +       char **name;
13771 +       
13772 +       if (HTTP_STD_REQUEST_METHOD(method)) {
13773 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Standard request methods cannot be unregistered");
13774 +               return FAILURE;
13775 +       }
13776 +
13777 +       if (SUCCESS != zend_hash_index_find(&HTTP_G->request.methods.registered, method, (void *) &name)) {
13778 +               http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Custom request method with id %d does not exist", method);
13779 +               return FAILURE;
13780 +       }
13781 +       
13782 +       unregister_method(*name TSRMLS_CC);
13783 +       
13784 +       zend_hash_index_del(&HTTP_G->request.methods.registered, method);
13785 +       return SUCCESS;
13786 +}
13787 +
13788 +/*
13789 + * Local variables:
13790 + * tab-width: 4
13791 + * c-basic-offset: 4
13792 + * End:
13793 + * vim600: noet sw=4 ts=4 fdm=marker
13794 + * vim<600: noet sw=4 ts=4
13795 + */
13796 +
13797 --- /dev/null
13798 +++ b/ext/http/http_request_object.c
13799 @@ -0,0 +1,1922 @@
13800 +/*
13801 +    +--------------------------------------------------------------------+
13802 +    | PECL :: http                                                       |
13803 +    +--------------------------------------------------------------------+
13804 +    | Redistribution and use in source and binary forms, with or without |
13805 +    | modification, are permitted provided that the conditions mentioned |
13806 +    | in the accompanying LICENSE file are met.                          |
13807 +    +--------------------------------------------------------------------+
13808 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
13809 +    +--------------------------------------------------------------------+
13810 +*/
13811 +
13812 +/* $Id: http_request_object.c 300299 2010-06-09 06:23:16Z mike $ */
13813 +
13814 +#define HTTP_WANT_CURL
13815 +#include "php_http.h"
13816 +
13817 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
13818 +
13819 +#include "zend_interfaces.h"
13820 +
13821 +#include "php_http_api.h"
13822 +#include "php_http_cookie_api.h"
13823 +#include "php_http_exception_object.h"
13824 +#include "php_http_message_api.h"
13825 +#include "php_http_message_object.h"
13826 +#include "php_http_request_api.h"
13827 +#include "php_http_request_object.h"
13828 +#include "php_http_request_pool_api.h"
13829 +#include "php_http_url_api.h"
13830 +
13831 +#define HTTP_BEGIN_ARGS(method, req_args)      HTTP_BEGIN_ARGS_EX(HttpRequest, method, 0, req_args)
13832 +#define HTTP_EMPTY_ARGS(method)                                HTTP_EMPTY_ARGS_EX(HttpRequest, method, 0)
13833 +#define HTTP_REQUEST_ME(method, visibility)    PHP_ME(HttpRequest, method, HTTP_ARGS(HttpRequest, method), visibility)
13834 +#define HTTP_REQUEST_ALIAS(method, func)       HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpRequest, method))
13835 +#define HTTP_REQUEST_MALIAS(me, al, vis)       ZEND_FENTRY(me, ZEND_MN(HttpRequest_##al), HTTP_ARGS(HttpRequest, al), vis)
13836 +
13837 +HTTP_BEGIN_ARGS(__construct, 0)
13838 +       HTTP_ARG_VAL(url, 0)
13839 +       HTTP_ARG_VAL(method, 0)
13840 +       HTTP_ARG_VAL(options, 0)
13841 +HTTP_END_ARGS;
13842 +
13843 +HTTP_BEGIN_ARGS(factory, 0)
13844 +       HTTP_ARG_VAL(url, 0)
13845 +       HTTP_ARG_VAL(method, 0)
13846 +       HTTP_ARG_VAL(options, 0)
13847 +       HTTP_ARG_VAL(class_name, 0)
13848 +HTTP_END_ARGS;
13849 +
13850 +HTTP_EMPTY_ARGS(getOptions);
13851 +HTTP_BEGIN_ARGS(setOptions, 0)
13852 +       HTTP_ARG_VAL(options, 0)
13853 +HTTP_END_ARGS;
13854 +
13855 +HTTP_EMPTY_ARGS(getSslOptions);
13856 +HTTP_BEGIN_ARGS(setSslOptions, 0)
13857 +       HTTP_ARG_VAL(ssl_options, 0)
13858 +HTTP_END_ARGS;
13859 +
13860 +HTTP_BEGIN_ARGS(addSslOptions, 0)
13861 +       HTTP_ARG_VAL(ssl_optins, 0)
13862 +HTTP_END_ARGS;
13863 +
13864 +HTTP_EMPTY_ARGS(getHeaders);
13865 +HTTP_BEGIN_ARGS(setHeaders, 0)
13866 +       HTTP_ARG_VAL(headers, 0)
13867 +HTTP_END_ARGS;
13868 +
13869 +HTTP_BEGIN_ARGS(addHeaders, 1)
13870 +       HTTP_ARG_VAL(headers, 0)
13871 +HTTP_END_ARGS;
13872 +
13873 +HTTP_EMPTY_ARGS(getCookies);
13874 +HTTP_BEGIN_ARGS(setCookies, 0)
13875 +       HTTP_ARG_VAL(cookies, 0)
13876 +HTTP_END_ARGS;
13877 +
13878 +HTTP_BEGIN_ARGS(addCookies, 1)
13879 +       HTTP_ARG_VAL(cookies, 0)
13880 +HTTP_END_ARGS;
13881 +
13882 +HTTP_EMPTY_ARGS(enableCookies);
13883 +HTTP_BEGIN_ARGS(resetCookies, 0)
13884 +       HTTP_ARG_VAL(session_only, 0)
13885 +HTTP_END_ARGS;
13886 +HTTP_EMPTY_ARGS(flushCookies);
13887 +
13888 +HTTP_EMPTY_ARGS(getUrl);
13889 +HTTP_BEGIN_ARGS(setUrl, 1)
13890 +       HTTP_ARG_VAL(url, 0)
13891 +HTTP_END_ARGS;
13892 +
13893 +HTTP_EMPTY_ARGS(getMethod);
13894 +HTTP_BEGIN_ARGS(setMethod, 1)
13895 +       HTTP_ARG_VAL(request_method, 0)
13896 +HTTP_END_ARGS;
13897 +
13898 +HTTP_EMPTY_ARGS(getContentType);
13899 +HTTP_BEGIN_ARGS(setContentType, 1)
13900 +       HTTP_ARG_VAL(content_type, 0)
13901 +HTTP_END_ARGS;
13902 +
13903 +HTTP_EMPTY_ARGS(getQueryData);
13904 +HTTP_BEGIN_ARGS(setQueryData, 0)
13905 +       HTTP_ARG_VAL(query_data, 0)
13906 +HTTP_END_ARGS;
13907 +
13908 +HTTP_BEGIN_ARGS(addQueryData, 1)
13909 +       HTTP_ARG_VAL(query_data, 0)
13910 +HTTP_END_ARGS;
13911 +
13912 +HTTP_EMPTY_ARGS(getPostFields);
13913 +HTTP_BEGIN_ARGS(setPostFields, 0)
13914 +       HTTP_ARG_VAL(post_fields, 0)
13915 +HTTP_END_ARGS;
13916 +
13917 +HTTP_BEGIN_ARGS(addPostFields, 1)
13918 +       HTTP_ARG_VAL(post_fields, 0)
13919 +HTTP_END_ARGS;
13920 +
13921 +HTTP_EMPTY_ARGS(getPostFiles);
13922 +HTTP_BEGIN_ARGS(setPostFiles, 0)
13923 +       HTTP_ARG_VAL(post_files, 0)
13924 +HTTP_END_ARGS;
13925 +
13926 +HTTP_BEGIN_ARGS(addPostFile, 2)
13927 +       HTTP_ARG_VAL(formname, 0)
13928 +       HTTP_ARG_VAL(filename, 0)
13929 +       HTTP_ARG_VAL(content_type, 0)
13930 +HTTP_END_ARGS;
13931 +
13932 +HTTP_EMPTY_ARGS(getBody);
13933 +HTTP_BEGIN_ARGS(setBody, 0)
13934 +       HTTP_ARG_VAL(request_body_data, 0)
13935 +HTTP_END_ARGS;
13936 +
13937 +HTTP_BEGIN_ARGS(addBody, 1)
13938 +       HTTP_ARG_VAL(request_body_data, 0)
13939 +HTTP_END_ARGS;
13940 +
13941 +HTTP_EMPTY_ARGS(getPutFile);
13942 +HTTP_BEGIN_ARGS(setPutFile, 0)
13943 +       HTTP_ARG_VAL(filename, 0)
13944 +HTTP_END_ARGS;
13945 +
13946 +HTTP_EMPTY_ARGS(getPutData);
13947 +HTTP_BEGIN_ARGS(setPutData, 0)
13948 +       HTTP_ARG_VAL(put_data, 0)
13949 +HTTP_END_ARGS;
13950 +
13951 +HTTP_BEGIN_ARGS(addPutData, 1)
13952 +       HTTP_ARG_VAL(put_data, 0)
13953 +HTTP_END_ARGS;
13954 +
13955 +HTTP_EMPTY_ARGS(getResponseData);
13956 +HTTP_BEGIN_ARGS(getResponseHeader, 0)
13957 +       HTTP_ARG_VAL(name, 0)
13958 +HTTP_END_ARGS;
13959 +
13960 +HTTP_BEGIN_ARGS(getResponseCookies, 0)
13961 +       HTTP_ARG_VAL(flags, 0)
13962 +       HTTP_ARG_VAL(allowed_extras, 0)
13963 +HTTP_END_ARGS;
13964 +
13965 +HTTP_EMPTY_ARGS(getResponseBody);
13966 +HTTP_EMPTY_ARGS(getResponseCode);
13967 +HTTP_EMPTY_ARGS(getResponseStatus);
13968 +HTTP_BEGIN_ARGS(getResponseInfo, 0)
13969 +       HTTP_ARG_VAL(name, 0)
13970 +HTTP_END_ARGS;
13971 +
13972 +HTTP_EMPTY_ARGS(getMessageClass);
13973 +HTTP_BEGIN_ARGS(setMessageClass, 1)
13974 +       HTTP_ARG_VAL(message_class_name, 0)
13975 +HTTP_END_ARGS;
13976 +
13977 +HTTP_EMPTY_ARGS(getResponseMessage);
13978 +HTTP_EMPTY_ARGS(getRawResponseMessage);
13979 +HTTP_EMPTY_ARGS(getRequestMessage);
13980 +HTTP_EMPTY_ARGS(getRawRequestMessage);
13981 +HTTP_EMPTY_ARGS(getHistory);
13982 +HTTP_EMPTY_ARGS(clearHistory);
13983 +HTTP_EMPTY_ARGS(send);
13984 +
13985 +HTTP_BEGIN_ARGS(get, 1)
13986 +       HTTP_ARG_VAL(url, 0)
13987 +       HTTP_ARG_VAL(options, 0)
13988 +       HTTP_ARG_VAL(info, 1)
13989 +HTTP_END_ARGS;
13990 +
13991 +HTTP_BEGIN_ARGS(head, 1)
13992 +       HTTP_ARG_VAL(url, 0)
13993 +       HTTP_ARG_VAL(options, 0)
13994 +       HTTP_ARG_VAL(info, 1)
13995 +HTTP_END_ARGS;
13996 +
13997 +HTTP_BEGIN_ARGS(postData, 2)
13998 +       HTTP_ARG_VAL(url, 0)
13999 +       HTTP_ARG_VAL(data, 0)
14000 +       HTTP_ARG_VAL(options, 0)
14001 +       HTTP_ARG_VAL(info, 1)
14002 +HTTP_END_ARGS;
14003 +
14004 +HTTP_BEGIN_ARGS(postFields, 2)
14005 +       HTTP_ARG_VAL(url, 0)
14006 +       HTTP_ARG_VAL(data, 0)
14007 +       HTTP_ARG_VAL(options, 0)
14008 +       HTTP_ARG_VAL(info, 1)
14009 +HTTP_END_ARGS;
14010 +
14011 +HTTP_BEGIN_ARGS(putData, 2)
14012 +       HTTP_ARG_VAL(url, 0)
14013 +       HTTP_ARG_VAL(data, 0)
14014 +       HTTP_ARG_VAL(options, 0)
14015 +       HTTP_ARG_VAL(info, 1)
14016 +HTTP_END_ARGS;
14017 +
14018 +HTTP_BEGIN_ARGS(putFile, 2)
14019 +       HTTP_ARG_VAL(url, 0)
14020 +       HTTP_ARG_VAL(file, 0)
14021 +       HTTP_ARG_VAL(options, 0)
14022 +       HTTP_ARG_VAL(info, 1)
14023 +HTTP_END_ARGS;
14024 +
14025 +HTTP_BEGIN_ARGS(putStream, 2)
14026 +       HTTP_ARG_VAL(url, 0)
14027 +       HTTP_ARG_VAL(stream, 0)
14028 +       HTTP_ARG_VAL(options, 0)
14029 +       HTTP_ARG_VAL(info, 1)
14030 +HTTP_END_ARGS;
14031 +
14032 +HTTP_BEGIN_ARGS(methodRegister, 1)
14033 +       HTTP_ARG_VAL(method_name, 0)
14034 +HTTP_END_ARGS;
14035 +
14036 +HTTP_BEGIN_ARGS(methodUnregister, 1)
14037 +       HTTP_ARG_VAL(method, 0)
14038 +HTTP_END_ARGS;
14039 +
14040 +HTTP_BEGIN_ARGS(methodName, 1)
14041 +       HTTP_ARG_VAL(method_id, 0)
14042 +HTTP_END_ARGS;
14043 +
14044 +HTTP_BEGIN_ARGS(methodExists, 1)
14045 +       HTTP_ARG_VAL(method, 0)
14046 +HTTP_END_ARGS;
14047 +
14048 +#ifdef HAVE_CURL_FORMGET
14049 +HTTP_BEGIN_ARGS(encodeBody, 2)
14050 +       HTTP_ARG_VAL(fields, 0)
14051 +       HTTP_ARG_VAL(files, 0)
14052 +HTTP_END_ARGS;
14053 +#endif
14054 +
14055 +#define THIS_CE http_request_object_ce
14056 +zend_class_entry *http_request_object_ce;
14057 +zend_function_entry http_request_object_fe[] = {
14058 +       HTTP_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
14059 +
14060 +       HTTP_REQUEST_ME(setOptions, ZEND_ACC_PUBLIC)
14061 +       HTTP_REQUEST_ME(getOptions, ZEND_ACC_PUBLIC)
14062 +       HTTP_REQUEST_ME(setSslOptions, ZEND_ACC_PUBLIC)
14063 +       HTTP_REQUEST_ME(getSslOptions, ZEND_ACC_PUBLIC)
14064 +       HTTP_REQUEST_ME(addSslOptions, ZEND_ACC_PUBLIC)
14065 +
14066 +       HTTP_REQUEST_ME(addHeaders, ZEND_ACC_PUBLIC)
14067 +       HTTP_REQUEST_ME(getHeaders, ZEND_ACC_PUBLIC)
14068 +       HTTP_REQUEST_ME(setHeaders, ZEND_ACC_PUBLIC)
14069 +       
14070 +       HTTP_REQUEST_ME(addCookies, ZEND_ACC_PUBLIC)
14071 +       HTTP_REQUEST_ME(getCookies, ZEND_ACC_PUBLIC)
14072 +       HTTP_REQUEST_ME(setCookies, ZEND_ACC_PUBLIC)
14073 +
14074 +       HTTP_REQUEST_ME(enableCookies, ZEND_ACC_PUBLIC)
14075 +       HTTP_REQUEST_ME(resetCookies, ZEND_ACC_PUBLIC)
14076 +       HTTP_REQUEST_ME(flushCookies, ZEND_ACC_PUBLIC)
14077 +
14078 +       HTTP_REQUEST_ME(setMethod, ZEND_ACC_PUBLIC)
14079 +       HTTP_REQUEST_ME(getMethod, ZEND_ACC_PUBLIC)
14080 +
14081 +       HTTP_REQUEST_ME(setUrl, ZEND_ACC_PUBLIC)
14082 +       HTTP_REQUEST_ME(getUrl, ZEND_ACC_PUBLIC)
14083 +
14084 +       HTTP_REQUEST_ME(setContentType, ZEND_ACC_PUBLIC)
14085 +       HTTP_REQUEST_ME(getContentType, ZEND_ACC_PUBLIC)
14086 +
14087 +       HTTP_REQUEST_ME(setQueryData, ZEND_ACC_PUBLIC)
14088 +       HTTP_REQUEST_ME(getQueryData, ZEND_ACC_PUBLIC)
14089 +       HTTP_REQUEST_ME(addQueryData, ZEND_ACC_PUBLIC)
14090 +
14091 +       HTTP_REQUEST_ME(setPostFields, ZEND_ACC_PUBLIC)
14092 +       HTTP_REQUEST_ME(getPostFields, ZEND_ACC_PUBLIC)
14093 +       HTTP_REQUEST_ME(addPostFields, ZEND_ACC_PUBLIC)
14094 +       
14095 +       HTTP_REQUEST_ME(setBody, ZEND_ACC_PUBLIC)
14096 +       HTTP_REQUEST_ME(getBody, ZEND_ACC_PUBLIC)
14097 +       HTTP_REQUEST_ME(addBody, ZEND_ACC_PUBLIC)
14098 +       HTTP_REQUEST_MALIAS(setRawPostData, setBody, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
14099 +       HTTP_REQUEST_MALIAS(getRawPostData, getBody, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
14100 +       HTTP_REQUEST_MALIAS(addRawPostData, addBody, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
14101 +
14102 +       HTTP_REQUEST_ME(setPostFiles, ZEND_ACC_PUBLIC)
14103 +       HTTP_REQUEST_ME(addPostFile, ZEND_ACC_PUBLIC)
14104 +       HTTP_REQUEST_ME(getPostFiles, ZEND_ACC_PUBLIC)
14105 +
14106 +       HTTP_REQUEST_ME(setPutFile, ZEND_ACC_PUBLIC)
14107 +       HTTP_REQUEST_ME(getPutFile, ZEND_ACC_PUBLIC)
14108 +
14109 +       HTTP_REQUEST_ME(setPutData, ZEND_ACC_PUBLIC)
14110 +       HTTP_REQUEST_ME(getPutData, ZEND_ACC_PUBLIC)
14111 +       HTTP_REQUEST_ME(addPutData, ZEND_ACC_PUBLIC)
14112 +
14113 +       HTTP_REQUEST_ME(send, ZEND_ACC_PUBLIC)
14114 +
14115 +       HTTP_REQUEST_ME(getResponseData, ZEND_ACC_PUBLIC)
14116 +       HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC)
14117 +       HTTP_REQUEST_ME(getResponseCookies, ZEND_ACC_PUBLIC)
14118 +       HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC)
14119 +       HTTP_REQUEST_ME(getResponseStatus, ZEND_ACC_PUBLIC)
14120 +       HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC)
14121 +       HTTP_REQUEST_ME(getResponseInfo, ZEND_ACC_PUBLIC)
14122 +       HTTP_REQUEST_ME(getResponseMessage, ZEND_ACC_PUBLIC)
14123 +       HTTP_REQUEST_ME(getRawResponseMessage, ZEND_ACC_PUBLIC)
14124 +       HTTP_REQUEST_ME(getRequestMessage, ZEND_ACC_PUBLIC)
14125 +       HTTP_REQUEST_ME(getRawRequestMessage, ZEND_ACC_PUBLIC)
14126 +       HTTP_REQUEST_ME(getHistory, ZEND_ACC_PUBLIC)
14127 +       HTTP_REQUEST_ME(clearHistory, ZEND_ACC_PUBLIC)
14128 +
14129 +       HTTP_REQUEST_ME(getMessageClass, ZEND_ACC_PUBLIC)
14130 +       HTTP_REQUEST_ME(setMessageClass, ZEND_ACC_PUBLIC)
14131 +
14132 +       HTTP_REQUEST_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
14133 +
14134 +       HTTP_REQUEST_ALIAS(get, http_get)
14135 +       HTTP_REQUEST_ALIAS(head, http_head)
14136 +       HTTP_REQUEST_ALIAS(postData, http_post_data)
14137 +       HTTP_REQUEST_ALIAS(postFields, http_post_fields)
14138 +       HTTP_REQUEST_ALIAS(putData, http_put_data)
14139 +       HTTP_REQUEST_ALIAS(putFile, http_put_file)
14140 +       HTTP_REQUEST_ALIAS(putStream, http_put_stream)
14141 +
14142 +       HTTP_REQUEST_ALIAS(methodRegister, http_request_method_register)
14143 +       HTTP_REQUEST_ALIAS(methodUnregister, http_request_method_unregister)
14144 +       HTTP_REQUEST_ALIAS(methodName, http_request_method_name)
14145 +       HTTP_REQUEST_ALIAS(methodExists, http_request_method_exists)
14146 +#ifdef HAVE_CURL_FORMGET
14147 +       HTTP_REQUEST_ALIAS(encodeBody, http_request_body_encode)
14148 +#endif
14149 +       EMPTY_FUNCTION_ENTRY
14150 +};
14151 +static zend_object_handlers http_request_object_handlers;
14152 +
14153 +PHP_MINIT_FUNCTION(http_request_object)
14154 +{
14155 +       HTTP_REGISTER_CLASS_EX(HttpRequest, http_request_object, NULL, 0);
14156 +       http_request_object_handlers.clone_obj = _http_request_object_clone_obj;
14157 +
14158 +       zend_declare_property_null(THIS_CE, ZEND_STRS("options")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
14159 +       zend_declare_property_null(THIS_CE, ZEND_STRS("postFields")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
14160 +       zend_declare_property_null(THIS_CE, ZEND_STRS("postFiles")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
14161 +       zend_declare_property_null(THIS_CE, ZEND_STRS("responseInfo")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
14162 +       zend_declare_property_null(THIS_CE, ZEND_STRS("responseMessage")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
14163 +       zend_declare_property_long(THIS_CE, ZEND_STRS("responseCode")-1, 0, ZEND_ACC_PRIVATE TSRMLS_CC);
14164 +       zend_declare_property_string(THIS_CE, ZEND_STRS("responseStatus")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14165 +       zend_declare_property_long(THIS_CE, ZEND_STRS("method")-1, HTTP_GET, ZEND_ACC_PRIVATE TSRMLS_CC);
14166 +       zend_declare_property_string(THIS_CE, ZEND_STRS("url")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14167 +       zend_declare_property_string(THIS_CE, ZEND_STRS("contentType")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14168 +       zend_declare_property_string(THIS_CE, ZEND_STRS("requestBody")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14169 +       zend_declare_property_string(THIS_CE, ZEND_STRS("queryData")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14170 +       zend_declare_property_string(THIS_CE, ZEND_STRS("putFile")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14171 +       zend_declare_property_string(THIS_CE, ZEND_STRS("putData")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14172 +       zend_declare_property_null(THIS_CE, ZEND_STRS("history")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
14173 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("recordHistory")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);
14174 +       zend_declare_property_string(THIS_CE, ZEND_STRS("messageClass")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
14175 +
14176 +#ifndef WONKY
14177 +       /*
14178 +        * Request Method Constants
14179 +       */
14180 +       /* HTTP/1.1 */
14181 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_GET")-1, HTTP_GET TSRMLS_CC);
14182 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_HEAD")-1, HTTP_HEAD TSRMLS_CC);
14183 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_POST")-1, HTTP_POST TSRMLS_CC);
14184 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_PUT")-1, HTTP_PUT TSRMLS_CC);
14185 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_DELETE")-1, HTTP_DELETE TSRMLS_CC);
14186 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_OPTIONS")-1, HTTP_OPTIONS TSRMLS_CC);
14187 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_TRACE")-1, HTTP_TRACE TSRMLS_CC);
14188 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_CONNECT")-1, HTTP_CONNECT TSRMLS_CC);
14189 +       /* WebDAV - RFC 2518 */
14190 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_PROPFIND")-1, HTTP_PROPFIND TSRMLS_CC);
14191 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_PROPPATCH")-1, HTTP_PROPPATCH TSRMLS_CC);
14192 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MKCOL")-1, HTTP_MKCOL TSRMLS_CC);
14193 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_COPY")-1, HTTP_COPY TSRMLS_CC);
14194 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MOVE")-1, HTTP_MOVE TSRMLS_CC);
14195 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_LOCK")-1, HTTP_LOCK TSRMLS_CC);
14196 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_UNLOCK")-1, HTTP_UNLOCK TSRMLS_CC);
14197 +       /* WebDAV Versioning - RFC 3253 */
14198 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_VERSION_CONTROL")-1, HTTP_VERSION_CONTROL TSRMLS_CC);
14199 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_REPORT")-1, HTTP_REPORT TSRMLS_CC);
14200 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_CHECKOUT")-1, HTTP_CHECKOUT TSRMLS_CC);
14201 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_CHECKIN")-1, HTTP_CHECKIN TSRMLS_CC);
14202 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_UNCHECKOUT")-1, HTTP_UNCHECKOUT TSRMLS_CC);
14203 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MKWORKSPACE")-1, HTTP_MKWORKSPACE TSRMLS_CC);
14204 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_UPDATE")-1, HTTP_UPDATE TSRMLS_CC);
14205 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_LABEL")-1, HTTP_LABEL TSRMLS_CC);
14206 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MERGE")-1, HTTP_MERGE TSRMLS_CC);
14207 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_BASELINE_CONTROL")-1, HTTP_BASELINE_CONTROL TSRMLS_CC);
14208 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MKACTIVITY")-1, HTTP_MKACTIVITY TSRMLS_CC);
14209 +       /* WebDAV Access Control - RFC 3744 */
14210 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_ACL")-1, HTTP_ACL TSRMLS_CC);
14211 +
14212 +       /*
14213 +       * HTTP Protocol Version Constants
14214 +       */
14215 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_1_0")-1, CURL_HTTP_VERSION_1_0 TSRMLS_CC);
14216 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_1_1")-1, CURL_HTTP_VERSION_1_1 TSRMLS_CC);
14217 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_NONE")-1, CURL_HTTP_VERSION_NONE TSRMLS_CC); /* to be removed */
14218 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_ANY")-1, CURL_HTTP_VERSION_NONE TSRMLS_CC);
14219 +
14220 +       /*
14221 +       * SSL Version Constants
14222 +       */
14223 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_TLSv1")-1, CURL_SSLVERSION_TLSv1 TSRMLS_CC);
14224 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_SSLv2")-1, CURL_SSLVERSION_SSLv2 TSRMLS_CC);
14225 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_SSLv3")-1, CURL_SSLVERSION_SSLv3 TSRMLS_CC);
14226 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_ANY")-1, CURL_SSLVERSION_DEFAULT TSRMLS_CC);
14227 +
14228 +       /*
14229 +       * DNS IPvX resolving
14230 +       */
14231 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("IPRESOLVE_V4")-1, CURL_IPRESOLVE_V4 TSRMLS_CC);
14232 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("IPRESOLVE_V6")-1, CURL_IPRESOLVE_V6 TSRMLS_CC);
14233 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("IPRESOLVE_ANY")-1, CURL_IPRESOLVE_WHATEVER TSRMLS_CC);
14234 +
14235 +       /*
14236 +       * Auth Constants
14237 +       */
14238 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_BASIC")-1, CURLAUTH_BASIC TSRMLS_CC);
14239 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_DIGEST")-1, CURLAUTH_DIGEST TSRMLS_CC);
14240 +#if HTTP_CURL_VERSION(7,19,3)
14241 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_DIGEST_IE")-1, CURLAUTH_DIGEST_IE TSRMLS_CC);
14242 +#endif
14243 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_NTLM")-1, CURLAUTH_NTLM TSRMLS_CC);
14244 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_GSSNEG")-1, CURLAUTH_GSSNEGOTIATE TSRMLS_CC);
14245 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_ANY")-1, CURLAUTH_ANY TSRMLS_CC);
14246 +       
14247 +       /*
14248 +       * Proxy Type Constants
14249 +       */
14250 +#      if HTTP_CURL_VERSION(7,15,2)
14251 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS4")-1, CURLPROXY_SOCKS4 TSRMLS_CC);
14252 +#      endif
14253 +#if HTTP_CURL_VERSION(7,18,0)
14254 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS4A")-1, CURLPROXY_SOCKS5 TSRMLS_CC);
14255 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS5_HOSTNAME")-1, CURLPROXY_SOCKS5 TSRMLS_CC);
14256 +#endif
14257 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS5")-1, CURLPROXY_SOCKS5 TSRMLS_CC);
14258 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_HTTP")-1, CURLPROXY_HTTP TSRMLS_CC);
14259 +#      if HTTP_CURL_VERSION(7,19,4)
14260 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_HTTP_1_0")-1, CURLPROXY_HTTP_1_0 TSRMLS_CC);
14261 +#      endif
14262 +#endif /* WONKY */
14263 +
14264 +       /*
14265 +       * Post Redirection Constants
14266 +       */
14267 +#if HTTP_CURL_VERSION(7,19,1)
14268 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("POSTREDIR_301")-1, CURL_REDIR_POST_301 TSRMLS_CC);
14269 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("POSTREDIR_302")-1, CURL_REDIR_POST_302 TSRMLS_CC);
14270 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("POSTREDIR_ALL")-1, CURL_REDIR_POST_ALL TSRMLS_CC);
14271 +#endif
14272 +       
14273 +       return SUCCESS;
14274 +}
14275 +
14276 +zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC)
14277 +{
14278 +       return http_request_object_new_ex(ce, NULL, NULL);
14279 +}
14280 +
14281 +zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL *ch, http_request_object **ptr TSRMLS_DC)
14282 +{
14283 +       zend_object_value ov;
14284 +       http_request_object *o;
14285 +
14286 +       o = ecalloc(1, sizeof(http_request_object));
14287 +       o->zo.ce = ce;
14288 +       o->request = http_request_init_ex(NULL, ch, 0, NULL);
14289 +       
14290 +       if (ptr) {
14291 +               *ptr = o;
14292 +       }
14293 +
14294 +       ALLOC_HASHTABLE(OBJ_PROP(o));
14295 +       zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
14296 +       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
14297 +
14298 +       ov.handle = putObject(http_request_object, o);
14299 +       ov.handlers = &http_request_object_handlers;
14300 +
14301 +       return ov;
14302 +}
14303 +
14304 +zend_object_value _http_request_object_clone_obj(zval *this_ptr TSRMLS_DC)
14305 +{
14306 +       zend_object_value new_ov;
14307 +       http_request_object *new_obj;
14308 +       getObject(http_request_object, old_obj);
14309 +       
14310 +       new_ov = http_request_object_new_ex(old_obj->zo.ce, NULL, &new_obj);
14311 +       if (old_obj->request->ch) {
14312 +               http_curl_init_ex(http_curl_copy(old_obj->request->ch), new_obj->request);
14313 +       }
14314 +       
14315 +       zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
14316 +       phpstr_append(&new_obj->request->conv.request, old_obj->request->conv.request.data, old_obj->request->conv.request.used);
14317 +       phpstr_append(&new_obj->request->conv.response, old_obj->request->conv.response.data, old_obj->request->conv.response.used);
14318 +       
14319 +       return new_ov;
14320 +}
14321 +
14322 +void _http_request_object_free(zend_object *object TSRMLS_DC)
14323 +{
14324 +       http_request_object *o = (http_request_object *) object;
14325 +
14326 +       http_request_free(&o->request);
14327 +       freeObject(o);
14328 +}
14329 +
14330 +#define http_request_object_check_request_content_type(t) _http_request_object_check_request_content_type((t) TSRMLS_CC)
14331 +static inline void _http_request_object_check_request_content_type(zval *this_ptr TSRMLS_DC)
14332 +{
14333 +       zval *ctype = zend_read_property(THIS_CE, getThis(), ZEND_STRS("contentType")-1, 0 TSRMLS_CC);
14334 +                               
14335 +       if (Z_STRLEN_P(ctype)) {
14336 +               zval **headers, *opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC);
14337 +               
14338 +               if (    (Z_TYPE_P(opts) == IS_ARRAY) &&
14339 +                               (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void *) &headers)) && 
14340 +                               (Z_TYPE_PP(headers) == IS_ARRAY)) {
14341 +                       zval **ct_header;
14342 +                       
14343 +                       /* only override if not already set */
14344 +                       if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(headers), "Content-Type", sizeof("Content-Type"), (void *) &ct_header))) {
14345 +                               add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
14346 +                       } else
14347 +                       /* or not a string, zero length string or a string of spaces */
14348 +                       if ((Z_TYPE_PP(ct_header) != IS_STRING) || !Z_STRLEN_PP(ct_header)) {
14349 +                               add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
14350 +                       } else {
14351 +                               int i, only_space = 1;
14352 +                               
14353 +                               /* check for spaces only */
14354 +                               for (i = 0; i < Z_STRLEN_PP(ct_header); ++i) {
14355 +                                       if (!HTTP_IS_CTYPE(space, Z_STRVAL_PP(ct_header)[i])) {
14356 +                                               only_space = 0;
14357 +                                               break;
14358 +                                       }
14359 +                               }
14360 +                               if (only_space) {
14361 +                                       add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
14362 +                               }
14363 +                       }
14364 +               } else {
14365 +                       zval *headers;
14366 +               
14367 +                       MAKE_STD_ZVAL(headers);
14368 +                       array_init(headers);
14369 +                       add_assoc_stringl(headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
14370 +                       zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, headers);
14371 +                       zval_ptr_dtor(&headers);
14372 +               }
14373 +       }
14374 +}
14375 +
14376 +#define http_request_object_message(zo, msg) _http_request_object_message((zo), (msg) TSRMLS_CC)
14377 +static inline zend_object_value _http_request_object_message(zval *this_ptr, http_message *msg TSRMLS_DC)
14378 +{
14379 +       zend_object_value ov;
14380 +       zval *zcn = zend_read_property(THIS_CE, getThis(), ZEND_STRS("messageClass")-1, 0 TSRMLS_CC);
14381 +
14382 +       if (Z_STRLEN_P(zcn) && (SUCCESS == http_object_new(&ov, Z_STRVAL_P(zcn), Z_STRLEN_P(zcn), _http_message_object_new_ex, http_message_object_ce, msg, NULL))) {
14383 +               return ov;
14384 +       } else {
14385 +               return http_message_object_new_ex(http_message_object_ce, msg, NULL);
14386 +       }
14387 +}
14388 +
14389 +STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr TSRMLS_DC)
14390 +{
14391 +       STATUS status = SUCCESS;
14392 +       char *url = http_absolute_url(Z_STRVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("url")-1, 0 TSRMLS_CC)));
14393 +
14394 +       if (!url) {
14395 +               return FAILURE;
14396 +       }
14397 +       
14398 +       http_request_reset(obj->request);
14399 +       obj->request->url = url;
14400 +       HTTP_CHECK_CURL_INIT(obj->request->ch, http_curl_init(obj->request), return FAILURE);
14401 +       
14402 +       switch (obj->request->meth = Z_LVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("method")-1, 0 TSRMLS_CC)))
14403 +       {
14404 +               case HTTP_GET:
14405 +               case HTTP_HEAD:
14406 +                       break;
14407 +
14408 +               case HTTP_PUT:
14409 +               {
14410 +                       zval *put_file = zend_read_property(THIS_CE, getThis(), ZEND_STRS("putFile")-1, 0 TSRMLS_CC);
14411 +                       
14412 +                       http_request_object_check_request_content_type(getThis());
14413 +                       
14414 +                       if (Z_STRLEN_P(put_file)) {
14415 +                               php_stream_statbuf ssb;
14416 +                               php_stream *stream = php_stream_open_wrapper_ex(Z_STRVAL_P(put_file), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT);
14417 +                               
14418 +                               if (stream && SUCCESS == php_stream_stat(stream, &ssb)) {
14419 +                                       obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 1);
14420 +                               } else {
14421 +                                       status = FAILURE;
14422 +                               }
14423 +                       } else {
14424 +                               zval *put_data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("putData")-1, 0 TSRMLS_CC);
14425 +                               obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_CSTRING,
14426 +                                       estrndup(Z_STRVAL_P(put_data), Z_STRLEN_P(put_data)), Z_STRLEN_P(put_data), 1);
14427 +                       }
14428 +                       break;
14429 +               }
14430 +
14431 +               case HTTP_POST:
14432 +               default:
14433 +               {
14434 +                       /* check for raw request body */
14435 +                       zval *raw_data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, 0 TSRMLS_CC);
14436 +                       
14437 +                       if (Z_STRLEN_P(raw_data)) {
14438 +                               http_request_object_check_request_content_type(getThis());
14439 +                               obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_CSTRING,
14440 +                                       estrndup(Z_STRVAL_P(raw_data), Z_STRLEN_P(raw_data)), Z_STRLEN_P(raw_data), 1);
14441 +                       } else {
14442 +                               zval *zfields = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, 0 TSRMLS_CC), *zfiles = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, 0 TSRMLS_CC);
14443 +                               HashTable *fields;
14444 +                               HashTable *files;
14445 +                               
14446 +                               fields = (Z_TYPE_P(zfields) == IS_ARRAY) ? Z_ARRVAL_P(zfields) : NULL;
14447 +                               files = (Z_TYPE_P(zfiles) == IS_ARRAY) ? Z_ARRVAL_P(zfiles) : NULL;
14448 +                               
14449 +                               if ((fields && zend_hash_num_elements(fields)) || (files && zend_hash_num_elements(files))) {
14450 +                                       if (!(obj->request->body = http_request_body_fill(obj->request->body, fields, files))) {
14451 +                                               status = FAILURE;
14452 +                                       }
14453 +                               }
14454 +                       }
14455 +                       break;
14456 +               }
14457 +       }
14458 +
14459 +       if (status == SUCCESS) {
14460 +               zval *qdata = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryData")-1, 0 TSRMLS_CC);
14461 +               zval *options = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC);
14462 +               
14463 +               if (Z_STRLEN_P(qdata)) {
14464 +                       if (!strchr(obj->request->url, '?')) {
14465 +                               strlcat(obj->request->url, "?", HTTP_URL_MAXLEN);
14466 +                       } else {
14467 +                               strlcat(obj->request->url, "&", HTTP_URL_MAXLEN);
14468 +                       }
14469 +                       strlcat(obj->request->url, Z_STRVAL_P(qdata), HTTP_URL_MAXLEN);
14470 +               }
14471 +               
14472 +               http_request_prepare(obj->request, Z_ARRVAL_P(options));
14473 +               
14474 +               /* check if there's a onProgress method and add it as progress callback if one isn't already set */
14475 +               if (zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, "onprogress", sizeof("onprogress"))) {
14476 +                       zval **entry, *pcb;
14477 +                       
14478 +                       if (    (Z_TYPE_P(options) != IS_ARRAY)
14479 +                               ||      (SUCCESS != zend_hash_find(Z_ARRVAL_P(options), "onprogress", sizeof("onprogress"), (void *) &entry)
14480 +                               ||      (!IS_CALLABLE(*entry, 0, NULL)))) {
14481 +                               MAKE_STD_ZVAL(pcb);
14482 +                               array_init(pcb);
14483 +                               ZVAL_ADDREF(getThis());
14484 +                               add_next_index_zval(pcb, getThis());
14485 +                               add_next_index_stringl(pcb, "onprogress", lenof("onprogress"), 1);
14486 +                               http_request_set_progress_callback(obj->request, pcb);
14487 +                               zval_ptr_dtor(&pcb);
14488 +                       }
14489 +               }
14490 +       }
14491 +
14492 +       return status;
14493 +}
14494 +
14495 +STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr TSRMLS_DC)
14496 +{
14497 +       STATUS ret;
14498 +       zval *info;
14499 +       http_message *msg;
14500 +       
14501 +       /* always fetch info */
14502 +       MAKE_STD_ZVAL(info);
14503 +       array_init(info);
14504 +       http_request_info(obj->request, Z_ARRVAL_P(info));
14505 +       zend_update_property(THIS_CE, getThis(), ZEND_STRS("responseInfo")-1, info TSRMLS_CC);
14506 +       zval_ptr_dtor(&info);
14507 +       
14508 +       /* parse response message */
14509 +       phpstr_fix(&obj->request->conv.request);
14510 +       phpstr_fix(&obj->request->conv.response);
14511 +       
14512 +       if ((msg = http_message_parse(PHPSTR_VAL(&obj->request->conv.response), PHPSTR_LEN(&obj->request->conv.response)))) {
14513 +               zval *message;
14514 +
14515 +               if (i_zend_is_true(zend_read_property(THIS_CE, getThis(), ZEND_STRS("recordHistory")-1, 0 TSRMLS_CC))) {
14516 +                       zval *hist, *history = zend_read_property(THIS_CE, getThis(), ZEND_STRS("history")-1, 0 TSRMLS_CC);
14517 +                       http_message *response = http_message_parse(PHPSTR_VAL(&obj->request->conv.response), PHPSTR_LEN(&obj->request->conv.response));
14518 +                       http_message *request = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request));
14519 +                       
14520 +                       MAKE_STD_ZVAL(hist);
14521 +                       ZVAL_OBJVAL(hist, http_request_object_message(getThis(), http_message_interconnect(response, request)), 0);
14522 +                       if (Z_TYPE_P(history) == IS_OBJECT) {
14523 +                               http_message_object_prepend(hist, history);
14524 +                       }
14525 +                       zend_update_property(THIS_CE, getThis(), ZEND_STRS("history")-1, hist TSRMLS_CC);
14526 +                       zval_ptr_dtor(&hist);
14527 +               }
14528 +
14529 +               zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("responseCode")-1, msg->http.info.response.code TSRMLS_CC);
14530 +               zend_update_property_string(THIS_CE, getThis(), ZEND_STRS("responseStatus")-1, STR_PTR(msg->http.info.response.status) TSRMLS_CC);
14531 +
14532 +               MAKE_STD_ZVAL(message);
14533 +               ZVAL_OBJVAL(message, http_request_object_message(getThis(), msg), 0);
14534 +               zend_update_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, message TSRMLS_CC);
14535 +               zval_ptr_dtor(&message);
14536 +
14537 +               ret = SUCCESS;
14538 +       } else {
14539 +               /* update properties with empty values*/
14540 +               zval *znull;
14541 +               
14542 +               MAKE_STD_ZVAL(znull);
14543 +               ZVAL_NULL(znull);
14544 +               zend_update_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, znull TSRMLS_CC);
14545 +               zval_ptr_dtor(&znull);
14546 +               
14547 +               zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("responseCode")-1, 0 TSRMLS_CC);
14548 +               zend_update_property_string(THIS_CE, getThis(), ZEND_STRS("responseStatus")-1, "" TSRMLS_CC);
14549 +               
14550 +               /* append request message to history */
14551 +               if (i_zend_is_true(zend_read_property(THIS_CE, getThis(), ZEND_STRS("recordHistory")-1, 0 TSRMLS_CC))) {
14552 +                       http_message *request;
14553 +                       
14554 +                       if ((request = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request)))) {
14555 +                               zval *hist, *history = zend_read_property(THIS_CE, getThis(), ZEND_STRS("history")-1, 0 TSRMLS_CC);
14556 +                               
14557 +                               MAKE_STD_ZVAL(hist);
14558 +                               ZVAL_OBJVAL(hist, http_request_object_message(getThis(), request), 0);
14559 +                               if (Z_TYPE_P(history) == IS_OBJECT) {
14560 +                                       http_message_object_prepend(hist, history);
14561 +                               }
14562 +                               zend_update_property(THIS_CE, getThis(), ZEND_STRS("history")-1, hist TSRMLS_CC);
14563 +                               zval_ptr_dtor(&hist);
14564 +                       }
14565 +               }
14566 +               
14567 +               ret = FAILURE;
14568 +       }
14569 +       
14570 +       http_request_set_progress_callback(obj->request, NULL);
14571 +       
14572 +       if (!EG(exception) && zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, "onfinish", sizeof("onfinish"))) {
14573 +               zval *param;
14574 +               
14575 +               MAKE_STD_ZVAL(param);
14576 +               ZVAL_BOOL(param, ret == SUCCESS);
14577 +               with_error_handling(EH_NORMAL, NULL) {
14578 +                       zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "onfinish", NULL, param);
14579 +               } end_error_handling();
14580 +               zval_ptr_dtor(&param);
14581 +       }
14582 +       
14583 +       return ret;
14584 +}
14585 +
14586 +static int apply_pretty_key(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
14587 +{
14588 +       if (hash_key->arKey && hash_key->nKeyLength > 1) {
14589 +               hash_key->h = zend_hash_func(pretty_key(hash_key->arKey, hash_key->nKeyLength - 1, 1, 0), hash_key->nKeyLength);
14590 +       }
14591 +       return ZEND_HASH_APPLY_KEEP;
14592 +}
14593 +
14594 +#define http_request_object_set_options_subr(key, ow, pk) \
14595 +       _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key), (ow), (pk))
14596 +static inline void _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len, int overwrite, int prettify_keys)
14597 +{
14598 +       zval *old_opts, *new_opts, *opts = NULL, **entry = NULL;
14599 +
14600 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &opts)) {
14601 +               RETURN_FALSE;
14602 +       }
14603 +
14604 +       MAKE_STD_ZVAL(new_opts);
14605 +       array_init(new_opts);
14606 +       old_opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC);
14607 +       if (Z_TYPE_P(old_opts) == IS_ARRAY) {
14608 +               array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
14609 +       }
14610 +
14611 +       if (SUCCESS == zend_hash_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) {
14612 +               if (overwrite) {
14613 +                       zend_hash_clean(Z_ARRVAL_PP(entry));
14614 +               }
14615 +               if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
14616 +                       if (overwrite) {
14617 +                               array_copy(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry));
14618 +                       } else {
14619 +                               array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, prettify_keys ? ARRAY_JOIN_PRETTIFY : 0);
14620 +                       }
14621 +               }
14622 +       } else if (opts) {
14623 +               if (prettify_keys) {
14624 +                       zend_hash_apply_with_arguments(Z_ARRVAL_P(opts) HTTP_ZAPI_HASH_TSRMLS_CC, apply_pretty_key, 0, NULL);
14625 +               }
14626 +               ZVAL_ADDREF(opts);
14627 +               add_assoc_zval_ex(new_opts, key, len, opts);
14628 +       }
14629 +       zend_update_property(THIS_CE, getThis(), ZEND_STRS("options")-1, new_opts TSRMLS_CC);
14630 +       zval_ptr_dtor(&new_opts);
14631 +
14632 +       RETURN_TRUE;
14633 +}
14634 +
14635 +#define http_request_object_get_options_subr(key) \
14636 +       _http_request_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key))
14637 +static inline void _http_request_get_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len)
14638 +{
14639 +       NO_ARGS;
14640 +
14641 +       if (return_value_used) {
14642 +               zval *opts, **options;
14643 +
14644 +               opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC);
14645 +               array_init(return_value);
14646 +
14647 +               if (    (Z_TYPE_P(opts) == IS_ARRAY) && 
14648 +                               (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) {
14649 +                       convert_to_array(*options);
14650 +                       array_copy(Z_ARRVAL_PP(options), Z_ARRVAL_P(return_value));
14651 +               }
14652 +       }
14653 +}
14654 +
14655 +
14656 +/* ### USERLAND ### */
14657 +
14658 +/* {{{ proto void HttpRequest::__construct([string url[, int request_method = HTTP_METH_GET[, array options]]])
14659 +       Create a new HttpRequest object instance. */
14660 +PHP_METHOD(HttpRequest, __construct)
14661 +{
14662 +       char *URL = NULL;
14663 +       int URL_len;
14664 +       long meth = -1;
14665 +       zval *options = NULL;
14666 +
14667 +       SET_EH_THROW_HTTP();
14668 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla!", &URL, &URL_len, &meth, &options)) {
14669 +               if (URL) {
14670 +                       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("url")-1, URL, URL_len TSRMLS_CC);
14671 +               }
14672 +               if (meth > -1) {
14673 +                       zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("method")-1, meth TSRMLS_CC);
14674 +               }
14675 +               if (options) {
14676 +                       zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setoptions", NULL, options);
14677 +               }
14678 +       }
14679 +       SET_EH_NORMAL();
14680 +}
14681 +/* }}} */
14682 +
14683 +/* {{{ proto HttpRequest HttpRequest::factory([string url[, int request_method HTTP_METH_GET[, array options[, string class_name = "HttpRequest"]]]])
14684 +       Create a new HttpRequest object instance. */
14685 +PHP_METHOD(HttpRequest, factory)
14686 +{
14687 +       char *cn = NULL, *URL = NULL;
14688 +       int cl = 0, URL_len = 0;
14689 +       long meth = -1;
14690 +       zval *options = NULL;
14691 +       zend_object_value ov;
14692 +       
14693 +       SET_EH_THROW_HTTP();
14694 +       if (    SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla!s", &URL, &URL_len, &meth, &options, &cn, &cl) &&
14695 +                       SUCCESS == http_object_new(&ov, cn, cl, _http_request_object_new_ex, http_request_object_ce, NULL, NULL)) {
14696 +               RETVAL_OBJVAL(ov, 0);
14697 +               getThis() = return_value;
14698 +               if (URL) {
14699 +                       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("url")-1, URL, URL_len TSRMLS_CC);
14700 +               }
14701 +               if (meth > -1) {
14702 +                       zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("method")-1, meth TSRMLS_CC);
14703 +               }
14704 +               if (options) {
14705 +                       zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setoptions", NULL, options);
14706 +               }
14707 +       }
14708 +       SET_EH_NORMAL();
14709 +}
14710 +/* }}} */
14711 +
14712 +/* {{{ proto bool HttpRequest::setOptions([array options])
14713 +       Set the request options to use.  See http_get() for a full list of available options. */
14714 +PHP_METHOD(HttpRequest, setOptions)
14715 +{
14716 +       HashKey key = initHashKey(0);
14717 +       HashPosition pos;
14718 +       zval *opts = NULL, *old_opts, *new_opts, *add_opts, **opt;
14719 +
14720 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
14721 +               RETURN_FALSE;
14722 +       }
14723 +       
14724 +       MAKE_STD_ZVAL(new_opts);
14725 +       array_init(new_opts);
14726 +               
14727 +       if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
14728 +               zend_update_property(THIS_CE, getThis(), ZEND_STRS("options")-1, new_opts TSRMLS_CC);
14729 +               zval_ptr_dtor(&new_opts);
14730 +               RETURN_TRUE;
14731 +       }
14732 +       
14733 +       MAKE_STD_ZVAL(add_opts);
14734 +       array_init(add_opts);
14735 +       /* some options need extra attention -- thus cannot use array_merge() directly */
14736 +       FOREACH_KEYVAL(pos, opts, key, opt) {
14737 +               if (key.type == HASH_KEY_IS_STRING) {
14738 +#define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
14739 +                       if (KEYMATCH(key, "headers")) {
14740 +                               zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, *opt);
14741 +                       } else if (KEYMATCH(key, "cookies")) {
14742 +                               zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addcookies", NULL, *opt);
14743 +                       } else if (KEYMATCH(key, "ssl")) {
14744 +                               zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addssloptions", NULL, *opt);
14745 +                       } else if (KEYMATCH(key, "url") || KEYMATCH(key, "uri")) {
14746 +                               zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "seturl", NULL, *opt);
14747 +                       } else if (KEYMATCH(key, "method")) {
14748 +                               zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmethod", NULL, *opt);
14749 +                       } else if (KEYMATCH(key, "flushcookies")) {
14750 +                               getObject(http_request_object, obj);
14751 +                               if (i_zend_is_true(*opt)) {
14752 +                                       http_request_flush_cookies(obj->request);
14753 +                               }
14754 +                       } else if (KEYMATCH(key, "resetcookies")) {
14755 +                               getObject(http_request_object, obj);
14756 +                               http_request_reset_cookies(obj->request, (zend_bool) i_zend_is_true(*opt));
14757 +                       } else if (KEYMATCH(key, "enablecookies")) {
14758 +                               getObject(http_request_object, obj);
14759 +                               http_request_enable_cookies(obj->request);
14760 +                       } else if (KEYMATCH(key, "recordHistory")) {
14761 +                               zend_update_property(THIS_CE, getThis(), ZEND_STRS("recordHistory")-1, *opt TSRMLS_CC);
14762 +                       } else if (KEYMATCH(key, "messageClass")) {
14763 +                               zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmessageclass", NULL, *opt);
14764 +                       } else if (Z_TYPE_PP(opt) == IS_NULL) {
14765 +                               old_opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC);
14766 +                               if (Z_TYPE_P(old_opts) == IS_ARRAY) {
14767 +                                       zend_hash_del(Z_ARRVAL_P(old_opts), key.str, key.len);
14768 +                               }
14769 +                       } else {
14770 +                               ZVAL_ADDREF(*opt);
14771 +                               add_assoc_zval_ex(add_opts, key.str, key.len, *opt);
14772 +                       }
14773 +               }
14774 +       }
14775 +       
14776 +       old_opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC);
14777 +       if (Z_TYPE_P(old_opts) == IS_ARRAY) {
14778 +               array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
14779 +       }
14780 +       array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0);
14781 +       zend_update_property(THIS_CE, getThis(), ZEND_STRS("options")-1, new_opts TSRMLS_CC);
14782 +       zval_ptr_dtor(&new_opts);
14783 +       zval_ptr_dtor(&add_opts);
14784 +       
14785 +       RETURN_TRUE;
14786 +}
14787 +/* }}} */
14788 +
14789 +/* {{{ proto array HttpRequest::getOptions()
14790 +       Get currently set options. */
14791 +PHP_METHOD(HttpRequest, getOptions)
14792 +{
14793 +       NO_ARGS;
14794 +
14795 +       if (return_value_used) {
14796 +               RETURN_PROP(options);
14797 +       }
14798 +}
14799 +/* }}} */
14800 +
14801 +/* {{{ proto bool HttpRequest::setSslOptions([array options])
14802 +       Set SSL options. */
14803 +PHP_METHOD(HttpRequest, setSslOptions)
14804 +{
14805 +       http_request_object_set_options_subr("ssl", 1, 0);
14806 +}
14807 +/* }}} */
14808 +
14809 +/* {{{ proto bool HttpRequest::addSslOptions(array options)
14810 +       Set additional SSL options. */
14811 +PHP_METHOD(HttpRequest, addSslOptions)
14812 +{
14813 +       http_request_object_set_options_subr("ssl", 0, 0);
14814 +}
14815 +/* }}} */
14816 +
14817 +/* {{{ proto array HttpRequest::getSslOtpions()
14818 +       Get previously set SSL options. */
14819 +PHP_METHOD(HttpRequest, getSslOptions)
14820 +{
14821 +       http_request_object_get_options_subr("ssl");
14822 +}
14823 +/* }}} */
14824 +
14825 +/* {{{ proto bool HttpRequest::addHeaders(array headers)
14826 +       Add request header name/value pairs. */
14827 +PHP_METHOD(HttpRequest, addHeaders)
14828 +{
14829 +       http_request_object_set_options_subr("headers", 0, 1);
14830 +}
14831 +
14832 +/* {{{ proto bool HttpRequest::setHeaders([array headers])
14833 +       Set request header name/value pairs. */
14834 +PHP_METHOD(HttpRequest, setHeaders)
14835 +{
14836 +       http_request_object_set_options_subr("headers", 1, 1);
14837 +}
14838 +/* }}} */
14839 +
14840 +/* {{{ proto array HttpRequest::getHeaders()
14841 +       Get previously set request headers. */
14842 +PHP_METHOD(HttpRequest, getHeaders)
14843 +{
14844 +       http_request_object_get_options_subr("headers");
14845 +}
14846 +/* }}} */
14847 +
14848 +/* {{{ proto bool HttpRequest::setCookies([array cookies])
14849 +       Set cookies. */
14850 +PHP_METHOD(HttpRequest, setCookies)
14851 +{
14852 +       http_request_object_set_options_subr("cookies", 1, 0);
14853 +}
14854 +/* }}} */
14855 +
14856 +/* {{{ proto bool HttpRequest::addCookies(array cookies)
14857 +       Add cookies. */
14858 +PHP_METHOD(HttpRequest, addCookies)
14859 +{
14860 +       http_request_object_set_options_subr("cookies", 0, 0);
14861 +}
14862 +/* }}} */
14863 +
14864 +/* {{{ proto array HttpRequest::getCookies()
14865 +       Get previously set cookies. */
14866 +PHP_METHOD(HttpRequest, getCookies)
14867 +{
14868 +       http_request_object_get_options_subr("cookies");
14869 +}
14870 +/* }}} */
14871 +
14872 +/* {{{ proto bool HttpRequest::enableCookies()
14873 +       Enable automatic sending of received cookies. Note that customly set cookies will be sent anyway. */
14874 +PHP_METHOD(HttpRequest, enableCookies)
14875 +{
14876 +       NO_ARGS {
14877 +               getObject(http_request_object, obj);
14878 +               RETURN_SUCCESS(http_request_enable_cookies(obj->request));
14879 +       }
14880 +       
14881 +}
14882 +/* }}} */
14883 +
14884 +/* {{{ proto bool HttpRequest::resetCookies([bool session_only = FALSE])
14885 +       Reset all automatically received/sent cookies. Note that customly set cookies are not affected. */
14886 +PHP_METHOD(HttpRequest, resetCookies)
14887 +{
14888 +       zend_bool session_only = 0;
14889 +       getObject(http_request_object, obj);
14890 +       
14891 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &session_only)) {
14892 +               RETURN_FALSE;
14893 +       }
14894 +       RETURN_SUCCESS(http_request_reset_cookies(obj->request, session_only));
14895 +}
14896 +/* }}} */
14897 +
14898 +/* {{{ proto bool HttpRequest::flushCookies()
14899 +       Flush internal cookies to the cookiestore file */
14900 +PHP_METHOD(HttpRequest, flushCookies)
14901 +{
14902 +       NO_ARGS {
14903 +               getObject(http_request_object, obj);
14904 +               RETURN_SUCCESS(http_request_flush_cookies(obj->request));
14905 +       }
14906 +}
14907 +/* }}} */
14908 +
14909 +/* {{{ proto bool HttpRequest::setUrl(string url)
14910 +       Set the request URL. */
14911 +PHP_METHOD(HttpRequest, setUrl)
14912 +{
14913 +       char *URL = NULL;
14914 +       int URL_len;
14915 +
14916 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
14917 +               RETURN_FALSE;
14918 +       }
14919 +
14920 +       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("url")-1, URL, URL_len TSRMLS_CC);
14921 +       RETURN_TRUE;
14922 +}
14923 +/* }}} */
14924 +
14925 +/* {{{ proto string HttpRequest::getUrl()
14926 +       Get the previously set request URL. */
14927 +PHP_METHOD(HttpRequest, getUrl)
14928 +{
14929 +       NO_ARGS;
14930 +
14931 +       if (return_value_used) {
14932 +               RETURN_PROP(url);
14933 +       }
14934 +}
14935 +/* }}} */
14936 +
14937 +/* {{{ proto bool HttpRequest::setMethod(int request_method)
14938 +       Set the request method. */
14939 +PHP_METHOD(HttpRequest, setMethod)
14940 +{
14941 +       long meth;
14942 +
14943 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
14944 +               RETURN_FALSE;
14945 +       }
14946 +
14947 +       zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("method")-1, meth TSRMLS_CC);
14948 +       RETURN_TRUE;
14949 +}
14950 +/* }}} */
14951 +
14952 +/* {{{ proto int HttpRequest::getMethod()
14953 +       Get the previously set request method. */
14954 +PHP_METHOD(HttpRequest, getMethod)
14955 +{
14956 +       NO_ARGS;
14957 +
14958 +       if (return_value_used) {
14959 +               RETURN_PROP(method);
14960 +       }
14961 +}
14962 +/* }}} */
14963 +
14964 +/* {{{ proto bool HttpRequest::setContentType(string content_type)
14965 +       Set the content type the post request should have. */
14966 +PHP_METHOD(HttpRequest, setContentType)
14967 +{
14968 +       char *ctype;
14969 +       int ct_len;
14970 +
14971 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
14972 +               RETURN_FALSE;
14973 +       }
14974 +
14975 +       if (ct_len) {
14976 +               HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE);
14977 +       }
14978 +       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("contentType")-1, ctype, ct_len TSRMLS_CC);
14979 +       RETURN_TRUE;
14980 +}
14981 +/* }}} */
14982 +
14983 +/* {{{ proto string HttpRequest::getContentType()
14984 +       Get the previously content type. */
14985 +PHP_METHOD(HttpRequest, getContentType)
14986 +{
14987 +       NO_ARGS;
14988 +
14989 +       if (return_value_used) {
14990 +               RETURN_PROP(contentType);
14991 +       }
14992 +}
14993 +/* }}} */
14994 +
14995 +/* {{{ proto bool HttpRequest::setQueryData([mixed query_data])
14996 +       Set the URL query parameters to use, overwriting previously set query parameters. */
14997 +PHP_METHOD(HttpRequest, setQueryData)
14998 +{
14999 +       zval *qdata = NULL;
15000 +
15001 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &qdata)) {
15002 +               RETURN_FALSE;
15003 +       }
15004 +
15005 +       if ((!qdata) || Z_TYPE_P(qdata) == IS_NULL) {
15006 +               zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryData")-1, "", 0 TSRMLS_CC);
15007 +       } else if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
15008 +               char *query_data = NULL;
15009 +               
15010 +               if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
15011 +                       RETURN_FALSE;
15012 +               }
15013 +               
15014 +               zend_update_property_string(THIS_CE, getThis(), ZEND_STRS("queryData")-1, query_data TSRMLS_CC);
15015 +               efree(query_data);
15016 +       } else {
15017 +               zval *data = http_zsep(IS_STRING, qdata);
15018 +               
15019 +               zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryData")-1, Z_STRVAL_P(data), Z_STRLEN_P(data) TSRMLS_CC);
15020 +               zval_ptr_dtor(&data);
15021 +       }
15022 +       RETURN_TRUE;
15023 +}
15024 +/* }}} */
15025 +
15026 +/* {{{ proto string HttpRequest::getQueryData()
15027 +       Get the current query data in form of an urlencoded query string. */
15028 +PHP_METHOD(HttpRequest, getQueryData)
15029 +{
15030 +       NO_ARGS;
15031 +
15032 +       if (return_value_used) {
15033 +               RETURN_PROP(queryData);
15034 +       }
15035 +}
15036 +/* }}} */
15037 +
15038 +/* {{{ proto bool HttpRequest::addQueryData(array query_params)
15039 +       Add parameters to the query parameter list, leaving previously set unchanged. */
15040 +PHP_METHOD(HttpRequest, addQueryData)
15041 +{
15042 +       zval *qdata, *old_qdata;
15043 +       char *query_data = NULL;
15044 +       size_t query_data_len = 0;
15045 +
15046 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &qdata)) {
15047 +               RETURN_FALSE;
15048 +       }
15049 +
15050 +       old_qdata = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryData")-1, 0 TSRMLS_CC);
15051 +
15052 +       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)) {
15053 +               RETURN_FALSE;
15054 +       }
15055 +
15056 +       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryData")-1, query_data, query_data_len TSRMLS_CC);
15057 +       efree(query_data);
15058 +
15059 +       RETURN_TRUE;
15060 +}
15061 +/* }}} */
15062 +
15063 +/* {{{ proto bool HttpRequest::addPostFields(array post_data)
15064 +       Adds POST data entries, leaving previously set unchanged, unless a post entry with the same name already exists. */
15065 +PHP_METHOD(HttpRequest, addPostFields)
15066 +{
15067 +       zval *post_data, *old_post, *new_post;
15068 +
15069 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &post_data)) {
15070 +               RETURN_FALSE;
15071 +       }
15072 +
15073 +       if (zend_hash_num_elements(Z_ARRVAL_P(post_data))) {
15074 +               MAKE_STD_ZVAL(new_post);
15075 +               array_init(new_post);
15076 +               old_post = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, 0 TSRMLS_CC);
15077 +               if (Z_TYPE_P(old_post) == IS_ARRAY) {
15078 +                       array_copy(Z_ARRVAL_P(old_post), Z_ARRVAL_P(new_post));
15079 +               }
15080 +               array_join(Z_ARRVAL_P(post_data), Z_ARRVAL_P(new_post), 0, 0);
15081 +               zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, new_post TSRMLS_CC);
15082 +               zval_ptr_dtor(&new_post);
15083 +       }
15084 +       
15085 +       RETURN_TRUE;
15086 +}
15087 +/* }}} */
15088 +
15089 +/* {{{ proto bool HttpRequest::setPostFields([array post_data])
15090 +       Set the POST data entries, overwriting previously set POST data. */
15091 +PHP_METHOD(HttpRequest, setPostFields)
15092 +{
15093 +       zval *post, *post_data = NULL;
15094 +
15095 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &post_data)) {
15096 +               RETURN_FALSE;
15097 +       }
15098 +
15099 +       MAKE_STD_ZVAL(post);
15100 +       array_init(post);
15101 +       if (post_data && zend_hash_num_elements(Z_ARRVAL_P(post_data))) {
15102 +               array_copy(Z_ARRVAL_P(post_data), Z_ARRVAL_P(post));
15103 +       }
15104 +       zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, post TSRMLS_CC);
15105 +       zval_ptr_dtor(&post);
15106 +
15107 +       RETURN_TRUE;
15108 +}
15109 +/* }}}*/
15110 +
15111 +/* {{{ proto array HttpRequest::getPostFields()
15112 +       Get previously set POST data. */
15113 +PHP_METHOD(HttpRequest, getPostFields)
15114 +{
15115 +       NO_ARGS;
15116 +
15117 +       if (return_value_used) {
15118 +               RETURN_PROP(postFields);
15119 +       }
15120 +}
15121 +/* }}} */
15122 +
15123 +/* {{{ proto bool HttpRequest::setBody([string request_body_data])
15124 +       Set request body to send, overwriting previously set request body. Don't forget to specify a content type. */
15125 +PHP_METHOD(HttpRequest, setBody)
15126 +{
15127 +       char *raw_data = NULL;
15128 +       int data_len = 0;
15129 +       
15130 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &raw_data, &data_len)) {
15131 +               RETURN_FALSE;
15132 +       }
15133 +       
15134 +       if (!raw_data) {
15135 +               raw_data = "";
15136 +       }
15137 +       
15138 +       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, raw_data, data_len TSRMLS_CC);
15139 +       RETURN_TRUE;
15140 +}
15141 +/* }}} */
15142 +
15143 +/* {{{ proto bool HttpRequest::addBody(string request_body_data)
15144 +       Add request body data, leaving previously set request body data unchanged. */
15145 +PHP_METHOD(HttpRequest, addBody)
15146 +{
15147 +       char *raw_data;
15148 +       int data_len;
15149 +       
15150 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &raw_data, &data_len)) {
15151 +               RETURN_FALSE;
15152 +       }
15153 +       
15154 +       if (data_len) {
15155 +               zval *data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, 0 TSRMLS_CC);
15156 +               
15157 +               if (Z_STRLEN_P(data)) {
15158 +                       Z_STRVAL_P(data) = erealloc(Z_STRVAL_P(data), (Z_STRLEN_P(data) += data_len) + 1);
15159 +                       Z_STRVAL_P(data)[Z_STRLEN_P(data)] = '\0';
15160 +                       memcpy(Z_STRVAL_P(data) + Z_STRLEN_P(data) - data_len, raw_data, data_len);
15161 +               } else {
15162 +                       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, raw_data, data_len TSRMLS_CC);
15163 +               }
15164 +       }
15165 +       
15166 +       RETURN_TRUE;
15167 +}
15168 +/* }}} */
15169 +
15170 +/* {{{ proto string HttpRequest::getBody()
15171 +       Get previously set request body data. */
15172 +PHP_METHOD(HttpRequest, getBody)
15173 +{
15174 +       NO_ARGS;
15175 +       
15176 +       if (return_value_used) {
15177 +               RETURN_PROP(requestBody);
15178 +       }
15179 +}
15180 +/* }}} */
15181 +
15182 +/* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
15183 +       Add a file to the POST request, leaving previously set files unchanged. */
15184 +PHP_METHOD(HttpRequest, addPostFile)
15185 +{
15186 +       zval *entry, *old_post, *new_post;
15187 +       char *name, *file, *type = NULL;
15188 +       int name_len, file_len, type_len = 0;
15189 +
15190 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
15191 +               RETURN_FALSE;
15192 +       }
15193 +
15194 +       if (type_len) {
15195 +               HTTP_CHECK_CONTENT_TYPE(type, RETURN_FALSE);
15196 +       } else {
15197 +               type = "application/x-octetstream";
15198 +               type_len = sizeof("application/x-octetstream") - 1;
15199 +       }
15200 +
15201 +       MAKE_STD_ZVAL(entry);
15202 +       array_init(entry);
15203 +
15204 +       add_assoc_stringl(entry, "name", name, name_len, 1);
15205 +       add_assoc_stringl(entry, "type", type, type_len, 1);
15206 +       add_assoc_stringl(entry, "file", file, file_len, 1);
15207 +
15208 +       MAKE_STD_ZVAL(new_post);
15209 +       array_init(new_post);
15210 +       old_post = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, 0 TSRMLS_CC);
15211 +       if (Z_TYPE_P(old_post) == IS_ARRAY) {
15212 +               array_copy(Z_ARRVAL_P(old_post), Z_ARRVAL_P(new_post));
15213 +       }
15214 +       add_next_index_zval(new_post, entry);
15215 +       zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, new_post TSRMLS_CC);
15216 +       zval_ptr_dtor(&new_post);
15217 +
15218 +       RETURN_TRUE;
15219 +}
15220 +/* }}} */
15221 +
15222 +/* {{{ proto bool HttpRequest::setPostFiles([array post_files])
15223 +       Set files to post, overwriting previously set post files. */
15224 +PHP_METHOD(HttpRequest, setPostFiles)
15225 +{
15226 +       zval *files = NULL, *post;
15227 +
15228 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!/", &files)) {
15229 +               RETURN_FALSE;
15230 +       }
15231 +
15232 +       MAKE_STD_ZVAL(post);
15233 +       array_init(post);
15234 +       if (files && (Z_TYPE_P(files) == IS_ARRAY)) {
15235 +               array_copy(Z_ARRVAL_P(files), Z_ARRVAL_P(post));
15236 +       }
15237 +       zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, post TSRMLS_CC);
15238 +       zval_ptr_dtor(&post);
15239 +
15240 +       RETURN_TRUE;
15241 +}
15242 +/* }}} */
15243 +
15244 +/* {{{ proto array HttpRequest::getPostFiles()
15245 +       Get all previously added POST files. */
15246 +PHP_METHOD(HttpRequest, getPostFiles)
15247 +{
15248 +       NO_ARGS;
15249 +
15250 +       if (return_value_used) {
15251 +               RETURN_PROP(postFiles);
15252 +       }
15253 +}
15254 +/* }}} */
15255 +
15256 +/* {{{ proto bool HttpRequest::setPutFile([string file])
15257 +       Set file to put. Affects only PUT requests. */
15258 +PHP_METHOD(HttpRequest, setPutFile)
15259 +{
15260 +       char *file = "";
15261 +       int file_len = 0;
15262 +
15263 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &file, &file_len)) {
15264 +               RETURN_FALSE;
15265 +       }
15266 +
15267 +       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("putFile")-1, file, file_len TSRMLS_CC);
15268 +       RETURN_TRUE;
15269 +}
15270 +/* }}} */
15271 +
15272 +/* {{{ proto string HttpRequest::getPutFile()
15273 +       Get previously set put file. */
15274 +PHP_METHOD(HttpRequest, getPutFile)
15275 +{
15276 +       NO_ARGS;
15277 +
15278 +       if (return_value_used) {
15279 +               RETURN_PROP(putFile);
15280 +       }
15281 +}
15282 +/* }}} */
15283 +
15284 +/* {{{ proto bool HttpRequest::setPutData([string put_data])
15285 +       Set PUT data to send, overwriting previously set PUT data. */
15286 +PHP_METHOD(HttpRequest, setPutData)
15287 +{
15288 +       char *put_data = NULL;
15289 +       int data_len = 0;
15290 +       
15291 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &put_data, &data_len)) {
15292 +               RETURN_FALSE;
15293 +       }
15294 +       
15295 +       if (!put_data) {
15296 +               put_data = "";
15297 +       }
15298 +       
15299 +       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("putData")-1, put_data, data_len TSRMLS_CC);
15300 +       RETURN_TRUE;
15301 +}
15302 +/* }}} */
15303 +
15304 +/* {{{ proto bool HttpRequest::addPutData(string put_data)
15305 +       Add PUT data, leaving previously set PUT data unchanged. */
15306 +PHP_METHOD(HttpRequest, addPutData)
15307 +{
15308 +       char *put_data;
15309 +       int data_len;
15310 +       
15311 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &put_data, &data_len)) {
15312 +               RETURN_FALSE;
15313 +       }
15314 +       
15315 +       if (data_len) {
15316 +               zval *data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("putData")-1, 0 TSRMLS_CC);
15317 +               
15318 +               if (Z_STRLEN_P(data)) {
15319 +                       Z_STRVAL_P(data) = erealloc(Z_STRVAL_P(data), (Z_STRLEN_P(data) += data_len) + 1);
15320 +                       Z_STRVAL_P(data)[Z_STRLEN_P(data)] = '\0';
15321 +                       memcpy(Z_STRVAL_P(data) + Z_STRLEN_P(data) - data_len, put_data, data_len);
15322 +               } else {
15323 +                       zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("putData")-1, put_data, data_len TSRMLS_CC);
15324 +               }
15325 +       }
15326 +       
15327 +       RETURN_TRUE;
15328 +}
15329 +/* }}} */
15330 +
15331 +/* {{{ proto string HttpRequest::getPutData()
15332 +       Get previously set PUT data. */
15333 +PHP_METHOD(HttpRequest, getPutData)
15334 +{
15335 +       NO_ARGS;
15336 +       
15337 +       if (return_value_used) {
15338 +               RETURN_PROP(putData);
15339 +       }
15340 +}
15341 +/* }}} */
15342 +
15343 +/* {{{ proto array HttpRequest::getResponseData()
15344 +       Get all response data after the request has been sent. */
15345 +PHP_METHOD(HttpRequest, getResponseData)
15346 +{
15347 +       NO_ARGS;
15348 +
15349 +       if (return_value_used) {
15350 +               char *body;
15351 +               size_t body_len;
15352 +               zval *headers, *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC);
15353 +               
15354 +               if (Z_TYPE_P(message) == IS_OBJECT) {
15355 +                       getObjectEx(http_message_object, msg, message);
15356 +                       
15357 +                       array_init(return_value);
15358 +                       
15359 +                       MAKE_STD_ZVAL(headers);
15360 +                       array_init(headers);
15361 +                       zend_hash_copy(Z_ARRVAL_P(headers), &msg->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
15362 +                       add_assoc_zval(return_value, "headers", headers);
15363 +                       
15364 +                       phpstr_data(PHPSTR(msg->message), &body, &body_len);
15365 +                       add_assoc_stringl(return_value, "body", body, body_len, 0);
15366 +               }
15367 +       }
15368 +}
15369 +/* }}} */
15370 +
15371 +/* {{{ proto mixed HttpRequest::getResponseHeader([string name])
15372 +       Get response header(s) after the request has been sent. */
15373 +PHP_METHOD(HttpRequest, getResponseHeader)
15374 +{
15375 +       if (return_value_used) {
15376 +               zval *header;
15377 +               char *header_name = NULL;
15378 +               int header_len = 0;
15379 +
15380 +               if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
15381 +                       zval *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC);
15382 +                       
15383 +                       if (Z_TYPE_P(message) == IS_OBJECT) {
15384 +                               getObjectEx(http_message_object, msg, message);
15385 +                               
15386 +                               if (header_len) {
15387 +                                       if ((header = http_message_header_ex(msg->message, pretty_key(header_name, header_len, 1, 1), header_len + 1, 0))) {
15388 +                                               RETURN_ZVAL(header, 1, 1);
15389 +                                       }
15390 +                               } else {
15391 +                                       array_init(return_value);
15392 +                                       zend_hash_copy(Z_ARRVAL_P(return_value), &msg->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
15393 +                                       return;
15394 +                               }
15395 +                       }
15396 +               }
15397 +               RETURN_FALSE;
15398 +       }
15399 +}
15400 +/* }}} */
15401 +
15402 +/* {{{ proto array HttpRequest::getResponseCookies([int flags[, array allowed_extras]])
15403 +       Get response cookie(s) after the request has been sent. */
15404 +PHP_METHOD(HttpRequest, getResponseCookies)
15405 +{
15406 +       if (return_value_used) {
15407 +               long flags = 0;
15408 +               zval *allowed_extras_array = NULL;
15409 +               
15410 +               if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|la!", &flags, &allowed_extras_array)) {
15411 +                       int i = 0;
15412 +                       HashKey key = initHashKey(0);
15413 +                       char **allowed_extras = NULL;
15414 +                       zval **header = NULL, **entry = NULL, *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC);
15415 +                       HashPosition pos, pos1, pos2;
15416 +                       
15417 +                       if (Z_TYPE_P(message) == IS_OBJECT) {
15418 +                               getObjectEx(http_message_object, msg, message);
15419 +                               
15420 +                               array_init(return_value);
15421 +                               
15422 +                               if (allowed_extras_array) {
15423 +                                       allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
15424 +                                       FOREACH_VAL(pos, allowed_extras_array, entry) {
15425 +                                               zval *data = http_zsep(IS_STRING, *entry);
15426 +                                               allowed_extras[i++] = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
15427 +                                               zval_ptr_dtor(&data);
15428 +                                       }
15429 +                               }
15430 +                               
15431 +                               FOREACH_HASH_KEYVAL(pos1, &msg->message->hdrs, key, header) {
15432 +                                       if (key.type == HASH_KEY_IS_STRING && !strcasecmp(key.str, "Set-Cookie")) {
15433 +                                               http_cookie_list list;
15434 +                                               
15435 +                                               if (Z_TYPE_PP(header) == IS_ARRAY) {
15436 +                                                       zval **single_header;
15437 +                                                       
15438 +                                                       FOREACH_VAL(pos2, *header, single_header) {
15439 +                                                               zval *data = http_zsep(IS_STRING, *single_header);
15440 +                                                               
15441 +                                                               if (http_parse_cookie_ex(&list, Z_STRVAL_P(data), flags, allowed_extras)) {
15442 +                                                                       zval *cookie;
15443 +                                                                       
15444 +                                                                       MAKE_STD_ZVAL(cookie);
15445 +                                                                       object_init(cookie);
15446 +                                                                       http_cookie_list_tostruct(&list, cookie);
15447 +                                                                       add_next_index_zval(return_value, cookie);
15448 +                                                                       http_cookie_list_dtor(&list);
15449 +                                                               }
15450 +                                                               zval_ptr_dtor(&data);
15451 +                                                       }
15452 +                                               } else {
15453 +                                                       zval *data = http_zsep(IS_STRING, *header);
15454 +                                                       if (http_parse_cookie_ex(&list, Z_STRVAL_P(data), flags, allowed_extras)) {
15455 +                                                               zval *cookie;
15456 +                                                               
15457 +                                                               MAKE_STD_ZVAL(cookie);
15458 +                                                               object_init(cookie);
15459 +                                                               http_cookie_list_tostruct(&list, cookie);
15460 +                                                               add_next_index_zval(return_value, cookie);
15461 +                                                               http_cookie_list_dtor(&list);
15462 +                                                       }
15463 +                                                       zval_ptr_dtor(&data);
15464 +                                               }
15465 +                                       }
15466 +                               }
15467 +                               
15468 +                               if (allowed_extras) {
15469 +                                       for (i = 0; allowed_extras[i]; ++i) {
15470 +                                               efree(allowed_extras[i]);
15471 +                                       }
15472 +                                       efree(allowed_extras);
15473 +                               }
15474 +                               
15475 +                               return;
15476 +                       }
15477 +               }
15478 +               RETURN_FALSE;
15479 +       }
15480 +}
15481 +/* }}} */
15482 +
15483 +/* {{{ proto string HttpRequest::getResponseBody()
15484 +       Get the response body after the request has been sent. */
15485 +PHP_METHOD(HttpRequest, getResponseBody)
15486 +{
15487 +       NO_ARGS;
15488 +
15489 +       if (return_value_used) {
15490 +               zval *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC);
15491 +               
15492 +               if (Z_TYPE_P(message) == IS_OBJECT) {
15493 +                       getObjectEx(http_message_object, msg, message);
15494 +                       RETURN_PHPSTR_DUP(&msg->message->body);
15495 +               } else {
15496 +                       RETURN_FALSE;
15497 +               }
15498 +       }
15499 +}
15500 +/* }}} */
15501 +
15502 +/* {{{ proto int HttpRequest::getResponseCode()
15503 +       Get the response code after the request has been sent. */
15504 +PHP_METHOD(HttpRequest, getResponseCode)
15505 +{
15506 +       NO_ARGS;
15507 +
15508 +       if (return_value_used) {
15509 +               RETURN_PROP(responseCode);
15510 +       }
15511 +}
15512 +/* }}} */
15513 +
15514 +/* {{{ proto string HttpRequest::getResponseStatus()
15515 +       Get the response status (i.e. the string after the response code) after the message has been sent. */
15516 +PHP_METHOD(HttpRequest, getResponseStatus)
15517 +{
15518 +       NO_ARGS;
15519 +       
15520 +       if (return_value_used) {
15521 +               RETURN_PROP(responseStatus);
15522 +       }
15523 +}
15524 +/* }}} */
15525 +
15526 +/* {{{ proto mixed HttpRequest::getResponseInfo([string name])
15527 +       Get response info after the request has been sent. */
15528 +PHP_METHOD(HttpRequest, getResponseInfo)
15529 +{
15530 +       if (return_value_used) {
15531 +               zval *info, **infop;
15532 +               char *info_name = NULL;
15533 +               int info_len = 0;
15534 +
15535 +               if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
15536 +                       RETURN_FALSE;
15537 +               }
15538 +
15539 +               info = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseInfo")-1, 0 TSRMLS_CC);
15540 +               
15541 +               if (Z_TYPE_P(info) != IS_ARRAY) {
15542 +                       RETURN_FALSE;
15543 +               }
15544 +
15545 +               if (info_len && info_name) {
15546 +                       if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void *) &infop)) {
15547 +                               RETURN_ZVAL(*infop, 1, 0);
15548 +                       } else {
15549 +                               http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Could not find response info named %s", info_name);
15550 +                               RETURN_FALSE;
15551 +                       }
15552 +               } else {
15553 +                       RETURN_ZVAL(info, 1, 0);
15554 +               }
15555 +       }
15556 +}
15557 +/* }}}*/
15558 +
15559 +/* {{{ proto HttpMessage HttpRequest::getResponseMessage()
15560 +       Get the full response as HttpMessage object after the request has been sent. */
15561 +PHP_METHOD(HttpRequest, getResponseMessage)
15562 +{
15563 +       NO_ARGS {
15564 +               zval *message;
15565 +
15566 +               SET_EH_THROW_HTTP();
15567 +               message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC);
15568 +               if (Z_TYPE_P(message) == IS_OBJECT) {
15569 +                       RETVAL_OBJECT(message, 1);
15570 +               } else {
15571 +                       http_error(HE_WARNING, HTTP_E_RUNTIME, "HttpRequest does not contain a response message");
15572 +               }
15573 +               SET_EH_NORMAL();
15574 +       }
15575 +}
15576 +/* }}} */
15577 +
15578 +/* {{{ proto HttpMessage HttpRequest::getRequestMessage()
15579 +       Get sent HTTP message. */
15580 +PHP_METHOD(HttpRequest, getRequestMessage)
15581 +{
15582 +       NO_ARGS;
15583 +
15584 +       if (return_value_used) {
15585 +               http_message *msg;
15586 +               getObject(http_request_object, obj);
15587 +
15588 +               SET_EH_THROW_HTTP();
15589 +               if ((msg = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request)))) {
15590 +                       RETVAL_OBJVAL(http_request_object_message(getThis(), msg), 0);
15591 +               }
15592 +               SET_EH_NORMAL();
15593 +       }
15594 +}
15595 +/* }}} */
15596 +
15597 +/* {{{ proto string HttpRequest::getRawRequestMessage()
15598 +       Get sent HTTP message. */
15599 +PHP_METHOD(HttpRequest, getRawRequestMessage)
15600 +{
15601 +       NO_ARGS;
15602 +
15603 +       if (return_value_used) {
15604 +               getObject(http_request_object, obj);
15605 +
15606 +               RETURN_PHPSTR_DUP(&obj->request->conv.request);
15607 +       }
15608 +}
15609 +/* }}} */
15610 +
15611 +/* {{{ proto string HttpRequest::getRawResponseMessage()
15612 +       Get the entire HTTP response. */
15613 +PHP_METHOD(HttpRequest, getRawResponseMessage)
15614 +{
15615 +       NO_ARGS;
15616 +
15617 +       if (return_value_used) {
15618 +               getObject(http_request_object, obj);
15619 +
15620 +               RETURN_PHPSTR_DUP(&obj->request->conv.response);
15621 +       }
15622 +}
15623 +/* }}} */
15624 +
15625 +/* {{{ proto HttpMessage HttpRequest::getHistory()
15626 +       Get all sent requests and received responses as an HttpMessage object. */
15627 +PHP_METHOD(HttpRequest, getHistory)
15628 +{
15629 +       NO_ARGS;
15630 +
15631 +       if (return_value_used) {
15632 +               zval *hist;
15633 +               
15634 +               SET_EH_THROW_HTTP();
15635 +               hist = zend_read_property(THIS_CE, getThis(), ZEND_STRS("history")-1, 0 TSRMLS_CC);
15636 +               if (Z_TYPE_P(hist) == IS_OBJECT) {
15637 +                       RETVAL_OBJECT(hist, 1);
15638 +               } else {
15639 +                       http_error(HE_WARNING, HTTP_E_RUNTIME, "The history is empty");
15640 +               }
15641 +               SET_EH_NORMAL();
15642 +       }
15643 +}
15644 +/* }}} */
15645 +
15646 +/* {{{ proto void HttpRequest::clearHistory()
15647 +       Clear the history. */
15648 +PHP_METHOD(HttpRequest, clearHistory)
15649 +{
15650 +       NO_ARGS {
15651 +               zval *hist;
15652 +               
15653 +               MAKE_STD_ZVAL(hist);
15654 +               ZVAL_NULL(hist);
15655 +               zend_update_property(THIS_CE, getThis(), ZEND_STRS("history")-1, hist TSRMLS_CC);
15656 +               zval_ptr_dtor(&hist);
15657 +       }
15658 +}
15659 +/* }}} */
15660 +
15661 +/* {{{ proto string HttpRequest::getMessageClass()
15662 +       Get the message class name. */
15663 +PHP_METHOD(HttpRequest, getMessageClass)
15664 +{
15665 +       NO_ARGS;
15666 +
15667 +       if (return_value_used) {
15668 +               RETURN_PROP("messageClass");
15669 +       }
15670 +}
15671 +/* }}} */
15672 +
15673 +/* {{{ proto void setMessageClass(string class_name)
15674 +       Set the message class name. */
15675 +PHP_METHOD(HttpRequest, setMessageClass)
15676 +{
15677 +       char *cn;
15678 +       int cl;
15679 +
15680 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cn, &cl)) {
15681 +               zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("messageClass")-1, cn, cl TSRMLS_CC);
15682 +       }
15683 +}
15684 +/* }}} */
15685 +
15686 +/* {{{ proto HttpMessage HttpRequest::send()
15687 +       Send the HTTP request. */
15688 +PHP_METHOD(HttpRequest, send)
15689 +{
15690 +       getObject(http_request_object, obj);
15691 +
15692 +       NO_ARGS;
15693 +
15694 +       SET_EH_THROW_HTTP();
15695 +
15696 +       RETVAL_FALSE;
15697 +       
15698 +       if (obj->pool) {
15699 +               http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot perform HttpRequest::send() while attached to an HttpRequestPool");
15700 +       } else if (SUCCESS == http_request_object_requesthandler(obj, getThis())) {
15701 +               http_request_exec(obj->request);
15702 +               if (SUCCESS == http_request_object_responsehandler(obj, getThis())) {
15703 +                       RETVAL_OBJECT(zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC), 1);
15704 +               }
15705 +       }
15706 +
15707 +       SET_EH_NORMAL();
15708 +}
15709 +/* }}} */
15710 +
15711 +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
15712 +
15713 +/*
15714 + * Local variables:
15715 + * tab-width: 4
15716 + * c-basic-offset: 4
15717 + * End:
15718 + * vim600: noet sw=4 ts=4 fdm=marker
15719 + * vim<600: noet sw=4 ts=4
15720 + */
15721 +
15722 --- /dev/null
15723 +++ b/ext/http/http_request_pool_api.c
15724 @@ -0,0 +1,660 @@
15725 +/*
15726 +    +--------------------------------------------------------------------+
15727 +    | PECL :: http                                                       |
15728 +    +--------------------------------------------------------------------+
15729 +    | Redistribution and use in source and binary forms, with or without |
15730 +    | modification, are permitted provided that the conditions mentioned |
15731 +    | in the accompanying LICENSE file are met.                          |
15732 +    +--------------------------------------------------------------------+
15733 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
15734 +    +--------------------------------------------------------------------+
15735 +*/
15736 +
15737 +/* $Id: http_request_pool_api.c 292841 2009-12-31 08:48:57Z mike $ */
15738 +
15739 +#define HTTP_WANT_CURL
15740 +#define HTTP_WANT_EVENT
15741 +#include "php_http.h"
15742 +
15743 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
15744 +
15745 +#include "php_http_api.h"
15746 +#include "php_http_exception_object.h"
15747 +#include "php_http_persistent_handle_api.h"
15748 +#include "php_http_request_api.h"
15749 +#include "php_http_request_object.h"
15750 +#include "php_http_request_pool_api.h"
15751 +#include "php_http_requestpool_object.h"
15752 +
15753 +#ifndef HTTP_DEBUG_REQPOOLS
15754 +#      define HTTP_DEBUG_REQPOOLS 0
15755 +#endif
15756 +
15757 +#ifdef HTTP_HAVE_EVENT
15758 +typedef struct _http_request_pool_event_t {
15759 +       struct event evnt;
15760 +       http_request_pool *pool;
15761 +} http_request_pool_event;
15762 +
15763 +static void http_request_pool_timeout_callback(int socket, short action, void *event_data);
15764 +static void http_request_pool_event_callback(int socket, short action, void *event_data);
15765 +static int http_request_pool_socket_callback(CURL *easy, curl_socket_t s, int action, void *, void *);
15766 +static void http_request_pool_timer_callback(CURLM *multi, long timeout_ms, void *timer_data);
15767 +#endif
15768 +
15769 +static int http_request_pool_compare_handles(void *h1, void *h2);
15770 +
15771 +PHP_MINIT_FUNCTION(http_request_pool)
15772 +{
15773 +       if (SUCCESS != http_persistent_handle_provide("http_request_pool", curl_multi_init, (http_persistent_handle_dtor) curl_multi_cleanup, NULL)) {
15774 +               return FAILURE;
15775 +       }
15776 +       return SUCCESS;
15777 +}
15778 +
15779 +#ifdef HTTP_HAVE_EVENT
15780 +PHP_RINIT_FUNCTION(http_request_pool)
15781 +{
15782 +       if (!HTTP_G->request.pool.event.base && !(HTTP_G->request.pool.event.base = event_init())) {
15783 +               return FAILURE;
15784 +       }
15785 +       
15786 +       return SUCCESS;
15787 +}
15788 +#endif
15789 +
15790 +/* {{{ http_request_pool *http_request_pool_init(http_request_pool *) */
15791 +PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC)
15792 +{
15793 +       zend_bool free_pool;
15794 +       
15795 +#if HTTP_DEBUG_REQPOOLS
15796 +       fprintf(stderr, "Initializing request pool %p\n", pool);
15797 +#endif
15798 +       
15799 +       if ((free_pool = (!pool))) {
15800 +               pool = emalloc(sizeof(http_request_pool));
15801 +               pool->ch = NULL;
15802 +       }
15803 +
15804 +       if (SUCCESS != http_persistent_handle_acquire("http_request_pool", &pool->ch)) {
15805 +               if (free_pool) {
15806 +                       efree(pool);
15807 +               }
15808 +               return NULL;
15809 +       }
15810 +       
15811 +       TSRMLS_SET_CTX(pool->tsrm_ls);
15812 +       
15813 +#ifdef HTTP_HAVE_EVENT
15814 +       pool->timeout = ecalloc(1, sizeof(struct event));
15815 +       curl_multi_setopt(pool->ch, CURLMOPT_SOCKETDATA, pool);
15816 +       curl_multi_setopt(pool->ch, CURLMOPT_SOCKETFUNCTION, http_request_pool_socket_callback);
15817 +       curl_multi_setopt(pool->ch, CURLMOPT_TIMERDATA, pool);
15818 +       curl_multi_setopt(pool->ch, CURLMOPT_TIMERFUNCTION, http_request_pool_timer_callback);
15819 +#endif
15820 +       
15821 +       pool->unfinished = 0;
15822 +       zend_llist_init(&pool->finished, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
15823 +       zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
15824 +       
15825 +#if HTTP_DEBUG_REQPOOLS
15826 +       fprintf(stderr, "Initialized request pool %p\n", pool);
15827 +#endif
15828 +       
15829 +       return pool;
15830 +}
15831 +/* }}} */
15832 +
15833 +/* {{{ STATUS http_request_pool_attach(http_request_pool *, zval *) */
15834 +PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request)
15835 +{
15836 +#ifdef ZTS
15837 +       TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
15838 +#endif
15839 +       getObjectEx(http_request_object, req, request);
15840 +       
15841 +#if HTTP_DEBUG_REQPOOLS
15842 +       fprintf(stderr, "Attaching HttpRequest(#%d) %p to pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
15843 +#endif
15844 +       
15845 +       if (req->pool) {
15846 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is already member of %s HttpRequestPool", Z_OBJ_HANDLE_P(request), req->pool == pool ? "this" : "another");
15847 +       } else if (SUCCESS != http_request_object_requesthandler(req, request)) {
15848 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not initialize HttpRequest object(#%d) for attaching to the HttpRequestPool", Z_OBJ_HANDLE_P(request));
15849 +       } else {
15850 +               CURLMcode code = curl_multi_add_handle(pool->ch, req->request->ch);
15851 +               
15852 +               if (CURLM_OK != code) {
15853 +                       http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "Could not attach HttpRequest object(#%d) to the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code));
15854 +               } else {
15855 +                       req->pool = pool;
15856 +
15857 +                       ZVAL_ADDREF(request);
15858 +                       zend_llist_add_element(&pool->handles, &request);
15859 +                       ++pool->unfinished;
15860 +
15861 +#if HTTP_DEBUG_REQPOOLS
15862 +                       fprintf(stderr, "> %d HttpRequests attached to pool %p\n", zend_llist_count(&pool->handles), pool);
15863 +#endif
15864 +                       return SUCCESS;
15865 +               }
15866 +       }
15867 +       return FAILURE;
15868 +}
15869 +/* }}} */
15870 +
15871 +/* {{{ STATUS http_request_pool_detach(http_request_pool *, zval *) */
15872 +PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request)
15873 +{
15874 +       CURLMcode code;
15875 +#ifdef ZTS
15876 +       TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
15877 +#endif
15878 +       getObjectEx(http_request_object, req, request);
15879 +       
15880 +#if HTTP_DEBUG_REQPOOLS
15881 +       fprintf(stderr, "Detaching HttpRequest(#%d) %p from pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
15882 +#endif
15883 +       
15884 +       if (!req->pool) {
15885 +               /* not attached to any pool */
15886 +#if HTTP_DEBUG_REQPOOLS
15887 +               fprintf(stderr, "HttpRequest object(#%d) %p is not attached to any HttpRequestPool\n", Z_OBJ_HANDLE_P(request), req);
15888 +#endif
15889 +       } else if (req->pool != pool) {
15890 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is not attached to this HttpRequestPool", Z_OBJ_HANDLE_P(request));
15891 +       } else if (req->request->_in_progress_cb) {
15892 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback", Z_OBJ_HANDLE_P(request));
15893 +       } else if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->request->ch))) {
15894 +               http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "Could not detach HttpRequest object(#%d) from the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code));
15895 +       } else {
15896 +               req->pool = NULL;
15897 +               zend_llist_del_element(&pool->finished, request, http_request_pool_compare_handles);
15898 +               zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles);
15899 +               
15900 +#if HTTP_DEBUG_REQPOOLS
15901 +               fprintf(stderr, "> %d HttpRequests remaining in pool %p\n", zend_llist_count(&pool->handles), pool);
15902 +#endif
15903 +               
15904 +               return SUCCESS;
15905 +       }
15906 +       return FAILURE;
15907 +}
15908 +/* }}} */
15909 +
15910 +/* {{{ void http_request_pool_apply(http_request_pool *, http_request_pool_apply_func) */
15911 +PHP_HTTP_API void _http_request_pool_apply(http_request_pool *pool, http_request_pool_apply_func cb)
15912 +{
15913 +       int count = zend_llist_count(&pool->handles);
15914 +       
15915 +       if (count) {
15916 +               int i = 0;
15917 +               zend_llist_position pos;
15918 +               zval **handle, **handles = emalloc(count * sizeof(zval *));
15919 +
15920 +               for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
15921 +                       handles[i++] = *handle;
15922 +               }
15923 +               
15924 +               /* should never happen */
15925 +               if (i != count) {
15926 +                       zend_error(E_ERROR, "number of fetched request handles do not match overall count");
15927 +                       count = i;
15928 +               }
15929 +               
15930 +               for (i = 0; i < count; ++i) {
15931 +                       if (cb(pool, handles[i])) {
15932 +                               break;
15933 +                       }
15934 +               }
15935 +               efree(handles);
15936 +       }
15937 +}
15938 +/* }}} */
15939 +
15940 +/* {{{ void http_request_pool_apply_with_arg(http_request_pool *, http_request_pool_apply_with_arg_func, void *) */
15941 +PHP_HTTP_API void _http_request_pool_apply_with_arg(http_request_pool *pool, http_request_pool_apply_with_arg_func cb, void *arg)
15942 +{
15943 +       int count = zend_llist_count(&pool->handles);
15944 +       
15945 +       if (count) {
15946 +               int i = 0;
15947 +               zend_llist_position pos;
15948 +               zval **handle, **handles = emalloc(count * sizeof(zval *));
15949 +
15950 +               for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
15951 +                       handles[i++] = *handle;
15952 +               }
15953 +               
15954 +               /* should never happen */
15955 +               if (i != count) {
15956 +                       zend_error(E_ERROR, "number of fetched request handles do not match overall count");
15957 +                       count = i;
15958 +               }
15959 +               
15960 +               for (i = 0; i < count; ++i) {
15961 +                       if (cb(pool, handles[i], arg)) {
15962 +                               break;
15963 +                       }
15964 +               }
15965 +               efree(handles);
15966 +       }
15967 +}
15968 +/* }}} */
15969 +
15970 +/* {{{ void http_request_pool_detach_all(http_request_pool *) */
15971 +PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool)
15972 +{
15973 +#if HTTP_DEBUG_REQPOOLS
15974 +       fprintf(stderr, "Detaching %d requests from pool %p\n", zend_llist_count(&pool->handles), pool);
15975 +#endif
15976 +       http_request_pool_apply(pool, _http_request_pool_detach);
15977 +}
15978 +/* }}} */
15979 +
15980 +/* {{{ STATUS http_request_pool_send(http_request_pool *) */
15981 +PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool)
15982 +{
15983 +       TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
15984 +       
15985 +#if HTTP_DEBUG_REQPOOLS
15986 +       fprintf(stderr, "Attempt to send %d requests of pool %p\n", zend_llist_count(&pool->handles), pool);
15987 +#endif
15988 +       
15989 +#ifdef HTTP_HAVE_EVENT
15990 +       if (pool->useevents) {
15991 +               do {
15992 +#if HTTP_DEBUG_REQPOOLS
15993 +                       fprintf(stderr, "& Starting event dispatcher of pool %p\n", pool);
15994 +#endif
15995 +                       event_base_dispatch(HTTP_G->request.pool.event.base);
15996 +               } while (pool->unfinished);
15997 +       } else
15998 +#endif
15999 +       {
16000 +               while (http_request_pool_perform(pool)) {
16001 +                       if (SUCCESS != http_request_pool_select(pool)) {
16002 +#ifdef PHP_WIN32
16003 +                               /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
16004 +                               http_error_ex(HE_WARNING, HTTP_E_SOCKET, "WinSock error: %d", WSAGetLastError());
16005 +#else
16006 +                               http_error(HE_WARNING, HTTP_E_SOCKET, strerror(errno));
16007 +#endif
16008 +                               return FAILURE;
16009 +                       }
16010 +               }
16011 +       }
16012 +       
16013 +#if HTTP_DEBUG_REQPOOLS
16014 +       fprintf(stderr, "Finished sending %d HttpRequests of pool %p (still unfinished: %d)\n", zend_llist_count(&pool->handles), pool, pool->unfinished);
16015 +#endif
16016 +       
16017 +       return SUCCESS;
16018 +}
16019 +/* }}} */
16020 +
16021 +/* {{{ void http_request_pool_dtor(http_request_pool *) */
16022 +PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool)
16023 +{
16024 +       TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16025 +       
16026 +#if HTTP_DEBUG_REQPOOLS
16027 +       fprintf(stderr, "Destructing request pool %p\n", pool);
16028 +#endif
16029 +       
16030 +#ifdef HTTP_HAVE_EVENT
16031 +       efree(pool->timeout);
16032 +#endif
16033 +       
16034 +       http_request_pool_detach_all(pool);
16035 +       
16036 +       pool->unfinished = 0;
16037 +       zend_llist_clean(&pool->finished);
16038 +       zend_llist_clean(&pool->handles);
16039 +       http_persistent_handle_release("http_request_pool", &pool->ch);
16040 +}
16041 +/* }}} */
16042 +
16043 +#ifdef PHP_WIN32
16044 +#      define SELECT_ERROR SOCKET_ERROR
16045 +#else
16046 +#      define SELECT_ERROR -1
16047 +#endif
16048 +
16049 +/* {{{ STATUS http_request_pool_select(http_request_pool *) */
16050 +PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool)
16051 +{
16052 +       return http_request_pool_select_ex(pool, NULL);
16053 +}
16054 +/* }}} */
16055 +
16056 +/* {{{ STATUS http_request_pool_select_ex(http_request_pool *, struct timeval *) */
16057 +PHP_HTTP_API STATUS _http_request_pool_select_ex(http_request_pool *pool, struct timeval *custom_timeout)
16058 +{
16059 +       int MAX;
16060 +       fd_set R, W, E;
16061 +       struct timeval timeout;
16062 +
16063 +#ifdef HTTP_HAVE_EVENT
16064 +       if (pool->useevents) {
16065 +               TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16066 +               http_error(HE_WARNING, HTTP_E_RUNTIME, "not implemented; use HttpRequest callbacks");
16067 +               return FAILURE;
16068 +       }
16069 +#endif
16070 +       
16071 +       if (custom_timeout && timerisset(custom_timeout)) {
16072 +               timeout = *custom_timeout;
16073 +       } else {
16074 +               http_request_pool_timeout(pool, &timeout);
16075 +       }
16076 +       
16077 +       FD_ZERO(&R);
16078 +       FD_ZERO(&W);
16079 +       FD_ZERO(&E);
16080 +
16081 +       if (CURLM_OK == curl_multi_fdset(pool->ch, &R, &W, &E, &MAX)) {
16082 +               if (MAX == -1) {
16083 +                       http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / HTTP_MCROSEC));
16084 +                       return SUCCESS;
16085 +               } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) {
16086 +                       return SUCCESS;
16087 +               }
16088 +       }
16089 +       return FAILURE;
16090 +}
16091 +/* }}} */
16092 +
16093 +/* {{{ int http_request_pool_perform(http_request_pool *) */
16094 +PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool)
16095 +{
16096 +       TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16097 +       
16098 +#ifdef HTTP_HAVE_EVENT
16099 +       if (pool->useevents) {
16100 +               http_error(HE_WARNING, HTTP_E_RUNTIME, "not implemented; use HttpRequest callbacks");
16101 +               return FAILURE;
16102 +       }
16103 +#endif
16104 +       
16105 +       while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished));
16106 +       
16107 +#if HTTP_DEBUG_REQPOOLS
16108 +       fprintf(stderr, "%u unfinished requests of pool %p remaining\n", pool->unfinished, pool);
16109 +#endif
16110 +       
16111 +       http_request_pool_responsehandler(pool);
16112 +       
16113 +       return pool->unfinished;
16114 +}
16115 +/* }}} */
16116 +
16117 +/* {{{ void http_request_pool_responsehandler(http_request_pool *) */
16118 +void _http_request_pool_responsehandler(http_request_pool *pool)
16119 +{
16120 +       CURLMsg *msg;
16121 +       int remaining = 0;
16122 +       TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16123 +       
16124 +       do {
16125 +               msg = curl_multi_info_read(pool->ch, &remaining);
16126 +               if (msg && CURLMSG_DONE == msg->msg) {
16127 +                       if (CURLE_OK != msg->data.result) {
16128 +                               http_request_storage *st = http_request_storage_get(msg->easy_handle);
16129 +                               http_error_ex(HE_WARNING, HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(msg->data.result), st?st->errorbuffer:"", st?st->url:"");
16130 +                       }
16131 +                       http_request_pool_apply_with_arg(pool, _http_request_pool_apply_responsehandler, msg->easy_handle);
16132 +               }
16133 +       } while (remaining);
16134 +}
16135 +/* }}} */
16136 +
16137 +/* {{{ int http_request_pool_apply_responsehandler(http_request_pool *, zval *, void *) */
16138 +int _http_request_pool_apply_responsehandler(http_request_pool *pool, zval *req, void *ch)
16139 +{
16140 +#ifdef ZTS
16141 +       TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16142 +#endif
16143 +       getObjectEx(http_request_object, obj, req);
16144 +       
16145 +       if ((!ch) || obj->request->ch == (CURL *) ch) {
16146 +               
16147 +#if HTTP_DEBUG_REQPOOLS
16148 +               fprintf(stderr, "Fetching data from HttpRequest(#%d) %p of pool %p\n", Z_OBJ_HANDLE_P(req), obj, obj->pool);
16149 +#endif
16150 +               
16151 +               ZVAL_ADDREF(req);
16152 +               zend_llist_add_element(&obj->pool->finished, &req);
16153 +               http_request_object_responsehandler(obj, req);
16154 +               return 1;
16155 +       }
16156 +       return 0;
16157 +}
16158 +/* }}} */
16159 +
16160 +/* {{{ struct timeval *_http_request_pool_timeout(http_request_pool *, struct timeval *) */
16161 +struct timeval *_http_request_pool_timeout(http_request_pool *pool, struct timeval *timeout)
16162 +{
16163 +#ifdef HAVE_CURL_MULTI_TIMEOUT
16164 +       long max_tout = 1000;
16165 +       
16166 +       if ((CURLM_OK == curl_multi_timeout(pool->ch, &max_tout)) && (max_tout > 0)) {
16167 +               timeout->tv_sec = max_tout / 1000;
16168 +               timeout->tv_usec = (max_tout % 1000) * 1000;
16169 +       } else {
16170 +#endif
16171 +               timeout->tv_sec = 0;
16172 +               timeout->tv_usec = 1000;
16173 +#ifdef HAVE_CURL_MULTI_TIMEOUT
16174 +       }
16175 +#endif
16176 +       
16177 +#if HTTP_DEBUG_REQPOOLS
16178 +       fprintf(stderr, "Calculating timeout (%lu, %lu) of pool %p\n", (ulong) timeout->tv_sec, (ulong) timeout->tv_usec, pool);
16179 +#endif
16180 +       
16181 +       return timeout;
16182 +}
16183 +/* }}} */
16184 +
16185 +/*#*/
16186 +
16187 +/* {{{ static int http_request_pool_compare_handles(void *, void *) */
16188 +static int http_request_pool_compare_handles(void *h1, void *h2)
16189 +{
16190 +       return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
16191 +}
16192 +/* }}} */
16193 +
16194 +#ifdef HTTP_HAVE_EVENT
16195 +/* {{{ static void http_request_pool_timeout_callback(int, short, void *) */
16196 +static void http_request_pool_timeout_callback(int socket, short action, void *event_data)
16197 +{
16198 +       http_request_pool *pool = event_data;
16199 +       
16200 +       if (pool->useevents) {
16201 +               CURLMcode rc;
16202 +               TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16203 +               
16204 +#if HTTP_DEBUG_REQPOOLS
16205 +               fprintf(stderr, "Timeout occurred of pool %p\n", pool);
16206 +#endif
16207 +               
16208 +               while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket(pool->ch, CURL_SOCKET_TIMEOUT, &pool->unfinished)));
16209 +               
16210 +               if (CURLM_OK != rc) {
16211 +                       http_error(HE_WARNING, HTTP_E_SOCKET, curl_multi_strerror(rc));
16212 +               }
16213 +
16214 +               http_request_pool_responsehandler(pool);
16215 +       }
16216 +}
16217 +/* }}} */
16218 +
16219 +/* {{{ static void http_request_pool_event_callback(int, short, void *) */
16220 +static void http_request_pool_event_callback(int socket, short action, void *event_data)
16221 +{
16222 +       http_request_pool_event *ev = event_data;
16223 +       http_request_pool *pool = ev->pool;
16224 +       
16225 +       if (pool->useevents) {
16226 +               CURLMcode rc = CURLE_OK;
16227 +               TSRMLS_FETCH_FROM_CTX(ev->pool->tsrm_ls);
16228 +                       
16229 +#if HTTP_DEBUG_REQPOOLS
16230 +               {
16231 +                       static const char event_strings[][20] = {"NONE","TIMEOUT","READ","TIMEOUT|READ","WRITE","TIMEOUT|WRITE","READ|WRITE","TIMEOUT|READ|WRITE","SIGNAL"};
16232 +                       fprintf(stderr, "Event on socket %d (%s) event %p of pool %p\n", socket, event_strings[action], ev, pool);
16233 +               }
16234 +#endif
16235 +               
16236 +               /* don't use 'ev' below this loop as it might 've been freed in the socket callback */
16237 +               do {
16238 +#ifdef HAVE_CURL_MULTI_SOCKET_ACTION
16239 +                       switch (action & (EV_READ|EV_WRITE)) {
16240 +                               case EV_READ:
16241 +                                       rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_IN, &pool->unfinished);
16242 +                                       break;
16243 +                               case EV_WRITE:
16244 +                                       rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_OUT, &pool->unfinished);
16245 +                                       break;
16246 +                               case EV_READ|EV_WRITE:
16247 +                                       rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_IN|CURL_CSELECT_OUT, &pool->unfinished);
16248 +                                       break;
16249 +                               default:
16250 +                                       http_error_ex(HE_WARNING, HTTP_E_SOCKET, "Unknown event %d", (int) action);
16251 +                                       return;
16252 +                       }
16253 +#else
16254 +                       rc = curl_multi_socket(pool->ch, socket, &pool->unfinished);
16255 +#endif
16256 +               } while (CURLM_CALL_MULTI_PERFORM == rc);
16257 +               
16258 +               switch (rc) {
16259 +                       case CURLM_BAD_SOCKET:
16260 +#if 0
16261 +                               fprintf(stderr, "!!! Bad socket: %d (%d)\n", socket, (int) action);
16262 +#endif
16263 +                       case CURLM_OK:
16264 +                               break;
16265 +                       default:
16266 +                               http_error(HE_WARNING, HTTP_E_SOCKET, curl_multi_strerror(rc));
16267 +                               break;
16268 +               }
16269 +               
16270 +               http_request_pool_responsehandler(pool);
16271 +               
16272 +               /* remove timeout if there are no transfers left */
16273 +               if (!pool->unfinished && event_initialized(pool->timeout) && event_pending(pool->timeout, EV_TIMEOUT, NULL)) {
16274 +                       event_del(pool->timeout);
16275 +#if HTTP_DEBUG_REQPOOLS
16276 +                       fprintf(stderr, "Removed timeout of pool %p\n", pool);
16277 +#endif
16278 +               }
16279 +       }
16280 +}
16281 +/* }}} */
16282 +
16283 +/* {{{ static int http_request_pool_socket_callback(CURL *, curl_socket_t, int, void *, void *) */
16284 +static int http_request_pool_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
16285 +{
16286 +       http_request_pool *pool = socket_data;
16287 +       
16288 +       if (pool->useevents) {
16289 +               int events = EV_PERSIST;
16290 +               http_request_pool_event *ev = assign_data;
16291 +               TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16292 +               
16293 +               if (!ev) {
16294 +                       ev = ecalloc(1, sizeof(http_request_pool_event));
16295 +                       ev->pool = pool;
16296 +                       curl_multi_assign(pool->ch, sock, ev);
16297 +                       event_base_set(HTTP_G->request.pool.event.base, &ev->evnt);
16298 +               } else {
16299 +                       event_del(&ev->evnt);
16300 +               }
16301 +               
16302 +#if HTTP_DEBUG_REQPOOLS
16303 +               {
16304 +                       static const char action_strings[][8] = {"NONE", "IN", "OUT", "INOUT", "REMOVE"};
16305 +                       http_request *r;
16306 +                       curl_easy_getinfo(easy, CURLINFO_PRIVATE, &r);
16307 +                       fprintf(stderr, "Callback on socket %2d (%8s) event %p of pool %p (%d)\n", (int) sock, action_strings[action], ev, pool, pool->unfinished);
16308 +               }
16309 +#endif
16310 +               
16311 +               switch (action) {
16312 +                       case CURL_POLL_IN:
16313 +                               events |= EV_READ;
16314 +                               break;
16315 +                       case CURL_POLL_OUT:
16316 +                               events |= EV_WRITE;
16317 +                               break;
16318 +                       case CURL_POLL_INOUT:
16319 +                               events |= EV_READ|EV_WRITE;
16320 +                               break;
16321 +                               
16322 +                       case CURL_POLL_REMOVE:
16323 +                               efree(ev);
16324 +                       case CURL_POLL_NONE:
16325 +                               return 0;
16326 +                               
16327 +                       default:
16328 +                               http_error_ex(HE_WARNING, HTTP_E_SOCKET, "Unknown socket action %d", action);
16329 +                               return -1;
16330 +               }
16331 +               
16332 +               event_set(&ev->evnt, sock, events, http_request_pool_event_callback, ev);
16333 +               event_add(&ev->evnt, NULL);
16334 +       }
16335 +       
16336 +       return 0;
16337 +}
16338 +/* }}} */
16339 +
16340 +/* {{{ static void http_request_pool_timer_callback(CURLM *, long, void*) */
16341 +static void http_request_pool_timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
16342 +{
16343 +       http_request_pool *pool = timer_data;
16344 +       
16345 +       if (pool->useevents) {
16346 +               TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls);
16347 +               struct timeval timeout;
16348 +
16349 +               if (!event_initialized(pool->timeout)) {
16350 +                       event_set(pool->timeout, -1, 0, http_request_pool_timeout_callback, pool);
16351 +                       event_base_set(HTTP_G->request.pool.event.base, pool->timeout);
16352 +               } else if (event_pending(pool->timeout, EV_TIMEOUT, NULL)) {
16353 +                       event_del(pool->timeout);
16354 +               }
16355 +               
16356 +               if (timeout_ms > 0) {
16357 +                       timeout.tv_sec = timeout_ms / 1000;
16358 +                       timeout.tv_usec = (timeout_ms % 1000) * 1000;
16359 +               } else {
16360 +                       http_request_pool_timeout(pool, &timeout);
16361 +               }
16362 +
16363 +               event_add(pool->timeout, &timeout);
16364 +
16365 +#if HTTP_DEBUG_REQPOOLS
16366 +               fprintf(stderr, "Updating timeout %lu (%lu, %lu) of pool %p\n", (ulong) timeout_ms, (ulong) timeout.tv_sec, (ulong) timeout.tv_usec, pool);
16367 +#endif
16368 +       }
16369 +}
16370 +/* }}} */
16371 +#endif /* HTTP_HAVE_EVENT */
16372 +
16373 +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
16374 +
16375 +
16376 +/*
16377 + * Local variables:
16378 + * tab-width: 4
16379 + * c-basic-offset: 4
16380 + * End:
16381 + * vim600: noet sw=4 ts=4 fdm=marker
16382 + * vim<600: noet sw=4 ts=4
16383 + */
16384 +
16385 --- /dev/null
16386 +++ b/ext/http/http_requestdatashare_object.c
16387 @@ -0,0 +1,315 @@
16388 +/*
16389 +    +--------------------------------------------------------------------+
16390 +    | PECL :: http                                                       |
16391 +    +--------------------------------------------------------------------+
16392 +    | Redistribution and use in source and binary forms, with or without |
16393 +    | modification, are permitted provided that the conditions mentioned |
16394 +    | in the accompanying LICENSE file are met.                          |
16395 +    +--------------------------------------------------------------------+
16396 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
16397 +    +--------------------------------------------------------------------+
16398 +*/
16399 +
16400 +/* $Id: http_requestdatashare_object.c 300299 2010-06-09 06:23:16Z mike $ */
16401 +
16402 +#define HTTP_WANT_CURL
16403 +#include "php_http.h"
16404 +
16405 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
16406 +
16407 +#include "zend_interfaces.h"
16408 +
16409 +#include "php_http_api.h"
16410 +#include "php_http_exception_object.h"
16411 +#include "php_http_request_api.h"
16412 +#include "php_http_request_object.h"
16413 +#include "php_http_request_datashare_api.h"
16414 +#include "php_http_requestdatashare_object.h"
16415 +
16416 +#define HTTP_BEGIN_ARGS(method, req_args)      HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args)
16417 +#define HTTP_EMPTY_ARGS(method)                                HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0)
16418 +#define HTTP_RSHARE_ME(method, visibility)     PHP_ME(HttpRequestDataShare, method, HTTP_ARGS(HttpRequestDataShare, method), visibility)
16419 +
16420 +#if defined(HAVE_SPL) && !defined(WONKY)
16421 +/* SPL doesn't install its headers */
16422 +extern PHPAPI zend_class_entry *spl_ce_Countable;
16423 +#endif
16424 +
16425 +HTTP_EMPTY_ARGS(__destruct);
16426 +HTTP_EMPTY_ARGS(count);
16427 +
16428 +HTTP_BEGIN_ARGS(attach, 1)
16429 +       HTTP_ARG_OBJ(HttpRequest, request, 0)
16430 +HTTP_END_ARGS;
16431 +HTTP_BEGIN_ARGS(detach, 1)
16432 +       HTTP_ARG_OBJ(HttpRequest, request, 0)
16433 +HTTP_END_ARGS;
16434 +
16435 +HTTP_EMPTY_ARGS(reset);
16436 +
16437 +HTTP_BEGIN_ARGS(factory, 0)
16438 +       HTTP_ARG_VAL(global, 0)
16439 +       HTTP_ARG_VAL(class_name, 0)
16440 +HTTP_END_ARGS;
16441 +
16442 +#ifndef WONKY
16443 +HTTP_BEGIN_ARGS(singleton, 0)
16444 +       HTTP_ARG_VAL(global, 0)
16445 +HTTP_END_ARGS;
16446 +#endif
16447 +
16448 +
16449 +#define http_requestdatashare_object_read_prop _http_requestdatashare_object_read_prop
16450 +static zval *_http_requestdatashare_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC);
16451 +#define http_requestdatashare_object_write_prop _http_requestdatashare_object_write_prop
16452 +static void _http_requestdatashare_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC);
16453 +#define http_requestdatashare_instantiate(t, g) _http_requestdatashare_instantiate((t), (g) TSRMLS_CC)
16454 +static inline zval *_http_requestdatashare_instantiate(zval *this_ptr, zend_bool global TSRMLS_DC);
16455 +
16456 +#define THIS_CE http_requestdatashare_object_ce
16457 +zend_class_entry *http_requestdatashare_object_ce;
16458 +zend_function_entry http_requestdatashare_object_fe[] = {
16459 +       HTTP_RSHARE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
16460 +       HTTP_RSHARE_ME(count, ZEND_ACC_PUBLIC)
16461 +       HTTP_RSHARE_ME(attach, ZEND_ACC_PUBLIC)
16462 +       HTTP_RSHARE_ME(detach, ZEND_ACC_PUBLIC)
16463 +       HTTP_RSHARE_ME(reset, ZEND_ACC_PUBLIC)
16464 +       HTTP_RSHARE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
16465 +#ifndef WONKY
16466 +       HTTP_RSHARE_ME(singleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
16467 +#endif
16468 +       EMPTY_FUNCTION_ENTRY
16469 +};
16470 +static zend_object_handlers http_requestdatashare_object_handlers;
16471 +
16472 +PHP_MINIT_FUNCTION(http_requestdatashare_object)
16473 +{
16474 +       HTTP_REGISTER_CLASS_EX(HttpRequestDataShare, http_requestdatashare_object, NULL, 0);
16475 +       http_requestdatashare_object_handlers.clone_obj = NULL;
16476 +       http_requestdatashare_object_handlers.read_property = http_requestdatashare_object_read_prop;
16477 +       http_requestdatashare_object_handlers.write_property = http_requestdatashare_object_write_prop;
16478 +
16479 +#if defined(HAVE_SPL) && !defined(WONKY)
16480 +       zend_class_implements(http_requestdatashare_object_ce TSRMLS_CC, 1, spl_ce_Countable);
16481 +#endif
16482 +       
16483 +       zend_declare_property_null(THIS_CE, ZEND_STRS("instance")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
16484 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("cookie")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);
16485 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("dns")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);
16486 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("ssl")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);
16487 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("connect")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);
16488 +       
16489 +       return SUCCESS;
16490 +}
16491 +
16492 +zend_object_value _http_requestdatashare_object_new(zend_class_entry *ce TSRMLS_DC)
16493 +{
16494 +       return http_requestdatashare_object_new_ex(ce, NULL, NULL);
16495 +}
16496 +
16497 +zend_object_value _http_requestdatashare_object_new_ex(zend_class_entry *ce, http_request_datashare *share, http_requestdatashare_object **ptr TSRMLS_DC)
16498 +{
16499 +       zend_object_value ov;
16500 +       http_requestdatashare_object *o;
16501 +
16502 +       o = ecalloc(1, sizeof(http_requestdatashare_object));
16503 +       o->zo.ce = ce;
16504 +
16505 +       if (share) {
16506 +               o->share = share;
16507 +       } else {
16508 +               o->share = http_request_datashare_new();
16509 +       }
16510 +       
16511 +       if (ptr) {
16512 +               *ptr = o;
16513 +       }
16514 +
16515 +       ALLOC_HASHTABLE(OBJ_PROP(o));
16516 +       zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
16517 +       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
16518 +
16519 +       ov.handle = putObject(http_requestdatashare_object, o);
16520 +       ov.handlers = &http_requestdatashare_object_handlers;
16521 +
16522 +       return ov;
16523 +}
16524 +
16525 +void _http_requestdatashare_object_free(zend_object *object TSRMLS_DC)
16526 +{
16527 +       http_requestdatashare_object *o = (http_requestdatashare_object *) object;
16528 +
16529 +       if (!o->share->persistent) {
16530 +               http_request_datashare_free(&o->share);
16531 +       }
16532 +       freeObject(o);
16533 +}
16534 +
16535 +static zval *_http_requestdatashare_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC)
16536 +{
16537 +       if (type == BP_VAR_W && zend_hash_exists(&THIS_CE->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1)) {
16538 +               zend_error(E_ERROR, "Cannot access HttpRequestDataShare default properties by reference or array key/index");
16539 +               return NULL;
16540 +       }
16541 +       
16542 +       return zend_get_std_object_handlers()->read_property(object, member, type ZEND_LITERAL_KEY_CC TSRMLS_CC);
16543 +}
16544 +
16545 +static void _http_requestdatashare_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC)
16546 +{
16547 +       if (zend_hash_exists(&THIS_CE->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1)) {
16548 +               int status;
16549 +               getObjectEx(http_requestdatashare_object, obj, object);
16550 +               
16551 +               status = http_request_datashare_set(obj->share, Z_STRVAL_P(member), Z_STRLEN_P(member), (zend_bool) i_zend_is_true(value));
16552 +               if (SUCCESS != status) {
16553 +                       return;
16554 +               }
16555 +       }
16556 +       
16557 +       zend_get_std_object_handlers()->write_property(object, member, value ZEND_LITERAL_KEY_CC TSRMLS_CC);
16558 +}
16559 +
16560 +/* {{{ proto void HttpRequestDataShare::__destruct()
16561 +       Clean up HttpRequestDataShare object. */
16562 +PHP_METHOD(HttpRequestDataShare, __destruct)
16563 +{
16564 +       NO_ARGS {
16565 +               getObject(http_requestdatashare_object, obj);
16566 +               http_request_datashare_detach_all(obj->share);
16567 +       }
16568 +}
16569 +/* }}} */
16570 +
16571 +/* {{{ proto int HttpRequestDataShare::count()
16572 +       Implements Countable::count(). */
16573 +PHP_METHOD(HttpRequestDataShare, count)
16574 +{
16575 +       getObject(http_requestdatashare_object, obj);
16576 +       
16577 +       NO_ARGS;
16578 +       
16579 +       RETURN_LONG(zend_llist_count(HTTP_RSHARE_HANDLES(obj->share)));
16580 +}
16581 +/* }}} */
16582 +
16583 +PHP_METHOD(HttpRequestDataShare, attach)
16584 +{
16585 +       zval *request;
16586 +       getObject(http_requestdatashare_object, obj);
16587 +       
16588 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
16589 +               RETURN_FALSE;
16590 +       }
16591 +       
16592 +       RETURN_SUCCESS(http_request_datashare_attach(obj->share, request));
16593 +}
16594 +
16595 +PHP_METHOD(HttpRequestDataShare, detach)
16596 +{
16597 +       zval *request;
16598 +       getObject(http_requestdatashare_object, obj);
16599 +       
16600 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
16601 +               RETURN_FALSE;
16602 +       }
16603 +       
16604 +       RETURN_SUCCESS(http_request_datashare_detach(obj->share, request));
16605 +}
16606 +
16607 +PHP_METHOD(HttpRequestDataShare, reset)
16608 +{
16609 +       NO_ARGS {
16610 +               getObject(http_requestdatashare_object, obj);
16611 +               http_request_datashare_detach_all(obj->share);
16612 +       }
16613 +}
16614 +
16615 +PHP_METHOD(HttpRequestDataShare, factory)
16616 +{
16617 +       zend_bool global = 0;
16618 +       char *cn = NULL;
16619 +       int cl = 0;
16620 +       zend_object_value ov;
16621 +       
16622 +       SET_EH_THROW_HTTP();
16623 +       if (    SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bs", &global, &cn, &cl) &&
16624 +                       SUCCESS == http_object_new(&ov, cn, cl, _http_requestdatashare_object_new_ex, http_requestdatashare_object_ce, NULL, NULL)) {
16625 +               RETVAL_OBJVAL(ov, 0);
16626 +               http_requestdatashare_instantiate(return_value, global);
16627 +       }
16628 +       SET_EH_NORMAL();
16629 +}
16630 +
16631 +#ifndef WONKY
16632 +/* {{{ proto static HttpRequestDataShare HttpRequestDataShare::singleton([bool global = false])
16633 +       Get a single instance (differentiates between the global setting). */
16634 +PHP_METHOD(HttpRequestDataShare, singleton)
16635 +{
16636 +       zend_bool global = 0;
16637 +       zval *instance = *zend_std_get_static_property(THIS_CE, ZEND_STRS("instance")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC);
16638 +       
16639 +       SET_EH_THROW_HTTP();
16640 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &global)) {
16641 +               zval **zobj_ptr = NULL, *zobj = NULL;
16642 +               
16643 +               if (Z_TYPE_P(instance) == IS_ARRAY) {
16644 +                       if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(instance), global, (void *) &zobj_ptr)) {
16645 +                               RETVAL_ZVAL(*zobj_ptr, 1, 0);
16646 +                       } else {
16647 +                               zobj = http_requestdatashare_instantiate(NULL, global);
16648 +                               add_index_zval(instance, global, zobj);
16649 +                               RETVAL_OBJECT(zobj, 1);
16650 +                       }
16651 +               } else {
16652 +                       MAKE_STD_ZVAL(instance);
16653 +                       array_init(instance);
16654 +                       
16655 +                       zobj = http_requestdatashare_instantiate(NULL, global);
16656 +                       add_index_zval(instance, global, zobj);
16657 +                       RETVAL_OBJECT(zobj, 1);
16658 +                       
16659 +                       zend_update_static_property(THIS_CE, ZEND_STRS("instance")-1, instance TSRMLS_CC);
16660 +                       zval_ptr_dtor(&instance);
16661 +               }
16662 +       }
16663 +       SET_EH_NORMAL();
16664 +}
16665 +/* }}} */
16666 +#endif /* !WONKY */
16667 +
16668 +static inline zval *_http_requestdatashare_instantiate(zval *this_ptr, zend_bool global TSRMLS_DC)
16669 +{
16670 +       if (!this_ptr) {
16671 +               MAKE_STD_ZVAL(this_ptr);
16672 +               Z_TYPE_P(this_ptr) = IS_OBJECT;
16673 +               this_ptr->value.obj = http_requestdatashare_object_new_ex(http_requestdatashare_object_ce, global ? http_request_datashare_global_get() : NULL, NULL);
16674 +       }
16675 +       if (global) {
16676 +               if (HTTP_G->request.datashare.cookie) {
16677 +                       zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("cookie")-1, HTTP_G->request.datashare.cookie TSRMLS_CC);
16678 +               }
16679 +               if (HTTP_G->request.datashare.dns) {
16680 +                       zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("dns")-1, HTTP_G->request.datashare.dns TSRMLS_CC);
16681 +               }
16682 +               if (HTTP_G->request.datashare.ssl) {
16683 +                       zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("ssl")-1, HTTP_G->request.datashare.ssl TSRMLS_CC);
16684 +               }
16685 +               if (HTTP_G->request.datashare.connect) {
16686 +                       zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("connect")-1, HTTP_G->request.datashare.connect TSRMLS_CC);
16687 +               }
16688 +       }
16689 +       return this_ptr;
16690 +}
16691 +
16692 +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
16693 +
16694 +/*
16695 + * Local variables:
16696 + * tab-width: 4
16697 + * c-basic-offset: 4
16698 + * End:
16699 + * vim600: noet sw=4 ts=4 fdm=marker
16700 + * vim<600: noet sw=4 ts=4
16701 + */
16702 +
16703 --- /dev/null
16704 +++ b/ext/http/http_requestpool_object.c
16705 @@ -0,0 +1,466 @@
16706 +/*
16707 +    +--------------------------------------------------------------------+
16708 +    | PECL :: http                                                       |
16709 +    +--------------------------------------------------------------------+
16710 +    | Redistribution and use in source and binary forms, with or without |
16711 +    | modification, are permitted provided that the conditions mentioned |
16712 +    | in the accompanying LICENSE file are met.                          |
16713 +    +--------------------------------------------------------------------+
16714 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
16715 +    +--------------------------------------------------------------------+
16716 +*/
16717 +
16718 +/* $Id: http_requestpool_object.c 300299 2010-06-09 06:23:16Z mike $ */
16719 +
16720 +#define HTTP_WANT_CURL
16721 +#include "php_http.h"
16722 +
16723 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
16724 +
16725 +#include "zend_interfaces.h"
16726 +
16727 +#include "php_http_api.h"
16728 +#include "php_http_exception_object.h"
16729 +#include "php_http_request_api.h"
16730 +#include "php_http_request_object.h"
16731 +#include "php_http_request_pool_api.h"
16732 +#include "php_http_requestpool_object.h"
16733 +
16734 +#if defined(HAVE_SPL) && !defined(WONKY)
16735 +/* SPL doesn't install its headers */
16736 +extern PHPAPI zend_class_entry *spl_ce_Countable;
16737 +#endif
16738 +
16739 +#define HTTP_BEGIN_ARGS(method, req_args)      HTTP_BEGIN_ARGS_EX(HttpRequestPool, method, 0, req_args)
16740 +#define HTTP_EMPTY_ARGS(method)                                HTTP_EMPTY_ARGS_EX(HttpRequestPool, method, 0)
16741 +#define HTTP_REQPOOL_ME(method, visibility)    PHP_ME(HttpRequestPool, method, HTTP_ARGS(HttpRequestPool, method), visibility)
16742 +
16743 +HTTP_EMPTY_ARGS(__construct);
16744 +
16745 +HTTP_EMPTY_ARGS(__destruct);
16746 +HTTP_EMPTY_ARGS(reset);
16747 +
16748 +HTTP_BEGIN_ARGS(attach, 1)
16749 +       HTTP_ARG_OBJ(HttpRequest, request, 0)
16750 +HTTP_END_ARGS;
16751 +
16752 +HTTP_BEGIN_ARGS(detach, 1)
16753 +       HTTP_ARG_OBJ(HttpRequest, request, 0)
16754 +HTTP_END_ARGS;
16755 +
16756 +HTTP_EMPTY_ARGS(send);
16757 +HTTP_EMPTY_ARGS(socketPerform);
16758 +HTTP_BEGIN_ARGS(socketSelect, 0)
16759 +       HTTP_ARG_VAL(timeout, 0)
16760 +HTTP_END_ARGS;
16761 +
16762 +HTTP_EMPTY_ARGS(valid);
16763 +HTTP_EMPTY_ARGS(current);
16764 +HTTP_EMPTY_ARGS(key);
16765 +HTTP_EMPTY_ARGS(next);
16766 +HTTP_EMPTY_ARGS(rewind);
16767 +
16768 +HTTP_EMPTY_ARGS(count);
16769 +
16770 +HTTP_EMPTY_ARGS(getAttachedRequests);
16771 +HTTP_EMPTY_ARGS(getFinishedRequests);
16772 +
16773 +HTTP_BEGIN_ARGS(enablePipelining, 0)
16774 +       HTTP_ARG_VAL(enable, 0)
16775 +HTTP_END_ARGS;
16776 +
16777 +HTTP_BEGIN_ARGS(enableEvents, 0)
16778 +       HTTP_ARG_VAL(enable, 0)
16779 +HTTP_END_ARGS;
16780 +
16781 +zend_class_entry *http_requestpool_object_ce;
16782 +zend_function_entry http_requestpool_object_fe[] = {
16783 +       HTTP_REQPOOL_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
16784 +       HTTP_REQPOOL_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
16785 +       HTTP_REQPOOL_ME(attach, ZEND_ACC_PUBLIC)
16786 +       HTTP_REQPOOL_ME(detach, ZEND_ACC_PUBLIC)
16787 +       HTTP_REQPOOL_ME(send, ZEND_ACC_PUBLIC)
16788 +       HTTP_REQPOOL_ME(reset, ZEND_ACC_PUBLIC)
16789 +
16790 +       HTTP_REQPOOL_ME(socketPerform, ZEND_ACC_PROTECTED)
16791 +       HTTP_REQPOOL_ME(socketSelect, ZEND_ACC_PROTECTED)
16792 +
16793 +       /* implements Iterator */
16794 +       HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC)
16795 +       HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC)
16796 +       HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC)
16797 +       HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC)
16798 +       HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC)
16799 +       
16800 +       /* implmenents Countable */
16801 +       HTTP_REQPOOL_ME(count, ZEND_ACC_PUBLIC)
16802 +       
16803 +       HTTP_REQPOOL_ME(getAttachedRequests, ZEND_ACC_PUBLIC)
16804 +       HTTP_REQPOOL_ME(getFinishedRequests, ZEND_ACC_PUBLIC)
16805 +       
16806 +       HTTP_REQPOOL_ME(enablePipelining, ZEND_ACC_PUBLIC)
16807 +       HTTP_REQPOOL_ME(enableEvents, ZEND_ACC_PUBLIC)
16808 +
16809 +       EMPTY_FUNCTION_ENTRY
16810 +};
16811 +static zend_object_handlers http_requestpool_object_handlers;
16812 +
16813 +PHP_MINIT_FUNCTION(http_requestpool_object)
16814 +{
16815 +       HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0);
16816 +       http_requestpool_object_handlers.clone_obj = NULL;
16817 +       
16818 +#if defined(HAVE_SPL) && !defined(WONKY)
16819 +       zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 2, spl_ce_Countable, zend_ce_iterator);
16820 +#else
16821 +       zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 1, zend_ce_iterator);
16822 +#endif
16823 +       
16824 +       return SUCCESS;
16825 +}
16826 +
16827 +zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC)
16828 +{
16829 +       zend_object_value ov;
16830 +       http_requestpool_object *o;
16831 +
16832 +       o = ecalloc(1, sizeof(http_requestpool_object));
16833 +       o->zo.ce = ce;
16834 +
16835 +       http_request_pool_init(&o->pool);
16836 +
16837 +       ALLOC_HASHTABLE(OBJ_PROP(o));
16838 +       zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
16839 +       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
16840 +
16841 +       ov.handle = putObject(http_requestpool_object, o);
16842 +       ov.handlers = &http_requestpool_object_handlers;
16843 +
16844 +       return ov;
16845 +}
16846 +
16847 +void _http_requestpool_object_free(zend_object *object TSRMLS_DC)
16848 +{
16849 +       http_requestpool_object *o = (http_requestpool_object *) object;
16850 +
16851 +       http_request_pool_dtor(&o->pool);
16852 +       freeObject(o);
16853 +}
16854 +
16855 +#define http_requestpool_object_llist2array _http_requestpool_object_llist2array
16856 +static void _http_requestpool_object_llist2array(zval **req, zval *array TSRMLS_DC)
16857 +{
16858 +       ZVAL_ADDREF(*req);
16859 +       add_next_index_zval(array, *req);
16860 +}
16861 +
16862 +/* ### USERLAND ### */
16863 +
16864 +/* {{{ proto void HttpRequestPool::__construct([HttpRequest request[, ...]])
16865 +       Creates a new HttpRequestPool object instance. */
16866 +PHP_METHOD(HttpRequestPool, __construct)
16867 +{
16868 +       int argc = ZEND_NUM_ARGS();
16869 +       zval ***argv = safe_emalloc(argc, sizeof(zval *), 0);
16870 +       getObject(http_requestpool_object, obj);
16871 +
16872 +       SET_EH_THROW_HTTP();
16873 +       if (SUCCESS == zend_get_parameters_array_ex(argc, argv)) {
16874 +               int i;
16875 +
16876 +               for (i = 0; i < argc; ++i) {
16877 +                       if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), http_request_object_ce TSRMLS_CC)) {
16878 +                               http_request_pool_attach(&obj->pool, *(argv[i]));
16879 +                       }
16880 +               }
16881 +       }
16882 +       efree(argv);
16883 +       http_final(HTTP_EX_CE(request_pool));
16884 +       SET_EH_NORMAL();
16885 +}
16886 +/* }}} */
16887 +
16888 +/* {{{ proto void HttpRequestPool::__destruct()
16889 +       Clean up HttpRequestPool object. */
16890 +PHP_METHOD(HttpRequestPool, __destruct)
16891 +{
16892 +       getObject(http_requestpool_object, obj);
16893 +
16894 +       NO_ARGS;
16895 +
16896 +       http_request_pool_detach_all(&obj->pool);
16897 +}
16898 +/* }}} */
16899 +
16900 +/* {{{ proto void HttpRequestPool::reset()
16901 +       Detach all attached HttpRequest objects. */
16902 +PHP_METHOD(HttpRequestPool, reset)
16903 +{
16904 +       getObject(http_requestpool_object, obj);
16905 +
16906 +       NO_ARGS;
16907 +       
16908 +       obj->iterator.pos = 0;
16909 +       http_request_pool_detach_all(&obj->pool);
16910 +}
16911 +
16912 +/* {{{ proto bool HttpRequestPool::attach(HttpRequest request)
16913 +       Attach an HttpRequest object to this HttpRequestPool. WARNING: set all options prior attaching! */
16914 +PHP_METHOD(HttpRequestPool, attach)
16915 +{
16916 +       zval *request;
16917 +       STATUS status = FAILURE;
16918 +       getObject(http_requestpool_object, obj);
16919 +
16920 +       SET_EH_THROW_HTTP();
16921 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
16922 +               if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
16923 +                       http_error(HE_THROW, HTTP_E_REQUEST_POOL, "Cannot attach to the HttpRequestPool while the iterator is active");
16924 +               } else {
16925 +                       status = http_request_pool_attach(&obj->pool, request);
16926 +               }
16927 +       }
16928 +       SET_EH_NORMAL();
16929 +       RETURN_SUCCESS(status);
16930 +}
16931 +/* }}} */
16932 +
16933 +/* {{{ proto bool HttpRequestPool::detach(HttpRequest request)
16934 +       Detach an HttpRequest object from this HttpRequestPool. */
16935 +PHP_METHOD(HttpRequestPool, detach)
16936 +{
16937 +       zval *request;
16938 +       STATUS status = FAILURE;
16939 +       getObject(http_requestpool_object, obj);
16940 +
16941 +       SET_EH_THROW_HTTP();
16942 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
16943 +               obj->iterator.pos = -1;
16944 +               status = http_request_pool_detach(&obj->pool, request);
16945 +       }
16946 +       SET_EH_NORMAL();
16947 +       RETURN_SUCCESS(status);
16948 +}
16949 +/* }}} */
16950 +
16951 +/* {{{ proto bool HttpRequestPool::send()
16952 +       Send all attached HttpRequest objects in parallel. */
16953 +PHP_METHOD(HttpRequestPool, send)
16954 +{
16955 +       STATUS status;
16956 +       getObject(http_requestpool_object, obj);
16957 +
16958 +       NO_ARGS;
16959 +
16960 +       SET_EH_THROW_HTTP();
16961 +       status = http_request_pool_send(&obj->pool);
16962 +       SET_EH_NORMAL();
16963 +       
16964 +       /* rethrow as HttpRequestPoolException */
16965 +       http_final(HTTP_EX_CE(request_pool));
16966 +
16967 +       RETURN_SUCCESS(status);
16968 +}
16969 +/* }}} */
16970 +
16971 +/* {{{ proto protected bool HttpRequestPool::socketPerform()
16972 +       Returns TRUE until each request has finished its transaction. */
16973 +PHP_METHOD(HttpRequestPool, socketPerform)
16974 +{
16975 +       getObject(http_requestpool_object, obj);
16976 +
16977 +       NO_ARGS;
16978 +
16979 +       if (0 < http_request_pool_perform(&obj->pool)) {
16980 +               RETURN_TRUE;
16981 +       } else {
16982 +               RETURN_FALSE;
16983 +       }
16984 +}
16985 +/* }}} */
16986 +
16987 +/* {{{ proto protected bool HttpRequestPool::socketSelect([double timeout]) */
16988 +PHP_METHOD(HttpRequestPool, socketSelect)
16989 +{
16990 +       double timeout = 0;
16991 +       struct timeval custom_timeout, *custom_timeout_ptr = NULL;
16992 +       getObject(http_requestpool_object, obj);
16993 +
16994 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) {
16995 +               RETURN_FALSE;
16996 +       }
16997 +       if (ZEND_NUM_ARGS() && timeout > 0) {
16998 +               custom_timeout.tv_sec = (time_t) timeout;
16999 +               custom_timeout.tv_usec = HTTP_USEC(timeout) % HTTP_MCROSEC;
17000 +               custom_timeout_ptr = &custom_timeout;
17001 +       }
17002 +
17003 +       RETURN_SUCCESS(http_request_pool_select_ex(&obj->pool, custom_timeout_ptr));
17004 +}
17005 +/* }}} */
17006 +
17007 +/* {{{ proto bool HttpRequestPool::valid()
17008 +       Implements Iterator::valid(). */
17009 +PHP_METHOD(HttpRequestPool, valid)
17010 +{
17011 +       NO_ARGS;
17012 +
17013 +       if (return_value_used) {
17014 +               getObject(http_requestpool_object, obj);
17015 +               RETURN_BOOL(obj->iterator.pos >= 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles));
17016 +       }
17017 +}
17018 +/* }}} */
17019 +
17020 +/* {{{ proto HttpRequest HttpRequestPool::current()
17021 +       Implements Iterator::current(). */
17022 +PHP_METHOD(HttpRequestPool, current)
17023 +{
17024 +       NO_ARGS;
17025 +
17026 +       if (return_value_used) {
17027 +               long pos = 0;
17028 +               zval **current = NULL;
17029 +               zend_llist_position lpos;
17030 +               getObject(http_requestpool_object, obj);
17031 +
17032 +               if (obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
17033 +                       for (   current = zend_llist_get_first_ex(&obj->pool.handles, &lpos);
17034 +                                       current && obj->iterator.pos != pos++;
17035 +                                       current = zend_llist_get_next_ex(&obj->pool.handles, &lpos));
17036 +                       if (current) {
17037 +                               RETURN_OBJECT(*current, 1);
17038 +                       }
17039 +               }
17040 +               RETURN_NULL();
17041 +       }
17042 +}
17043 +/* }}} */
17044 +
17045 +/* {{{ proto int HttpRequestPool::key()
17046 +       Implements Iterator::key(). */
17047 +PHP_METHOD(HttpRequestPool, key)
17048 +{
17049 +       NO_ARGS;
17050 +
17051 +       if (return_value_used) {
17052 +               getObject(http_requestpool_object, obj);
17053 +               RETURN_LONG(obj->iterator.pos);
17054 +       }
17055 +}
17056 +/* }}} */
17057 +
17058 +/* {{{ proto void HttpRequestPool::next()
17059 +       Implements Iterator::next(). */
17060 +PHP_METHOD(HttpRequestPool, next)
17061 +{
17062 +       NO_ARGS {
17063 +               getObject(http_requestpool_object, obj);
17064 +               ++(obj->iterator.pos);
17065 +       }
17066 +}
17067 +/* }}} */
17068 +
17069 +/* {{{ proto void HttpRequestPool::rewind()
17070 +       Implements Iterator::rewind(). */
17071 +PHP_METHOD(HttpRequestPool, rewind)
17072 +{
17073 +       NO_ARGS {
17074 +               getObject(http_requestpool_object, obj);
17075 +               obj->iterator.pos = 0;
17076 +       }
17077 +}
17078 +/* }}} */
17079 +
17080 +/* {{{ proto int HttpRequestPool::count()
17081 +       Implements Countable::count(). */
17082 +PHP_METHOD(HttpRequestPool, count)
17083 +{
17084 +       NO_ARGS {
17085 +               getObject(http_requestpool_object, obj);
17086 +               RETURN_LONG((long) zend_llist_count(&obj->pool.handles));
17087 +       }
17088 +}
17089 +/* }}} */
17090 +
17091 +/* {{{ proto array HttpRequestPool::getAttachedRequests()
17092 +       Get attached HttpRequest objects. */
17093 +PHP_METHOD(HttpRequestPool, getAttachedRequests)
17094 +{
17095 +       getObject(http_requestpool_object, obj);
17096 +       
17097 +       NO_ARGS;
17098 +       
17099 +       array_init(return_value);
17100 +       zend_llist_apply_with_argument(&obj->pool.handles, 
17101 +               (llist_apply_with_arg_func_t) http_requestpool_object_llist2array, 
17102 +               return_value TSRMLS_CC);
17103 +}
17104 +/* }}} */
17105 +
17106 +/* {{{ proto array HttpRequestPool::getFinishedRequests()
17107 +       Get attached HttpRequest objects that already have finished their work. */
17108 +PHP_METHOD(HttpRequestPool, getFinishedRequests)
17109 +{
17110 +       getObject(http_requestpool_object, obj);
17111 +       
17112 +       NO_ARGS;
17113 +               
17114 +       array_init(return_value);
17115 +       zend_llist_apply_with_argument(&obj->pool.finished,
17116 +               (llist_apply_with_arg_func_t) http_requestpool_object_llist2array,
17117 +               return_value TSRMLS_CC);
17118 +}
17119 +/* }}} */
17120 +
17121 +/* {{{ proto bool HttpRequestPool::enablePipelining([bool enable = true])
17122 +       Enables pipelining support for all attached requests if support in libcurl is given. */
17123 +PHP_METHOD(HttpRequestPool, enablePipelining)
17124 +{
17125 +       zend_bool enable = 1;
17126 +#if defined(HAVE_CURL_MULTI_SETOPT) && HTTP_CURL_VERSION(7,16,0)
17127 +       getObject(http_requestpool_object, obj);
17128 +#endif
17129 +       
17130 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
17131 +               RETURN_FALSE;
17132 +       }
17133 +#if defined(HAVE_CURL_MULTI_SETOPT) && HTTP_CURL_VERSION(7,16,0)
17134 +       if (CURLM_OK == curl_multi_setopt(obj->pool.ch, CURLMOPT_PIPELINING, (long) enable)) {
17135 +               RETURN_TRUE;
17136 +       }
17137 +#endif
17138 +       RETURN_FALSE;
17139 +}
17140 +/* }}} */
17141 +
17142 +/* {{{ proto bool HttpRequestPool::enableEvents([bool enable = true])
17143 +       Enables event-driven I/O if support in libcurl is given. */
17144 +PHP_METHOD(HttpRequestPool, enableEvents)
17145 +{
17146 +       zend_bool enable = 1;
17147 +#if defined(HTTP_HAVE_EVENT)
17148 +       getObject(http_requestpool_object, obj);
17149 +#endif
17150 +       
17151 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
17152 +#if defined(HTTP_HAVE_EVENT)
17153 +               obj->pool.useevents = enable;
17154 +               RETURN_TRUE;
17155 +#endif
17156 +       }
17157 +       RETURN_FALSE;
17158 +}
17159 +/* }}} */
17160 +
17161 +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
17162 +
17163 +/*
17164 + * Local variables:
17165 + * tab-width: 4
17166 + * c-basic-offset: 4
17167 + * End:
17168 + * vim600: noet sw=4 ts=4 fdm=marker
17169 + * vim<600: noet sw=4 ts=4
17170 + */
17171 +
17172 --- /dev/null
17173 +++ b/ext/http/http_response_object.c
17174 @@ -0,0 +1,915 @@
17175 +/*
17176 +    +--------------------------------------------------------------------+
17177 +    | PECL :: http                                                       |
17178 +    +--------------------------------------------------------------------+
17179 +    | Redistribution and use in source and binary forms, with or without |
17180 +    | modification, are permitted provided that the conditions mentioned |
17181 +    | in the accompanying LICENSE file are met.                          |
17182 +    +--------------------------------------------------------------------+
17183 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
17184 +    +--------------------------------------------------------------------+
17185 +*/
17186 +
17187 +/* $Id: http_response_object.c 298891 2010-05-03 08:26:38Z mike $ */
17188 +
17189 +#define HTTP_WANT_SAPI
17190 +#define HTTP_WANT_MAGIC
17191 +#include "php_http.h"
17192 +
17193 +/* broken static properties in PHP 5.0 */
17194 +#if defined(ZEND_ENGINE_2) && !defined(WONKY)
17195 +
17196 +#include "php_ini.h"
17197 +
17198 +#include "php_http_api.h"
17199 +#include "php_http_cache_api.h"
17200 +#include "php_http_exception_object.h"
17201 +#include "php_http_headers_api.h"
17202 +#include "php_http_response_object.h"
17203 +#include "php_http_send_api.h"
17204 +
17205 +#define HTTP_BEGIN_ARGS(method, req_args)              HTTP_BEGIN_ARGS_EX(HttpResponse, method, 0, req_args)
17206 +#define HTTP_EMPTY_ARGS(method)                                        HTTP_EMPTY_ARGS_EX(HttpResponse, method, 0)
17207 +#define HTTP_RESPONSE_ME(method, visibility)   PHP_ME(HttpResponse, method, HTTP_ARGS(HttpResponse, method), visibility|ZEND_ACC_STATIC)
17208 +#define HTTP_RESPONSE_ALIAS(method, func)              HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpResponse, method))
17209 +
17210 +HTTP_BEGIN_ARGS(setHeader, 1)
17211 +       HTTP_ARG_VAL(name, 0)
17212 +       HTTP_ARG_VAL(value, 0)
17213 +       HTTP_ARG_VAL(replace, 0)
17214 +HTTP_END_ARGS;
17215 +
17216 +HTTP_BEGIN_ARGS(getHeader, 0)
17217 +       HTTP_ARG_VAL(name, 0)
17218 +HTTP_END_ARGS;
17219 +
17220 +HTTP_EMPTY_ARGS(getETag);
17221 +HTTP_BEGIN_ARGS(setETag, 1)
17222 +       HTTP_ARG_VAL(etag, 0)
17223 +HTTP_END_ARGS;
17224 +
17225 +HTTP_EMPTY_ARGS(getLastModified);
17226 +HTTP_BEGIN_ARGS(setLastModified, 1)
17227 +       HTTP_ARG_VAL(timestamp, 0)
17228 +HTTP_END_ARGS;
17229 +
17230 +HTTP_EMPTY_ARGS(getCache);
17231 +HTTP_BEGIN_ARGS(setCache, 1)
17232 +       HTTP_ARG_VAL(cache, 0)
17233 +HTTP_END_ARGS;
17234 +
17235 +HTTP_EMPTY_ARGS(getGzip);
17236 +HTTP_BEGIN_ARGS(setGzip, 1)
17237 +       HTTP_ARG_VAL(gzip, 0)
17238 +HTTP_END_ARGS;
17239 +
17240 +HTTP_EMPTY_ARGS(getCacheControl);
17241 +HTTP_BEGIN_ARGS(setCacheControl, 1)
17242 +       HTTP_ARG_VAL(cache_control, 0)
17243 +       HTTP_ARG_VAL(max_age, 0)
17244 +       HTTP_ARG_VAL(must_revalidate, 0)
17245 +HTTP_END_ARGS;
17246 +
17247 +HTTP_EMPTY_ARGS(getContentType);
17248 +HTTP_BEGIN_ARGS(setContentType, 1)
17249 +       HTTP_ARG_VAL(content_type, 0)
17250 +HTTP_END_ARGS;
17251 +
17252 +HTTP_BEGIN_ARGS(guessContentType, 1)
17253 +       HTTP_ARG_VAL(magic_file, 0)
17254 +       HTTP_ARG_VAL(magic_mode, 0)
17255 +HTTP_END_ARGS;
17256 +
17257 +HTTP_EMPTY_ARGS(getContentDisposition);
17258 +HTTP_BEGIN_ARGS(setContentDisposition, 1)
17259 +       HTTP_ARG_VAL(filename, 0)
17260 +       HTTP_ARG_VAL(send_inline, 0)
17261 +HTTP_END_ARGS;
17262 +
17263 +HTTP_EMPTY_ARGS(getThrottleDelay);
17264 +HTTP_BEGIN_ARGS(setThrottleDelay, 1)
17265 +       HTTP_ARG_VAL(seconds, 0)
17266 +HTTP_END_ARGS;
17267 +
17268 +HTTP_EMPTY_ARGS(getBufferSize);
17269 +HTTP_BEGIN_ARGS(setBufferSize, 1)
17270 +       HTTP_ARG_VAL(bytes, 0)
17271 +HTTP_END_ARGS;
17272 +
17273 +HTTP_EMPTY_ARGS(getData);
17274 +HTTP_BEGIN_ARGS(setData, 1)
17275 +       HTTP_ARG_VAL(data, 0)
17276 +HTTP_END_ARGS;
17277 +
17278 +HTTP_EMPTY_ARGS(getStream);
17279 +HTTP_BEGIN_ARGS(setStream, 1)
17280 +       HTTP_ARG_VAL(stream, 0)
17281 +HTTP_END_ARGS;
17282 +
17283 +HTTP_EMPTY_ARGS(getFile);
17284 +HTTP_BEGIN_ARGS(setFile, 1)
17285 +       HTTP_ARG_VAL(filepath, 0)
17286 +HTTP_END_ARGS;
17287 +
17288 +HTTP_BEGIN_ARGS(send, 0)
17289 +       HTTP_ARG_VAL(clean_ob, 0)
17290 +HTTP_END_ARGS;
17291 +
17292 +HTTP_EMPTY_ARGS(capture);
17293 +
17294 +HTTP_BEGIN_ARGS(redirect, 0)
17295 +       HTTP_ARG_VAL(url, 0)
17296 +       HTTP_ARG_VAL(params, 0)
17297 +       HTTP_ARG_VAL(session, 0)
17298 +       HTTP_ARG_VAL(permanent, 0)
17299 +HTTP_END_ARGS;
17300 +
17301 +HTTP_BEGIN_ARGS(status, 1)
17302 +       HTTP_ARG_VAL(code, 0)
17303 +HTTP_END_ARGS;
17304 +
17305 +HTTP_EMPTY_ARGS(getRequestHeaders);
17306 +HTTP_EMPTY_ARGS(getRequestBody);
17307 +HTTP_EMPTY_ARGS(getRequestBodyStream);
17308 +
17309 +#define THIS_CE http_response_object_ce
17310 +zend_class_entry *http_response_object_ce;
17311 +zend_function_entry http_response_object_fe[] = {
17312 +
17313 +       HTTP_RESPONSE_ME(setHeader, ZEND_ACC_PUBLIC)
17314 +       HTTP_RESPONSE_ME(getHeader, ZEND_ACC_PUBLIC)
17315 +
17316 +       HTTP_RESPONSE_ME(setETag, ZEND_ACC_PUBLIC)
17317 +       HTTP_RESPONSE_ME(getETag, ZEND_ACC_PUBLIC)
17318 +       
17319 +       HTTP_RESPONSE_ME(setLastModified, ZEND_ACC_PUBLIC)
17320 +       HTTP_RESPONSE_ME(getLastModified, ZEND_ACC_PUBLIC)
17321 +
17322 +       HTTP_RESPONSE_ME(setContentDisposition, ZEND_ACC_PUBLIC)
17323 +       HTTP_RESPONSE_ME(getContentDisposition, ZEND_ACC_PUBLIC)
17324 +
17325 +       HTTP_RESPONSE_ME(setContentType, ZEND_ACC_PUBLIC)
17326 +       HTTP_RESPONSE_ME(getContentType, ZEND_ACC_PUBLIC)
17327 +       
17328 +       HTTP_RESPONSE_ME(guessContentType, ZEND_ACC_PUBLIC)
17329 +
17330 +       HTTP_RESPONSE_ME(setCache, ZEND_ACC_PUBLIC)
17331 +       HTTP_RESPONSE_ME(getCache, ZEND_ACC_PUBLIC)
17332 +
17333 +       HTTP_RESPONSE_ME(setCacheControl, ZEND_ACC_PUBLIC)
17334 +       HTTP_RESPONSE_ME(getCacheControl, ZEND_ACC_PUBLIC)
17335 +
17336 +       HTTP_RESPONSE_ME(setGzip, ZEND_ACC_PUBLIC)
17337 +       HTTP_RESPONSE_ME(getGzip, ZEND_ACC_PUBLIC)
17338 +
17339 +       HTTP_RESPONSE_ME(setThrottleDelay, ZEND_ACC_PUBLIC)
17340 +       HTTP_RESPONSE_ME(getThrottleDelay, ZEND_ACC_PUBLIC)
17341 +
17342 +       HTTP_RESPONSE_ME(setBufferSize, ZEND_ACC_PUBLIC)
17343 +       HTTP_RESPONSE_ME(getBufferSize, ZEND_ACC_PUBLIC)
17344 +
17345 +       HTTP_RESPONSE_ME(setData, ZEND_ACC_PUBLIC)
17346 +       HTTP_RESPONSE_ME(getData, ZEND_ACC_PUBLIC)
17347 +
17348 +       HTTP_RESPONSE_ME(setFile, ZEND_ACC_PUBLIC)
17349 +       HTTP_RESPONSE_ME(getFile, ZEND_ACC_PUBLIC)
17350 +
17351 +       HTTP_RESPONSE_ME(setStream, ZEND_ACC_PUBLIC)
17352 +       HTTP_RESPONSE_ME(getStream, ZEND_ACC_PUBLIC)
17353 +
17354 +       HTTP_RESPONSE_ME(send, ZEND_ACC_PUBLIC)
17355 +       HTTP_RESPONSE_ME(capture, ZEND_ACC_PUBLIC)
17356 +
17357 +       HTTP_RESPONSE_ALIAS(redirect, http_redirect)
17358 +       HTTP_RESPONSE_ALIAS(status, http_send_status)
17359 +       HTTP_RESPONSE_ALIAS(getRequestHeaders, http_get_request_headers)
17360 +       HTTP_RESPONSE_ALIAS(getRequestBody, http_get_request_body)
17361 +       HTTP_RESPONSE_ALIAS(getRequestBodyStream, http_get_request_body_stream)
17362 +
17363 +       EMPTY_FUNCTION_ENTRY
17364 +};
17365 +
17366 +PHP_MINIT_FUNCTION(http_response_object)
17367 +{
17368 +       HTTP_REGISTER_CLASS(HttpResponse, http_response_object, NULL, 0);
17369 +       
17370 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("sent")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
17371 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("catch")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
17372 +       zend_declare_property_long(THIS_CE, ZEND_STRS("mode")-1, -1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
17373 +       zend_declare_property_long(THIS_CE, ZEND_STRS("stream")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
17374 +       zend_declare_property_null(THIS_CE, ZEND_STRS("file")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
17375 +       zend_declare_property_null(THIS_CE, ZEND_STRS("data")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
17376 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("cache")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17377 +       zend_declare_property_bool(THIS_CE, ZEND_STRS("gzip")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17378 +       zend_declare_property_null(THIS_CE, ZEND_STRS("eTag")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17379 +       zend_declare_property_long(THIS_CE, ZEND_STRS("lastModified")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17380 +       zend_declare_property_null(THIS_CE, ZEND_STRS("cacheControl")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17381 +       zend_declare_property_null(THIS_CE, ZEND_STRS("contentType")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17382 +       zend_declare_property_null(THIS_CE, ZEND_STRS("contentDisposition")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17383 +       zend_declare_property_long(THIS_CE, ZEND_STRS("bufferSize")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17384 +       zend_declare_property_double(THIS_CE, ZEND_STRS("throttleDelay")-1, 0.0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC);
17385 +
17386 +#ifndef WONKY
17387 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT")-1, HTTP_REDIRECT TSRMLS_CC);
17388 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_PERM")-1, HTTP_REDIRECT_PERM TSRMLS_CC);
17389 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_FOUND")-1, HTTP_REDIRECT_FOUND TSRMLS_CC);
17390 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_POST")-1, HTTP_REDIRECT_POST TSRMLS_CC);
17391 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_PROXY")-1, HTTP_REDIRECT_PROXY TSRMLS_CC);
17392 +       zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_TEMP")-1, HTTP_REDIRECT_TEMP TSRMLS_CC);
17393 +#endif /* WONKY */
17394 +       
17395 +       return SUCCESS;
17396 +}
17397 +
17398 +/* ### USERLAND ### */
17399 +
17400 +/* {{{ proto static bool HttpResponse::setHeader(string name[, mixed value[, bool replace = true]])
17401 +       Send an HTTP header. */
17402 +PHP_METHOD(HttpResponse, setHeader)
17403 +{
17404 +       zend_bool replace = 1;
17405 +       char *name;
17406 +       int name_len = 0;
17407 +       zval *value = NULL;
17408 +
17409 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/!b", &name, &name_len, &value, &replace)) {
17410 +               RETURN_FALSE;
17411 +       }
17412 +       if (SG(headers_sent)) {
17413 +               http_error(HE_WARNING, HTTP_E_HEADER, "Cannot add another header when headers have already been sent");
17414 +               RETURN_FALSE;
17415 +       }
17416 +       if (!name_len) {
17417 +               http_error(HE_WARNING, HTTP_E_HEADER, "Cannot send anonymous headers");
17418 +               RETURN_FALSE;
17419 +       }
17420 +       http_send_header_zval_ex(name, name_len, &value, replace);
17421 +       RETURN_TRUE;
17422 +}
17423 +/* }}} */
17424 +
17425 +/* {{{ proto static mixed HttpResponse::getHeader([string name])
17426 +       Get header(s) about to be sent. */
17427 +PHP_METHOD(HttpResponse, getHeader)
17428 +{
17429 +       char *name = NULL;
17430 +       int name_len = 0;
17431 +       
17432 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len)) {
17433 +               RETURN_FALSE;
17434 +       }
17435 +       
17436 +       if (name && name_len) {
17437 +               zval **header;
17438 +               HashTable headers_ht;
17439 +               
17440 +               zend_hash_init(&headers_ht, sizeof(zval *), NULL, ZVAL_PTR_DTOR, 0);
17441 +               if (    (SUCCESS == http_get_response_headers(&headers_ht)) &&
17442 +                               (SUCCESS == zend_hash_find(&headers_ht, name, name_len + 1, (void *) &header))) {
17443 +                       RETVAL_ZVAL(*header, 1, 0);
17444 +               } else {
17445 +                       RETVAL_NULL();
17446 +               }
17447 +               zend_hash_destroy(&headers_ht);
17448 +       } else {
17449 +               array_init(return_value);
17450 +               http_get_response_headers(Z_ARRVAL_P(return_value));
17451 +       }
17452 +}
17453 +/* }}} */
17454 +
17455 +/* {{{ proto static bool HttpResponse::setCache(bool cache)
17456 +       Whether it should be attempted to cache the entity. */
17457 +PHP_METHOD(HttpResponse, setCache)
17458 +{
17459 +       zend_bool do_cache = 0;
17460 +
17461 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) {
17462 +               RETURN_FALSE;
17463 +       }
17464 +
17465 +       RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE, ZEND_STRS("cache")-1, do_cache TSRMLS_CC));
17466 +}
17467 +/* }}} */
17468 +
17469 +/* {{{ proto static bool HttpResponse::getCache()
17470 +       Get current caching setting. */
17471 +PHP_METHOD(HttpResponse, getCache)
17472 +{
17473 +       NO_ARGS;
17474 +
17475 +       if (return_value_used) {
17476 +               zval *cache = http_zsep(IS_BOOL, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cache")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17477 +               RETVAL_ZVAL(cache, 1, 1);
17478 +       }
17479 +}
17480 +/* }}}*/
17481 +
17482 +/* {{{ proto static bool HttpResponse::setGzip(bool gzip)
17483 +       Enable on-thy-fly gzipping of the sent entity. */
17484 +PHP_METHOD(HttpResponse, setGzip)
17485 +{
17486 +       zend_bool do_gzip = 0;
17487 +
17488 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) {
17489 +               RETURN_FALSE;
17490 +       }
17491 +
17492 +       RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE, ZEND_STRS("gzip")-1, do_gzip TSRMLS_CC));
17493 +}
17494 +/* }}} */
17495 +
17496 +/* {{{ proto static bool HttpResponse::getGzip()
17497 +       Get current gzipping setting. */
17498 +PHP_METHOD(HttpResponse, getGzip)
17499 +{
17500 +       NO_ARGS;
17501 +
17502 +       if (return_value_used) {
17503 +               zval *gzip = http_zsep(IS_BOOL, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("gzip")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17504 +               RETVAL_ZVAL(gzip, 1, 1);
17505 +       }
17506 +}
17507 +/* }}} */
17508 +
17509 +/* {{{ proto static bool HttpResponse::setCacheControl(string control[, int max_age = 0[, bool must_revalidate = true]])
17510 +       Set a custom cache-control header, usually being "private" or "public"; The max_age parameter controls how long the cache entry is valid on the client side. */
17511 +PHP_METHOD(HttpResponse, setCacheControl)
17512 +{
17513 +       char *ccontrol, *cctl;
17514 +       int cc_len;
17515 +       long max_age = 0;
17516 +       zend_bool must_revalidate = 1;
17517 +
17518 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lb", &ccontrol, &cc_len, &max_age, &must_revalidate)) {
17519 +               RETURN_FALSE;
17520 +       }
17521 +
17522 +       if (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache")) {
17523 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol);
17524 +               RETURN_FALSE;
17525 +       } else {
17526 +               size_t cctl_len = spprintf(&cctl, 0, "%s,%s max-age=%ld", ccontrol, must_revalidate?" must-revalidate,":"", max_age);
17527 +               RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("cacheControl")-1, cctl, cctl_len TSRMLS_CC));
17528 +               efree(cctl);
17529 +       }
17530 +}
17531 +/* }}} */
17532 +
17533 +/* {{{ proto static string HttpResponse::getCacheControl()
17534 +       Get current Cache-Control header setting. */
17535 +PHP_METHOD(HttpResponse, getCacheControl)
17536 +{
17537 +       NO_ARGS;
17538 +
17539 +       if (return_value_used) {
17540 +               zval *cctl = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cacheControl")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17541 +               RETVAL_ZVAL(cctl, 1, 1);
17542 +       }
17543 +}
17544 +/* }}} */
17545 +
17546 +/* {{{ proto static bool HttpResponse::setContentType(string content_type)
17547 +       Set the content-type of the sent entity. */
17548 +PHP_METHOD(HttpResponse, setContentType)
17549 +{
17550 +       char *ctype;
17551 +       int ctype_len;
17552 +
17553 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) {
17554 +               RETURN_FALSE;
17555 +       }
17556 +
17557 +       HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE);
17558 +       RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("contentType")-1, ctype, ctype_len TSRMLS_CC));
17559 +}
17560 +/* }}} */
17561 +
17562 +/* {{{ proto static string HttpResponse::getContentType()
17563 +       Get current Content-Type header setting. */
17564 +PHP_METHOD(HttpResponse, getContentType)
17565 +{
17566 +       NO_ARGS;
17567 +
17568 +       if (return_value_used) {
17569 +               zval *ctype = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentType")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17570 +               RETVAL_ZVAL(ctype, 1, 1);
17571 +       }
17572 +}
17573 +/* }}} */
17574 +
17575 +/* {{{ proto static string HttpResponse::guessContentType(string magic_file[, int magic_mode = MAGIC_MIME])
17576 +       Attempts to guess the content type of supplied payload through libmagic. */
17577 +PHP_METHOD(HttpResponse, guessContentType)
17578 +{
17579 +#ifdef HTTP_HAVE_MAGIC
17580 +       char *magic_file, *ct = NULL;
17581 +       int magic_file_len;
17582 +       long magic_mode = MAGIC_MIME;
17583 +       
17584 +       RETVAL_FALSE;
17585 +       SET_EH_THROW_HTTP();
17586 +       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &magic_file, &magic_file_len, &magic_mode)) {
17587 +               switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) {
17588 +                       case SEND_DATA:
17589 +                       {
17590 +                               zval *data = *zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC);
17591 +                               ct = http_guess_content_type(magic_file, magic_mode, Z_STRVAL_P(data), Z_STRLEN_P(data), SEND_DATA);
17592 +                               break;
17593 +                       }
17594 +                       
17595 +                       case SEND_RSRC:
17596 +                       {
17597 +                               php_stream *s;
17598 +                               zval *z = *zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC);
17599 +                               z->type = IS_RESOURCE;
17600 +                               php_stream_from_zval(s, &z);
17601 +                               ct = http_guess_content_type(magic_file, magic_mode, s, 0, SEND_RSRC);
17602 +                               break;
17603 +                       }
17604 +                       
17605 +                       default:
17606 +                               ct = http_guess_content_type(magic_file, magic_mode, Z_STRVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)), 0, -1);
17607 +                               break;
17608 +               }
17609 +               if (ct) {
17610 +                       zend_update_static_property_string(THIS_CE, ZEND_STRS("contentType")-1, ct TSRMLS_CC);
17611 +                       RETVAL_STRING(ct, 0);
17612 +               }
17613 +       }
17614 +       SET_EH_NORMAL();
17615 +#else
17616 +       http_error(HE_THROW, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available");
17617 +       RETURN_FALSE;
17618 +#endif
17619 +}
17620 +/* }}} */
17621 +
17622 +/* {{{ proto static bool HttpResponse::setContentDisposition(string filename[, bool inline = false])
17623 +       Set the Content-Disposition. */
17624 +PHP_METHOD(HttpResponse, setContentDisposition)
17625 +{
17626 +       char *file, *cd;
17627 +       int file_len;
17628 +       size_t cd_len;
17629 +       zend_bool send_inline = 0;
17630 +
17631 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &file, &file_len, &send_inline)) {
17632 +               RETURN_FALSE;
17633 +       }
17634 +
17635 +       cd_len = spprintf(&cd, 0, "%s; filename=\"%s\"", send_inline ? "inline" : "attachment", file);
17636 +       RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("contentDisposition")-1, cd, cd_len TSRMLS_CC));
17637 +       efree(cd);
17638 +}
17639 +/* }}} */
17640 +
17641 +/* {{{ proto static string HttpResponse::getContentDisposition()
17642 +       Get current Content-Disposition setting. */
17643 +PHP_METHOD(HttpResponse, getContentDisposition)
17644 +{
17645 +       NO_ARGS;
17646 +
17647 +       if (return_value_used) {
17648 +               zval *cdisp = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentDisposition")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17649 +               RETVAL_ZVAL(cdisp, 1, 1);
17650 +       }
17651 +}
17652 +/* }}} */
17653 +
17654 +/* {{{ proto static bool HttpResponse::setETag(string etag)
17655 +       Set a custom ETag.  Use this only if you know what you're doing. */
17656 +PHP_METHOD(HttpResponse, setETag)
17657 +{
17658 +       char *etag;
17659 +       int etag_len;
17660 +
17661 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len)) {
17662 +               RETURN_FALSE;
17663 +       }
17664 +
17665 +       RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("eTag")-1, etag, etag_len TSRMLS_CC));
17666 +}
17667 +/* }}} */
17668 +
17669 +/* {{{ proto static string HttpResponse::getETag()
17670 +       Get calculated or previously set custom ETag. */
17671 +PHP_METHOD(HttpResponse, getETag)
17672 +{
17673 +       NO_ARGS;
17674 +
17675 +       if (return_value_used) {
17676 +               zval *etag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17677 +               RETVAL_ZVAL(etag, 1, 1);
17678 +       }
17679 +}
17680 +/* }}} */
17681 +
17682 +/* {{{ proto static bool HttpResponse::setLastModified(int timestamp)
17683 +       Set a custom Last-Modified date. */
17684 +PHP_METHOD(HttpResponse, setLastModified)
17685 +{
17686 +       long lm;
17687 +       
17688 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &lm)) {
17689 +               RETURN_FALSE;
17690 +       }
17691 +       
17692 +       RETURN_SUCCESS(zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, lm TSRMLS_CC));
17693 +}
17694 +/* }}} */
17695 +
17696 +/* {{{ proto static int HttpResponse::getLastModified()
17697 +       Get calculated or previously set custom Last-Modified date. */
17698 +PHP_METHOD(HttpResponse, getLastModified)
17699 +{
17700 +       NO_ARGS;
17701 +       
17702 +       if (return_value_used) {
17703 +               zval *lmod = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("lastModified")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17704 +               RETVAL_ZVAL(lmod, 1, 1);
17705 +       }
17706 +}
17707 +/* }}} */
17708 +
17709 +/* {{{ proto static bool HttpResponse::setThrottleDelay(double seconds)
17710 +       Sets the throttle delay for use with HttpResponse::setBufferSize(). */
17711 +PHP_METHOD(HttpResponse, setThrottleDelay)
17712 +{
17713 +       double seconds;
17714 +
17715 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &seconds)) {
17716 +               RETURN_FALSE;
17717 +       }
17718 +       RETURN_SUCCESS(zend_update_static_property_double(THIS_CE, ZEND_STRS("throttleDelay")-1, seconds TSRMLS_CC));
17719 +}
17720 +/* }}} */
17721 +
17722 +/* {{{ proto static double HttpResponse::getThrottleDelay()
17723 +       Get the current throttle delay. */
17724 +PHP_METHOD(HttpResponse, getThrottleDelay)
17725 +{
17726 +       NO_ARGS;
17727 +
17728 +       if (return_value_used) {
17729 +               zval *tdel = http_zsep(IS_DOUBLE, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("throttleDelay")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17730 +               RETVAL_ZVAL(tdel, 1, 1);
17731 +       }
17732 +}
17733 +/* }}} */
17734 +
17735 +/* {{{ proto static bool HttpResponse::setBufferSize(int bytes)
17736 +       Sets the send buffer size for use with HttpResponse::setThrottleDelay(). */
17737 +PHP_METHOD(HttpResponse, setBufferSize)
17738 +{
17739 +       long bytes;
17740 +
17741 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bytes)) {
17742 +               RETURN_FALSE;
17743 +       }
17744 +       RETURN_SUCCESS(zend_update_static_property_long(THIS_CE, ZEND_STRS("bufferSize")-1, bytes TSRMLS_CC));
17745 +}
17746 +/* }}} */
17747 +
17748 +/* {{{ proto static int HttpResponse::getBufferSize()
17749 +       Get current buffer size. */
17750 +PHP_METHOD(HttpResponse, getBufferSize)
17751 +{
17752 +       NO_ARGS;
17753 +
17754 +       if (return_value_used) {
17755 +               zval *bsize = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("bufferSize")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17756 +               RETVAL_ZVAL(bsize, 1, 1);
17757 +       }
17758 +}
17759 +/* }}} */
17760 +
17761 +/* {{{ proto static bool HttpResponse::setData(mixed data)
17762 +       Set the data to be sent. */
17763 +PHP_METHOD(HttpResponse, setData)
17764 +{
17765 +       char *etag;
17766 +       zval *the_data;
17767 +
17768 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &the_data)) {
17769 +               RETURN_FALSE;
17770 +       }
17771 +       if (Z_TYPE_P(the_data) != IS_STRING) {
17772 +               convert_to_string(the_data);
17773 +       }
17774 +
17775 +       if (    (SUCCESS != zend_update_static_property(THIS_CE, ZEND_STRS("data")-1, the_data TSRMLS_CC)) ||
17776 +                       (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, SEND_DATA TSRMLS_CC))) {
17777 +               RETURN_FALSE;
17778 +       }
17779 +       
17780 +       zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_data, SEND_DATA) TSRMLS_CC);
17781 +       if ((etag = http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA))) {
17782 +               zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
17783 +               efree(etag);
17784 +       }
17785 +
17786 +       RETURN_TRUE;
17787 +}
17788 +/* }}} */
17789 +
17790 +/* {{{ proto static string HttpResponse::getData()
17791 +       Get the previously set data to be sent. */
17792 +PHP_METHOD(HttpResponse, getData)
17793 +{
17794 +       NO_ARGS;
17795 +
17796 +       if (return_value_used) {
17797 +               zval *the_data = *zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC);
17798 +               
17799 +               RETURN_ZVAL(the_data, 1, 0);
17800 +       }
17801 +}
17802 +/* }}} */
17803 +
17804 +/* {{{ proto static bool HttpResponse::setStream(resource stream)
17805 +       Set the resource to be sent. */
17806 +PHP_METHOD(HttpResponse, setStream)
17807 +{
17808 +       char *etag;
17809 +       zval *the_stream;
17810 +       php_stream *the_real_stream;
17811 +       php_stream_statbuf ssb;
17812 +
17813 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) {
17814 +               RETURN_FALSE;
17815 +       }
17816 +       
17817 +       php_stream_from_zval(the_real_stream, &the_stream);
17818 +       if (php_stream_stat(the_real_stream, &ssb)) {
17819 +               RETURN_FALSE;
17820 +       }
17821 +
17822 +       if (    (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("stream")-1, Z_LVAL_P(the_stream) TSRMLS_CC)) ||
17823 +                       (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, SEND_RSRC TSRMLS_CC))) {
17824 +               RETURN_FALSE;
17825 +       }
17826 +       zend_list_addref(Z_LVAL_P(the_stream));
17827 +       
17828 +       zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_real_stream, SEND_RSRC) TSRMLS_CC);
17829 +       if ((etag = http_etag(the_real_stream, 0, SEND_RSRC))) {
17830 +               zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
17831 +               efree(etag);
17832 +       }
17833 +
17834 +       RETURN_TRUE;
17835 +}
17836 +/* }}} */
17837 +
17838 +/* {{{ proto static resource HttpResponse::getStream()
17839 +       Get the previously set resource to be sent. */
17840 +PHP_METHOD(HttpResponse, getStream)
17841 +{
17842 +       NO_ARGS;
17843 +
17844 +       if (return_value_used) {
17845 +               zval *stream = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17846 +               RETVAL_RESOURCE(Z_LVAL_P(stream));
17847 +               zval_ptr_dtor(&stream);
17848 +       }
17849 +}
17850 +/* }}} */
17851 +
17852 +/* {{{ proto static bool HttpResponse::setFile(string file)
17853 +       Set the file to be sent. */
17854 +PHP_METHOD(HttpResponse, setFile)
17855 +{
17856 +       char *the_file, *etag;
17857 +       int file_len;
17858 +       php_stream_statbuf ssb;
17859 +
17860 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &the_file, &file_len)) {
17861 +               RETURN_FALSE;
17862 +       }
17863 +       
17864 +       if (php_stream_stat_path(the_file, &ssb)) {
17865 +               RETURN_FALSE;
17866 +       }
17867 +       
17868 +       if (    (SUCCESS != zend_update_static_property_stringl(THIS_CE, ZEND_STRS("file")-1, the_file, file_len TSRMLS_CC)) ||
17869 +                       (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, -1 TSRMLS_CC))) {
17870 +               RETURN_FALSE;
17871 +       }
17872 +
17873 +       zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_file, -1) TSRMLS_CC);
17874 +       if ((etag = http_etag(the_file, 0, -1))) {
17875 +               zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
17876 +               efree(etag);
17877 +       }
17878 +
17879 +       RETURN_TRUE;
17880 +}
17881 +/* }}} */
17882 +
17883 +/* {{{ proto static string HttpResponse::getFile()
17884 +       Get the previously set file to be sent. */
17885 +PHP_METHOD(HttpResponse, getFile)
17886 +{
17887 +       NO_ARGS;
17888 +
17889 +       if (return_value_used) {
17890 +               zval *file = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17891 +               RETVAL_ZVAL(file, 1, 1);
17892 +       }
17893 +}
17894 +/* }}} */
17895 +
17896 +/* {{{ proto static bool HttpResponse::send([bool clean_ob = true])
17897 +       Finally send the entity. */
17898 +PHP_METHOD(HttpResponse, send)
17899 +{
17900 +       zval *sent;
17901 +       zend_bool clean_ob = 1;
17902 +
17903 +       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean_ob)) {
17904 +               RETURN_FALSE;
17905 +       }
17906 +       
17907 +       HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
17908 +
17909 +       sent = *zend_std_get_static_property(THIS_CE, ZEND_STRS("sent")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC);
17910 +       if (Z_LVAL_P(sent)) {
17911 +               http_error(HE_WARNING, HTTP_E_RESPONSE, "Cannot send HttpResponse, response has already been sent");
17912 +               RETURN_FALSE;
17913 +       } else {
17914 +               Z_LVAL_P(sent) = 1;
17915 +       }
17916 +
17917 +       /* capture mode */
17918 +       if (i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("catch")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) {
17919 +               zval *zetag, *the_data;
17920 +
17921 +               MAKE_STD_ZVAL(the_data);
17922 +               php_ob_get_buffer(the_data TSRMLS_CC);
17923 +               zend_update_static_property(THIS_CE, ZEND_STRS("data")-1, the_data TSRMLS_CC);
17924 +               ZVAL_LONG(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC), SEND_DATA);
17925 +
17926 +               zetag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17927 +               if (!Z_STRLEN_P(zetag)) {
17928 +                       char *etag = http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA);
17929 +                       if (etag) {
17930 +                               zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC);
17931 +                               efree(etag);
17932 +                       }
17933 +               }
17934 +               zval_ptr_dtor(&the_data);
17935 +               zval_ptr_dtor(&zetag);
17936 +
17937 +               clean_ob = 1;
17938 +       }
17939 +
17940 +       if (clean_ob) {
17941 +               /* interrupt on-the-fly etag generation */
17942 +               HTTP_G->etag.started = 0;
17943 +               /* discard previous output buffers */
17944 +               php_end_ob_buffers(0 TSRMLS_CC);
17945 +       }
17946 +
17947 +       /* caching */
17948 +       if (i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("cache")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) {
17949 +               zval *cctl, *etag, *lmod;
17950 +               
17951 +               lmod = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("lastModified")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17952 +               etag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17953 +               cctl = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cacheControl")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17954 +               
17955 +               if (Z_LVAL_P(lmod) || Z_STRLEN_P(etag)) {
17956 +                       if (Z_STRLEN_P(cctl)) {
17957 +                               http_send_cache_control(Z_STRVAL_P(cctl), Z_STRLEN_P(cctl));
17958 +                       } else {
17959 +                               http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL));
17960 +                       }
17961 +                       if (Z_STRLEN_P(etag)) {
17962 +                               http_send_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag));
17963 +                       }
17964 +                       if (Z_LVAL_P(lmod)) {
17965 +                               http_send_last_modified(Z_LVAL_P(lmod));
17966 +                       }
17967 +               }
17968 +               
17969 +               zval_ptr_dtor(&etag);
17970 +               zval_ptr_dtor(&lmod);
17971 +               zval_ptr_dtor(&cctl);
17972 +       }
17973 +
17974 +       /* content type */
17975 +       {
17976 +               zval *ctype = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentType")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17977 +               if (Z_STRLEN_P(ctype)) {
17978 +                       http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
17979 +               } else {
17980 +                       char *ctypes = INI_STR("default_mimetype");
17981 +                       size_t ctlen = ctypes ? strlen(ctypes) : 0;
17982 +
17983 +                       if (ctlen) {
17984 +                               http_send_content_type(ctypes, ctlen);
17985 +                       } else {
17986 +                               http_send_content_type("application/x-octetstream", lenof("application/x-octetstream"));
17987 +                       }
17988 +               }
17989 +               zval_ptr_dtor(&ctype);
17990 +       }
17991 +
17992 +       /* content disposition */
17993 +       {
17994 +               zval *cd = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentDisposition")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
17995 +               if (Z_STRLEN_P(cd)) {
17996 +                       http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd), Z_STRLEN_P(cd), 1, NULL);
17997 +               }
17998 +               zval_ptr_dtor(&cd);
17999 +       }
18000 +
18001 +       /* throttling */
18002 +       {
18003 +               zval *bsize = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("bufferSize")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
18004 +               zval *delay = http_zsep(IS_DOUBLE, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("throttleDelay")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
18005 +               HTTP_G->send.buffer_size    = Z_LVAL_P(bsize);
18006 +               HTTP_G->send.throttle_delay = Z_DVAL_P(delay);
18007 +               zval_ptr_dtor(&bsize);
18008 +               zval_ptr_dtor(&delay);
18009 +       }
18010 +
18011 +       /* gzip */
18012 +       HTTP_G->send.deflate.response = i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("gzip")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC));
18013 +       
18014 +       /* send */
18015 +       switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) {
18016 +               case SEND_DATA:
18017 +               {
18018 +                       zval *zdata = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
18019 +                       RETVAL_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
18020 +                       zval_ptr_dtor(&zdata);
18021 +                       return;
18022 +               }
18023 +
18024 +               case SEND_RSRC:
18025 +               {
18026 +                       php_stream *the_real_stream;
18027 +                       zval *the_stream = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
18028 +                       the_stream->type = IS_RESOURCE;
18029 +                       php_stream_from_zval(the_real_stream, &the_stream);
18030 +                       RETVAL_SUCCESS(http_send_stream(the_real_stream));
18031 +                       zval_ptr_dtor(&the_stream);
18032 +                       return;
18033 +               }
18034 +
18035 +               default:
18036 +               {
18037 +                       zval *file = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)));
18038 +                       RETVAL_SUCCESS(http_send_file(Z_STRVAL_P(file)));
18039 +                       zval_ptr_dtor(&file);
18040 +                       return;
18041 +               }
18042 +       }
18043 +}
18044 +/* }}} */
18045 +
18046 +/* {{{ proto static void HttpResponse::capture()
18047 +       Capture script output.
18048 + */
18049 +PHP_METHOD(HttpResponse, capture)
18050 +{
18051 +       NO_ARGS;
18052 +       
18053 +       HTTP_CHECK_HEADERS_SENT(RETURN_FALSE);
18054 +
18055 +       zend_update_static_property_long(THIS_CE, ZEND_STRS("catch")-1, 1 TSRMLS_CC);
18056 +
18057 +       php_end_ob_buffers(0 TSRMLS_CC);
18058 +       php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC);
18059 +
18060 +       /* register shutdown function */
18061 +       {
18062 +               zval func, retval, arg, *argp[1];
18063 +
18064 +               INIT_PZVAL(&arg);
18065 +               INIT_PZVAL(&func);
18066 +               INIT_PZVAL(&retval);
18067 +               ZVAL_STRINGL(&func, "register_shutdown_function", lenof("register_shutdown_function"), 0);
18068 +
18069 +               array_init(&arg);
18070 +               add_next_index_stringl(&arg, "HttpResponse", lenof("HttpResponse"), 1);
18071 +               add_next_index_stringl(&arg, "send", lenof("send"), 1);
18072 +               argp[0] = &arg;
18073 +               call_user_function(EG(function_table), NULL, &func, &retval, 1, argp TSRMLS_CC);
18074 +               zval_dtor(&arg);
18075 +       }
18076 +}
18077 +/* }}} */
18078 +
18079 +#endif /* ZEND_ENGINE_2 && !WONKY */
18080 +
18081 +/*
18082 + * Local variables:
18083 + * tab-width: 4
18084 + * c-basic-offset: 4
18085 + * End:
18086 + * vim600: noet sw=4 ts=4 fdm=marker
18087 + * vim<600: noet sw=4 ts=4
18088 + */
18089 +
18090 --- /dev/null
18091 +++ b/ext/http/http_send_api.c
18092 @@ -0,0 +1,607 @@
18093 +/*
18094 +    +--------------------------------------------------------------------+
18095 +    | PECL :: http                                                       |
18096 +    +--------------------------------------------------------------------+
18097 +    | Redistribution and use in source and binary forms, with or without |
18098 +    | modification, are permitted provided that the conditions mentioned |
18099 +    | in the accompanying LICENSE file are met.                          |
18100 +    +--------------------------------------------------------------------+
18101 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
18102 +    +--------------------------------------------------------------------+
18103 +*/
18104 +
18105 +/* $Id: http_send_api.c 300299 2010-06-09 06:23:16Z mike $ */
18106 +
18107 +#define HTTP_WANT_SAPI
18108 +#define HTTP_WANT_ZLIB
18109 +#define HTTP_WANT_MAGIC
18110 +#include "php_http.h"
18111 +
18112 +#include "php_streams.h"
18113 +
18114 +#include "php_http_api.h"
18115 +#include "php_http_cache_api.h"
18116 +#include "php_http_date_api.h"
18117 +#include "php_http_encoding_api.h"
18118 +#include "php_http_headers_api.h"
18119 +#include "php_http_send_api.h"
18120 +
18121 +/* {{{ http_flush() */
18122 +#define http_flush(d, l) _http_flush(NULL, (d), (l) TSRMLS_CC)
18123 +static inline void _http_flush(void *nothing, const char *data, size_t data_len TSRMLS_DC)
18124 +{
18125 +       PHPWRITE(data, data_len);
18126 +       /*      we really only need to flush when throttling is enabled,
18127 +               because we push the data as fast as possible anyway if not */
18128 +       if (HTTP_G->send.throttle_delay >= HTTP_DIFFSEC) {
18129 +               if (OG(ob_nesting_level)) {
18130 +                       php_end_ob_buffer(1, 1 TSRMLS_CC);
18131 +               }
18132 +               if (!OG(implicit_flush)) {
18133 +                       sapi_flush(TSRMLS_C);
18134 +               }
18135 +               http_sleep(HTTP_G->send.throttle_delay);
18136 +       }
18137 +}
18138 +/* }}} */
18139 +
18140 +/* {{{ http_send_response_start */
18141 +#define http_send_response_start(b, cl) _http_send_response_start((b), (cl) TSRMLS_CC)
18142 +static inline void _http_send_response_start(void **buffer, size_t content_length TSRMLS_DC)
18143 +{
18144 +       int encoding;
18145 +       
18146 +       if ((encoding = http_encoding_response_start(content_length, 0))) {
18147 +#ifdef HTTP_HAVE_ZLIB
18148 +               *((http_encoding_stream **) buffer) = http_encoding_deflate_stream_init(NULL, 
18149 +                       (encoding == HTTP_ENCODING_GZIP) ? 
18150 +                               HTTP_DEFLATE_TYPE_GZIP : HTTP_DEFLATE_TYPE_ZLIB);
18151 +#endif
18152 +       }
18153 +       /* flush headers */
18154 +       sapi_flush(TSRMLS_C);
18155 +}
18156 +/* }}} */
18157 +
18158 +/* {{{ http_send_response_data_plain */
18159 +#define http_send_response_data_plain(b, d, dl) _http_send_response_data_plain((b), (d), (dl) TSRMLS_CC)
18160 +static inline void _http_send_response_data_plain(void **buffer, const char *data, size_t data_len TSRMLS_DC)
18161 +{
18162 +       if (HTTP_G->send.deflate.response && HTTP_G->send.deflate.encoding) {
18163 +#ifdef HTTP_HAVE_ZLIB
18164 +               char *encoded;
18165 +               size_t encoded_len;
18166 +               http_encoding_stream *s = *((http_encoding_stream **) buffer);
18167 +               
18168 +               http_encoding_deflate_stream_update(s, data, data_len, &encoded, &encoded_len);
18169 +               if (HTTP_G->send.buffer_size) {
18170 +                       phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, HTTP_G->send.buffer_size, _http_flush, NULL TSRMLS_CC);
18171 +               } else {
18172 +                       http_flush(encoded, encoded_len);
18173 +               }
18174 +               efree(encoded);
18175 +#else
18176 +               http_error(HE_ERROR, HTTP_E_RESPONSE, "Attempt to send GZIP response despite being able to do so; please report this bug");
18177 +#endif
18178 +       } else if (HTTP_G->send.buffer_size) {
18179 +               phpstr_chunked_output((phpstr **) buffer, data, data_len, HTTP_G->send.buffer_size, _http_flush, NULL TSRMLS_CC);
18180 +       } else {
18181 +               http_flush(data, data_len);
18182 +       }
18183 +}
18184 +/* }}} */
18185 +
18186 +/* {{{ http_send_response_data_fetch */
18187 +#define http_send_response_data_fetch(b, d, l, m, s, e) _http_send_response_data_fetch((b), (d), (l), (m), (s), (e) TSRMLS_CC)
18188 +static inline void _http_send_response_data_fetch(void **buffer, const void *data, size_t data_len, http_send_mode mode, size_t begin, size_t end TSRMLS_DC)
18189 +{
18190 +       long bsz, got, len = end - begin;
18191 +       
18192 +       if (!(bsz = HTTP_G->send.buffer_size)) {
18193 +               bsz = HTTP_SENDBUF_SIZE;
18194 +       }
18195 +       
18196 +       switch (mode) {
18197 +               case SEND_RSRC: {
18198 +                       php_stream *s = (php_stream *) data;
18199 +                       if (SUCCESS == php_stream_seek(s, begin, SEEK_SET)) {
18200 +                               char *buf = emalloc(bsz);
18201 +                               
18202 +                               while (len > 0) {
18203 +                                       got = php_stream_read(s, buf, MIN(len, bsz));
18204 +                                       http_send_response_data_plain(buffer, buf, got);
18205 +                                       len -= got;
18206 +                               }
18207 +                               
18208 +                               efree(buf);
18209 +                       }
18210 +                       break;
18211 +               }
18212 +               case SEND_DATA: {
18213 +                       const char *buf = ((const char *) data) + begin;
18214 +                       while (len > 0) {
18215 +                               got = MIN(len, bsz);
18216 +                               http_send_response_data_plain(buffer, buf, got);
18217 +                               len -= got;
18218 +                               buf += got;
18219 +                       }
18220 +                       break;
18221 +               }
18222 +               EMPTY_SWITCH_DEFAULT_CASE();
18223 +       }
18224 +}
18225 +/* }}} */
18226 +
18227 +/* {{{ http_send_response_finish */
18228 +#define http_send_response_finish(b) _http_send_response_finish((b) TSRMLS_CC)
18229 +static inline void _http_send_response_finish(void **buffer TSRMLS_DC)
18230 +{
18231 +       if (HTTP_G->send.deflate.response && HTTP_G->send.deflate.encoding) {
18232 +#ifdef HTTP_HAVE_ZLIB
18233 +               char *encoded = NULL;
18234 +               size_t encoded_len = 0;
18235 +               http_encoding_stream *s = *((http_encoding_stream **) buffer);
18236 +               
18237 +               http_encoding_deflate_stream_finish(s, &encoded, &encoded_len);
18238 +               if (HTTP_G->send.buffer_size) {
18239 +                       phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, 0, _http_flush, NULL TSRMLS_CC);
18240 +               } else {
18241 +                       http_flush(encoded, encoded_len);
18242 +               }
18243 +               http_encoding_deflate_stream_free(&s);
18244 +               STR_FREE(encoded);
18245 +#else
18246 +               http_error(HE_ERROR, HTTP_E_RESPONSE, "Attempt to send GZIP response despite being able to do so; please report this bug");
18247 +#endif
18248 +       } else if (HTTP_G->send.buffer_size) {
18249 +               phpstr_chunked_output((phpstr **) buffer, NULL, 0, 0, _http_flush, NULL TSRMLS_CC);
18250 +       }
18251 +}
18252 +/* }}} */
18253 +
18254 +/* {{{ */
18255 +PHP_MINIT_FUNCTION(http_send)
18256 +{
18257 +       HTTP_LONG_CONSTANT("HTTP_REDIRECT", HTTP_REDIRECT);
18258 +       HTTP_LONG_CONSTANT("HTTP_REDIRECT_PERM", HTTP_REDIRECT_PERM);
18259 +       HTTP_LONG_CONSTANT("HTTP_REDIRECT_FOUND", HTTP_REDIRECT_FOUND);
18260 +       HTTP_LONG_CONSTANT("HTTP_REDIRECT_POST", HTTP_REDIRECT_POST);
18261 +       HTTP_LONG_CONSTANT("HTTP_REDIRECT_PROXY", HTTP_REDIRECT_PROXY);
18262 +       HTTP_LONG_CONSTANT("HTTP_REDIRECT_TEMP", HTTP_REDIRECT_TEMP);
18263 +       
18264 +       return SUCCESS;
18265 +}
18266 +/* }}} */
18267 +
18268 +/* {{{ http_find_header */
18269 +typedef struct {
18270 +       const char *h;
18271 +       size_t l;
18272 +} http_response_header_t;
18273 +
18274 +static int http_find_header(void *data, void *arg)
18275 +{
18276 +       http_response_header_t *h = arg;
18277 +       sapi_header_struct *s = data;
18278 +       
18279 +       return (!strncasecmp(s->header, h->h, h->l)) && s->header[h->l] == ':';
18280 +}
18281 +/* }}} */
18282 +
18283 +/* {{{ void http_hide_header(char *) */
18284 +PHP_HTTP_API void _http_hide_header_ex(const char *name, size_t name_len TSRMLS_DC)
18285 +{
18286 +       http_response_header_t h = {name, name_len};
18287 +       zend_llist_del_element(&SG(sapi_headers).headers, (void *) &h, http_find_header);
18288 +}
18289 +/* }}} */
18290 +
18291 +/* {{{ void http_send_header_zval(char*, zval **, zend_bool) */
18292 +PHP_HTTP_API void _http_send_header_zval_ex(const char *name, size_t name_len, zval **val, zend_bool replace TSRMLS_DC)
18293 +{
18294 +       if (!val || !*val || Z_TYPE_PP(val) == IS_NULL || (Z_TYPE_PP(val) == IS_STRING && !Z_STRLEN_PP(val))) {
18295 +               http_hide_header_ex(name, name_len);
18296 +       } else if (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT) {
18297 +               zend_bool first = replace;
18298 +               zval **data_ptr;
18299 +               HashPosition pos;
18300 +               
18301 +               FOREACH_HASH_VAL(pos, HASH_OF(*val), data_ptr) {
18302 +                       zval *data = http_zsep(IS_STRING, *data_ptr);
18303 +                       
18304 +                       http_send_header_ex(name, name_len, Z_STRVAL_P(data), Z_STRLEN_P(data), first, NULL);
18305 +                       zval_ptr_dtor(&data);
18306 +                       first = 0;
18307 +               }
18308 +       } else {
18309 +               zval *data = http_zsep(IS_STRING, *val);
18310 +               
18311 +               http_send_header_ex(name, name_len, Z_STRVAL_P(data), Z_STRLEN_P(data), replace, NULL);
18312 +               zval_ptr_dtor(&data);
18313 +       }
18314 +}
18315 +/* }}} */
18316 +
18317 +/* {{{ STATUS http_send_header(char *, char *, zend_bool) */
18318 +PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC)
18319 +{
18320 +       STATUS ret;
18321 +       
18322 +       if (value && value_len) {
18323 +               size_t header_len = sizeof(": ") + name_len + value_len + 1;
18324 +               char *header = emalloc(header_len + 1);
18325 +       
18326 +               header[header_len] = '\0';
18327 +               header_len = snprintf(header, header_len, "%s: %s", name, value);
18328 +               ret = http_send_header_string_ex(header, header_len, replace);
18329 +               if (sent_header) {
18330 +                       *sent_header = header;
18331 +               } else {
18332 +                       efree(header);
18333 +               }
18334 +       } else {
18335 +               http_hide_header_ex(name, name_len);
18336 +               ret = SUCCESS;
18337 +       }
18338 +       return ret;
18339 +}
18340 +/* }}} */
18341 +
18342 +/* {{{ STATUS http_send_status_header(int, char *) */
18343 +PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header, size_t header_len, zend_bool replace TSRMLS_DC)
18344 +{
18345 +       STATUS ret;
18346 +       sapi_header_line h = {(char *) header, header_len, status};
18347 +       if (SUCCESS != (ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, &h TSRMLS_CC))) {
18348 +               http_error_ex(HE_WARNING, HTTP_E_HEADER, "Could not send header: %s (%d)", header, status);
18349 +       }
18350 +       return ret;
18351 +}
18352 +/* }}} */
18353 +
18354 +/* {{{ STATUS http_send_last_modified(int) */
18355 +PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC)
18356 +{
18357 +       STATUS ret;
18358 +       char *date = http_date(t);
18359 +
18360 +       if (!date) {
18361 +               return FAILURE;
18362 +       }
18363 +
18364 +       ret = http_send_header_ex("Last-Modified", lenof("Last-Modified"), date, strlen(date), 1, sent_header);
18365 +       efree(date);
18366 +
18367 +       /* remember */
18368 +       HTTP_G->send.last_modified = t;
18369 +
18370 +       return ret;
18371 +}
18372 +/* }}} */
18373 +
18374 +/* {{{ STATUS http_send_etag(char *, size_t) */
18375 +PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC)
18376 +{
18377 +       STATUS status;
18378 +       char *etag_header;
18379 +       size_t etag_header_len;
18380 +
18381 +       if (!etag_len){
18382 +               http_error_ex(HE_WARNING, HTTP_E_HEADER, "Attempt to send empty ETag (previous: %s)\n", HTTP_G->send.unquoted_etag);
18383 +               return FAILURE;
18384 +       }
18385 +
18386 +       etag_header_len = spprintf(&etag_header, 0, "ETag: \"%s\"", etag);
18387 +       status = http_send_header_string_ex(etag_header, etag_header_len, 1);
18388 +       
18389 +       /* remember */
18390 +       STR_SET(HTTP_G->send.unquoted_etag, estrndup(etag, etag_len));
18391 +
18392 +       if (sent_header) {
18393 +               *sent_header = etag_header;
18394 +       } else {
18395 +               efree(etag_header);
18396 +       }
18397 +       
18398 +       return status;
18399 +}
18400 +/* }}} */
18401 +
18402 +/* {{{ STATUS http_send_content_type(char *, size_t) */
18403 +PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_len TSRMLS_DC)
18404 +{
18405 +       HTTP_CHECK_CONTENT_TYPE(content_type, return FAILURE);
18406 +
18407 +       /* remember for multiple ranges */
18408 +       STR_FREE(HTTP_G->send.content_type);
18409 +       HTTP_G->send.content_type = estrndup(content_type, ct_len);
18410 +
18411 +       return http_send_header_ex("Content-Type", lenof("Content-Type"), content_type, ct_len, 1, NULL);
18412 +}
18413 +/* }}} */
18414 +
18415 +/* {{{ STATUS http_send_content_disposition(char *, size_t, zend_bool) */
18416 +PHP_HTTP_API STATUS _http_send_content_disposition(const char *filename, size_t f_len, zend_bool send_inline TSRMLS_DC)
18417 +{
18418 +       STATUS status;
18419 +       char *cd_header;
18420 +
18421 +       if (send_inline) {
18422 +               cd_header = ecalloc(1, sizeof("Content-Disposition: inline; filename=\"\"") + f_len);
18423 +               sprintf(cd_header, "Content-Disposition: inline; filename=\"%s\"", filename);
18424 +       } else {
18425 +               cd_header = ecalloc(1, sizeof("Content-Disposition: attachment; filename=\"\"") + f_len);
18426 +               sprintf(cd_header, "Content-Disposition: attachment; filename=\"%s\"", filename);
18427 +       }
18428 +
18429 +       status = http_send_header_string(cd_header);
18430 +       efree(cd_header);
18431 +       return status;
18432 +}
18433 +/* }}} */
18434 +
18435 +/* {{{ STATUS http_send(void *, size_t, http_send_mode) */
18436 +PHP_HTTP_API STATUS _http_send_ex(const void *data_ptr, size_t data_size, http_send_mode data_mode, zend_bool no_cache TSRMLS_DC)
18437 +{
18438 +       void *s = NULL;
18439 +       HashTable ranges;
18440 +       http_range_status range_status;
18441 +       
18442 +       if (!data_ptr) {
18443 +               return FAILURE;
18444 +       }
18445 +       if (!data_size) {
18446 +               return SUCCESS;
18447 +       }
18448 +       
18449 +       /* enable partial dl and resume */
18450 +       http_send_header_string("Accept-Ranges: bytes");
18451 +
18452 +       zend_hash_init(&ranges, 0, NULL, ZVAL_PTR_DTOR, 0);
18453 +       range_status = http_get_request_ranges(&ranges, data_size);
18454 +
18455 +       switch (range_status) {
18456 +               case RANGE_ERR:
18457 +               {
18458 +                       zend_hash_destroy(&ranges);
18459 +                       http_send_status(416);
18460 +                       return FAILURE;
18461 +               }
18462 +               case RANGE_OK:
18463 +               {
18464 +                       /* Range Request - only send ranges if entity hasn't changed */
18465 +                       if (    http_got_server_var("HTTP_IF_RANGE") &&
18466 +                                       !http_match_etag("HTTP_IF_RANGE", HTTP_G->send.unquoted_etag) &&
18467 +                                       !http_match_last_modified("HTTP_IF_RANGE", HTTP_G->send.last_modified)) {
18468 +                               /* fallthrough to send full entity with 200 Ok */
18469 +                               no_cache = 1;
18470 +                       } else if (     !http_match_etag_ex("HTTP_IF_MATCH", HTTP_G->send.unquoted_etag, 0) ||
18471 +                                               !http_match_last_modified_ex("HTTP_IF_UNMODIFIED_SINCE", HTTP_G->send.last_modified, 0) ||
18472 +                                               !http_match_last_modified_ex("HTTP_UNLESS_MODIFIED_SINCE", HTTP_G->send.last_modified, 0)) {
18473 +                               /* 412 Precondition failed */
18474 +                               zend_hash_destroy(&ranges);
18475 +                               http_send_status(412);
18476 +                               return FAILURE;
18477 +                       } else if (zend_hash_num_elements(&ranges) == 1) {
18478 +                               /* single range */
18479 +                               zval **range, **begin, **end;
18480 +                               
18481 +                               if (    SUCCESS != zend_hash_index_find(&ranges, 0, (void *) &range) ||
18482 +                                               SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(range), 0, (void *) &begin) ||
18483 +                                               SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(range), 1, (void *) &end)) {
18484 +                                       /* this should never happen */
18485 +                                       zend_hash_destroy(&ranges);
18486 +                                       http_send_status(500);
18487 +                                       return FAILURE;
18488 +                               } else {
18489 +                                       phpstr header;
18490 +
18491 +                                       phpstr_init(&header);
18492 +                                       phpstr_appendf(&header, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_PP(begin), Z_LVAL_PP(end), data_size);
18493 +                                       phpstr_fix(&header);
18494 +                                       http_send_status_header_ex(206, PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1);
18495 +                                       phpstr_dtor(&header);
18496 +                                       http_send_response_start(&s, Z_LVAL_PP(end)-Z_LVAL_PP(begin)+1);
18497 +                                       http_send_response_data_fetch(&s, data_ptr, data_size, data_mode, Z_LVAL_PP(begin), Z_LVAL_PP(end) + 1);
18498 +                                       http_send_response_finish(&s);
18499 +                                       zend_hash_destroy(&ranges);
18500 +                                       return SUCCESS;
18501 +                               }
18502 +                       } else {
18503 +                               /* multi range */
18504 +                               HashPosition pos;
18505 +                               zval **range, **begin, **end;
18506 +                               const char *content_type = HTTP_G->send.content_type;
18507 +                               char boundary_str[32];
18508 +                               size_t boundary_len;
18509 +                               phpstr header, preface;
18510 +                               
18511 +                               boundary_len = http_boundary(boundary_str, sizeof(boundary_str));
18512 +                               phpstr_init(&header);
18513 +                               phpstr_appendf(&header, "Content-Type: multipart/byteranges; boundary=%s", boundary_str);
18514 +                               phpstr_fix(&header);
18515 +                               http_send_status_header_ex(206, PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1);
18516 +                               phpstr_dtor(&header);
18517 +                               http_send_response_start(&s, 0);
18518 +                               
18519 +                               if (!content_type) {
18520 +                                       content_type = "application/x-octetstream";
18521 +                               }
18522 +
18523 +                               phpstr_init(&preface);
18524 +                               FOREACH_HASH_VAL(pos, &ranges, range) {
18525 +                                       if (    SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(range), 0, (void *) &begin) &&
18526 +                                                       SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(range), 1, (void *) &end)) {
18527 +                                               
18528 +#define HTTP_RANGE_PREFACE \
18529 +       HTTP_CRLF "--%s" \
18530 +       HTTP_CRLF "Content-Type: %s" \
18531 +       HTTP_CRLF "Content-Range: bytes %ld-%ld/%zu" \
18532 +       HTTP_CRLF HTTP_CRLF
18533 +
18534 +                                               phpstr_appendf(&preface, HTTP_RANGE_PREFACE, boundary_str, content_type, Z_LVAL_PP(begin), Z_LVAL_PP(end), data_size);
18535 +                                               phpstr_fix(&preface);
18536 +                                               http_send_response_data_plain(&s, PHPSTR_VAL(&preface), PHPSTR_LEN(&preface));
18537 +                                               phpstr_reset(&preface);
18538 +                                               http_send_response_data_fetch(&s, data_ptr, data_size, data_mode, Z_LVAL_PP(begin), Z_LVAL_PP(end) + 1);
18539 +                                       }
18540 +                               }
18541 +                               phpstr_dtor(&preface);
18542 +                               
18543 +                               http_send_response_data_plain(&s, HTTP_CRLF "--", lenof(HTTP_CRLF "--"));
18544 +                               http_send_response_data_plain(&s, boundary_str, boundary_len);
18545 +                               http_send_response_data_plain(&s, "--", lenof("--"));
18546 +                               
18547 +                               http_send_response_finish(&s);
18548 +                               zend_hash_destroy(&ranges);
18549 +                               return SUCCESS;
18550 +                       }
18551 +               }
18552 +               case RANGE_NO:
18553 +               {
18554 +                       zend_hash_destroy(&ranges);
18555 +
18556 +                       /* send 304 Not Modified if etag matches - DON'T return on ETag generation failure */
18557 +                       if (!no_cache && (http_interrupt_ob_etaghandler() || (HTTP_G->send.unquoted_etag != NULL))) {
18558 +                               char *etag = NULL;
18559 +                               
18560 +                               if (HTTP_G->send.unquoted_etag) {
18561 +                                       etag = estrdup(HTTP_G->send.unquoted_etag);
18562 +                               }
18563 +                               
18564 +                               if (etag || (etag = http_etag(data_ptr, data_size, data_mode))) {
18565 +                                       char *sent_header = NULL;
18566 +                                       
18567 +                                       http_send_etag_ex(etag, strlen(etag), &sent_header);
18568 +                                       if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
18569 +                                               return http_exit_ex(304, sent_header, NULL, 0);
18570 +                                       } else {
18571 +                                               STR_FREE(sent_header);
18572 +                                               /* no caching for Last-Modified if ETags really don't match */
18573 +                                               no_cache = http_got_server_var("HTTP_IF_NONE_MATCH");
18574 +                                       }
18575 +                                       efree(etag);
18576 +                               }
18577 +                       }
18578 +               
18579 +                       /* send 304 Not Modified if last modified matches */
18580 +                       if (!no_cache && HTTP_G->send.last_modified && http_match_last_modified("HTTP_IF_MODIFIED_SINCE", HTTP_G->send.last_modified)) {
18581 +                               char *sent_header = NULL;
18582 +                               http_send_last_modified_ex(HTTP_G->send.last_modified, &sent_header);
18583 +                               return http_exit_ex(304, sent_header, NULL, 0);
18584 +                       }
18585 +                       
18586 +                       /* send full response */
18587 +                       http_send_response_start(&s, data_size);
18588 +                       http_send_response_data_fetch(&s, data_ptr, data_size, data_mode, 0, data_size);
18589 +                       http_send_response_finish(&s);
18590 +                       return SUCCESS;
18591 +               }
18592 +       }
18593 +       return FAILURE;
18594 +}
18595 +/* }}} */
18596 +
18597 +/* {{{ STATUS http_send_stream(php_stream *) */
18598 +PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *file, zend_bool close_stream, zend_bool no_cache TSRMLS_DC)
18599 +{
18600 +       STATUS status;
18601 +       php_stream_statbuf ssb;
18602 +       int orig_flags;
18603 +
18604 +       if ((!file) || php_stream_stat(file, &ssb)) {
18605 +               char *defct = sapi_get_default_content_type(TSRMLS_C);
18606 +               
18607 +               http_hide_header("Content-Disposition");
18608 +               http_send_content_type(defct, strlen(defct));
18609 +               http_error(HE_WARNING, HTTP_E_RESPONSE, "File not found; stat failed");
18610 +               STR_FREE(defct);
18611 +               
18612 +               if (HTTP_G->send.not_found_404) {
18613 +                       http_exit_ex(404, NULL, estrdup("File not found\n"), 0);
18614 +               }
18615 +               return FAILURE;
18616 +       }
18617 +
18618 +       orig_flags = file->flags;
18619 +       file->flags |= PHP_STREAM_FLAG_NO_BUFFER;
18620 +       status = http_send_ex(file, ssb.sb.st_size, SEND_RSRC, no_cache);
18621 +       file->flags = orig_flags;
18622 +       
18623 +       if (close_stream) {
18624 +               php_stream_close(file);
18625 +       }
18626 +
18627 +       return status;
18628 +}
18629 +/* }}} */
18630 +
18631 +/* {{{ char *http_guess_content_type(char *magic_file, long magic_mode, void *data, size_t size, http_send_mode mode) */
18632 +PHP_HTTP_API char *_http_guess_content_type(const char *magicfile, long magicmode, void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC)
18633 +{
18634 +       char *ct = NULL;
18635 +
18636 +#ifdef HTTP_HAVE_MAGIC
18637 +       struct magic_set *magic = NULL;
18638 +       
18639 +       HTTP_CHECK_OPEN_BASEDIR(magicfile, return NULL);
18640 +       
18641 +       if (!data_ptr) {
18642 +               http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Supplied payload is empty");
18643 +       } else if (!(magic = magic_open(magicmode &~ MAGIC_MIME))) {
18644 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid magic mode: %ld", magicmode);
18645 +       } else if (-1 == magic_load(magic, magicfile)) {
18646 +               http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Failed to load magic database '%s' (%s)", magicfile, magic_error(magic));
18647 +       } else {
18648 +               const char *ctype = NULL;
18649 +               
18650 +               magic_setflags(magic, magicmode);
18651 +               
18652 +               switch (data_mode) {
18653 +                       case SEND_RSRC:
18654 +                       {
18655 +                               char *buffer;
18656 +                               size_t b_len;
18657 +                               
18658 +                               b_len = php_stream_copy_to_mem(data_ptr, &buffer, 65536, 0);
18659 +                               ctype = magic_buffer(magic, buffer, b_len);
18660 +                               efree(buffer);
18661 +                               break;
18662 +                       }
18663 +                       
18664 +                       case SEND_DATA:
18665 +                               ctype = magic_buffer(magic, data_ptr, data_len);
18666 +                               break;
18667 +                       
18668 +                       default:
18669 +                               HTTP_CHECK_OPEN_BASEDIR(data_ptr, magic_close(magic); return NULL);
18670 +                               ctype = magic_file(magic, data_ptr);
18671 +                               break;
18672 +               }
18673 +               
18674 +               if (ctype) {
18675 +                       ct = estrdup(ctype);
18676 +               } else {
18677 +                       http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Failed to guess Content-Type: %s", magic_error(magic));
18678 +               }
18679 +       }
18680 +       if (magic) {
18681 +               magic_close(magic);
18682 +       }
18683 +#else
18684 +       http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available");
18685 +#endif
18686 +       
18687 +       return ct;
18688 +}
18689 +/* }}} */
18690 +
18691 +/*
18692 + * Local variables:
18693 + * tab-width: 4
18694 + * c-basic-offset: 4
18695 + * End:
18696 + * vim600: sw=4 ts=4 fdm=marker
18697 + * vim<600: sw=4 ts=4
18698 + */
18699 +
18700 --- /dev/null
18701 +++ b/ext/http/http_url_api.c
18702 @@ -0,0 +1,482 @@
18703 +/*
18704 +    +--------------------------------------------------------------------+
18705 +    | PECL :: http                                                       |
18706 +    +--------------------------------------------------------------------+
18707 +    | Redistribution and use in source and binary forms, with or without |
18708 +    | modification, are permitted provided that the conditions mentioned |
18709 +    | in the accompanying LICENSE file are met.                          |
18710 +    +--------------------------------------------------------------------+
18711 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
18712 +    +--------------------------------------------------------------------+
18713 +*/
18714 +
18715 +/* $Id: http_url_api.c 292841 2009-12-31 08:48:57Z mike $ */
18716 +
18717 +#define HTTP_WANT_SAPI
18718 +#define HTTP_WANT_NETDB
18719 +#include "php_http.h"
18720 +
18721 +#include "zend_ini.h"
18722 +#include "php_output.h"
18723 +#include "ext/standard/php_string.h"
18724 +
18725 +#include "php_http_api.h"
18726 +#include "php_http_querystring_api.h"
18727 +#include "php_http_url_api.h"
18728 +
18729 +static inline char *localhostname(void)
18730 +{
18731 +       char hostname[1024] = {0};
18732 +       
18733 +#ifdef PHP_WIN32
18734 +       if (SUCCESS == gethostname(hostname, lenof(hostname))) {
18735 +               return estrdup(hostname);
18736 +       }
18737 +#elif defined(HAVE_GETHOSTNAME)
18738 +       if (SUCCESS == gethostname(hostname, lenof(hostname))) {
18739 +#      if defined(HAVE_GETDOMAINNAME)
18740 +               size_t hlen = strlen(hostname);
18741 +               if (hlen <= lenof(hostname) - lenof("(none)")) {
18742 +                       hostname[hlen++] = '.';
18743 +                       if (SUCCESS == getdomainname(&hostname[hlen], lenof(hostname) - hlen)) {
18744 +                               if (!strcmp(&hostname[hlen], "(none)")) {
18745 +                                       hostname[hlen - 1] = '\0';
18746 +                               }
18747 +                               return estrdup(hostname);
18748 +                       }
18749 +               }
18750 +#      endif
18751 +               if (strcmp(hostname, "(none)")) {
18752 +                       return estrdup(hostname);
18753 +               }
18754 +       }
18755 +#endif
18756 +       return estrndup("localhost", lenof("localhost"));
18757 +}
18758 +
18759 +PHP_MINIT_FUNCTION(http_url)
18760 +{
18761 +       HTTP_LONG_CONSTANT("HTTP_URL_REPLACE", HTTP_URL_REPLACE);
18762 +       HTTP_LONG_CONSTANT("HTTP_URL_JOIN_PATH", HTTP_URL_JOIN_PATH);
18763 +       HTTP_LONG_CONSTANT("HTTP_URL_JOIN_QUERY", HTTP_URL_JOIN_QUERY);
18764 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_USER", HTTP_URL_STRIP_USER);
18765 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PASS", HTTP_URL_STRIP_PASS);
18766 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_AUTH", HTTP_URL_STRIP_AUTH);
18767 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PORT", HTTP_URL_STRIP_PORT);
18768 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PATH", HTTP_URL_STRIP_PATH);
18769 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_QUERY", HTTP_URL_STRIP_QUERY);
18770 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_FRAGMENT", HTTP_URL_STRIP_FRAGMENT);
18771 +       HTTP_LONG_CONSTANT("HTTP_URL_STRIP_ALL", HTTP_URL_STRIP_ALL);
18772 +       HTTP_LONG_CONSTANT("HTTP_URL_FROM_ENV", HTTP_URL_FROM_ENV);
18773 +       return SUCCESS;
18774 +}
18775 +
18776 +PHP_HTTP_API char *_http_absolute_url_ex(const char *url, int flags TSRMLS_DC)
18777 +{
18778 +       char *abs = NULL;
18779 +       php_url *purl = NULL;
18780 +       
18781 +       if (url) {
18782 +               purl = php_url_parse(abs = estrdup(url));
18783 +               STR_SET(abs, NULL);
18784 +               if (!purl) {
18785 +                       http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", url);
18786 +                       return NULL;
18787 +               }
18788 +       }
18789 +       
18790 +       http_build_url(flags, purl, NULL, NULL, &abs, NULL);
18791 +       
18792 +       if (purl) {
18793 +               php_url_free(purl);
18794 +       }
18795 +       
18796 +       return abs;
18797 +}
18798 +
18799 +/* {{{ void http_build_url(int flags, const php_url *, const php_url *, php_url **, char **, size_t *) */
18800 +PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC)
18801 +{
18802 +#if defined(HAVE_GETSERVBYPORT) || defined(HAVE_GETSERVBYNAME)
18803 +       struct servent *se;
18804 +#endif
18805 +       php_url *url = ecalloc(1, sizeof(php_url));
18806 +
18807 +#define __URLSET(u,n) \
18808 +       ((u)&&(u)->n)
18809 +#define __URLCPY(n) \
18810 +       url->n = __URLSET(new_url,n) ? estrdup(new_url->n) : (__URLSET(old_url,n) ? estrdup(old_url->n) : NULL)
18811 +       
18812 +       if (!(flags & HTTP_URL_STRIP_PORT)) {
18813 +               url->port = __URLSET(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0);
18814 +       }
18815 +       if (!(flags & HTTP_URL_STRIP_USER)) {
18816 +               __URLCPY(user);
18817 +       }
18818 +       if (!(flags & HTTP_URL_STRIP_PASS)) {
18819 +               __URLCPY(pass);
18820 +       }
18821 +       
18822 +       __URLCPY(scheme);
18823 +       __URLCPY(host);
18824 +       
18825 +       if (!(flags & HTTP_URL_STRIP_PATH)) {
18826 +               if ((flags & HTTP_URL_JOIN_PATH) && __URLSET(old_url, path) && __URLSET(new_url, path) && *new_url->path != '/') {
18827 +                       size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path);
18828 +                       
18829 +                       url->path = ecalloc(1, old_path_len + new_path_len + 1 + 1);
18830 +                       
18831 +                       strcat(url->path, old_url->path);
18832 +                       if (url->path[old_path_len - 1] != '/') {
18833 +                               php_dirname(url->path, old_path_len);
18834 +                               strcat(url->path, "/");
18835 +                       }
18836 +                       strcat(url->path, new_url->path);
18837 +               } else {
18838 +                       __URLCPY(path);
18839 +               }
18840 +       }
18841 +       if (!(flags & HTTP_URL_STRIP_QUERY)) {
18842 +               if ((flags & HTTP_URL_JOIN_QUERY) && __URLSET(new_url, query) && __URLSET(old_url, query)) {
18843 +                       zval qarr, qstr;
18844 +                       
18845 +                       INIT_PZVAL(&qstr);
18846 +                       INIT_PZVAL(&qarr);
18847 +                       array_init(&qarr);
18848 +                       
18849 +                       ZVAL_STRING(&qstr, old_url->query, 0);
18850 +                       http_querystring_modify(&qarr, &qstr);
18851 +                       ZVAL_STRING(&qstr, new_url->query, 0);
18852 +                       http_querystring_modify(&qarr, &qstr);
18853 +                       
18854 +                       ZVAL_NULL(&qstr);
18855 +                       http_querystring_update(&qarr, &qstr);
18856 +                       url->query = Z_STRVAL(qstr);
18857 +                       zval_dtor(&qarr);
18858 +               } else {
18859 +                       __URLCPY(query);
18860 +               }
18861 +       }
18862 +       if (!(flags & HTTP_URL_STRIP_FRAGMENT)) {
18863 +               __URLCPY(fragment);
18864 +       }
18865 +       
18866 +       if (!url->scheme) {
18867 +               if (flags & HTTP_URL_FROM_ENV) {
18868 +                       zval *https = http_get_server_var("HTTPS", 1);
18869 +                       if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
18870 +                               url->scheme = estrndup("https", lenof("https"));
18871 +                       } else switch (url->port) {
18872 +                               case 443:
18873 +                                       url->scheme = estrndup("https", lenof("https"));
18874 +                                       break;
18875 +
18876 +#ifndef HAVE_GETSERVBYPORT
18877 +                               default:
18878 +#endif
18879 +                               case 80:
18880 +                               case 0:
18881 +                                       url->scheme = estrndup("http", lenof("http"));
18882 +                                       break;
18883 +                       
18884 +#ifdef HAVE_GETSERVBYPORT
18885 +                               default:
18886 +                                       if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) {
18887 +                                               url->scheme = estrdup(se->s_name);
18888 +                                       } else {
18889 +                                               url->scheme = estrndup("http", lenof("http"));
18890 +                                       }
18891 +                                       break;
18892 +#endif
18893 +                       }
18894 +               } else {
18895 +                       url->scheme = estrndup("http", lenof("http"));
18896 +               }
18897 +       }
18898 +
18899 +       if (!url->host) {
18900 +               if (flags & HTTP_URL_FROM_ENV) {
18901 +                       zval *zhost;
18902 +                       
18903 +                       if ((((zhost = http_get_server_var("HTTP_HOST", 1)) || 
18904 +                                       (zhost = http_get_server_var("SERVER_NAME", 1)))) && Z_STRLEN_P(zhost)) {
18905 +                               url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost));
18906 +                       } else {
18907 +                               url->host = localhostname();
18908 +                       }
18909 +               } else {
18910 +                       url->host = estrndup("localhost", lenof("localhost"));
18911 +               }
18912 +       }
18913 +       
18914 +       if (!url->path) {
18915 +               if ((flags & HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) {
18916 +                       const char *q = strchr(SG(request_info).request_uri, '?');
18917 +                       
18918 +                       if (q) {
18919 +                               url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri);
18920 +                       } else {
18921 +                               url->path = estrdup(SG(request_info).request_uri);
18922 +                       }
18923 +               } else {
18924 +                       url->path = estrndup("/", 1);
18925 +               }
18926 +       } else if (url->path[0] != '/') {
18927 +               if ((flags & HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) {
18928 +                       size_t ulen = strlen(SG(request_info).request_uri);
18929 +                       size_t plen = strlen(url->path);
18930 +                       char *path;
18931 +                       
18932 +                       if (SG(request_info).request_uri[ulen-1] != '/') {
18933 +                               for (--ulen; ulen && SG(request_info).request_uri[ulen - 1] != '/'; --ulen);
18934 +                       }
18935 +                       
18936 +                       path = emalloc(ulen + plen + 1);
18937 +                       memcpy(path, SG(request_info).request_uri, ulen);
18938 +                       memcpy(path + ulen, url->path, plen);
18939 +                       path[ulen + plen] = '\0';
18940 +                       STR_SET(url->path, path);
18941 +               } else {
18942 +                       size_t plen = strlen(url->path);
18943 +                       char *path = emalloc(plen + 1 + 1);
18944 +                       
18945 +                       path[0] = '/';
18946 +                       memcpy(&path[1], url->path, plen + 1);
18947 +                       STR_SET(url->path, path);
18948 +               }
18949 +       }
18950 +       /* replace directory references if path is not a single slash */
18951 +       if (url->path[0] && (url->path[0] != '/' || url->path[1])) {
18952 +               char *ptr, *end = url->path + strlen(url->path) + 1;
18953 +                       
18954 +               for (ptr = strstr(url->path, "/."); ptr; ptr = strstr(ptr, "/.")) {
18955 +                       switch (ptr[2]) {
18956 +                               case '\0':
18957 +                                       ptr[1] = '\0';
18958 +                                       break;
18959 +                               
18960 +                               case '/':
18961 +                                       memmove(&ptr[1], &ptr[3], end - &ptr[3]);
18962 +                                       break;
18963 +                                       
18964 +                               case '.':
18965 +                                       if (ptr[3] == '/') {
18966 +                                               char *pos = &ptr[4];
18967 +                                               while (ptr != url->path) {
18968 +                                                       if (*--ptr == '/') {
18969 +                                                               break;
18970 +                                                       }
18971 +                                               }
18972 +                                               memmove(&ptr[1], pos, end - pos);
18973 +                                               break;
18974 +                                       } else if (!ptr[3]) {
18975 +                                               /* .. at the end */
18976 +                                               ptr[1] = '\0';
18977 +                                       }
18978 +                                       /* fallthrough */
18979 +                               
18980 +                               default:
18981 +                                       /* something else */
18982 +                                       ++ptr;
18983 +                                       break;
18984 +                       }
18985 +               }
18986 +       }
18987 +       
18988 +       if (url->port) {
18989 +               if (    ((url->port == 80) && !strcmp(url->scheme, "http"))
18990 +                       ||      ((url->port ==443) && !strcmp(url->scheme, "https"))
18991 +#ifdef HAVE_GETSERVBYNAME
18992 +                       ||      ((se = getservbyname(url->scheme, "tcp")) && se->s_port && 
18993 +                                       (url->port == ntohs(se->s_port)))
18994 +#endif
18995 +               ) {
18996 +                       url->port = 0;
18997 +               }
18998 +       }
18999 +       
19000 +       if (url_str) {
19001 +               size_t len;
19002 +               
19003 +               *url_str = emalloc(HTTP_URL_MAXLEN + 1);
19004 +               
19005 +               **url_str = '\0';
19006 +               strlcat(*url_str, url->scheme, HTTP_URL_MAXLEN);
19007 +               strlcat(*url_str, "://", HTTP_URL_MAXLEN);
19008 +               
19009 +               if (url->user && *url->user) {
19010 +                       strlcat(*url_str, url->user, HTTP_URL_MAXLEN);
19011 +                       if (url->pass && *url->pass) {
19012 +                               strlcat(*url_str, ":", HTTP_URL_MAXLEN);
19013 +                               strlcat(*url_str, url->pass, HTTP_URL_MAXLEN);
19014 +                       }
19015 +                       strlcat(*url_str, "@", HTTP_URL_MAXLEN);
19016 +               }
19017 +               
19018 +               strlcat(*url_str, url->host, HTTP_URL_MAXLEN);
19019 +               
19020 +               if (url->port) {
19021 +                       char port_str[8];
19022 +                       
19023 +                       snprintf(port_str, sizeof(port_str), "%d", (int) url->port);
19024 +                       strlcat(*url_str, ":", HTTP_URL_MAXLEN);
19025 +                       strlcat(*url_str, port_str, HTTP_URL_MAXLEN);
19026 +               }
19027 +               
19028 +               strlcat(*url_str, url->path, HTTP_URL_MAXLEN);
19029 +               
19030 +               if (url->query && *url->query) {
19031 +                       strlcat(*url_str, "?", HTTP_URL_MAXLEN);
19032 +                       strlcat(*url_str, url->query, HTTP_URL_MAXLEN);
19033 +               }
19034 +               
19035 +               if (url->fragment && *url->fragment) {
19036 +                       strlcat(*url_str, "#", HTTP_URL_MAXLEN);
19037 +                       strlcat(*url_str, url->fragment, HTTP_URL_MAXLEN);
19038 +               }
19039 +               
19040 +               if (HTTP_URL_MAXLEN == (len = strlen(*url_str))) {
19041 +                       http_error(HE_NOTICE, HTTP_E_URL, "Length of URL exceeds HTTP_URL_MAXLEN");
19042 +               }
19043 +               if (url_len) {
19044 +                       *url_len = len;
19045 +               }
19046 +       }
19047 +       
19048 +       if (url_ptr) {
19049 +               *url_ptr = url;
19050 +       } else {
19051 +               php_url_free(url);
19052 +       }
19053 +}
19054 +/* }}} */
19055 +
19056 +/* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
19057 +PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
19058 +       char *pre_encoded_data, size_t pre_encoded_len,
19059 +       char **encoded_data, size_t *encoded_len TSRMLS_DC)
19060 +{
19061 +       char *arg_sep;
19062 +       size_t arg_sep_len;
19063 +       phpstr *qstr = phpstr_new();
19064 +
19065 +       if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) {
19066 +               arg_sep = HTTP_URL_ARGSEP;
19067 +               arg_sep_len = lenof(HTTP_URL_ARGSEP);
19068 +       }
19069 +
19070 +       if (pre_encoded_len && pre_encoded_data) {
19071 +               phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
19072 +       }
19073 +
19074 +       if (SUCCESS != http_urlencode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) {
19075 +               phpstr_free(&qstr);
19076 +               return FAILURE;
19077 +       }
19078 +
19079 +       phpstr_data(qstr, encoded_data, encoded_len);
19080 +       phpstr_free(&qstr);
19081 +
19082 +       return SUCCESS;
19083 +}
19084 +/* }}} */
19085 +
19086 +/* {{{ http_urlencode_hash_recursive */
19087 +PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC)
19088 +{
19089 +       HashKey key = initHashKey(0);
19090 +       zval **data = NULL;
19091 +       HashPosition pos;
19092 +
19093 +       if (!ht || !str) {
19094 +               http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
19095 +               return FAILURE;
19096 +       }
19097 +       if (ht->nApplyCount > 0) {
19098 +               return SUCCESS;
19099 +       }
19100 +       
19101 +       FOREACH_HASH_KEYVAL(pos, ht, key, data) {
19102 +               char *encoded_key;
19103 +               int encoded_len;
19104 +               phpstr new_prefix;
19105 +               
19106 +               if (!data || !*data) {
19107 +                       phpstr_dtor(str);
19108 +                       return FAILURE;
19109 +               }
19110 +               
19111 +               if (key.type == HASH_KEY_IS_STRING) {
19112 +                       if (!*key.str) {
19113 +                               /* only public properties */
19114 +                               continue;
19115 +                       }
19116 +                       if (key.len && key.str[key.len - 1] == '\0') {
19117 +                               --key.len;
19118 +                       }
19119 +                       encoded_key = php_url_encode(key.str, key.len, &encoded_len);
19120 +               } else {
19121 +                       encoded_len = spprintf(&encoded_key, 0, "%ld", key.num);
19122 +               }
19123 +               
19124 +               {
19125 +                       phpstr_init(&new_prefix);
19126 +                       if (prefix && prefix_len) {
19127 +                               phpstr_append(&new_prefix, prefix, prefix_len);
19128 +                               phpstr_appends(&new_prefix, "%5B");
19129 +                       }
19130 +                       
19131 +                       phpstr_append(&new_prefix, encoded_key, encoded_len);
19132 +                       efree(encoded_key);
19133 +                       
19134 +                       if (prefix && prefix_len) {
19135 +                               phpstr_appends(&new_prefix, "%5D");
19136 +                       }
19137 +                       phpstr_fix(&new_prefix);
19138 +               }
19139 +               
19140 +               if (Z_TYPE_PP(data) == IS_ARRAY || Z_TYPE_PP(data) == IS_OBJECT) {
19141 +                       STATUS status;
19142 +                       ++ht->nApplyCount;
19143 +                       status = http_urlencode_hash_recursive(HASH_OF(*data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
19144 +                       --ht->nApplyCount;
19145 +                       if (SUCCESS != status) {
19146 +                               phpstr_dtor(&new_prefix);
19147 +                               phpstr_dtor(str);
19148 +                               return FAILURE;
19149 +                       }
19150 +               } else {
19151 +                       zval *val = http_zsep(IS_STRING, *data);
19152 +                       
19153 +                       if (PHPSTR_LEN(str)) {
19154 +                               phpstr_append(str, arg_sep, arg_sep_len);
19155 +                       }
19156 +                       phpstr_append(str, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
19157 +                       phpstr_appends(str, "=");
19158 +                       
19159 +                       if (Z_STRLEN_P(val) && Z_STRVAL_P(val)) {
19160 +                               char *encoded_val;
19161 +                               int encoded_len;
19162 +                               
19163 +                               encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len);
19164 +                               phpstr_append(str, encoded_val, encoded_len);
19165 +                               efree(encoded_val);
19166 +                       }
19167 +                       
19168 +                       zval_ptr_dtor(&val);
19169 +               }
19170 +               phpstr_dtor(&new_prefix);
19171 +       }
19172 +       return SUCCESS;
19173 +}
19174 +/* }}} */
19175 +
19176 +/*
19177 + * Local variables:
19178 + * tab-width: 4
19179 + * c-basic-offset: 4
19180 + * End:
19181 + * vim600: noet sw=4 ts=4 fdm=marker
19182 + * vim<600: noet sw=4 ts=4
19183 + */
19184 +
19185 --- /dev/null
19186 +++ b/ext/http/http_util_object.c
19187 @@ -0,0 +1,158 @@
19188 +/*
19189 +    +--------------------------------------------------------------------+
19190 +    | PECL :: http                                                       |
19191 +    +--------------------------------------------------------------------+
19192 +    | Redistribution and use in source and binary forms, with or without |
19193 +    | modification, are permitted provided that the conditions mentioned |
19194 +    | in the accompanying LICENSE file are met.                          |
19195 +    +--------------------------------------------------------------------+
19196 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
19197 +    +--------------------------------------------------------------------+
19198 +*/
19199 +
19200 +/* $Id: http_util_object.c 292841 2009-12-31 08:48:57Z mike $ */
19201 +
19202 +#include "php_http.h"
19203 +
19204 +#ifdef ZEND_ENGINE_2
19205 +
19206 +#include "ext/standard/php_http.h"
19207 +
19208 +#include "php_http_util_object.h"
19209 +
19210 +#define HTTP_BEGIN_ARGS(method, req_args)      HTTP_BEGIN_ARGS_EX(HttpUtil, method, 0, req_args)
19211 +#define HTTP_EMPTY_ARGS(method)                                HTTP_EMPTY_ARGS_EX(HttpUtil, method, 0)
19212 +
19213 +#define HTTP_UTIL_ALIAS(method, func)          HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpUtil, method))
19214 +
19215 +HTTP_BEGIN_ARGS(date, 0)
19216 +       HTTP_ARG_VAL(timestamp, 0)
19217 +HTTP_END_ARGS;
19218 +
19219 +HTTP_BEGIN_ARGS(buildStr, 1)
19220 +       HTTP_ARG_VAL(query, 0)
19221 +       HTTP_ARG_VAL(prefix, 0)
19222 +       HTTP_ARG_VAL(arg_sep, 0)
19223 +HTTP_END_ARGS;
19224 +
19225 +HTTP_BEGIN_ARGS(buildUrl, 1)
19226 +       HTTP_ARG_VAL(url, 0)
19227 +       HTTP_ARG_VAL(parts, 0)
19228 +       HTTP_ARG_VAL(flags, 0)
19229 +       HTTP_ARG_VAL(composed, 1)
19230 +HTTP_END_ARGS;
19231 +
19232 +HTTP_BEGIN_ARGS(negotiateLanguage, 1)
19233 +       HTTP_ARG_VAL(supported, 0)
19234 +       HTTP_ARG_VAL(result, 1)
19235 +HTTP_END_ARGS;
19236 +
19237 +HTTP_BEGIN_ARGS(negotiateCharset, 1)
19238 +       HTTP_ARG_VAL(supported, 0)
19239 +       HTTP_ARG_VAL(result, 1)
19240 +HTTP_END_ARGS;
19241 +
19242 +HTTP_BEGIN_ARGS(negotiateContentType, 1)
19243 +       HTTP_ARG_VAL(supported, 0)
19244 +       HTTP_ARG_VAL(result, 1)
19245 +HTTP_END_ARGS;
19246 +
19247 +HTTP_BEGIN_ARGS(matchModified, 1)
19248 +       HTTP_ARG_VAL(last_modified, 0)
19249 +       HTTP_ARG_VAL(for_range, 0)
19250 +HTTP_END_ARGS;
19251 +
19252 +HTTP_BEGIN_ARGS(matchEtag, 1)
19253 +       HTTP_ARG_VAL(plain_etag, 0)
19254 +       HTTP_ARG_VAL(for_range, 0)
19255 +HTTP_END_ARGS;
19256 +
19257 +HTTP_BEGIN_ARGS(matchRequestHeader, 2)
19258 +       HTTP_ARG_VAL(header_name, 0)
19259 +       HTTP_ARG_VAL(header_value, 0)
19260 +       HTTP_ARG_VAL(case_sensitive, 0)
19261 +HTTP_END_ARGS;
19262 +
19263 +HTTP_BEGIN_ARGS(parseMessage, 1)
19264 +       HTTP_ARG_VAL(message_string, 0)
19265 +HTTP_END_ARGS;
19266 +
19267 +HTTP_BEGIN_ARGS(parseHeaders, 1)
19268 +       HTTP_ARG_VAL(headers_string, 0)
19269 +HTTP_END_ARGS;
19270 +
19271 +HTTP_BEGIN_ARGS(parseCookie, 1)
19272 +       HTTP_ARG_VAL(cookie_string, 0)
19273 +HTTP_END_ARGS;
19274 +
19275 +HTTP_BEGIN_ARGS(buildCookie, 1)
19276 +       HTTP_ARG_VAL(cookie_array, 0)
19277 +HTTP_END_ARGS;
19278 +
19279 +HTTP_BEGIN_ARGS(parseParams, 1)
19280 +       HTTP_ARG_VAL(param_string, 0)
19281 +       HTTP_ARG_VAL(flags, 0)
19282 +HTTP_END_ARGS;
19283 +
19284 +HTTP_BEGIN_ARGS(chunkedDecode, 1)
19285 +       HTTP_ARG_VAL(encoded_string, 0)
19286 +HTTP_END_ARGS;
19287 +
19288 +#ifdef HTTP_HAVE_ZLIB
19289 +HTTP_BEGIN_ARGS(deflate, 1)
19290 +       HTTP_ARG_VAL(plain, 0)
19291 +       HTTP_ARG_VAL(flags, 0)
19292 +HTTP_END_ARGS;
19293 +
19294 +HTTP_BEGIN_ARGS(inflate, 1)
19295 +       HTTP_ARG_VAL(encoded, 0)
19296 +HTTP_END_ARGS;
19297 +#endif
19298 +
19299 +HTTP_BEGIN_ARGS(support, 0)
19300 +       HTTP_ARG_VAL(feature, 0)
19301 +HTTP_END_ARGS;
19302 +
19303 +zend_class_entry *http_util_object_ce;
19304 +zend_function_entry http_util_object_fe[] = {
19305 +       HTTP_UTIL_ALIAS(date, http_date)
19306 +       HTTP_UTIL_ALIAS(buildUrl, http_build_url)
19307 +       HTTP_UTIL_ALIAS(buildStr, http_build_str)
19308 +       HTTP_UTIL_ALIAS(negotiateLanguage, http_negotiate_language)
19309 +       HTTP_UTIL_ALIAS(negotiateCharset, http_negotiate_charset)
19310 +       HTTP_UTIL_ALIAS(negotiateContentType, http_negotiate_content_type)
19311 +       HTTP_UTIL_ALIAS(matchModified, http_match_modified)
19312 +       HTTP_UTIL_ALIAS(matchEtag, http_match_etag)
19313 +       HTTP_UTIL_ALIAS(matchRequestHeader, http_match_request_header)
19314 +       HTTP_UTIL_ALIAS(parseMessage, http_parse_message)
19315 +       HTTP_UTIL_ALIAS(parseHeaders, http_parse_headers)
19316 +       HTTP_UTIL_ALIAS(parseCookie, http_parse_cookie)
19317 +       HTTP_UTIL_ALIAS(buildCookie, http_build_cookie)
19318 +       HTTP_UTIL_ALIAS(parseParams, http_parse_params)
19319 +       HTTP_UTIL_ALIAS(chunkedDecode, http_chunked_decode)
19320 +#ifdef HTTP_HAVE_ZLIB
19321 +       HTTP_UTIL_ALIAS(deflate, http_deflate)
19322 +       HTTP_UTIL_ALIAS(inflate, http_inflate)
19323 +#endif /* HTTP_HAVE_ZLIB */
19324 +       HTTP_UTIL_ALIAS(support, http_support)
19325 +       
19326 +       EMPTY_FUNCTION_ENTRY
19327 +};
19328 +
19329 +PHP_MINIT_FUNCTION(http_util_object)
19330 +{
19331 +       HTTP_REGISTER_CLASS(HttpUtil, http_util_object, NULL, 0);
19332 +       return SUCCESS;
19333 +}
19334 +
19335 +#endif /* ZEND_ENGINE_2 */
19336 +
19337 +/*
19338 + * Local variables:
19339 + * tab-width: 4
19340 + * c-basic-offset: 4
19341 + * End:
19342 + * vim600: noet sw=4 ts=4 fdm=marker
19343 + * vim<600: noet sw=4 ts=4
19344 + */
19345 +
19346 --- /dev/null
19347 +++ b/ext/http/lib/BigGet.php
19348 @@ -0,0 +1,213 @@
19349 +<?php
19350 +
19351 +/**
19352 + * BigGet - download big files efficiently
19353 + * $Id: BigGet.php 220502 2006-09-25 08:27:32Z mike $
19354 + * 
19355 + * @copyright   Michael Wallner, <mike@iworks.at>
19356 + * @license     BSD, revised
19357 + * @version     $Revision: 220502 $
19358 + */
19359 +class BigGet extends HttpRequestPool
19360 +{
19361 +    /**
19362 +     * File split size
19363 +     */
19364 +    const SIZE = 1048576;
19365 +    
19366 +    /**
19367 +     * Parallel Request count
19368 +     */
19369 +    const RMAX = 5;
19370 +    
19371 +    /**
19372 +     * Whether to output debug messages
19373 +     * 
19374 +     * @var bool
19375 +     */
19376 +    public $dbg = false;
19377 +    
19378 +    /**
19379 +     * URL
19380 +     *
19381 +     * @var string
19382 +     */
19383 +    private $url;
19384 +    
19385 +    /**
19386 +     * Temp file prefix
19387 +     * 
19388 +     * @var string
19389 +     */
19390 +    private $tmp;
19391 +    
19392 +    /**
19393 +     * Size of requested resource
19394 +     *
19395 +     * @var int
19396 +     */
19397 +    private $size;
19398 +    
19399 +    /**
19400 +     * Whether the requests have been sent
19401 +     *
19402 +     * @var bool
19403 +     */
19404 +    private $sent = false;
19405 +    
19406 +    /**
19407 +     * Request counter
19408 +     *
19409 +     * @var int
19410 +     */
19411 +    private $count = 0;
19412 +    
19413 +    /**
19414 +     * Static constructor
19415 +     *
19416 +     * @param string $url
19417 +     * @param string $tmp
19418 +     * @return BigGet
19419 +     * @throws Exception
19420 +     */
19421 +    public static function url($url, $tmp = '/tmp')
19422 +    {
19423 +        $head = new HttpRequest($url, HttpRequest::METH_HEAD);
19424 +        $headers = $head->send()->getHeaders();
19425 +        
19426 +        if (200 != $head->getResponseCode()) {
19427 +            throw new HttpException("Did not receive '200 Ok' from HEAD $url");
19428 +        }
19429 +        if (!isset($headers['Accept-Ranges'])) {
19430 +            throw new HttpException("Did not receive an Accept-Ranges header from HEAD $url");
19431 +        }
19432 +        if (!isset($headers['Content-Length'])) {
19433 +            throw new HttpException("Did not receive a Content-Length header from HEAD $url");
19434 +        }
19435 +        
19436 +        $bigget = new BigGet;
19437 +        $bigget->url = $url;
19438 +        $bigget->tmp = tempnam($tmp, 'BigGet.');
19439 +        $bigget->size = $headers['Content-Length'];
19440 +        return $bigget;
19441 +    }
19442 +    
19443 +    /**
19444 +     * Save the resource to a file
19445 +     *
19446 +     * @param string $file
19447 +     * @return bool
19448 +     * @throws Exception
19449 +     */
19450 +    public function saveTo($file)
19451 +    {
19452 +        $this->sent or $this->send();
19453 +        
19454 +        if ($w = fopen($this->tmp, 'wb')) {
19455 +            
19456 +            $this->dbg && print "\nCopying temp files to $file ...\n";
19457 +            
19458 +            foreach (glob($this->tmp .".????") as $tmp) {
19459 +                
19460 +                $this->dbg && print "\t$tmp\n";
19461 +                
19462 +                if ($r = fopen($tmp, 'rb')) {
19463 +                    stream_copy_to_stream($r, $w);
19464 +                    fclose($r);
19465 +                }
19466 +                unlink($tmp);
19467 +            }
19468 +            fclose($w);
19469 +            rename($this->tmp, $file);
19470 +            
19471 +            $this->dbg && print "\nDone.\n";
19472 +            
19473 +            return true;
19474 +        }
19475 +        return false;
19476 +    }
19477 +    
19478 +    /**
19479 +     * Overrides HttpRequestPool::send()
19480 +     *
19481 +     * @return void
19482 +     * @throws Exception
19483 +     */
19484 +    public function send()
19485 +    {
19486 +        $this->sent = true;
19487 +        
19488 +        // use max RMAX simultanous requests with a req size of SIZE
19489 +        while ($this->count < self::RMAX && -1 != $offset = $this->getRangeOffset()) {
19490 +            $this->attachNew($offset);
19491 +        }
19492 +        
19493 +        while ($this->socketPerform()) {
19494 +            if (!$this->socketSelect()) {
19495 +                throw new HttpSocketException;
19496 +            }
19497 +        }
19498 +    }
19499 +    
19500 +    /**
19501 +     * Overrides HttpRequestPool::socketPerform()
19502 +     *
19503 +     * @return bool
19504 +     */
19505 +    protected function socketPerform()
19506 +    {
19507 +        $rs = parent::socketPerform();
19508 +        
19509 +        foreach ($this->getFinishedRequests() as $r) {
19510 +            $this->detach($r);
19511 +            
19512 +            if (206 != $rc = $r->getResponseCode()) {
19513 +                throw new HttpException("Unexpected response code: $rc");
19514 +            }
19515 +            
19516 +            file_put_contents(sprintf("%s.%04d", $this->tmp, $r->id), $r->getResponseBody());
19517 +            
19518 +            if (-1 != $offset = $this->getRangeOffset()) {
19519 +                $this->attachNew($offset);
19520 +            }
19521 +        }
19522 +        
19523 +        return $rs;
19524 +    }
19525 +    
19526 +    private function attachNew($offset)
19527 +    {
19528 +        $stop = min($this->count * self::SIZE + self::SIZE, $this->size) - 1;
19529 +        
19530 +        $this->dbg && print "Attaching new request to get range: $offset-$stop\n";
19531 +        
19532 +        $req = new BigGetRequest(
19533 +            $this->url,
19534 +            HttpRequest::METH_GET,
19535 +            array(
19536 +                'headers' => array(
19537 +                    'Range' => "bytes=$offset-$stop"
19538 +                )
19539 +            )
19540 +        );
19541 +        $this->attach($req);
19542 +        $req->id = $this->count++;
19543 +    }
19544 +    
19545 +    private function getRangeOffset()
19546 +    {
19547 +        return ($this->size >= $start = $this->count * self::SIZE) ? $start : -1;
19548 +    }
19549 +}
19550 +
19551 +
19552 +/**
19553 + * BigGet request
19554 + * @ignore
19555 + */
19556 +class BigGetRequest extends HttpRequest
19557 +{
19558 +    public $id;
19559 +}
19560 +
19561 +?>
19562 --- /dev/null
19563 +++ b/ext/http/lib/FeedAggregator.php
19564 @@ -0,0 +1,187 @@
19565 +<?php
19566 +
19567 +/**
19568 + * Simple Feed Aggregator
19569 + * $Id: FeedAggregator.php 208774 2006-03-06 16:07:19Z mike $
19570 + * 
19571 + * @copyright   Michael Wallner, <mike@iworks.at>
19572 + * @license     BSD, revised
19573 + * @package     pecl/http
19574 + * @version     $Revision: 208774 $
19575 + */
19576 +class FeedAggregator
19577 +{
19578 +    /**
19579 +     * Cache directory
19580 +     *
19581 +     * @var string
19582 +     */
19583 +    public $directory;
19584 +    
19585 +    /**
19586 +     * Feeds
19587 +     *
19588 +     * @var array
19589 +     */
19590 +    protected $feeds = array();
19591 +
19592 +    /**
19593 +     * Constructor
19594 +     *
19595 +     * @param string $directory
19596 +     */
19597 +    public function __construct($directory = 'feeds')
19598 +    {
19599 +        $this->setDirectory($directory);
19600 +    }
19601 +
19602 +    /**
19603 +     * Set cache directory
19604 +     *
19605 +     * @param string $directory
19606 +     */
19607 +    public function setDirectory($directory)
19608 +    {
19609 +        $this->directory = $directory;
19610 +        foreach (glob($this->directory .'/*.xml') as $feed) {
19611 +            $this->feeds[basename($feed, '.xml')] = filemtime($feed);
19612 +        }
19613 +    }
19614 +
19615 +    /**
19616 +     * Strips all special chars
19617 +     *
19618 +     * @param string $url
19619 +     * @return string
19620 +     */
19621 +    public function url2name($url)
19622 +    {
19623 +        return preg_replace('/[^\w\.-]+/', '_', $url);
19624 +    }
19625 +    
19626 +    /**
19627 +     * Checks if $url is a known feed
19628 +     *
19629 +     * @param string $url
19630 +     * @return bool
19631 +     */
19632 +    public function hasFeed($url)
19633 +    {
19634 +        return isset($this->feeds[$this->url2name($url)]);
19635 +    }
19636 +
19637 +    /**
19638 +     * Add an URL as feed
19639 +     *
19640 +     * @param string $url
19641 +     * @return void
19642 +     * @throws Exception
19643 +     */
19644 +    public function addFeed($url)
19645 +    {
19646 +        $r = $this->setupRequest($url);
19647 +        $r->send();
19648 +        $this->handleResponse($r);
19649 +    }
19650 +
19651 +    /**
19652 +     * Add several URLs as feeds
19653 +     *
19654 +     * @param array $urls
19655 +     * @return void
19656 +     * @throws Exception
19657 +     */
19658 +    public function addFeeds(array $urls)
19659 +    {
19660 +        $pool = new HttpRequestPool;
19661 +        foreach ($urls as $url) {
19662 +            $pool->attach($r = $this->setupRequest($url));
19663 +        }
19664 +        $pool->send();
19665 +
19666 +        foreach ($pool as $request) {
19667 +            $this->handleResponse($request);
19668 +        }
19669 +    }
19670 +
19671 +    /**
19672 +     * Load a feed (from cache)
19673 +     *
19674 +     * @param string $url
19675 +     * @return string
19676 +     * @throws Exception
19677 +     */
19678 +    public function getFeed($url)
19679 +    {
19680 +        $this->addFeed($url);
19681 +        return $this->loadFeed($this->url2name($url));
19682 +    }
19683 +
19684 +    /**
19685 +     * Load several feeds (from cache)
19686 +     *
19687 +     * @param array $urls
19688 +     * @return array
19689 +     * @throws Exception
19690 +     */
19691 +    public function getFeeds(array $urls)
19692 +    {
19693 +        $feeds = array();
19694 +        $this->addFeeds($urls);
19695 +        foreach ($urls as $url) {
19696 +            $feeds[] = $this->loadFeed($this->url2name($url));
19697 +        }
19698 +        return $feeds;
19699 +    }
19700 +
19701 +    protected function saveFeed($file, $contents)
19702 +    {
19703 +        if (file_put_contents($this->directory .'/'. $file .'.xml', $contents)) {
19704 +            $this->feeds[$file] = time();
19705 +        } else {
19706 +            throw new Exception("Could not save feed contents to $file.xml");
19707 +        }
19708 +    }
19709 +
19710 +    protected function loadFeed($file)
19711 +    {
19712 +        if (isset($this->feeds[$file])) {
19713 +            if ($data = file_get_contents($this->directory .'/'. $file .'.xml')) {
19714 +                return $data;
19715 +            } else {
19716 +                throw new Exception("Could not load feed contents from $file.xml");
19717 +            }
19718 +        } else {
19719 +            throw new Exception("Unknown feed/file $file.xml");
19720 +        }
19721 +    }
19722 +
19723 +    protected function setupRequest($url, $escape = true)
19724 +    {
19725 +        $r = new HttpRequest($url);
19726 +        $r->setOptions(array('redirect' => true));
19727 +
19728 +        $file = $escape ? $this->url2name($url) : $url;
19729 +
19730 +        if (isset($this->feeds[$file])) {
19731 +            $r->setOptions(array('lastmodified' => $this->feeds[$file]));
19732 +        }
19733 +
19734 +        return $r;
19735 +    }
19736 +
19737 +    protected function handleResponse(HttpRequest $r)
19738 +    {
19739 +        if ($r->getResponseCode() != 304) {
19740 +            if ($r->getResponseCode() != 200) {
19741 +                throw new Exception("Unexpected response code ". $r->getResponseCode());
19742 +            }
19743 +            if (!strlen($body = $r->getResponseBody())) {
19744 +                throw new Exception("Received empty feed from ". $r->getUrl());
19745 +            }
19746 +            $this->saveFeed($this->url2name($r->getUrl()), $body);
19747 +        }
19748 +    }
19749 +}
19750 +
19751 +?>
19752 --- /dev/null
19753 +++ b/ext/http/lib/PgLobStream.php
19754 @@ -0,0 +1,100 @@
19755 +<?php
19756 +
19757 +/**
19758 + * PostgreSQL LOB stream
19759 + * $Id: PgLobStream.php 210232 2006-03-27 17:41:25Z mike $
19760 + * 
19761 + * Usage:
19762 + * <code>
19763 + * // GET /image.php?image=1234
19764 + * if (PgLobStream::$loId = (int) $_GET['image']) {
19765 + *     if ($lob = fopen('pglob://dbname=database user=mike', 'r')) {
19766 + *         HttpResponse::setContentType('image/jpeg');
19767 + *         HttpResponse::setStream($lob);
19768 + *         HttpResponse::send();
19769 + *     }
19770 + * }
19771 + * </code>
19772 + * 
19773 + * @copyright   Michael Wallner, <mike@iworks.at>
19774 + * @license     BSD, revised
19775 + * @package     pecl/http
19776 + * @version     $Revision: 210232 $
19777 + */
19778 +class PgLobStream
19779 +{
19780 +    private $dbh;
19781 +    private $loh;
19782 +    private $lon;
19783 +    private $size = 0;
19784 +    
19785 +    public static $loId;
19786 +
19787 +    function stream_open($path, $mode)
19788 +    {
19789 +        $path = trim(parse_url($path, PHP_URL_HOST));
19790 +        
19791 +        if ($path) {
19792 +            if ($this->dbh = pg_connect($path)) {
19793 +                if (pg_query($this->dbh, 'BEGIN')) {
19794 +                    if (is_resource($this->loh = pg_lo_open($this->dbh, $this->lon = self::$loId, $mode))) {
19795 +                        pg_lo_seek($this->loh, 0, PGSQL_SEEK_END);
19796 +                        $this->size = (int) pg_lo_tell($this->loh);
19797 +                        pg_lo_seek($this->loh, 0, PGSQL_SEEK_SET);
19798 +                        return true;
19799 +                    }
19800 +                }
19801 +            }
19802 +        }
19803 +        return false;
19804 +    }
19805 +    
19806 +    function stream_read($length)
19807 +    {
19808 +        return pg_lo_read($this->loh, $length);
19809 +    }
19810 +    
19811 +    function stream_seek($offset, $whence = PGSQL_SEEK_SET)
19812 +    {
19813 +        return pg_lo_seek($this->loh, $offset, $whence);
19814 +    }
19815 +    
19816 +    function stream_tell()
19817 +    {
19818 +        return pg_lo_tell($this->loh);
19819 +    }
19820 +    
19821 +    function stream_eof()
19822 +    {
19823 +        return pg_lo_tell($this->loh) >= $this->size;
19824 +    }
19825 +    
19826 +    function stream_flush()
19827 +    {
19828 +        return true;
19829 +    }
19830 +    
19831 +    function stream_stat()
19832 +    {
19833 +        return array('size' => $this->size, 'ino' => $this->lon);
19834 +    }
19835 +    
19836 +    function stream_write($data)
19837 +    {
19838 +        return pg_lo_write($this->loh, $data);
19839 +    }
19840 +    
19841 +    function stream_close()
19842 +    {
19843 +        if (pg_lo_close($this->loh)) {
19844 +            return pg_query($this->dbh, 'COMMIT');
19845 +        } else {
19846 +            pg_query($this->dbh, 'ROLLBACK');
19847 +            return false;
19848 +        }
19849 +    }
19850 +}
19851 +
19852 +stream_register_wrapper('pglob', 'PgLobStream');
19853 +
19854 +?>
19855 --- /dev/null
19856 +++ b/ext/http/lib/XmlRpcClient.php
19857 @@ -0,0 +1,119 @@
19858 +<?php
19859 +
19860 +/**
19861 + * XMLRPC Client, very KISS
19862 + * $Id: XmlRpcClient.php 227268 2007-01-15 08:01:35Z mike $
19863 + * 
19864 + * NOTE: requires ext/xmlrpc
19865 + * 
19866 + * Usage:
19867 + * <code>
19868 + * <?php
19869 + * $rpc = new XmlRpcClient('http://mike:secret@example.com/cgi-bin/vpop-xmlrpc');
19870 + * $rpc->__request->setOptions(array('compress' => true));
19871 + * try {
19872 + *     print_r($rpc->vpop->listdomain(array('domain' => 'example.com')));
19873 + * } catch (Exception $ex) {
19874 + *     echo $ex;
19875 + * }
19876 + * ?>
19877 + * </code>
19878 + * 
19879 + * @copyright   Michael Wallner, <mike@iworks.at>
19880 + * @license     BSD, revised
19881 + * @package     pecl/http
19882 + * @version        $Revision: 227268 $
19883 + */
19884 +class XmlRpcClient
19885 +{
19886 +       /**
19887 +        * RPC namespace
19888 +        *
19889 +        * @var string
19890 +        */
19891 +       public $__namespace;
19892 +       
19893 +       /**
19894 +        * HttpRequest instance
19895 +        *
19896 +        * @var HttpRequest
19897 +        */
19898 +       public $__request;
19899 +       
19900 +       /**
19901 +        * Client charset
19902 +        * 
19903 +        * @var string
19904 +        */
19905 +       public $__encoding = "iso-8859-1";
19906 +       
19907 +       /**
19908 +        * RPC options
19909 +        * 
19910 +        * @var array
19911 +        */
19912 +       public $__options;
19913 +       
19914 +       /**
19915 +        * Constructor
19916 +        *
19917 +        * @param string $url RPC endpoint
19918 +        * @param string $namespace RPC namespace
19919 +        * @param array  $options HttpRequest options
19920 +        */
19921 +       public function __construct($url, $namespace = '', array $options = null)
19922 +       {
19923 +               $this->__request = new HttpRequest($url, HttpRequest::METH_POST, (array) $options);
19924 +               $this->__namespace = $namespace;
19925 +       }
19926 +       
19927 +       /**
19928 +        * RPC method proxy
19929 +        *
19930 +        * @param string $method RPC method name
19931 +        * @param array $params RPC method arguments
19932 +        * @return mixed decoded RPC response
19933 +        * @throws Exception
19934 +        */
19935 +       public function __call($method, array $params)
19936 +       {
19937 +               if (strlen($this->__namespace)) {
19938 +                       $method = $this->__namespace .'.'. $method;
19939 +               }
19940 +               $this->__request->setContentType("text/xml");
19941 +               $this->__request->setRawPostData(
19942 +                       xmlrpc_encode_request($method, $params, 
19943 +                               array("encoding" => $this->__encoding) + (array) $this->__options));
19944 +               $response = $this->__request->send();
19945 +               if ($response->getResponseCode() != 200) {
19946 +                       throw new Exception(
19947 +                               $response->getResponseStatus(), 
19948 +                               $response->getResponseCode()
19949 +                       );
19950 +               }
19951 +               
19952 +               $data = xmlrpc_decode($response->getBody(), $this->__encoding);
19953 +               if (xmlrpc_is_fault($data)) {
19954 +                       throw new Exception(
19955 +                               (string) $data['faultString'],
19956 +                               (int) $data['faultCode']
19957 +                       );
19958 +               }
19959 +               
19960 +               return $data;
19961 +       }
19962 +       
19963 +       /**
19964 +        * Returns self, where namespace is set to variable name
19965 +        *
19966 +        * @param string $ns
19967 +        * @return XmlRpcRequest
19968 +        */
19969 +       public function __get($ns)
19970 +       {
19971 +               $this->__namespace = $ns;
19972 +               return $this;
19973 +       }
19974 +}
19975 +
19976 +?>
19977 --- /dev/null
19978 +++ b/ext/http/lib/XmlRpcServer.php
19979 @@ -0,0 +1,254 @@
19980 +<?php
19981 +
19982 +XmlRpcServer::setContentType("text/xml");
19983 +XmlRpcServer::capture();
19984 +
19985 +/**
19986 + * XMLRPC Server, very KISS
19987 + * $Id: XmlRpcServer.php 227268 2007-01-15 08:01:35Z mike $
19988 + * 
19989 + * NOTE: requires ext/xmlrpc
19990 + * 
19991 + * Usage:
19992 + * <code>
19993 + * <?php
19994 + *     class Handler extends XmlRpcRequestHandlerStub {
19995 + *             public function xmlrpcPing(array $values) {
19996 + *                     return true;
19997 + *             }
19998 + *     }
19999 + *     try {
20000 + *             XmlRpcServer::factory("namespace")->registerHandler(new Handler);
20001 + *             XmlRpcServer::run();
20002 + *     } catch (Exception $ex) {
20003 + *             XmlRpcServer::error($ex->getCode(), $ex->getMessage());
20004 + *  }
20005 + * </code>
20006 + * 
20007 + * @copyright   Michael Wallner, <mike@iworks.at>
20008 + * @license     BSD, revised
20009 + * @package     pecl/http
20010 + * @version     $Revision: 227268 $
20011 + */
20012 +
20013 +class XmlRpcServer extends HttpResponse
20014 +{
20015 +       /**
20016 +        * Server charset
20017 +        *
20018 +        * @var string
20019 +        */
20020 +       public static $encoding = "iso-8859-1";
20021 +       
20022 +       /**
20023 +        * RPC namespace
20024 +        *
20025 +        * @var string
20026 +        */
20027 +       public $namespace;
20028 +       
20029 +       /**
20030 +        * RPC handler attached to this server instance
20031 +        *
20032 +        * @var XmlRpcRequestHandler
20033 +        */
20034 +       protected $handler;
20035 +       
20036 +       private static $xmlreq;
20037 +       private static $xmlrpc;
20038 +       private static $refcnt = 0;
20039 +       private static $handle = array();
20040 +       
20041 +       /**
20042 +        * Create a new XmlRpcServer instance
20043 +        *
20044 +        * @param string $namespace
20045 +        * @param string $encoding
20046 +        */
20047 +       public function __construct($namespace)
20048 +       {
20049 +               $this->namespace = $namespace;
20050 +               self::initialize();
20051 +       }
20052 +       
20053 +       /**
20054 +        * Destructor
20055 +        */
20056 +       public function __destruct()
20057 +       {
20058 +               if (self::$refcnt && !--self::$refcnt) {
20059 +                       xmlrpc_server_destroy(self::$xmlrpc);
20060 +               }
20061 +       }
20062 +       
20063 +       /**
20064 +        * Static factory
20065 +        *
20066 +        * @param string $namespace
20067 +        * @return XmlRpcServer
20068 +        */
20069 +       public static function factory($namespace)
20070 +       {
20071 +               return new XmlRpcServer($namespace);
20072 +       }
20073 +       
20074 +       /**
20075 +        * Run all servers and send response
20076 +        *
20077 +        * @param array $options
20078 +        */
20079 +       public static function run(array $options = null)
20080 +       {
20081 +               self::initialize(false, true);
20082 +               self::setContentType("text/xml; charset=". self::$encoding);
20083 +               echo xmlrpc_server_call_method(self::$xmlrpc, self::$xmlreq, null, 
20084 +                       array("encoding" => self::$encoding) + (array) $options);
20085 +       }
20086 +       
20087 +       /**
20088 +        * Test hook; call instead of XmlRpcServer::run()
20089 +        *
20090 +        * @param string $method
20091 +        * @param array $params
20092 +        * @param array $request_options
20093 +        * @param array $response_options
20094 +        */
20095 +       public static function test($method, array $params, array $request_options = null, array $response_options = null)
20096 +       {
20097 +               self::$xmlreq = xmlrpc_encode_request($method, $params, $request_options);
20098 +               self::run($response_options);
20099 +       }
20100 +       
20101 +       /**
20102 +        * Optional XMLRPC error handler
20103 +        *
20104 +        * @param int $code
20105 +        * @param string $msg
20106 +        */
20107 +       public static function error($code, $msg, array $options = null)
20108 +       {
20109 +               echo xmlrpc_encode(array("faultCode" => $code, "faultString" => $msg),
20110 +                       array("encoding" => self::$encoding) + (array) $options);
20111 +       }
20112 +       
20113 +       /**
20114 +        * Register a single method
20115 +        *
20116 +        * @param string $name
20117 +        * @param mixed $callback
20118 +        * @param mixed $dispatch
20119 +        * @param array $spec
20120 +        */
20121 +       public function registerMethod($name, $callback, $dispatch = null, array $spec = null)
20122 +       {
20123 +               if (!is_callable($callback, false, $cb_name)) {
20124 +                       throw new Exception("$cb_name is not a valid callback");
20125 +               }
20126 +               if (isset($dispatch)) {
20127 +                       if (!is_callable($dispatch, false, $cb_name)) {
20128 +                               throw new Exception("$cb_name is not a valid callback");
20129 +                       }
20130 +                       xmlrpc_server_register_method(self::$xmlrpc, $name, $dispatch);
20131 +                       self::$handle[$name] = $callback;
20132 +               } else {
20133 +                       xmlrpc_server_register_method(self::$xmlrpc, $name, $callback);
20134 +               }
20135 +               
20136 +               if (isset($spec)) {
20137 +                       xmlrpc_server_add_introspection_data(self::$xmlrpc, $spec);
20138 +               }
20139 +       }
20140 +       
20141 +       /**
20142 +        * Register an XmlRpcRequestHandler for this server instance
20143 +        *
20144 +        * @param XmlRpcRequestHandler $handler
20145 +        */
20146 +       public function registerHandler(XmlRpcRequestHandler $handler)
20147 +       {
20148 +               $this->handler = $handler;
20149 +               
20150 +               foreach (get_class_methods($handler) as $method) {
20151 +                       if (!strncmp($method, "xmlrpc", 6)) {
20152 +                               $this->registerMethod(
20153 +                                       $this->method($method, $handler->getNamespace()), 
20154 +                                       array($handler, $method), array($this, "dispatch"));
20155 +                       }
20156 +               }
20157 +               
20158 +               $handler->getIntrospectionData($spec);
20159 +               if (is_array($spec)) {
20160 +                       xmlrpc_server_add_introspection_data(self::$xmlrpc, $spec);
20161 +               }
20162 +       }
20163 +       
20164 +       private function method($method, $namespace = null)
20165 +       {
20166 +               if (!strlen($namespace)) {
20167 +                       $namespace = strlen($this->namespace) ? $this->namespace : "xmlrpc";
20168 +               }
20169 +               return $namespace .".". strtolower($method[6]) . substr($method, 7);
20170 +       }
20171 +       
20172 +       private function dispatch($method, array $params = null)
20173 +       {
20174 +               if (array_key_exists($method, self::$handle)) {
20175 +                       return call_user_func(self::$handle[$method], $params);
20176 +               }
20177 +               throw new Exception("Unknown XMLRPC method: $method");
20178 +       }
20179 +       
20180 +       private static function initialize($server = true, $data = false)
20181 +       {
20182 +               if ($data) {
20183 +                       if (!self::$xmlreq && !(self::$xmlreq = http_get_request_body())) {
20184 +                               throw new Exception("Failed to fetch XMLRPC request body");
20185 +                       }
20186 +               }
20187 +               if ($server) {
20188 +                       if (!self::$xmlrpc && !(self::$xmlrpc = xmlrpc_server_create())) {
20189 +                               throw new Exception("Failed to initialize XMLRPC server");
20190 +                       }
20191 +                       ++self::$refcnt;
20192 +               }
20193 +       }
20194 +}
20195 +
20196 +/**
20197 + * XmlRpcRequestHandler
20198 + * 
20199 + * Define XMLRPC methods with an "xmlrpc" prefix, eg:
20200 + * <code>
20201 + *     class IntOp implements XmlRpcRequestHandler {
20202 + *             public function getNamespace() {
20203 + *                     return "int";
20204 + *             }
20205 + *             public function getInstrospectionData(array &$spec = null) {
20206 + *             }
20207 + *             // XMLRPC method name: int.sumValues
20208 + *             public function xmlrpcSumValues(array $values) {
20209 + *                      return array_sum($values);
20210 + *             }
20211 + *     }
20212 + * </code>
20213 + */
20214 +interface XmlRpcRequestHandler
20215 +{
20216 +       public function getNamespace();
20217 +       public function getIntrospectionData(array &$spec = null);
20218 +}
20219 +
20220 +/**
20221 + * XmlRpcRequestHandlerStub
20222 + */
20223 +abstract class XmlRpcRequestHandlerStub implements XmlRpcRequestHandler
20224 +{
20225 +       public function getNamespace()
20226 +       {
20227 +       }
20228 +       public function getIntrospectionData(array &$spec = null)
20229 +       {
20230 +       }
20231 +}
20232 +
20233 +?>
20234 --- /dev/null
20235 +++ b/ext/http/missing.c
20236 @@ -0,0 +1,74 @@
20237 +/*
20238 +    +--------------------------------------------------------------------+
20239 +    | PECL :: http                                                       |
20240 +    +--------------------------------------------------------------------+
20241 +    | Redistribution and use in source and binary forms, with or without |
20242 +    | modification, are permitted provided that the conditions mentioned |
20243 +    | in the accompanying LICENSE file are met.                          |
20244 +    +--------------------------------------------------------------------+
20245 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
20246 +    +--------------------------------------------------------------------+
20247 +*/
20248 +
20249 +/* $Id: missing.c 292841 2009-12-31 08:48:57Z mike $ */
20250 +
20251 +#ifdef HAVE_CONFIG_H
20252 +#      include "config.h"
20253 +#endif
20254 +
20255 +#include "php.h"
20256 +#include "missing.h"
20257 +
20258 +#ifdef WONKY
20259 +int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC)
20260 +{
20261 +       zval *property = pemalloc(sizeof(zval), ce->type & ZEND_INTERNAL_CLASS);
20262 +       INIT_PZVAL(property);
20263 +       ZVAL_DOUBLE(property, value);
20264 +       return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
20265 +}
20266 +
20267 +void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC)
20268 +{
20269 +       zval *tmp = ecalloc(1, sizeof(zval));
20270 +       ZVAL_DOUBLE(tmp, value);
20271 +       zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
20272 +}
20273 +
20274 +int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC)
20275 +{
20276 +       zval *property = pemalloc(sizeof(zval), ce->type & ZEND_INTERNAL_CLASS);
20277 +       INIT_PZVAL(property);
20278 +       ZVAL_BOOL(property, value);
20279 +       return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
20280 +}
20281 +
20282 +void zend_update_property_bool(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC)
20283 +{
20284 +       zval *tmp = ecalloc(1, sizeof(zval));
20285 +       ZVAL_BOOL(tmp, value);
20286 +       zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
20287 +}
20288 +
20289 +void zend_update_property_stringl(zend_class_entry *scope, zval *object, char *name, int name_length, char *value, int value_len TSRMLS_DC)
20290 +{
20291 +       zval *tmp;
20292 +       
20293 +       ALLOC_ZVAL(tmp);
20294 +       tmp->is_ref = 0;
20295 +       tmp->refcount = 0;
20296 +       ZVAL_STRINGL(tmp, value, value_len, 1);
20297 +       zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
20298 +}
20299 +
20300 +#endif
20301 +
20302 +/*
20303 + * Local variables:
20304 + * tab-width: 4
20305 + * c-basic-offset: 4
20306 + * End:
20307 + * vim600: noet sw=4 ts=4 fdm=marker
20308 + * vim<600: noet sw=4 ts=4
20309 + */
20310 +
20311 --- /dev/null
20312 +++ b/ext/http/missing.h
20313 @@ -0,0 +1,180 @@
20314 +/*
20315 +    +--------------------------------------------------------------------+
20316 +    | PECL :: http                                                       |
20317 +    +--------------------------------------------------------------------+
20318 +    | Redistribution and use in source and binary forms, with or without |
20319 +    | modification, are permitted provided that the conditions mentioned |
20320 +    | in the accompanying LICENSE file are met.                          |
20321 +    +--------------------------------------------------------------------+
20322 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
20323 +    +--------------------------------------------------------------------+
20324 +*/
20325 +
20326 +/* $Id: missing.h 298892 2010-05-03 08:29:31Z mike $ */
20327 +
20328 +#ifndef PHP_HTTP_MISSING
20329 +#define PHP_HTTP_MISSING
20330 +
20331 +#include "php_version.h"
20332 +
20333 +#if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50399)
20334 +#      define ZEND_LITERAL_KEY_DC , const zend_literal *_zend_literal_key
20335 +#      define ZEND_LITERAL_KEY_CC , _zend_literal_key
20336 +#      define ZEND_LITERAL_NIL_CC , NULL
20337 +#      define HTTP_CHECK_OPEN_BASEDIR(file, act) \
20338 +       if ((PG(open_basedir) && *PG(open_basedir))) \
20339 +       { \
20340 +               const char *tmp = file; \
20341 + \
20342 +               if (!strncasecmp(tmp, "file:", lenof("file:"))) { \
20343 +                       tmp += lenof("file:"); \
20344 +                       while ((tmp - (const char *)file < 7) && (*tmp == '/' || *tmp == '\\')) ++tmp; \
20345 +               } \
20346 + \
20347 +               if (    (tmp != file || !strstr(file, "://")) && \
20348 +                               (!*tmp || php_check_open_basedir(tmp TSRMLS_CC))) { \
20349 +                               act; \
20350 +               } \
20351 +       }
20352 +
20353 +#else
20354 +#      define ZEND_LITERAL_KEY_DC
20355 +#      define ZEND_LITERAL_KEY_CC
20356 +#      define ZEND_LITERAL_NIL_CC
20357 +#      define HTTP_CHECK_OPEN_BASEDIR(file, act) \
20358 +       if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) \
20359 +       { \
20360 +               const char *tmp = file; \
20361 + \
20362 +               if (!strncasecmp(tmp, "file:", lenof("file:"))) { \
20363 +                       tmp += lenof("file:"); \
20364 +                       while ((tmp - (const char *)file < 7) && (*tmp == '/' || *tmp == '\\')) ++tmp; \
20365 +               } \
20366 + \
20367 +               if (    (tmp != file || !strstr(file, "://")) && \
20368 +                               (!*tmp || php_check_open_basedir(tmp TSRMLS_CC) || \
20369 +                               (PG(safe_mode) && !php_checkuid(tmp, "rb+", CHECKUID_CHECK_MODE_PARAM)))) { \
20370 +                               act; \
20371 +               } \
20372 +       }
20373 +
20374 +#endif
20375 +
20376 +#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3)
20377 +#      define HTTP_ZAPI_HASH_TSRMLS_CC TSRMLS_CC
20378 +#      define HTTP_ZAPI_HASH_TSRMLS_DC TSRMLS_DC
20379 +#      define HTTP_ZAPI_CONST_CAST(t) (const t)
20380 +#      define GLOBAL_ERROR_HANDLING EG(error_handling)
20381 +#      define GLOBAL_EXCEPTION_CLASS EG(exception_class)
20382 +#      define IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp) TSRMLS_CC)
20383 +#      define HTTP_STATIC_ARG_INFO
20384 +#else
20385 +#      define HTTP_ZAPI_HASH_TSRMLS_CC
20386 +#      define HTTP_ZAPI_HASH_TSRMLS_DC
20387 +#      define HTTP_ZAPI_CONST_CAST(t) (t)
20388 +#      define GLOBAL_ERROR_HANDLING PG(error_handling)
20389 +#      define GLOBAL_EXCEPTION_CLASS PG(exception_class)
20390 +#      define IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp))
20391 +#      define HTTP_STATIC_ARG_INFO static
20392 +#endif
20393 +
20394 +#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION == 0)
20395 +#      define WONKY
20396 +#endif
20397 +
20398 +#ifndef pemalloc_rel
20399 +#      define pemalloc_rel(size, persistent) ((persistent)?malloc(size):emalloc_rel(size))
20400 +#endif
20401 +
20402 +#ifndef ZEND_ACC_DEPRECATED
20403 +#      define ZEND_ACC_DEPRECATED 0
20404 +#endif
20405 +
20406 +#if PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION < 10
20407 +#      define php_url_parse_ex(u, l) php_url_parse(u)
20408 +#endif
20409 +
20410 +#ifndef TSRMLS_FETCH_FROM_CTX
20411 +#      ifdef ZTS
20412 +#              define TSRMLS_FETCH_FROM_CTX(ctx)       void ***tsrm_ls = (void ***) ctx
20413 +#      else
20414 +#              define TSRMLS_FETCH_FROM_CTX(ctx)
20415 +#      endif
20416 +#endif
20417 +
20418 +#ifndef TSRMLS_SET_CTX
20419 +#      ifdef ZTS
20420 +#              define TSRMLS_SET_CTX(ctx)      ctx = (void ***) tsrm_ls
20421 +#      else
20422 +#              define TSRMLS_SET_CTX(ctx)
20423 +#      endif
20424 +#endif
20425 +
20426 +#ifndef ZVAL_ADDREF
20427 +#      define ZVAL_ADDREF Z_ADDREF_P
20428 +#endif
20429 +
20430 +#ifndef SEPARATE_ARG_IF_REF
20431 +#define SEPARATE_ARG_IF_REF(zv) \
20432 +       if (PZVAL_IS_REF(zv)) { \
20433 +               zval *ov = zv; \
20434 +               ALLOC_INIT_ZVAL(zv); \
20435 +               Z_TYPE_P(zv) = Z_TYPE_P(ov); \
20436 +               zv->value = ov->value; \
20437 +               zval_copy_ctor(zv); \
20438 +       } else { \
20439 +               ZVAL_ADDREF(zv); \
20440 +       }
20441 +#endif
20442 +
20443 +#ifndef ZVAL_ZVAL
20444 +#define ZVAL_ZVAL(z, zv, copy, dtor) {  \
20445 +               int is_ref, refcount;           \
20446 +               is_ref = (z)->is_ref;           \
20447 +               refcount = (z)->refcount;       \
20448 +               *(z) = *(zv);                   \
20449 +               if (copy) {                     \
20450 +                       zval_copy_ctor(z);          \
20451 +           }                               \
20452 +               if (dtor) {                     \
20453 +                       if (!copy) {                \
20454 +                               ZVAL_NULL(zv);          \
20455 +                       }                           \
20456 +                       zval_ptr_dtor(&zv);         \
20457 +           }                               \
20458 +               (z)->is_ref = is_ref;           \
20459 +               (z)->refcount = refcount;       \
20460 +       }
20461 +#endif
20462 +#ifndef RETVAL_ZVAL
20463 +#      define RETVAL_ZVAL(zv, copy, dtor)              ZVAL_ZVAL(return_value, zv, copy, dtor)
20464 +#endif
20465 +#ifndef RETURN_ZVAL
20466 +#      define RETURN_ZVAL(zv, copy, dtor)              { RETVAL_ZVAL(zv, copy, dtor); return; }
20467 +#endif
20468 +
20469 +#ifndef ZEND_MN
20470 +#      define ZEND_MN(name) ZEND_FN(name)
20471 +#endif
20472 +
20473 +#ifdef WONKY
20474 +extern int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC);
20475 +extern void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC);
20476 +
20477 +extern int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC);
20478 +extern void zend_update_property_bool(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC);
20479 +
20480 +extern void zend_update_property_stringl(zend_class_entry *scope, zval *object, char *name, int name_length, char *value, int value_len TSRMLS_DC);
20481 +#endif
20482 +
20483 +#endif
20484 +
20485 +/*
20486 + * Local variables:
20487 + * tab-width: 4
20488 + * c-basic-offset: 4
20489 + * End:
20490 + * vim600: noet sw=4 ts=4 fdm=marker
20491 + * vim<600: noet sw=4 ts=4
20492 + */
20493 +
20494 --- /dev/null
20495 +++ b/ext/http/php_http.h
20496 @@ -0,0 +1,262 @@
20497 +/*
20498 +    +--------------------------------------------------------------------+
20499 +    | PECL :: http                                                       |
20500 +    +--------------------------------------------------------------------+
20501 +    | Redistribution and use in source and binary forms, with or without |
20502 +    | modification, are permitted provided that the conditions mentioned |
20503 +    | in the accompanying LICENSE file are met.                          |
20504 +    +--------------------------------------------------------------------+
20505 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
20506 +    +--------------------------------------------------------------------+
20507 +*/
20508 +
20509 +/* $Id: php_http.h 310776 2011-05-05 06:35:46Z mike $ */
20510 +
20511 +#ifndef PHP_EXT_HTTP_H
20512 +#define PHP_EXT_HTTP_H
20513 +
20514 +#define PHP_HTTP_VERSION "1.7.1"
20515 +
20516 +#ifdef HAVE_CONFIG_H
20517 +#      include "config.h"
20518 +#else
20519 +#      ifndef PHP_WIN32
20520 +#              include "php_config.h"
20521 +#      endif
20522 +#endif
20523 +
20524 +#include "php.h"
20525 +#include "missing.h"
20526 +#include "php_http_std_defs.h"
20527 +#include "phpstr/phpstr.h"
20528 +
20529 +#ifdef HTTP_WANT_SAPI
20530 +#      if PHP_API_VERSION > 20041225
20531 +#              define HTTP_HAVE_SAPI_RTIME
20532 +#      endif
20533 +#      include "SAPI.h"
20534 +#endif
20535 +
20536 +#ifdef HTTP_WANT_NETDB
20537 +#      ifdef PHP_WIN32
20538 +#              define HTTP_HAVE_NETDB
20539 +#              include <winsock2.h>
20540 +#      elif defined(HAVE_NETDB_H)
20541 +#              define HTTP_HAVE_NETDB
20542 +#              include <netdb.h>
20543 +#              ifdef HAVE_UNISTD_H
20544 +#                      include <unistd.h>
20545 +#              endif
20546 +#      endif
20547 +#endif
20548 +
20549 +#if defined(HTTP_WANT_CURL) && defined(HTTP_HAVE_CURL)
20550 +#      ifdef PHP_WIN32
20551 +#              include <winsock2.h>
20552 +#              define CURL_STATICLIB
20553 +#      endif
20554 +#      include <curl/curl.h>
20555 +#      define HTTP_CURL_VERSION(x, y, z) (LIBCURL_VERSION_NUM >= (((x)<<16) + ((y)<<8) + (z)))
20556 +#
20557 +#      if defined(HTTP_WANT_EVENT) && defined(HTTP_HAVE_EVENT)
20558 +#              include <event.h>
20559 +#      endif
20560 +#endif
20561 +
20562 +#if defined(HTTP_WANT_MAGIC) && defined(HTTP_HAVE_MAGIC)
20563 +#      if defined(PHP_WIN32) && !defined(USE_MAGIC_DLL) && !defined(USE_MAGIC_STATIC)
20564 +#              define USE_MAGIC_STATIC
20565 +#      endif
20566 +#      include <magic.h>
20567 +#endif
20568 +
20569 +#if defined(HTTP_WANT_ZLIB) && defined(HTTP_HAVE_ZLIB)
20570 +#      include <zlib.h>
20571 +#endif
20572 +
20573 +#include <ctype.h>
20574 +#define HTTP_IS_CTYPE(type, c) is##type((int) (unsigned char) (c))
20575 +#define HTTP_TO_CTYPE(type, c) to##type((int) (unsigned char) (c))
20576 +
20577 +extern zend_module_entry http_module_entry;
20578 +#define phpext_http_ptr &http_module_entry
20579 +
20580 +extern int http_module_number;
20581 +
20582 +ZEND_BEGIN_MODULE_GLOBALS(http)
20583 +
20584 +       struct _http_globals_etag {
20585 +               char *mode;
20586 +               void *ctx;
20587 +               zend_bool started;
20588 +       } etag;
20589 +
20590 +       struct _http_globals_log {
20591 +               char *cache;
20592 +               char *redirect;
20593 +               char *not_found;
20594 +               char *allowed_methods;
20595 +               char *composite;
20596 +       } log;
20597 +
20598 +       struct _http_globals_send {
20599 +               double throttle_delay;
20600 +               size_t buffer_size;
20601 +               char *content_type;
20602 +               char *unquoted_etag;
20603 +               time_t last_modified;
20604 +               struct _http_globals_send_deflate {
20605 +                       zend_bool response;
20606 +                       zend_bool start_auto;
20607 +                       long start_flags;
20608 +                       int encoding;
20609 +                       void *stream;
20610 +               } deflate;
20611 +               struct _http_globals_send_inflate {
20612 +                       zend_bool start_auto;
20613 +                       long start_flags;
20614 +                       void *stream;
20615 +               } inflate;
20616 +               zend_bool not_found_404;
20617 +       } send;
20618 +
20619 +       struct _http_globals_request {
20620 +               time_t time;
20621 +               HashTable *headers;
20622 +               struct _http_globals_request_methods {
20623 +                       HashTable registered;
20624 +                       char *allowed;
20625 +                       char *custom;
20626 +               } methods;
20627 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
20628 +               struct _http_globals_request_datashare {
20629 +                       zend_llist handles;
20630 +                       zend_bool cookie;
20631 +                       zend_bool dns;
20632 +                       zend_bool ssl;
20633 +                       zend_bool connect;
20634 +               } datashare;
20635 +#endif
20636 +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_EVENT)
20637 +               struct _http_globals_request_pool {
20638 +                       struct _http_globals_request_pool_event {
20639 +                               void *base;
20640 +                       } event;
20641 +               } pool;
20642 +#endif
20643 +       } request;
20644 +
20645 +       struct _http_globals_persistent {
20646 +               struct _http_globals_persistent_handles {
20647 +                       ulong limit;
20648 +                       struct _http_globals_persistent_handles_ident {
20649 +                               ulong h;
20650 +                               char *s;
20651 +                               size_t l;
20652 +                       } ident;
20653 +               } handles;
20654 +       } persistent;
20655 +
20656 +#ifdef ZEND_ENGINE_2
20657 +       zend_bool only_exceptions;
20658 +#endif
20659 +
20660 +       zend_bool force_exit;
20661 +       zend_bool read_post_data;
20662 +       zval *server_var;
20663 +
20664 +ZEND_END_MODULE_GLOBALS(http)
20665 +
20666 +ZEND_EXTERN_MODULE_GLOBALS(http);
20667 +
20668 +#ifdef ZTS
20669 +#      include "TSRM.h"
20670 +#      define HTTP_G ((zend_http_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(http_globals_id)])
20671 +#else
20672 +#      define HTTP_G (&http_globals)
20673 +#endif
20674 +
20675 +#if defined(HAVE_ICONV) && (HTTP_SHARED_DEPS || !defined(COMPILE_DL_ICONV))
20676 +#      define HTTP_HAVE_ICONV
20677 +#endif
20678 +
20679 +#if defined(HAVE_PHP_SESSION) && (HTTP_SHARED_DEPS || !defined(COMPILE_DL_SESSION))
20680 +#      define HTTP_HAVE_SESSION
20681 +#endif
20682 +
20683 +#if defined(HAVE_HASH_EXT) && (HTTP_SHARED_DEPS || !defined(COMPILE_DL_HASH)) && defined(HTTP_HAVE_PHP_HASH_H)
20684 +#      define HTTP_HAVE_HASH
20685 +#endif
20686 +
20687 +#if defined(HAVE_SPL)
20688 +#      define HTTP_HAVE_SPL
20689 +#endif
20690 +
20691 +PHP_FUNCTION(http_date);
20692 +PHP_FUNCTION(http_build_url);
20693 +PHP_FUNCTION(http_build_str);
20694 +PHP_FUNCTION(http_negotiate_language);
20695 +PHP_FUNCTION(http_negotiate_charset);
20696 +PHP_FUNCTION(http_negotiate_content_type);
20697 +PHP_FUNCTION(http_negotiate);
20698 +PHP_FUNCTION(http_redirect);
20699 +PHP_FUNCTION(http_throttle);
20700 +PHP_FUNCTION(http_send_status);
20701 +PHP_FUNCTION(http_send_last_modified);
20702 +PHP_FUNCTION(http_send_content_type);
20703 +PHP_FUNCTION(http_send_content_disposition);
20704 +PHP_FUNCTION(http_match_modified);
20705 +PHP_FUNCTION(http_match_etag);
20706 +PHP_FUNCTION(http_cache_last_modified);
20707 +PHP_FUNCTION(http_cache_etag);
20708 +PHP_FUNCTION(http_send_data);
20709 +PHP_FUNCTION(http_send_file);
20710 +PHP_FUNCTION(http_send_stream);
20711 +PHP_FUNCTION(http_chunked_decode);
20712 +PHP_FUNCTION(http_parse_message);
20713 +PHP_FUNCTION(http_parse_headers);
20714 +PHP_FUNCTION(http_parse_cookie);
20715 +PHP_FUNCTION(http_build_cookie);
20716 +PHP_FUNCTION(http_parse_params);
20717 +PHP_FUNCTION(http_get_request_headers);
20718 +PHP_FUNCTION(http_get_request_body);
20719 +PHP_FUNCTION(http_get_request_body_stream);
20720 +PHP_FUNCTION(http_match_request_header);
20721 +PHP_FUNCTION(http_persistent_handles_count);
20722 +PHP_FUNCTION(http_persistent_handles_clean);
20723 +PHP_FUNCTION(http_persistent_handles_ident);
20724 +#ifdef HTTP_HAVE_CURL
20725 +PHP_FUNCTION(http_get);
20726 +PHP_FUNCTION(http_head);
20727 +PHP_FUNCTION(http_post_data);
20728 +PHP_FUNCTION(http_post_fields);
20729 +PHP_FUNCTION(http_put_data);
20730 +PHP_FUNCTION(http_put_file);
20731 +PHP_FUNCTION(http_put_stream);
20732 +PHP_FUNCTION(http_request);
20733 +PHP_FUNCTION(http_request_body_encode);
20734 +#endif /* HTTP_HAVE_CURL */
20735 +PHP_FUNCTION(http_request_method_register);
20736 +PHP_FUNCTION(http_request_method_unregister);
20737 +PHP_FUNCTION(http_request_method_exists);
20738 +PHP_FUNCTION(http_request_method_name);
20739 +PHP_FUNCTION(ob_etaghandler);
20740 +#ifdef HTTP_HAVE_ZLIB
20741 +PHP_FUNCTION(http_deflate);
20742 +PHP_FUNCTION(http_inflate);
20743 +PHP_FUNCTION(ob_deflatehandler);
20744 +PHP_FUNCTION(ob_inflatehandler);
20745 +#endif
20746 +PHP_FUNCTION(http_support);
20747 +
20748 +#endif /* PHP_HTTP_H */
20749 +
20750 +/*
20751 + * Local variables:
20752 + * tab-width: 4
20753 + * c-basic-offset: 4
20754 + * End:
20755 + * vim600: noet sw=4 ts=4 fdm=marker
20756 + * vim<600: noet sw=4 ts=4
20757 + */
20758 +
20759 --- /dev/null
20760 +++ b/ext/http/php_http_api.h
20761 @@ -0,0 +1,318 @@
20762 +/*
20763 +    +--------------------------------------------------------------------+
20764 +    | PECL :: http                                                       |
20765 +    +--------------------------------------------------------------------+
20766 +    | Redistribution and use in source and binary forms, with or without |
20767 +    | modification, are permitted provided that the conditions mentioned |
20768 +    | in the accompanying LICENSE file are met.                          |
20769 +    +--------------------------------------------------------------------+
20770 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
20771 +    +--------------------------------------------------------------------+
20772 +*/
20773 +
20774 +/* $Id: php_http_api.h 298891 2010-05-03 08:26:38Z mike $ */
20775 +
20776 +#ifndef PHP_HTTP_API_H
20777 +#define PHP_HTTP_API_H
20778 +
20779 +#define HTTP_SUPPORT                           0x01L
20780 +#define HTTP_SUPPORT_REQUESTS          0x02L
20781 +#define HTTP_SUPPORT_MAGICMIME         0x04L
20782 +#define HTTP_SUPPORT_ENCODINGS         0x08L
20783 +#define HTTP_SUPPORT_SSLREQUESTS       0x20L
20784 +#define HTTP_SUPPORT_PERSISTENCE       0x40L
20785 +#define HTTP_SUPPORT_EVENTS                    0x80L
20786 +
20787 +#define HTTP_PARAMS_ALLOW_COMMA                0x01
20788 +#define HTTP_PARAMS_ALLOW_FAILURE      0x02
20789 +#define HTTP_PARAMS_RAISE_ERROR                0x04
20790 +#define HTTP_PARAMS_DEFAULT    (HTTP_PARAMS_ALLOW_COMMA|HTTP_PARAMS_ALLOW_FAILURE|HTTP_PARAMS_RAISE_ERROR)
20791 +#define HTTP_PARAMS_COLON_SEPARATOR    0x10
20792 +
20793 +extern PHP_MINIT_FUNCTION(http_support);
20794 +
20795 +#define http_support(f) _http_support(f)
20796 +PHP_HTTP_API long _http_support(long feature);
20797 +
20798 +#define pretty_key(key, key_len, uctitle, xhyphen) _http_pretty_key(key, key_len, uctitle, xhyphen)
20799 +extern char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen);
20800 +
20801 +#define http_boundary(b, l) _http_boundary((b), (l) TSRMLS_CC)
20802 +extern size_t _http_boundary(char *buf, size_t len TSRMLS_DC);
20803 +
20804 +#define http_error(type, code, string) _http_error_ex(type, code, "%s", string)
20805 +#define http_error_ex _http_error_ex
20806 +extern void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...);
20807 +
20808 +
20809 +#ifdef ZEND_ENGINE_2
20810 +#define http_exception_wrap(o, n, ce) _http_exception_wrap((o), (n), (ce) TSRMLS_CC)
20811 +extern zval *_http_exception_wrap(zval *old_exception, zval *new_exception, zend_class_entry *ce TSRMLS_DC);
20812 +
20813 +#define http_try \
20814 +{ \
20815 +               zval *old_exception = EG(exception); \
20816 +               EG(exception) = NULL;
20817 +#define http_catch(ex_ce) \
20818 +               if (EG(exception) && old_exception) { \
20819 +                       EG(exception) = http_exception_wrap(old_exception, EG(exception), ex_ce); \
20820 +               } \
20821 +}
20822 +#define http_final(ex_ce) \
20823 +       if (EG(exception)) { \
20824 +               EG(exception) = http_exception_wrap(EG(exception), NULL, ex_ce); \
20825 +       }
20826 +
20827 +typedef zend_object_value (*http_object_new_t)(zend_class_entry *ce, void *, void ** TSRMLS_DC);
20828 +
20829 +#define http_object_new(ov, cn, cl, co, ce, i, pp) _http_object_new((ov), (cn), (cl), (http_object_new_t) (co), (ce), (i), (void *) (pp) TSRMLS_CC)
20830 +extern STATUS _http_object_new(zend_object_value *ov, const char *cname_str, uint cname_len, http_object_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC);
20831 +#endif /* ZEND_ENGINE_2 */
20832 +
20833 +
20834 +#define HTTP_CHECK_CURL_INIT(ch, init, action) \
20835 +       if ((!(ch)) && (!((ch) = init))) { \
20836 +               http_error(HE_WARNING, HTTP_E_REQUEST, "Could not initialize curl"); \
20837 +               action; \
20838 +       }
20839 +#define HTTP_CHECK_CONTENT_TYPE(ct, action) \
20840 +       if (!strchr((ct), '/')) { \
20841 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, \
20842 +                       "Content type \"%s\" does not seem to contain a primary and a secondary part", (ct)); \
20843 +               action; \
20844 +       }
20845 +#define HTTP_CHECK_MESSAGE_TYPE_RESPONSE(msg, action) \
20846 +               if (!HTTP_MSG_TYPE(RESPONSE, (msg))) { \
20847 +                       http_error(HE_NOTICE, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_RESPONSE"); \
20848 +                       action; \
20849 +               }
20850 +#define HTTP_CHECK_MESSAGE_TYPE_REQUEST(msg, action) \
20851 +               if (!HTTP_MSG_TYPE(REQUEST, (msg))) { \
20852 +                       http_error(HE_NOTICE, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_REQUEST"); \
20853 +                       action; \
20854 +               }
20855 +#define HTTP_CHECK_GZIP_LEVEL(level, action) \
20856 +       if (level < -1 || level > 9) { \
20857 +               http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid compression level (-1 to 9): %d", level); \
20858 +               action; \
20859 +       }
20860 +
20861 +#define HTTP_CHECK_HEADERS_SENT(action) \
20862 +       if (SG(headers_sent) && !SG(request_info).no_headers) { \
20863 +               char *output_start_filename = php_get_output_start_filename(TSRMLS_C); \
20864 +               int output_start_lineno = php_get_output_start_lineno(TSRMLS_C); \
20865 +                \
20866 +               if (output_start_filename) { \
20867 +                       http_error_ex(HE_WARNING, HTTP_E_HEADER, "Cannot modify header information - headers already sent by (output started at %s:%d)", \
20868 +                               output_start_filename, output_start_lineno); \
20869 +               } else { \
20870 +                       http_error(HE_WARNING, HTTP_E_HEADER, "Cannot modify header information - headers already sent"); \
20871 +               } \
20872 +               action; \
20873 +       }
20874 +
20875 +#define http_log(f, i, m) _http_log_ex((f), (i), (m) TSRMLS_CC)
20876 +extern void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC);
20877 +
20878 +#define http_exit(s, h) http_exit_ex((s), (h), NULL, 1)
20879 +#define http_exit_ex(s, h, b, e) _http_exit_ex((s), (h), (b), (e) TSRMLS_CC)
20880 +extern STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC);
20881 +
20882 +#define http_check_method(m) http_check_method_ex((m), HTTP_KNOWN_METHODS)
20883 +#define http_check_method_ex(m, a) _http_check_method_ex((m), (a))
20884 +extern STATUS _http_check_method_ex(const char *method, const char *methods);
20885 +
20886 +#define http_got_server_var(v) (NULL != http_get_server_var_ex((v), strlen(v), 1))
20887 +#define http_get_server_var(v, c) http_get_server_var_ex((v), strlen(v), (c))
20888 +#define http_get_server_var_ex(v, l, c) _http_get_server_var_ex((v), (l), (c) TSRMLS_CC)
20889 +PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_len, zend_bool check TSRMLS_DC);
20890 +
20891 +#define http_get_request_body(b, l) _http_get_request_body_ex((b), (l), 1 TSRMLS_CC)
20892 +#define http_get_request_body_ex(b, l, d) _http_get_request_body_ex((b), (l), (d) TSRMLS_CC)
20893 +PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_bool dup TSRMLS_DC);
20894 +
20895 +#define http_get_request_body_stream() _http_get_request_body_stream(TSRMLS_C)
20896 +PHP_HTTP_API php_stream *_http_get_request_body_stream(TSRMLS_D);
20897 +
20898 +
20899 +typedef void (*http_parse_params_callback)(void *cb_arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC);
20900 +
20901 +#define http_parse_params_default_callback _http_parse_params_default_callback
20902 +PHP_HTTP_API void _http_parse_params_default_callback(void *ht, const char *key, int keylen, const char *val, int vallen TSRMLS_DC);
20903 +
20904 +#define http_parse_params(s, f, ht) _http_parse_params_ex((s), (f), _http_parse_params_default_callback, (ht) TSRMLS_CC)
20905 +#define http_parse_params_ex(s, f, cb, a) _http_parse_params_ex((s), (f), (cb), (a) TSRMLS_CC)
20906 +PHP_HTTP_API STATUS _http_parse_params_ex(const char *params, int flags, http_parse_params_callback cb, void *cb_arg TSRMLS_DC);
20907 +
20908 +
20909 +#define http_sleep(s) _http_sleep(s)
20910 +static inline void _http_sleep(double s)
20911 +{
20912 +#define HTTP_DIFFSEC (0.001)
20913 +#define HTTP_MLLISEC (1000)
20914 +#define HTTP_MCROSEC (1000 * 1000)
20915 +#define HTTP_NANOSEC (1000 * 1000 * 1000)
20916 +#define HTTP_MSEC(s) ((long)(s * HTTP_MLLISEC))
20917 +#define HTTP_USEC(s) ((long)(s * HTTP_MCROSEC))
20918 +#define HTTP_NSEC(s) ((long)(s * HTTP_NANOSEC))
20919 +
20920 +#if defined(PHP_WIN32)
20921 +       Sleep((DWORD) HTTP_MSEC(s));
20922 +#elif defined(HAVE_USLEEP)
20923 +       usleep(HTTP_USEC(s));
20924 +#elif defined(HAVE_NANOSLEEP)
20925 +       struct timespec req, rem;
20926 +
20927 +       req.tv_sec = (time_t) s;
20928 +       req.tv_nsec = HTTP_NSEC(s) % HTTP_NANOSEC;
20929 +
20930 +       while (nanosleep(&req, &rem) && (errno == EINTR) && (HTTP_NSEC(rem.tv_sec) + rem.tv_nsec) > HTTP_NSEC(HTTP_DIFFSEC))) {
20931 +               req.tv_sec = rem.tv_sec;
20932 +               req.tv_nsec = rem.tv_nsec;
20933 +       }
20934 +#else
20935 +       struct timeval timeout;
20936
20937 +       timeout.tv.sec = (time_t) s;
20938 +       timeout.tv_usec = HTTP_USEC(s) % HTTP_MCROSEC;
20939 +       
20940 +       select(0, NULL, NULL, NULL, &timeout);
20941 +#endif
20942 +}
20943 +
20944 +#define http_locate_str _http_locate_str
20945 +static inline const char *_http_locate_str(const char *h, size_t h_len, const char *n, size_t n_len)
20946 +{
20947 +       const char *p, *e;
20948 +       
20949 +       if (n_len && h_len) {
20950 +               e = h + h_len;
20951 +               do {
20952 +                       if (*h == *n) {
20953 +                               for (p = n; *p == h[p-n]; ++p) {
20954 +                                       if (p == n+n_len-1) {
20955 +                                               return h;
20956 +                                       }
20957 +                               }
20958 +                       }
20959 +               } while (h++ != e);
20960 +       }
20961 +       
20962 +       return NULL;
20963 +}
20964 +
20965 +#define http_locate_body _http_locate_body
20966 +static inline const char *_http_locate_body(const char *message)
20967 +{
20968 +       const char *body = NULL, *msg = message;
20969 +       
20970 +       while (*msg) {
20971 +               if (*msg == '\n') {
20972 +                       if (*(msg+1) == '\n') {
20973 +                               body = msg + 2;
20974 +                               break;
20975 +                       } else if (*(msg+1) == '\r' && *(msg+2) == '\n') {
20976 +                               body = msg + 3;
20977 +                               break;
20978 +                       }
20979 +               }
20980 +               ++msg;
20981 +       }
20982 +       return body;
20983 +}
20984 +
20985 +#define http_locate_eol _http_locate_eol
20986 +static inline const char *_http_locate_eol(const char *line, int *eol_len)
20987 +{
20988 +       const char *eol = strpbrk(line, "\r\n");
20989 +       
20990 +       if (eol_len) {
20991 +               *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0;
20992 +       }
20993 +       return eol;
20994 +}
20995 +
20996 +#define http_zset(t, z) _http_zset((t), (z))
20997 +static inline zval *_http_zset(int type, zval *z)
20998 +{
20999 +       if (Z_TYPE_P(z) != type) {
21000 +               switch (type) {
21001 +                       case IS_NULL:   convert_to_null(z);             break;
21002 +                       case IS_BOOL:   convert_to_boolean(z);  break;
21003 +                       case IS_LONG:   convert_to_long(z);             break;
21004 +                       case IS_DOUBLE: convert_to_double(z);   break;
21005 +                       case IS_STRING: convert_to_string(z);   break;
21006 +                       case IS_ARRAY:  convert_to_array(z);    break;
21007 +                       case IS_OBJECT: convert_to_object(z);   break;
21008 +               }
21009 +       }
21010 +       return z;
21011 +}
21012 +#define http_zsep(t, z) _http_zsep_ex((t), (z), NULL)
21013 +#define http_zsep_ex(t, z, p) _http_zsep_ex((t), (z), (p))
21014 +static inline zval *_http_zsep_ex(int type, zval *z, zval **p) {
21015 +       SEPARATE_ARG_IF_REF(z);
21016 +       if (Z_TYPE_P(z) != type) {
21017 +               switch (type) {
21018 +                       case IS_NULL:   convert_to_null_ex(&z);         break;
21019 +                       case IS_BOOL:   convert_to_boolean_ex(&z);      break;
21020 +                       case IS_LONG:   convert_to_long_ex(&z);         break;
21021 +                       case IS_DOUBLE: convert_to_double_ex(&z);       break;
21022 +                       case IS_STRING: convert_to_string_ex(&z);       break;
21023 +                       case IS_ARRAY:  convert_to_array_ex(&z);        break;
21024 +                       case IS_OBJECT: convert_to_object_ex(&z);       break;
21025 +               }
21026 +       }
21027 +       if (p) {
21028 +               *p = z;
21029 +       }
21030 +       return z;
21031 +}
21032 +
21033 +typedef struct _HashKey {
21034 +       char *str;
21035 +       uint len;
21036 +       ulong num;
21037 +       uint dup:1;
21038 +       uint type:31;
21039 +} HashKey;
21040 +#define initHashKey(dup) {NULL, 0, 0, (dup), 0}
21041 +
21042 +#define FOREACH_VAL(pos, array, val) FOREACH_HASH_VAL(pos, Z_ARRVAL_P(array), val)
21043 +#define FOREACH_HASH_VAL(pos, hash, val) \
21044 +       for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
21045 +                       zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \
21046 +                       zend_hash_move_forward_ex(hash, &pos))
21047 +
21048 +#define FOREACH_KEY(pos, array, key) FOREACH_HASH_KEY(pos, Z_ARRVAL_P(array), key)
21049 +#define FOREACH_HASH_KEY(pos, hash, _key) \
21050 +       for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
21051 +                       ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT; \
21052 +                       zend_hash_move_forward_ex(hash, &pos)) \
21053 +
21054 +#define FOREACH_KEYVAL(pos, array, key, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), key, val)
21055 +#define FOREACH_HASH_KEYVAL(pos, hash, _key, val) \
21056 +       for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
21057 +                       ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT && \
21058 +                       zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \
21059 +                       zend_hash_move_forward_ex(hash, &pos))
21060 +
21061 +#define array_copy(src, dst) zend_hash_copy(dst, src, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *))
21062 +#define ARRAY_JOIN_STRONLY 1
21063 +#define ARRAY_JOIN_PRETTIFY 2
21064 +#define array_join(src, dst, append, flags) zend_hash_apply_with_arguments(src HTTP_ZAPI_HASH_TSRMLS_CC, (append)?apply_array_append_func:apply_array_merge_func, 2, dst, (int)flags)
21065 +
21066 +extern int apply_array_append_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
21067 +extern int apply_array_merge_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
21068 +
21069 +#endif
21070 +
21071 +/*
21072 + * Local variables:
21073 + * tab-width: 4
21074 + * c-basic-offset: 4
21075 + * End:
21076 + * vim600: noet sw=4 ts=4 fdm=marker
21077 + * vim<600: noet sw=4 ts=4
21078 + */
21079 +
21080 --- /dev/null
21081 +++ b/ext/http/php_http_cache_api.h
21082 @@ -0,0 +1,162 @@
21083 +/*
21084 +    +--------------------------------------------------------------------+
21085 +    | PECL :: http                                                       |
21086 +    +--------------------------------------------------------------------+
21087 +    | Redistribution and use in source and binary forms, with or without |
21088 +    | modification, are permitted provided that the conditions mentioned |
21089 +    | in the accompanying LICENSE file are met.                          |
21090 +    +--------------------------------------------------------------------+
21091 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21092 +    +--------------------------------------------------------------------+
21093 +*/
21094 +
21095 +/* $Id: php_http_cache_api.h 292841 2009-12-31 08:48:57Z mike $ */
21096 +
21097 +#ifndef PHP_HTTP_CACHE_API_H
21098 +#define PHP_HTTP_CACHE_API_H
21099 +
21100 +#include "php_http_send_api.h"
21101 +
21102 +#include "ext/standard/crc32.h"
21103 +#include "ext/standard/sha1.h"
21104 +#include "ext/standard/md5.h"
21105 +
21106 +#ifdef HTTP_HAVE_HASH
21107 +#      include "php_hash.h"
21108 +#endif
21109 +
21110 +#define http_etag_digest(d, l) _http_etag_digest((d), (l))
21111 +static inline char *_http_etag_digest(const unsigned char *digest, int len)
21112 +{
21113 +       static const char hexdigits[17] = "0123456789abcdef";
21114 +       int i;
21115 +       char *hex = emalloc(len * 2 + 1);
21116 +       char *ptr = hex;
21117 +       
21118 +       for (i = 0; i < len; ++i) {
21119 +               *ptr++ = hexdigits[digest[i] >> 4];
21120 +               *ptr++ = hexdigits[digest[i] & 0xF];
21121 +       }
21122 +       *ptr = '\0';
21123 +       
21124 +       return hex;
21125 +}
21126 +
21127 +#define http_etag_init() _http_etag_init(TSRMLS_C)
21128 +static inline void *_http_etag_init(TSRMLS_D)
21129 +{
21130 +       void *ctx = NULL;
21131 +       char *mode = HTTP_G->etag.mode;
21132 +       
21133 +#ifdef HTTP_HAVE_HASH
21134 +       const php_hash_ops *eho = NULL;
21135 +       
21136 +       if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) {
21137 +               ctx = emalloc(eho->context_size);
21138 +               eho->hash_init(ctx);
21139 +       } else
21140 +#endif
21141 +       if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) {
21142 +               ctx = emalloc(sizeof(uint));
21143 +               *((uint *) ctx) = ~0;
21144 +       } else if (mode && !strcasecmp(mode, "sha1")) {
21145 +               PHP_SHA1Init(ctx = emalloc(sizeof(PHP_SHA1_CTX)));
21146 +       } else {
21147 +               PHP_MD5Init(ctx = emalloc(sizeof(PHP_MD5_CTX)));
21148 +       }
21149 +       
21150 +       return ctx;
21151 +}
21152 +
21153 +#define http_etag_finish(c) _http_etag_finish((c) TSRMLS_CC)
21154 +static inline char *_http_etag_finish(void *ctx TSRMLS_DC)
21155 +{
21156 +       unsigned char digest[128] = {0};
21157 +       char *etag = NULL, *mode = HTTP_G->etag.mode;
21158 +       
21159 +#ifdef HTTP_HAVE_HASH
21160 +       const php_hash_ops *eho = NULL;
21161 +       
21162 +       if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) {
21163 +               eho->hash_final(digest, ctx);
21164 +               etag = http_etag_digest(digest, eho->digest_size);
21165 +       } else
21166 +#endif
21167 +       if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) {
21168 +               *((uint *) ctx) = ~*((uint *) ctx);
21169 +               etag = http_etag_digest((const unsigned char *) ctx, sizeof(uint));
21170 +       } else if (mode && (!strcasecmp(mode, "sha1"))) {
21171 +               PHP_SHA1Final(digest, ctx);
21172 +               etag = http_etag_digest(digest, 20);
21173 +       } else {
21174 +               PHP_MD5Final(digest, ctx);
21175 +               etag = http_etag_digest(digest, 16);
21176 +       }
21177 +       efree(ctx);
21178 +       
21179 +       return etag;
21180 +}
21181 +
21182 +#define http_etag_update(c, d, l) _http_etag_update((c), (d), (l) TSRMLS_CC)
21183 +static inline void _http_etag_update(void *ctx, const char *data_ptr, size_t data_len TSRMLS_DC)
21184 +{
21185 +       char *mode = HTTP_G->etag.mode;
21186 +#ifdef HTTP_HAVE_HASH
21187 +       const php_hash_ops *eho = NULL;
21188 +       
21189 +       if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) {
21190 +               eho->hash_update(ctx, (const unsigned char *) data_ptr, data_len);
21191 +       } else
21192 +#endif
21193 +       if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) {
21194 +               uint i, c = *((uint *) ctx);
21195 +               for (i = 0; i < data_len; ++i) {
21196 +                       CRC32(c, data_ptr[i]);
21197 +               }
21198 +               *((uint *)ctx) = c;
21199 +       } else if (mode && (!strcasecmp(mode, "sha1"))) {
21200 +               PHP_SHA1Update(ctx, (const unsigned char *) data_ptr, data_len);
21201 +       } else {
21202 +               PHP_MD5Update(ctx, (const unsigned char *) data_ptr, data_len);
21203 +       }
21204 +}
21205 +
21206 +#define http_ob_etaghandler(o, l, ho, hl, m) _http_ob_etaghandler((o), (l), (ho), (hl), (m) TSRMLS_CC)
21207 +extern void _http_ob_etaghandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC);
21208 +
21209 +#define http_etag(p, l, m) _http_etag((p), (l), (m) TSRMLS_CC)
21210 +PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC);
21211 +
21212 +#define http_last_modified(p, m) _http_last_modified((p), (m) TSRMLS_CC)
21213 +PHP_HTTP_API time_t _http_last_modified(const void *data_ptr, http_send_mode data_mode TSRMLS_DC);
21214 +
21215 +#define http_match_last_modified(entry, modified) _http_match_last_modified_ex((entry), (modified), 1 TSRMLS_CC)
21216 +#define http_match_last_modified_ex(entry, modified, ep) _http_match_last_modified_ex((entry), (modified), (ep) TSRMLS_CC)
21217 +PHP_HTTP_API zend_bool _http_match_last_modified_ex(const char *entry, time_t t, zend_bool enforce_presence TSRMLS_DC);
21218 +
21219 +#define http_match_etag(entry, etag) _http_match_etag_ex((entry), (etag), 1 TSRMLS_CC)
21220 +#define http_match_etag_ex(entry, etag, ep) _http_match_etag_ex((entry), (etag), (ep) TSRMLS_CC)
21221 +PHP_HTTP_API zend_bool _http_match_etag_ex(const char *entry, const char *etag, zend_bool enforce_presence TSRMLS_DC);
21222 +
21223 +#define http_cache_last_modified(l, s, cc, ccl) _http_cache_last_modified((l), (s), (cc), (ccl) TSRMLS_CC)
21224 +PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified, time_t send_modified, const char *cache_control, size_t cc_len TSRMLS_DC);
21225 +
21226 +#define http_cache_etag(e, el, cc, ccl) _http_cache_etag((e), (el), (cc), (ccl) TSRMLS_CC)
21227 +PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len, const char *cache_control, size_t cc_len TSRMLS_DC);
21228 +
21229 +#define http_start_ob_etaghandler() _http_start_ob_etaghandler(TSRMLS_C)
21230 +PHP_HTTP_API STATUS _http_start_ob_etaghandler(TSRMLS_D);
21231 +#define http_interrupt_ob_etaghandler() _http_interrupt_ob_etaghandler(TSRMLS_C)
21232 +PHP_HTTP_API zend_bool _http_interrupt_ob_etaghandler(TSRMLS_D);
21233 +
21234 +#endif
21235 +
21236 +/*
21237 + * Local variables:
21238 + * tab-width: 4
21239 + * c-basic-offset: 4
21240 + * End:
21241 + * vim600: noet sw=4 ts=4 fdm=marker
21242 + * vim<600: noet sw=4 ts=4
21243 + */
21244 +
21245 --- /dev/null
21246 +++ b/ext/http/php_http_cookie_api.h
21247 @@ -0,0 +1,86 @@
21248 +/*
21249 +    +--------------------------------------------------------------------+
21250 +    | PECL :: http                                                       |
21251 +    +--------------------------------------------------------------------+
21252 +    | Redistribution and use in source and binary forms, with or without |
21253 +    | modification, are permitted provided that the conditions mentioned |
21254 +    | in the accompanying LICENSE file are met.                          |
21255 +    +--------------------------------------------------------------------+
21256 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21257 +    +--------------------------------------------------------------------+
21258 +*/
21259 +
21260 +/* $Id: php_http_cookie_api.h 292841 2009-12-31 08:48:57Z mike $ */
21261 +
21262 +#ifndef PHP_HTTP_COOKIE_API_H
21263 +#define PHP_HTTP_COOKIE_API_H
21264 +
21265 +#define HTTP_COOKIE_SECURE             0x10L
21266 +#define HTTP_COOKIE_HTTPONLY   0x20L
21267 +
21268 +#define HTTP_COOKIE_PARSE_RAW  0x01L
21269 +
21270 +extern PHP_MINIT_FUNCTION(http_cookie);
21271 +
21272 +/*
21273 +       generally a netscape cookie compliant struct, recognizing httpOnly attribute, too;
21274 +       cookie params like those from rfc2109 and rfc2965 are just put into extras, if
21275 +       one specifies them in allowed extras, else they're treated like cookies themself
21276 +*/
21277 +typedef struct _http_cookie_list_t {
21278 +       HashTable cookies;
21279 +       HashTable extras;
21280 +       long flags;
21281 +       char *path;
21282 +       char *domain;
21283 +       time_t expires;
21284 +} http_cookie_list;
21285 +
21286 +#define http_cookie_list_new() _http_cookie_list_init(NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21287 +#define http_cookie_list_init(l) _http_cookie_list_init((l) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21288 +PHP_HTTP_API http_cookie_list *_http_cookie_list_init(http_cookie_list *list ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21289 +
21290 +#define http_cookie_list_dtor(l) _http_cookie_list_dtor((l) TSRMLS_CC)
21291 +PHP_HTTP_API void _http_cookie_list_dtor(http_cookie_list *list TSRMLS_DC);
21292 +
21293 +#define http_cookie_list_free(l) _http_cookie_list_free((l) TSRMLS_CC)
21294 +PHP_HTTP_API void _http_cookie_list_free(http_cookie_list **list TSRMLS_DC);
21295 +
21296 +#define http_cookie_list_has_cookie(list, name, name_len) zend_hash_exists(&(list)->cookies, (name), (name_len)+1)
21297 +#define http_cookie_list_has_extra(list, name, name_len) zend_hash_exists(&(list)->extras, (name), (name_len)+1)
21298 +
21299 +#define http_cookie_list_add_cookie(l, n, nl, v, vl) _http_cookie_list_add_cookie((l), (n), (nl), (v), (vl) TSRMLS_CC)
21300 +PHP_HTTP_API void _http_cookie_list_add_cookie(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC);
21301 +
21302 +#define http_cookie_list_add_extra(l, n , nl, v, vl) _http_cookie_list_add_extra((l), (n), (nl), (v), (vl) TSRMLS_CC)
21303 +PHP_HTTP_API void _http_cookie_list_add_extra(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC);
21304 +
21305 +#define http_cookie_list_get_cookie(l, n, nl) _http_cookie_list_get_cookie((l), (n), (nl) TSRMLS_CC)
21306 +PHP_HTTP_API const char *_http_cookie_list_get_cookie(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC);
21307 +
21308 +#define http_cookie_list_get_extra(l, n, nl) _http_cookie_list_get_extra((l), (n), (nl) TSRMLS_CC)
21309 +PHP_HTTP_API const char *_http_cookie_list_get_extra(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC);
21310 +
21311 +#define http_parse_cookie(s) _http_parse_cookie_ex(NULL, (s), 0, NULL TSRMLS_CC)
21312 +#define http_parse_cookie_ex(l, s, f, a) _http_parse_cookie_ex((l), (s), (f), (a) TSRMLS_CC)
21313 +PHP_HTTP_API http_cookie_list *_http_parse_cookie_ex(http_cookie_list * list, const char *string, long flags, char **allowed_extras TSRMLS_DC);
21314 +
21315 +#define http_cookie_list_tostruct(l, s) _http_cookie_list_tostruct((l), (s) TSRMLS_CC)
21316 +PHP_HTTP_API void _http_cookie_list_tostruct(http_cookie_list *list, zval *strct TSRMLS_DC);
21317 +
21318 +#define http_cookie_list_fromstruct(l, s) _http_cookie_list_fromstruct((l), (s) TSRMLS_CC)
21319 +PHP_HTTP_API http_cookie_list *_http_cookie_list_fromstruct(http_cookie_list *list, zval *strct TSRMLS_DC);
21320 +
21321 +#define http_cookie_list_tostring(l, str, len) _http_cookie_list_tostring((l), (str), (len) TSRMLS_CC)
21322 +PHP_HTTP_API void _http_cookie_list_tostring(http_cookie_list *list, char **str, size_t *len TSRMLS_DC);
21323 +
21324 +#endif
21325 +
21326 +/*
21327 + * Local variables:
21328 + * tab-width: 4
21329 + * c-basic-offset: 4
21330 + * End:
21331 + * vim600: noet sw=4 ts=4 fdm=marker
21332 + * vim<600: noet sw=4 ts=4
21333 + */
21334 --- /dev/null
21335 +++ b/ext/http/php_http_date_api.h
21336 @@ -0,0 +1,35 @@
21337 +/*
21338 +    +--------------------------------------------------------------------+
21339 +    | PECL :: http                                                       |
21340 +    +--------------------------------------------------------------------+
21341 +    | Redistribution and use in source and binary forms, with or without |
21342 +    | modification, are permitted provided that the conditions mentioned |
21343 +    | in the accompanying LICENSE file are met.                          |
21344 +    +--------------------------------------------------------------------+
21345 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21346 +    +--------------------------------------------------------------------+
21347 +*/
21348 +
21349 +/* $Id: php_http_date_api.h 292841 2009-12-31 08:48:57Z mike $ */
21350 +
21351 +#ifndef PHP_HTTP_DATE_API_H
21352 +#define PHP_HTTP_DATE_API_H
21353 +
21354 +#define http_date(t) _http_date((t) TSRMLS_CC)
21355 +PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC);
21356 +
21357 +#define http_parse_date(d) _http_parse_date_ex((d), 0 TSRMLS_CC)
21358 +#define http_parse_date_ex(d, s) _http_parse_date_ex((d), (s) TSRMLS_CC)
21359 +PHP_HTTP_API time_t _http_parse_date_ex(const char *date, zend_bool silent TSRMLS_DC);
21360 +
21361 +#endif
21362 +
21363 +/*
21364 + * Local variables:
21365 + * tab-width: 4
21366 + * c-basic-offset: 4
21367 + * End:
21368 + * vim600: noet sw=4 ts=4 fdm=marker
21369 + * vim<600: noet sw=4 ts=4
21370 + */
21371 +
21372 --- /dev/null
21373 +++ b/ext/http/php_http_deflatestream_object.h
21374 @@ -0,0 +1,57 @@
21375 +/*
21376 +    +--------------------------------------------------------------------+
21377 +    | PECL :: http                                                       |
21378 +    +--------------------------------------------------------------------+
21379 +    | Redistribution and use in source and binary forms, with or without |
21380 +    | modification, are permitted provided that the conditions mentioned |
21381 +    | in the accompanying LICENSE file are met.                          |
21382 +    +--------------------------------------------------------------------+
21383 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21384 +    +--------------------------------------------------------------------+
21385 +*/
21386 +
21387 +/* $Id: php_http_deflatestream_object.h 292841 2009-12-31 08:48:57Z mike $ */
21388 +
21389 +#ifndef PHP_HTTP_DEFLATESTREAM_OBJECT_H
21390 +#define PHP_HTTP_DEFLATESTREAM_OBJECT_H
21391 +#ifdef HTTP_HAVE_ZLIB
21392 +#ifdef ZEND_ENGINE_2
21393 +
21394 +typedef struct _http_deflatestream_object_t {
21395 +       zend_object zo;
21396 +       http_encoding_stream *stream;
21397 +} http_deflatestream_object;
21398 +
21399 +extern zend_class_entry *http_deflatestream_object_ce;
21400 +extern zend_function_entry http_deflatestream_object_fe[];
21401 +
21402 +extern PHP_MINIT_FUNCTION(http_deflatestream_object);
21403 +
21404 +#define http_deflatestream_object_new(ce) _http_deflatestream_object_new((ce) TSRMLS_CC)
21405 +extern zend_object_value _http_deflatestream_object_new(zend_class_entry *ce TSRMLS_DC);
21406 +#define http_deflatestream_object_new_ex(ce, s, ptr) _http_deflatestream_object_new_ex((ce), (s), (ptr) TSRMLS_CC)
21407 +extern zend_object_value _http_deflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_deflatestream_object **ptr TSRMLS_DC);
21408 +#define http_deflatestream_object_clone(zobj) _http_deflatestream_object_clone_obj(zobj TSRMLS_CC)
21409 +extern zend_object_value _http_deflatestream_object_clone_obj(zval *object TSRMLS_DC);
21410 +#define http_deflatestream_object_free(o) _http_deflatestream_object_free((o) TSRMLS_CC)
21411 +extern void _http_deflatestream_object_free(zend_object *object TSRMLS_DC);
21412 +
21413 +PHP_METHOD(HttpDeflateStream, __construct);
21414 +PHP_METHOD(HttpDeflateStream, factory);
21415 +PHP_METHOD(HttpDeflateStream, update);
21416 +PHP_METHOD(HttpDeflateStream, flush);
21417 +PHP_METHOD(HttpDeflateStream, finish);
21418 +
21419 +#endif
21420 +#endif
21421 +#endif
21422 +
21423 +/*
21424 + * Local variables:
21425 + * tab-width: 4
21426 + * c-basic-offset: 4
21427 + * End:
21428 + * vim600: noet sw=4 ts=4 fdm=marker
21429 + * vim<600: noet sw=4 ts=4
21430 + */
21431 +
21432 --- /dev/null
21433 +++ b/ext/http/php_http_encoding_api.h
21434 @@ -0,0 +1,192 @@
21435 +/*
21436 +    +--------------------------------------------------------------------+
21437 +    | PECL :: http                                                       |
21438 +    +--------------------------------------------------------------------+
21439 +    | Redistribution and use in source and binary forms, with or without |
21440 +    | modification, are permitted provided that the conditions mentioned |
21441 +    | in the accompanying LICENSE file are met.                          |
21442 +    +--------------------------------------------------------------------+
21443 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21444 +    +--------------------------------------------------------------------+
21445 +*/
21446 +
21447 +/* $Id: php_http_encoding_api.h 292841 2009-12-31 08:48:57Z mike $ */
21448 +
21449 +#ifndef PHP_HTTP_ENCODING_API_H
21450 +#define PHP_HTTP_ENCODING_API_H
21451 +
21452 +#define http_encoding_dechunk(e, el, d, dl) _http_encoding_dechunk((e), (el), (d), (dl) TSRMLS_CC)
21453 +PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC);
21454 +
21455 +#define http_encoding_response_start(cl, i) _http_encoding_response_start((cl), (i) TSRMLS_CC)
21456 +PHP_HTTP_API int _http_encoding_response_start(size_t content_length, zend_bool ignore_http_ohandler TSRMLS_DC);
21457 +
21458 +#ifdef HTTP_HAVE_ZLIB
21459 +
21460 +extern PHP_MINIT_FUNCTION(http_encoding);
21461 +extern PHP_RINIT_FUNCTION(http_encoding);
21462 +extern PHP_RSHUTDOWN_FUNCTION(http_encoding);
21463 +
21464 +typedef enum _http_encoding_type_t {
21465 +       HTTP_ENCODING_NONE,
21466 +       HTTP_ENCODING_GZIP,
21467 +       HTTP_ENCODING_DEFLATE,
21468 +} http_encoding_type;
21469 +
21470 +#define HTTP_INFLATE_ROUNDS 100
21471 +
21472 +#define HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \
21473 +       (((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1)
21474 +#define HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \
21475 +       (((S) + 1) << 3)
21476 +#define HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \
21477 +       ((S) += (S) >> (3))
21478 +
21479 +#define HTTP_DEFLATE_BUFFER_SIZE               0x8000
21480 +#define HTTP_INFLATE_BUFFER_SIZE               0x1000
21481 +
21482 +#define HTTP_DEFLATE_LEVEL_DEF                 0x00000000
21483 +#define HTTP_DEFLATE_LEVEL_MIN                 0x00000001
21484 +#define HTTP_DEFLATE_LEVEL_MAX                 0x00000009
21485 +#define HTTP_DEFLATE_TYPE_ZLIB                 0x00000000
21486 +#define HTTP_DEFLATE_TYPE_GZIP                 0x00000010
21487 +#define HTTP_DEFLATE_TYPE_RAW                  0x00000020
21488 +#define HTTP_DEFLATE_STRATEGY_DEF              0x00000000
21489 +#define HTTP_DEFLATE_STRATEGY_FILT             0x00000100
21490 +#define HTTP_DEFLATE_STRATEGY_HUFF             0x00000200
21491 +#define HTTP_DEFLATE_STRATEGY_RLE              0x00000300
21492 +#define HTTP_DEFLATE_STRATEGY_FIXED            0x00000400
21493 +
21494 +#define HTTP_DEFLATE_LEVEL_SET(flags, level) \
21495 +       switch (flags & 0xf) \
21496 +       { \
21497 +               default: \
21498 +                       if ((flags & 0xf) < 10) { \
21499 +                               level = flags & 0xf; \
21500 +                               break; \
21501 +                       } \
21502 +               case HTTP_DEFLATE_LEVEL_DEF: \
21503 +                       level = Z_DEFAULT_COMPRESSION; \
21504 +               break; \
21505 +       }
21506 +       
21507 +#define HTTP_DEFLATE_WBITS_SET(flags, wbits) \
21508 +       switch (flags & 0xf0) \
21509 +       { \
21510 +               case HTTP_DEFLATE_TYPE_GZIP: \
21511 +                       wbits = HTTP_WINDOW_BITS_GZIP; \
21512 +               break; \
21513 +               case HTTP_DEFLATE_TYPE_RAW: \
21514 +                       wbits = HTTP_WINDOW_BITS_RAW; \
21515 +               break; \
21516 +               default: \
21517 +                       wbits = HTTP_WINDOW_BITS_ZLIB; \
21518 +               break; \
21519 +       }
21520 +
21521 +#define HTTP_INFLATE_WBITS_SET(flags, wbits) \
21522 +       if (flags & HTTP_INFLATE_TYPE_RAW) { \
21523 +               wbits = HTTP_WINDOW_BITS_RAW; \
21524 +} else { \
21525 +               wbits = HTTP_WINDOW_BITS_ANY; \
21526 +}
21527 +
21528 +#define HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \
21529 +       switch (flags & 0xf00) \
21530 +       { \
21531 +               case HTTP_DEFLATE_STRATEGY_FILT: \
21532 +                       strategy = Z_FILTERED; \
21533 +               break; \
21534 +               case HTTP_DEFLATE_STRATEGY_HUFF: \
21535 +                       strategy = Z_HUFFMAN_ONLY; \
21536 +               break; \
21537 +               case HTTP_DEFLATE_STRATEGY_RLE: \
21538 +                       strategy = Z_RLE; \
21539 +               break; \
21540 +               case HTTP_DEFLATE_STRATEGY_FIXED: \
21541 +                       strategy = Z_FIXED; \
21542 +               break; \
21543 +               default: \
21544 +                       strategy = Z_DEFAULT_STRATEGY; \
21545 +               break; \
21546 +       }
21547 +
21548 +#define HTTP_WINDOW_BITS_ZLIB  0x0000000f
21549 +#define HTTP_WINDOW_BITS_GZIP  0x0000001f
21550 +#define HTTP_WINDOW_BITS_ANY   0x0000002f
21551 +#define HTTP_WINDOW_BITS_RAW   -0x000000f
21552 +
21553 +#ifndef Z_FIXED
21554 +/* Z_FIXED does not exist prior 1.2.2.2 */
21555 +#      define Z_FIXED 0
21556 +#endif
21557 +
21558 +#define HTTP_INFLATE_TYPE_ZLIB                 0x00000000
21559 +#define HTTP_INFLATE_TYPE_GZIP                 0x00000000
21560 +#define HTTP_INFLATE_TYPE_RAW                  0x00000001
21561 +
21562 +#define HTTP_ENCODING_STREAM_FLUSH_NONE        0x00000000
21563 +#define HTTP_ENCODING_STREAM_FLUSH_SYNC 0x00100000
21564 +#define HTTP_ENCODING_STREAM_FLUSH_FULL 0x00200000
21565 +
21566 +#define HTTP_ENCODING_STREAM_FLUSH_FLAG(f) \
21567 +       (((f) & HTTP_ENCODING_STREAM_FLUSH_FULL) ? Z_FULL_FLUSH : \
21568 +       (((f) & HTTP_ENCODING_STREAM_FLUSH_SYNC) ? Z_SYNC_FLUSH : Z_NO_FLUSH))
21569 +
21570 +#define HTTP_ENCODING_STREAM_PERSISTENT        0x01000000
21571 +
21572 +typedef struct _http_encoding_stream_t {
21573 +       z_stream stream;
21574 +       int flags;
21575 +       void *storage;
21576 +} http_encoding_stream;
21577 +
21578 +#define http_encoding_deflate(f, d, dl, r, rl) _http_encoding_deflate((f), (d), (dl), (r), (rl) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21579 +PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21580 +#define http_encoding_inflate(d, dl, r, rl) _http_encoding_inflate((d), (dl), (r), (rl) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21581 +PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21582 +
21583 +#define http_encoding_deflate_stream_init(s, f) _http_encoding_deflate_stream_init((s), (f) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21584 +PHP_HTTP_API http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21585 +#define http_encoding_deflate_stream_update(s, d, dl, e, el) _http_encoding_deflate_stream_update((s), (d), (dl), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21586 +PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21587 +#define http_encoding_deflate_stream_flush(s, e, el) _http_encoding_deflate_stream_flush((s), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21588 +PHP_HTTP_API STATUS _http_encoding_deflate_stream_flush(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21589 +#define http_encoding_deflate_stream_finish(s, e, el) _http_encoding_deflate_stream_finish((s), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21590 +PHP_HTTP_API STATUS _http_encoding_deflate_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21591 +#define http_encoding_deflate_stream_dtor(s) _http_encoding_deflate_stream_dtor((s) TSRMLS_CC)
21592 +PHP_HTTP_API void _http_encoding_deflate_stream_dtor(http_encoding_stream *s TSRMLS_DC);
21593 +#define http_encoding_deflate_stream_free(s) _http_encoding_deflate_stream_free((s) TSRMLS_CC)
21594 +PHP_HTTP_API void _http_encoding_deflate_stream_free(http_encoding_stream **s TSRMLS_DC);
21595 +
21596 +#define http_encoding_inflate_stream_init(s, f) _http_encoding_inflate_stream_init((s), (f) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21597 +PHP_HTTP_API http_encoding_stream *_http_encoding_inflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21598 +#define http_encoding_inflate_stream_update(s, d, dl, e, el) _http_encoding_inflate_stream_update((s), (d), (dl), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21599 +PHP_HTTP_API STATUS _http_encoding_inflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21600 +#define http_encoding_inflate_stream_flush(s, d, dl) _http_encoding_inflate_stream_flush((s), (d), (dl) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21601 +PHP_HTTP_API STATUS _http_encoding_inflate_stream_flush(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21602 +#define http_encoding_inflate_stream_finish(s, e, el) _http_encoding_inflate_stream_finish((s), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
21603 +PHP_HTTP_API STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
21604 +#define http_encoding_inflate_stream_dtor(s) _http_encoding_inflate_stream_dtor((s) TSRMLS_CC)
21605 +PHP_HTTP_API void _http_encoding_inflate_stream_dtor(http_encoding_stream *s TSRMLS_DC);
21606 +#define http_encoding_inflate_stream_free(s) _http_encoding_inflate_stream_free((s) TSRMLS_CC)
21607 +PHP_HTTP_API void _http_encoding_inflate_stream_free(http_encoding_stream **s TSRMLS_DC);
21608 +
21609 +#define http_ob_deflatehandler(o, ol, h, hl, m) _http_ob_deflatehandler((o), (ol), (h), (hl), (m) TSRMLS_CC)
21610 +extern void _http_ob_deflatehandler(char *, uint, char **, uint *, int TSRMLS_DC);
21611 +
21612 +#define http_ob_inflatehandler(o, ol, h, hl, m) _http_ob_inflatehandler((o), (ol), (h), (hl), (m) TSRMLS_CC)
21613 +extern void _http_ob_inflatehandler(char *, uint, char **, uint *, int TSRMLS_DC);
21614 +
21615 +#endif /* HTTP_HAVE_ZLIB */
21616 +
21617 +#endif
21618 +
21619 +/*
21620 + * Local variables:
21621 + * tab-width: 4
21622 + * c-basic-offset: 4
21623 + * End:
21624 + * vim600: noet sw=4 ts=4 fdm=marker
21625 + * vim<600: noet sw=4 ts=4
21626 + */
21627 --- /dev/null
21628 +++ b/ext/http/php_http_exception_object.h
21629 @@ -0,0 +1,60 @@
21630 +/*
21631 +    +--------------------------------------------------------------------+
21632 +    | PECL :: http                                                       |
21633 +    +--------------------------------------------------------------------+
21634 +    | Redistribution and use in source and binary forms, with or without |
21635 +    | modification, are permitted provided that the conditions mentioned |
21636 +    | in the accompanying LICENSE file are met.                          |
21637 +    +--------------------------------------------------------------------+
21638 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21639 +    +--------------------------------------------------------------------+
21640 +*/
21641 +
21642 +/* $Id: php_http_exception_object.h 292841 2009-12-31 08:48:57Z mike $ */
21643 +
21644 +#ifndef PHP_HTTP_EXCEPTION_OBJECT_H
21645 +#define PHP_HTTP_EXCEPTION_OBJECT_H
21646 +#ifdef ZEND_ENGINE_2
21647 +
21648 +#include "zend_exceptions.h"
21649 +
21650 +PHP_MINIT_FUNCTION(http_exception_object);
21651 +
21652 +#define HTTP_EX_DEF_CE http_exception_object_ce
21653 +#define HTTP_EX_CE(name) http_ ##name## _exception_object_ce
21654 +
21655 +extern zend_class_entry *http_exception_object_ce;
21656 +extern zend_class_entry *HTTP_EX_CE(runtime);
21657 +extern zend_class_entry *HTTP_EX_CE(header);
21658 +extern zend_class_entry *HTTP_EX_CE(malformed_headers);
21659 +extern zend_class_entry *HTTP_EX_CE(request_method);
21660 +extern zend_class_entry *HTTP_EX_CE(message_type);
21661 +extern zend_class_entry *HTTP_EX_CE(invalid_param);
21662 +extern zend_class_entry *HTTP_EX_CE(encoding);
21663 +extern zend_class_entry *HTTP_EX_CE(request);
21664 +extern zend_class_entry *HTTP_EX_CE(request_pool);
21665 +extern zend_class_entry *HTTP_EX_CE(socket);
21666 +extern zend_class_entry *HTTP_EX_CE(response);
21667 +extern zend_class_entry *HTTP_EX_CE(url);
21668 +extern zend_function_entry http_exception_object_fe[];
21669 +
21670 +#define http_exception_get_default _http_exception_get_default
21671 +extern zend_class_entry *_http_exception_get_default();
21672 +
21673 +#define http_exception_get_for_code(c) _http_exception_get_for_code(c)
21674 +extern zend_class_entry *_http_exception_get_for_code(long code);
21675 +
21676 +PHP_METHOD(HttpException, __toString);
21677 +
21678 +#endif
21679 +#endif
21680 +
21681 +/*
21682 + * Local variables:
21683 + * tab-width: 4
21684 + * c-basic-offset: 4
21685 + * End:
21686 + * vim600: noet sw=4 ts=4 fdm=marker
21687 + * vim<600: noet sw=4 ts=4
21688 + */
21689 +
21690 --- /dev/null
21691 +++ b/ext/http/php_http_filter_api.h
21692 @@ -0,0 +1,33 @@
21693 +/*
21694 +    +--------------------------------------------------------------------+
21695 +    | PECL :: http                                                       |
21696 +    +--------------------------------------------------------------------+
21697 +    | Redistribution and use in source and binary forms, with or without |
21698 +    | modification, are permitted provided that the conditions mentioned |
21699 +    | in the accompanying LICENSE file are met.                          |
21700 +    +--------------------------------------------------------------------+
21701 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21702 +    +--------------------------------------------------------------------+
21703 +*/
21704 +
21705 +/* $Id: php_http_filter_api.h 292841 2009-12-31 08:48:57Z mike $ */
21706 +
21707 +#ifndef PHP_HTTP_FILTER_API_H
21708 +#define PHP_HTTP_FILTER_API_H
21709 +#ifdef ZEND_ENGINE_2
21710 +
21711 +extern php_stream_filter_factory http_filter_factory;
21712 +PHP_MINIT_FUNCTION(http_filter);
21713 +
21714 +#endif
21715 +#endif
21716 +
21717 +/*
21718 + * Local variables:
21719 + * tab-width: 4
21720 + * c-basic-offset: 4
21721 + * End:
21722 + * vim600: noet sw=4 ts=4 fdm=marker
21723 + * vim<600: noet sw=4 ts=4
21724 + */
21725 +
21726 --- /dev/null
21727 +++ b/ext/http/php_http_headers_api.h
21728 @@ -0,0 +1,77 @@
21729 +/*
21730 +    +--------------------------------------------------------------------+
21731 +    | PECL :: http                                                       |
21732 +    +--------------------------------------------------------------------+
21733 +    | Redistribution and use in source and binary forms, with or without |
21734 +    | modification, are permitted provided that the conditions mentioned |
21735 +    | in the accompanying LICENSE file are met.                          |
21736 +    +--------------------------------------------------------------------+
21737 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21738 +    +--------------------------------------------------------------------+
21739 +*/
21740 +
21741 +/* $Id: php_http_headers_api.h 300300 2010-06-09 07:29:35Z mike $ */
21742 +
21743 +#ifndef PHP_HTTP_HEADERS_API_H
21744 +#define PHP_HTTP_HEADERS_API_H
21745 +
21746 +#include "php_http_info_api.h"
21747 +
21748 +typedef enum http_range_status_t {
21749 +       RANGE_OK,
21750 +       RANGE_NO,
21751 +       RANGE_ERR
21752 +} http_range_status;
21753 +
21754 +#define http_parse_headers(h, a) _http_parse_headers_ex((h), Z_ARRVAL_P(a), 1, http_info_default_callback, NULL TSRMLS_CC)
21755 +#define http_parse_headers_ex(h, ht, p) _http_parse_headers_ex((h), (ht), (p), http_info_default_callback, NULL TSRMLS_CC)
21756 +#define http_parse_headers_cb(h, ht, p, f, d) _http_parse_headers_ex((h), (ht), (p), (f), (d) TSRMLS_CC)
21757 +PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_info_callback callback_func, void **callback_data TSRMLS_DC);
21758 +
21759 +typedef char *(*negotiate_func_t)(const char *test, double *quality, HashTable *supported TSRMLS_DC);
21760 +
21761 +#define http_negotiate_language_func _http_negotiate_language_func
21762 +extern char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC);
21763 +#define http_negotiate_content_type_func _http_negotiate_default_func
21764 +#define http_negotiate_encoding_func _http_negotiate_default_func
21765 +#define http_negotiate_charset_func _http_negotiate_default_func
21766 +#define http_negotiate_default_func _http_negotiate_default_func
21767 +extern char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC);
21768 +
21769 +#define http_negotiate_language(zsupported) http_negotiate_language_ex(Z_ARRVAL_P(zsupported))
21770 +#define http_negotiate_language_ex(supported) http_negotiate_q("HTTP_ACCEPT_LANGUAGE", (supported), http_negotiate_language_func)
21771 +#define http_negotiate_charset(zsupported) http_negotiate_charset_ex(Z_ARRVAL_P(zsupported))
21772 +#define http_negotiate_charset_ex(supported)  http_negotiate_q("HTTP_ACCEPT_CHARSET", (supported), http_negotiate_charset_func)
21773 +#define http_negotiate_encoding(zsupported) http_negotiate_encoding_ex(Z_ARRVAL_P(zsupported))
21774 +#define http_negotiate_encoding_ex(supported)  http_negotiate_q("HTTP_ACCEPT_ENCODING", (supported), http_negotiate_encoding_func)
21775 +#define http_negotiate_content_type(zsupported) http_negotiate_content_type_ex(Z_ARRVAL_P(zsupported))
21776 +#define http_negotiate_content_type_ex(supported) http_negotiate_q("HTTP_ACCEPT", (supported), http_negotiate_content_type_func)
21777 +#define http_negotiate_q(e, s, n) _http_negotiate_q((e), (s), (n) TSRMLS_CC)
21778 +PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC);
21779 +#define http_negotiate_z(z, s, n) _http_negotiate_z((z), (s), (n) TSRMLS_CC)
21780 +PHP_HTTP_API HashTable *_http_negotiate_z(zval *value, HashTable *supported, negotiate_func_t neg TSRMLS_DC);
21781 +
21782 +#define http_get_request_ranges(r, l) _http_get_request_ranges((r), (l) TSRMLS_CC)
21783 +PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, size_t length TSRMLS_DC);
21784 +
21785 +#define http_get_request_headers(h) _http_get_request_headers((h) TSRMLS_CC)
21786 +PHP_HTTP_API void _http_get_request_headers(HashTable *headers TSRMLS_DC);
21787 +
21788 +#define http_get_response_headers(h) _http_get_response_headers((h) TSRMLS_CC)
21789 +PHP_HTTP_API STATUS _http_get_response_headers(HashTable *headers_ht TSRMLS_DC);
21790 +
21791 +#define http_match_request_header(h, v) http_match_request_header_ex((h), (v), 0)
21792 +#define http_match_request_header_ex(h, v, c) _http_match_request_header_ex((h), (v), (c) TSRMLS_CC)
21793 +PHP_HTTP_API zend_bool _http_match_request_header_ex(const char *header, const char *value, zend_bool match_case TSRMLS_DC);
21794 +
21795 +#endif
21796 +
21797 +/*
21798 + * Local variables:
21799 + * tab-width: 4
21800 + * c-basic-offset: 4
21801 + * End:
21802 + * vim600: noet sw=4 ts=4 fdm=marker
21803 + * vim<600: noet sw=4 ts=4
21804 + */
21805 +
21806 --- /dev/null
21807 +++ b/ext/http/php_http_inflatestream_object.h
21808 @@ -0,0 +1,57 @@
21809 +/*
21810 +    +--------------------------------------------------------------------+
21811 +    | PECL :: http                                                       |
21812 +    +--------------------------------------------------------------------+
21813 +    | Redistribution and use in source and binary forms, with or without |
21814 +    | modification, are permitted provided that the conditions mentioned |
21815 +    | in the accompanying LICENSE file are met.                          |
21816 +    +--------------------------------------------------------------------+
21817 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21818 +    +--------------------------------------------------------------------+
21819 +*/
21820 +
21821 +/* $Id: php_http_inflatestream_object.h 292841 2009-12-31 08:48:57Z mike $ */
21822 +
21823 +#ifndef PHP_HTTP_INFLATESTREAM_OBJECT_H
21824 +#define PHP_HTTP_INFLATESTREAM_OBJECT_H
21825 +#ifdef HTTP_HAVE_ZLIB
21826 +#ifdef ZEND_ENGINE_2
21827 +
21828 +typedef struct _http_inflatestream_object_t {
21829 +       zend_object zo;
21830 +       http_encoding_stream *stream;
21831 +} http_inflatestream_object;
21832 +
21833 +extern zend_class_entry *http_inflatestream_object_ce;
21834 +extern zend_function_entry http_inflatestream_object_fe[];
21835 +
21836 +extern PHP_MINIT_FUNCTION(http_inflatestream_object);
21837 +
21838 +#define http_inflatestream_object_new(ce) _http_inflatestream_object_new((ce) TSRMLS_CC)
21839 +extern zend_object_value _http_inflatestream_object_new(zend_class_entry *ce TSRMLS_DC);
21840 +#define http_inflatestream_object_new_ex(ce, s, ptr) _http_inflatestream_object_new_ex((ce), (s), (ptr) TSRMLS_CC)
21841 +extern zend_object_value _http_inflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_inflatestream_object **ptr TSRMLS_DC);
21842 +#define http_inflatestream_object_clone(zobj) _http_inflatestream_object_clone_obj(zobj TSRMLS_CC)
21843 +extern zend_object_value _http_inflatestream_object_clone_obj(zval *object TSRMLS_DC);
21844 +#define http_inflatestream_object_free(o) _http_inflatestream_object_free((o) TSRMLS_CC)
21845 +extern void _http_inflatestream_object_free(zend_object *object TSRMLS_DC);
21846 +
21847 +PHP_METHOD(HttpInflateStream, __construct);
21848 +PHP_METHOD(HttpInflateStream, factory);
21849 +PHP_METHOD(HttpInflateStream, update);
21850 +PHP_METHOD(HttpInflateStream, flush);
21851 +PHP_METHOD(HttpInflateStream, finish);
21852 +
21853 +#endif
21854 +#endif
21855 +#endif
21856 +
21857 +/*
21858 + * Local variables:
21859 + * tab-width: 4
21860 + * c-basic-offset: 4
21861 + * End:
21862 + * vim600: noet sw=4 ts=4 fdm=marker
21863 + * vim<600: noet sw=4 ts=4
21864 + */
21865 +
21866 --- /dev/null
21867 +++ b/ext/http/php_http_info_api.h
21868 @@ -0,0 +1,79 @@
21869 +/*
21870 +    +--------------------------------------------------------------------+
21871 +    | PECL :: http                                                       |
21872 +    +--------------------------------------------------------------------+
21873 +    | Redistribution and use in source and binary forms, with or without |
21874 +    | modification, are permitted provided that the conditions mentioned |
21875 +    | in the accompanying LICENSE file are met.                          |
21876 +    +--------------------------------------------------------------------+
21877 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21878 +    +--------------------------------------------------------------------+
21879 +*/
21880 +
21881 +/* $Id: php_http_info_api.h 292841 2009-12-31 08:48:57Z mike $ */
21882 +
21883 +#ifndef PHP_HTTP_INFO_API_H
21884 +#define PHP_HTTP_INFO_API_H
21885 +
21886 +#define IS_HTTP_REQUEST                1
21887 +#define IS_HTTP_RESPONSE       2
21888 +
21889 +#define HTTP_INFO(ptr) (ptr)->http.info
21890 +
21891 +#define HTTP_INFO_REQUEST_FMT_ARGS(_http_ptr, _EOL) "%s %s HTTP/%1.1f" _EOL, \
21892 +                               (_http_ptr)->info.request.method?(_http_ptr)->info.request.method:"UNKNOWN", \
21893 +                               (_http_ptr)->info.request.url?(_http_ptr)->info.request.url:"/", \
21894 +                               (_http_ptr)->version>0.0?(_http_ptr)->version:1.1
21895 +
21896 +#define HTTP_INFO_RESPONSE_FMT_ARGS(_http_ptr, _EOL) "HTTP/%1.1f %d%s%s" _EOL, \
21897 +                               (_http_ptr)->version>0.0?(_http_ptr)->version:1.1, \
21898 +                               (_http_ptr)->info.response.code?(_http_ptr)->info.response.code:200, \
21899 +                               (_http_ptr)->info.response.status&&*(_http_ptr)->info.response.status ? " ":"", \
21900 +                               STR_PTR((_http_ptr)->info.response.status)
21901 +
21902 +typedef struct _http_request_info_t {
21903 +       char *method;
21904 +       char *url;
21905 +} http_request_info;
21906 +
21907 +typedef struct _http_response_info_t {
21908 +       int code;
21909 +       char *status;
21910 +} http_response_info;
21911 +
21912 +typedef union _http_info_union_t {
21913 +       http_request_info request;
21914 +       http_response_info response;
21915 +} http_info_union;
21916 +
21917 +struct http_info {
21918 +       http_info_union info;
21919 +       double version;
21920 +};
21921 +
21922 +typedef struct _http_info_t {
21923 +       struct http_info http;
21924 +       int type;
21925 +} http_info;
21926 +
21927 +typedef void (*http_info_callback)(void **callback_data, HashTable **headers, http_info *info TSRMLS_DC);
21928 +
21929 +#define http_info_default_callback _http_info_default_callback
21930 +PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC);
21931 +#define http_info_dtor _http_info_dtor
21932 +PHP_HTTP_API void _http_info_dtor(http_info *info);
21933 +#define http_info_parse(p, i) _http_info_parse_ex((p), (i), 1 TSRMLS_CC)
21934 +#define http_info_parse_ex(p, i, s) _http_info_parse_ex((p), (i), (s) TSRMLS_CC)
21935 +PHP_HTTP_API STATUS _http_info_parse_ex(const char *pre_header, http_info *info , zend_bool silent TSRMLS_DC);
21936 +
21937 +#endif
21938 +
21939 +/*
21940 + * Local variables:
21941 + * tab-width: 4
21942 + * c-basic-offset: 4
21943 + * End:
21944 + * vim600: noet sw=4 ts=4 fdm=marker
21945 + * vim<600: noet sw=4 ts=4
21946 + */
21947 +
21948 --- /dev/null
21949 +++ b/ext/http/php_http_message_api.h
21950 @@ -0,0 +1,131 @@
21951 +/*
21952 +    +--------------------------------------------------------------------+
21953 +    | PECL :: http                                                       |
21954 +    +--------------------------------------------------------------------+
21955 +    | Redistribution and use in source and binary forms, with or without |
21956 +    | modification, are permitted provided that the conditions mentioned |
21957 +    | in the accompanying LICENSE file are met.                          |
21958 +    +--------------------------------------------------------------------+
21959 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
21960 +    +--------------------------------------------------------------------+
21961 +*/
21962 +
21963 +/* $Id: php_http_message_api.h 292841 2009-12-31 08:48:57Z mike $ */
21964 +
21965 +#ifndef PHP_HTTP_MESSAGE_API_H
21966 +#define PHP_HTTP_MESSAGE_API_H
21967 +
21968 +#include "php_http_info_api.h"
21969 +
21970 +typedef enum _http_message_type_t {
21971 +       HTTP_MSG_NONE           = 0,
21972 +       HTTP_MSG_REQUEST        = IS_HTTP_REQUEST,
21973 +       HTTP_MSG_RESPONSE       = IS_HTTP_RESPONSE,
21974 +} http_message_type;
21975 +
21976 +typedef struct _http_message_t http_message;
21977 +
21978 +struct _http_message_t {
21979 +       phpstr body;
21980 +       HashTable hdrs;
21981 +       http_message_type type;
21982 +       struct http_info http;
21983 +       http_message *parent;
21984 +};
21985 +
21986 +/* required minimum length of an HTTP message "HTTP/1.1" */
21987 +#define HTTP_MSG_MIN_SIZE 8
21988 +
21989 +/* shorthand for type checks */
21990 +#define HTTP_MSG_TYPE(TYPE, msg) ((msg) && ((msg)->type == HTTP_MSG_ ##TYPE))
21991 +
21992 +#define http_message_new() http_message_init_ex(NULL, 0)
21993 +#define http_message_init(m) http_message_init_ex((m), 0)
21994 +#define http_message_init_ex(m, t) _http_message_init_ex((m), (t) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
21995 +#define http_message_init_rel(m, t) _http_message_init_ex((m), (t) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)
21996 +PHP_HTTP_API http_message *_http_message_init_ex(http_message *m, http_message_type t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
21997 +#define http_message_init_env(m, t) _http_message_init_env((m), (t) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
21998 +PHP_HTTP_API http_message *_http_message_init_env(http_message *m, http_message_type t TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
21999 +
22000 +#define http_message_set_type(m, t) _http_message_set_type((m), (t))
22001 +PHP_HTTP_API void _http_message_set_type(http_message *m, http_message_type t);
22002 +
22003 +#define http_message_set_info(m, i) _http_message_set_info((m), (i))
22004 +PHP_HTTP_API void _http_message_set_info(http_message *message, http_info *info);
22005 +
22006 +#define http_message_header(m, h) _http_message_header_ex((m), (h), sizeof(h), 1)
22007 +#define http_message_header_ex _http_message_header_ex
22008 +static inline zval *_http_message_header_ex(http_message *msg, char *key_str, size_t key_len, int join)
22009 +{
22010 +       zval **header;
22011 +       if (SUCCESS == zend_hash_find(&msg->hdrs, key_str, key_len, (void *) &header)) {
22012 +               if (join && Z_TYPE_PP(header) == IS_ARRAY) {
22013 +                       zval *header_str, **val;
22014 +                       HashPosition pos;
22015 +                       phpstr str;
22016 +                       
22017 +                       phpstr_init(&str);
22018 +                       MAKE_STD_ZVAL(header_str);
22019 +                       FOREACH_VAL(pos, *header, val) {
22020 +                               phpstr_appendf(&str, PHPSTR_LEN(&str) ? ", %s":"%s", Z_STRVAL_PP(val));
22021 +                       }
22022 +                       phpstr_fix(&str);
22023 +                       ZVAL_STRINGL(header_str, PHPSTR_VAL(&str), PHPSTR_LEN(&str), 0);
22024 +                       return header_str;
22025 +               } else {
22026 +                       ZVAL_ADDREF(*header);
22027 +                       return *header;
22028 +               }
22029 +       }
22030 +       return NULL;
22031 +}
22032 +
22033 +#define http_message_count(c, m) \
22034 +{ \
22035 +       http_message *__tmp_msg = (m); \
22036 +       for (c = 0; __tmp_msg; __tmp_msg = __tmp_msg->parent, ++(c)); \
22037 +}
22038 +
22039 +#define http_message_parse(m, l) http_message_parse_ex(NULL, (m), (l))
22040 +#define http_message_parse_ex(h, m, l) _http_message_parse_ex((h), (m), (l) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
22041 +#define http_message_parse_rel(h, m, l) _http_message_parse_ex((h), (m), (l) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC TSRMLS_CC)
22042 +PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
22043 +
22044 +#define http_message_tostring(m, s, l) _http_message_tostring((m), (s), (l))
22045 +PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length);
22046 +
22047 +#define http_message_serialize(m, s, l) _http_message_serialize((m), (s), (l))
22048 +PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length);
22049 +
22050 +#define http_message_reverse(m) _http_message_reverse(m)
22051 +PHP_HTTP_API http_message *_http_message_reverse(http_message *msg);
22052 +
22053 +#define http_message_interconnect(m1, m2) _http_message_interconnect((m1), (m2))
22054 +PHP_HTTP_API http_message *_http_message_interconnect(http_message *m1, http_message *m2);
22055 +
22056 +#define http_message_tostruct_recursive(m, s) _http_message_tostruct_recursive((m), (s) TSRMLS_CC)
22057 +PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *strct TSRMLS_DC);
22058 +
22059 +#define http_message_send(m) _http_message_send((m) TSRMLS_CC)
22060 +PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC);
22061 +
22062 +#define http_message_dup(m) _http_message_dup((m) TSRMLS_CC)
22063 +PHP_HTTP_API http_message *_http_message_dup(http_message *msg TSRMLS_DC);
22064 +
22065 +#define http_message_dtor(m) _http_message_dtor((m))
22066 +PHP_HTTP_API void _http_message_dtor(http_message *message);
22067 +
22068 +#define http_message_free(m) _http_message_free((m))
22069 +PHP_HTTP_API void _http_message_free(http_message **message);
22070 +
22071 +#endif
22072 +
22073 +/*
22074 + * Local variables:
22075 + * tab-width: 4
22076 + * c-basic-offset: 4
22077 + * End:
22078 + * vim600: noet sw=4 ts=4 fdm=marker
22079 + * vim<600: noet sw=4 ts=4
22080 + */
22081 +
22082 --- /dev/null
22083 +++ b/ext/http/php_http_message_object.h
22084 @@ -0,0 +1,115 @@
22085 +/*
22086 +    +--------------------------------------------------------------------+
22087 +    | PECL :: http                                                       |
22088 +    +--------------------------------------------------------------------+
22089 +    | Redistribution and use in source and binary forms, with or without |
22090 +    | modification, are permitted provided that the conditions mentioned |
22091 +    | in the accompanying LICENSE file are met.                          |
22092 +    +--------------------------------------------------------------------+
22093 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22094 +    +--------------------------------------------------------------------+
22095 +*/
22096 +
22097 +/* $Id: php_http_message_object.h 298590 2010-04-26 11:46:35Z mike $ */
22098 +
22099 +#ifndef PHP_HTTP_MESSAGE_OBJECT_H
22100 +#define PHP_HTTP_MESSAGE_OBJECT_H
22101 +#ifdef ZEND_ENGINE_2
22102 +
22103 +typedef struct _http_message_object_t {
22104 +       zend_object zo;
22105 +       http_message *message;
22106 +       zend_object_value parent;
22107 +       zval *iterator;
22108 +} http_message_object;
22109 +
22110 +extern zend_class_entry *http_message_object_ce;
22111 +extern zend_function_entry http_message_object_fe[];
22112 +
22113 +extern PHP_MINIT_FUNCTION(http_message_object);
22114 +extern PHP_MSHUTDOWN_FUNCTION(http_message_object);
22115 +
22116 +#define http_message_object_prepend(o, p) http_message_object_prepend_ex((o), (p), 1)
22117 +#define http_message_object_prepend_ex(o, p, t) _http_message_object_prepend_ex((o), (p), (t) TSRMLS_CC)
22118 +extern void _http_message_object_prepend_ex(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC);
22119 +
22120 +#define http_message_object_reverse(t, r) _http_message_object_reverse((t), (r) TSRMLS_CC)
22121 +extern void _http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC);
22122 +
22123 +#define http_message_object_new(ce) _http_message_object_new((ce) TSRMLS_CC)
22124 +extern zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC);
22125 +#define http_message_object_new_ex(ce, msg, ptr) _http_message_object_new_ex((ce), (msg), (ptr) TSRMLS_CC)
22126 +extern zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC);
22127 +#define http_message_object_clone(zobj) _http_message_object_clone_obj(zobj TSRMLS_CC)
22128 +extern zend_object_value _http_message_object_clone_obj(zval *object TSRMLS_DC);
22129 +#define http_message_object_free(o) _http_message_object_free((o) TSRMLS_CC)
22130 +extern void _http_message_object_free(zend_object *object TSRMLS_DC);
22131 +
22132 +#define HTTP_MSG_CHECK_OBJ(obj, dofail) \
22133 +       if (!(obj)->message) { \
22134 +               http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is empty"); \
22135 +               dofail; \
22136 +       }
22137 +#define HTTP_MSG_CHECK_STD() HTTP_MSG_CHECK_OBJ(obj, RETURN_FALSE)
22138 +
22139 +#define HTTP_MSG_INIT_OBJ(obj) \
22140 +       if (!(obj)->message) { \
22141 +               (obj)->message = http_message_new(); \
22142 +       }
22143 +#define HTTP_MSG_INIT_STD() HTTP_MSG_INIT_OBJ(obj)
22144 +
22145 +PHP_METHOD(HttpMessage, __construct);
22146 +PHP_METHOD(HttpMessage, getBody);
22147 +PHP_METHOD(HttpMessage, setBody);
22148 +PHP_METHOD(HttpMessage, getHeader);
22149 +PHP_METHOD(HttpMessage, getHeaders);
22150 +PHP_METHOD(HttpMessage, setHeaders);
22151 +PHP_METHOD(HttpMessage, addHeaders);
22152 +PHP_METHOD(HttpMessage, getType);
22153 +PHP_METHOD(HttpMessage, setType);
22154 +PHP_METHOD(HttpMessage, getInfo);
22155 +PHP_METHOD(HttpMessage, setInfo);
22156 +PHP_METHOD(HttpMessage, getResponseCode);
22157 +PHP_METHOD(HttpMessage, setResponseCode);
22158 +PHP_METHOD(HttpMessage, getResponseStatus);
22159 +PHP_METHOD(HttpMessage, setResponseStatus);
22160 +PHP_METHOD(HttpMessage, getRequestMethod);
22161 +PHP_METHOD(HttpMessage, setRequestMethod);
22162 +PHP_METHOD(HttpMessage, getRequestUrl);
22163 +PHP_METHOD(HttpMessage, setRequestUrl);
22164 +PHP_METHOD(HttpMessage, getHttpVersion);
22165 +PHP_METHOD(HttpMessage, setHttpVersion);
22166 +PHP_METHOD(HttpMessage, guessContentType);
22167 +PHP_METHOD(HttpMessage, getParentMessage);
22168 +PHP_METHOD(HttpMessage, send);
22169 +PHP_METHOD(HttpMessage, toString);
22170 +PHP_METHOD(HttpMessage, toMessageTypeObject);
22171 +
22172 +PHP_METHOD(HttpMessage, count);
22173 +PHP_METHOD(HttpMessage, serialize);
22174 +PHP_METHOD(HttpMessage, unserialize);
22175 +PHP_METHOD(HttpMessage, rewind);
22176 +PHP_METHOD(HttpMessage, valid);
22177 +PHP_METHOD(HttpMessage, current);
22178 +PHP_METHOD(HttpMessage, key);
22179 +PHP_METHOD(HttpMessage, next);
22180 +
22181 +PHP_METHOD(HttpMessage, factory);
22182 +PHP_METHOD(HttpMessage, fromEnv);
22183 +
22184 +PHP_METHOD(HttpMessage, detach);
22185 +PHP_METHOD(HttpMessage, prepend);
22186 +PHP_METHOD(HttpMessage, reverse);
22187 +
22188 +#endif
22189 +#endif
22190 +
22191 +/*
22192 + * Local variables:
22193 + * tab-width: 4
22194 + * c-basic-offset: 4
22195 + * End:
22196 + * vim600: noet sw=4 ts=4 fdm=marker
22197 + * vim<600: noet sw=4 ts=4
22198 + */
22199 +
22200 --- /dev/null
22201 +++ b/ext/http/php_http_persistent_handle_api.h
22202 @@ -0,0 +1,58 @@
22203 +/*
22204 +    +--------------------------------------------------------------------+
22205 +    | PECL :: http                                                       |
22206 +    +--------------------------------------------------------------------+
22207 +    | Redistribution and use in source and binary forms, with or without |
22208 +    | modification, are permitted provided that the conditions mentioned |
22209 +    | in the accompanying LICENSE file are met.                          |
22210 +    +--------------------------------------------------------------------+
22211 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22212 +    +--------------------------------------------------------------------+
22213 +*/
22214 +
22215 +/* $Id: php_http_persistent_handle_api.h 292841 2009-12-31 08:48:57Z mike $ */
22216 +
22217 +#ifndef HTTP_PERSISTENT_HANDLE_H
22218 +#define HTTP_PERSISTENT_HANDLE_H
22219 +
22220 +typedef void *(*http_persistent_handle_ctor)(void);
22221 +typedef void (*http_persistent_handle_dtor)(void *handle);
22222 +typedef void *(*http_persistent_handle_copy)(void *handle);
22223 +
22224 +PHP_MINIT_FUNCTION(http_persistent_handle);
22225 +PHP_MSHUTDOWN_FUNCTION(http_persistent_handle);
22226 +
22227 +#define http_persistent_handle_provide(n, c, d, cc) _http_persistent_handle_provide_ex((n), strlen(n), (c), (d), (cc))
22228 +#define http_persistent_handle_provide_ex(n, l, c, d, cc) _http_persistent_handle_provide_ex((n), (l), (c), (d), (cc))
22229 +PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor, http_persistent_handle_copy copy);
22230 +
22231 +#define http_persistent_handle_cleanup(n, c) _http_persistent_handle_cleanup_ex((n), strlen(n), (c) TSRMLS_CC)
22232 +#define http_persistent_handle_cleanup_ex(n, l,c ) _http_persistent_handle_cleanup_ex((n), (l), (c) TSRMLS_CC)
22233 +PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC);
22234 +
22235 +#define http_persistent_handle_statall() _http_persistent_handle_statall_ex(NULL TSRMLS_CC)
22236 +#define http_persistent_handle_statall_ex(ht) _http_persistent_handle_statall_ex((ht) TSRMLS_CC)
22237 +PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht TSRMLS_DC);
22238 +
22239 +#define http_persistent_handle_acquire(n, h) _http_persistent_handle_acquire_ex((n), strlen(n), (h) TSRMLS_CC)
22240 +#define http_persistent_handle_acquire_ex(n, l, h) _http_persistent_handle_acquire_ex((n), (l), (h) TSRMLS_CC)
22241 +PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC);
22242 +
22243 +#define http_persistent_handle_release(n, h) _http_persistent_handle_release_ex((n), strlen(n), (h) TSRMLS_CC)
22244 +#define http_persistent_handle_release_ex(n, l, h) _http_persistent_handle_release_ex((n), (l), (h) TSRMLS_CC)
22245 +PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC);
22246 +
22247 +#define http_persistent_handle_accrete(n, oh, nh) _http_persistent_handle_accrete_ex((n), strlen(n), (oh), (nh) TSRMLS_CC)
22248 +#define http_persistent_handle_accrete_ex(n, l, oh, nh) _http_persistent_handle_accrete_ex((n), (l), (oh), (nh) TSRMLS_CC)
22249 +PHP_HTTP_API STATUS _http_persistent_handle_accrete_ex(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC);
22250 +
22251 +#endif /* HTTP_PERSISTENT_HANDLE_H */
22252 +
22253 +/*
22254 + * Local variables:
22255 + * tab-width: 4
22256 + * c-basic-offset: 4
22257 + * End:
22258 + * vim600: noet sw=4 ts=4 fdm=marker
22259 + * vim<600: noet sw=4 ts=4
22260 + */
22261 --- /dev/null
22262 +++ b/ext/http/php_http_querystring_api.h
22263 @@ -0,0 +1,38 @@
22264 +/*
22265 +    +--------------------------------------------------------------------+
22266 +    | PECL :: http                                                       |
22267 +    +--------------------------------------------------------------------+
22268 +    | Redistribution and use in source and binary forms, with or without |
22269 +    | modification, are permitted provided that the conditions mentioned |
22270 +    | in the accompanying LICENSE file are met.                          |
22271 +    +--------------------------------------------------------------------+
22272 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22273 +    +--------------------------------------------------------------------+
22274 +*/
22275 +
22276 +/* $Id: php_http_querystring_api.h 292841 2009-12-31 08:48:57Z mike $ */
22277 +
22278 +#ifndef PHP_HTTP_QUERYSTRING_API_H
22279 +#define PHP_HTTP_QUERYSTRING_API_H
22280 +
22281 +#ifdef HTTP_HAVE_ICONV
22282 +#define http_querystring_xlate(a, p, ie, oe) _http_querystring_xlate((a), (p), (ie), (oe) TSRMLS_CC)
22283 +PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC);
22284 +#endif
22285 +
22286 +#define http_querystring_update(qa, qs) _http_querystring_update((qa), (qs) TSRMLS_CC)
22287 +PHP_HTTP_API void _http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC);
22288 +
22289 +#define http_querystring_modify(q, p) _http_querystring_modify((q), (p) TSRMLS_CC)
22290 +PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC);
22291 +
22292 +#endif
22293 +
22294 +/*
22295 + * Local variables:
22296 + * tab-width: 4
22297 + * c-basic-offset: 4
22298 + * End:
22299 + * vim600: noet sw=4 ts=4 fdm=marker
22300 + * vim<600: noet sw=4 ts=4
22301 + */
22302 --- /dev/null
22303 +++ b/ext/http/php_http_querystring_object.h
22304 @@ -0,0 +1,78 @@
22305 +/*
22306 +    +--------------------------------------------------------------------+
22307 +    | PECL :: http                                                       |
22308 +    +--------------------------------------------------------------------+
22309 +    | Redistribution and use in source and binary forms, with or without |
22310 +    | modification, are permitted provided that the conditions mentioned |
22311 +    | in the accompanying LICENSE file are met.                          |
22312 +    +--------------------------------------------------------------------+
22313 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22314 +    +--------------------------------------------------------------------+
22315 +*/
22316 +
22317 +/* $Id: php_http_querystring_object.h 292841 2009-12-31 08:48:57Z mike $ */
22318 +
22319 +#ifndef PHP_HTTP_QUERYSTRING_OBJECT_H
22320 +#define PHP_HTTP_QUERYSTRING_OBJECT_H
22321 +#ifdef ZEND_ENGINE_2
22322 +
22323 +typedef struct _http_querystring_object_t {
22324 +       zend_object zo;
22325 +} http_querystring_object;
22326 +
22327 +#define HTTP_QUERYSTRING_TYPE_BOOL             IS_BOOL
22328 +#define HTTP_QUERYSTRING_TYPE_INT              IS_LONG
22329 +#define HTTP_QUERYSTRING_TYPE_FLOAT            IS_DOUBLE
22330 +#define HTTP_QUERYSTRING_TYPE_STRING   IS_STRING
22331 +#define HTTP_QUERYSTRING_TYPE_ARRAY            IS_ARRAY
22332 +#define HTTP_QUERYSTRING_TYPE_OBJECT   IS_OBJECT
22333 +
22334 +extern zend_class_entry *http_querystring_object_ce;
22335 +extern zend_function_entry http_querystring_object_fe[];
22336 +
22337 +extern PHP_MINIT_FUNCTION(http_querystring_object);
22338 +
22339 +#define http_querystring_object_new(ce) _http_querystring_object_new((ce) TSRMLS_CC)
22340 +extern zend_object_value _http_querystring_object_new(zend_class_entry *ce TSRMLS_DC);
22341 +#define http_querystring_object_new_ex(ce, n, ptr) _http_querystring_object_new_ex((ce), (n), (ptr) TSRMLS_CC)
22342 +extern zend_object_value _http_querystring_object_new_ex(zend_class_entry *ce, void *nothing, http_querystring_object **ptr TSRMLS_DC);
22343 +#define http_querystring_object_free(o) _http_querystring_object_free((o) TSRMLS_CC)
22344 +extern void _http_querystring_object_free(zend_object *object TSRMLS_DC);
22345 +
22346 +PHP_METHOD(HttpQueryString, __construct);
22347 +PHP_METHOD(HttpQueryString, toString);
22348 +PHP_METHOD(HttpQueryString, toArray);
22349 +PHP_METHOD(HttpQueryString, get);
22350 +PHP_METHOD(HttpQueryString, set);
22351 +PHP_METHOD(HttpQueryString, mod);
22352 +PHP_METHOD(HttpQueryString, getBool);
22353 +PHP_METHOD(HttpQueryString, getInt);
22354 +PHP_METHOD(HttpQueryString, getFloat);
22355 +PHP_METHOD(HttpQueryString, getString);
22356 +PHP_METHOD(HttpQueryString, getArray);
22357 +PHP_METHOD(HttpQueryString, getObject);
22358 +#ifdef HTTP_HAVE_ICONV
22359 +PHP_METHOD(HttpQueryString, xlate);
22360 +#endif
22361 +PHP_METHOD(HttpQueryString, factory);
22362 +#ifndef WONKY
22363 +PHP_METHOD(HttpQueryString, singleton);
22364 +#endif
22365 +PHP_METHOD(HttpQueryString, serialize);
22366 +PHP_METHOD(HttpQueryString, unserialize);
22367 +PHP_METHOD(HttpQueryString, offsetGet);
22368 +PHP_METHOD(HttpQueryString, offsetSet);
22369 +PHP_METHOD(HttpQueryString, offsetExists);
22370 +PHP_METHOD(HttpQueryString, offsetUnset);
22371 +#endif
22372 +#endif
22373 +
22374 +/*
22375 + * Local variables:
22376 + * tab-width: 4
22377 + * c-basic-offset: 4
22378 + * End:
22379 + * vim600: noet sw=4 ts=4 fdm=marker
22380 + * vim<600: noet sw=4 ts=4
22381 + */
22382 +
22383 --- /dev/null
22384 +++ b/ext/http/php_http_request_api.h
22385 @@ -0,0 +1,144 @@
22386 +/*
22387 +    +--------------------------------------------------------------------+
22388 +    | PECL :: http                                                       |
22389 +    +--------------------------------------------------------------------+
22390 +    | Redistribution and use in source and binary forms, with or without |
22391 +    | modification, are permitted provided that the conditions mentioned |
22392 +    | in the accompanying LICENSE file are met.                          |
22393 +    +--------------------------------------------------------------------+
22394 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22395 +    +--------------------------------------------------------------------+
22396 +*/
22397 +
22398 +/* $Id: php_http_request_api.h 292841 2009-12-31 08:48:57Z mike $ */
22399 +
22400 +#ifndef PHP_HTTP_REQUEST_API_H
22401 +#define PHP_HTTP_REQUEST_API_H
22402 +
22403 +#ifdef HTTP_HAVE_CURL
22404 +
22405 +#include "php_http_request_body_api.h"
22406 +#include "php_http_request_method_api.h"
22407 +
22408 +extern PHP_MINIT_FUNCTION(http_request);
22409 +extern PHP_MSHUTDOWN_FUNCTION(http_request);
22410 +
22411 +typedef struct _http_request_t {
22412 +       CURL *ch;
22413 +       char *url;
22414 +       http_request_method meth;
22415 +       http_request_body *body;
22416 +       
22417 +       struct {
22418 +               curl_infotype last_type;
22419 +               phpstr request;
22420 +               phpstr response;
22421 +       } conv;
22422 +       
22423 +       struct {
22424 +               phpstr cookies;
22425 +               HashTable options;
22426 +               struct curl_slist *headers;
22427 +       } _cache;
22428 +       
22429 +       struct {
22430 +               uint count;
22431 +               double delay;
22432 +       } _retry;
22433 +       
22434 +       char _error[CURL_ERROR_SIZE+1];
22435 +       zval *_progress_callback;
22436 +
22437 +#ifdef ZTS
22438 +       void ***tsrm_ls;
22439 +#endif
22440 +
22441 +       uint _in_progress_cb:1;
22442 +
22443 +} http_request;
22444 +
22445 +#ifndef pestrndup
22446 +#      define pestrndup(s,l,p) _pestrndup((s),(l),(p))
22447 +static inline void *_pestrndup(const void *s, size_t l, int p)
22448 +{
22449 +       void *d = pemalloc(l+1, p);
22450 +       memcpy(d, s, l);
22451 +       ((char *) d)[l] = '\0';
22452 +       return d;
22453 +}
22454 +#endif
22455 +
22456 +/* CURLOPT_PRIVATE storage living as long as a CURL handle */
22457 +typedef struct _http_request_storage_t {
22458 +       char *url;
22459 +       char *cookiestore;
22460 +       char errorbuffer[CURL_ERROR_SIZE];
22461 +} http_request_storage;
22462 +
22463 +static inline http_request_storage *http_request_storage_get(CURL *ch)
22464 +{
22465 +       http_request_storage *st = NULL;
22466 +       curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st);
22467 +       return st;
22468 +}
22469 +
22470 +#define http_curl_init(r) http_curl_init_ex(NULL, (r))
22471 +#define http_curl_init_ex(c, r) _http_curl_init_ex((c), (r) TSRMLS_CC)
22472 +PHP_HTTP_API CURL *_http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC);
22473 +
22474 +#define http_curl_free(c) _http_curl_free((c) TSRMLS_CC)
22475 +PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC);
22476 +
22477 +#define http_curl_copy(c) _http_curl_copy((c) TSRMLS_CC)
22478 +PHP_HTTP_API CURL *_http_curl_copy(CURL *ch TSRMLS_DC);
22479 +
22480 +#define http_request_new() _http_request_init_ex(NULL, NULL, 0, NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
22481 +#define http_request_init(r) _http_request_init_ex((r), NULL, 0, NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
22482 +#define http_request_init_ex(r, c, m, u) _http_request_init_ex((r), (c), (m), (u) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
22483 +PHP_HTTP_API http_request *_http_request_init_ex(http_request *request, CURL *ch, http_request_method meth, const char *url ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
22484 +
22485 +#define http_request_dtor(r) _http_request_dtor((r))
22486 +PHP_HTTP_API void _http_request_dtor(http_request *request);
22487 +
22488 +#define http_request_free(r) _http_request_free((r))
22489 +PHP_HTTP_API void _http_request_free(http_request **request);
22490 +
22491 +#define http_request_reset(r) _http_request_reset(r)
22492 +PHP_HTTP_API void _http_request_reset(http_request *r);
22493 +
22494 +#define http_request_enable_cookies(r) _http_request_enable_cookies(r)
22495 +PHP_HTTP_API STATUS _http_request_enable_cookies(http_request *request);
22496 +
22497 +#define http_request_reset_cookies(r, s) _http_request_reset_cookies((r), (s))
22498 +PHP_HTTP_API STATUS _http_request_reset_cookies(http_request *request, int session_only);
22499 +
22500 +#define http_request_flush_cookies(r) _http_request_flush_cookies(r)
22501 +PHP_HTTP_API STATUS _http_request_flush_cookies(http_request *request);
22502 +
22503 +#define http_request_defaults(r) _http_request_defaults(r)
22504 +PHP_HTTP_API void _http_request_defaults(http_request *request);
22505 +
22506 +#define http_request_prepare(r, o) _http_request_prepare((r), (o))
22507 +PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *options);
22508 +
22509 +#define http_request_exec(r) _http_request_exec((r))
22510 +PHP_HTTP_API void _http_request_exec(http_request *request);
22511 +
22512 +#define http_request_info(r, i) _http_request_info((r), (i))
22513 +PHP_HTTP_API void _http_request_info(http_request *request, HashTable *info);
22514 +
22515 +#define http_request_set_progress_callback(r, cb) _http_request_set_progress_callback((r), (cb))
22516 +PHP_HTTP_API void _http_request_set_progress_callback(http_request *request, zval *cb);
22517 +
22518 +#endif
22519 +#endif
22520 +
22521 +/*
22522 + * Local variables:
22523 + * tab-width: 4
22524 + * c-basic-offset: 4
22525 + * End:
22526 + * vim600: noet sw=4 ts=4 fdm=marker
22527 + * vim<600: noet sw=4 ts=4
22528 + */
22529 +
22530 --- /dev/null
22531 +++ b/ext/http/php_http_request_body_api.h
22532 @@ -0,0 +1,62 @@
22533 +/*
22534 +    +--------------------------------------------------------------------+
22535 +    | PECL :: http                                                       |
22536 +    +--------------------------------------------------------------------+
22537 +    | Redistribution and use in source and binary forms, with or without |
22538 +    | modification, are permitted provided that the conditions mentioned |
22539 +    | in the accompanying LICENSE file are met.                          |
22540 +    +--------------------------------------------------------------------+
22541 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22542 +    +--------------------------------------------------------------------+
22543 +*/
22544 +
22545 +/* $Id: php_http_request_body_api.h 292841 2009-12-31 08:48:57Z mike $ */
22546 +
22547 +#ifndef PHP_HTTP_REQUEST_BODY_API_H
22548 +#define PHP_HTTP_REQUEST_BODY_API_H
22549 +
22550 +#ifdef HTTP_HAVE_CURL
22551 +
22552 +#define HTTP_REQUEST_BODY_EMPTY                        0
22553 +#define HTTP_REQUEST_BODY_CSTRING              1
22554 +#define HTTP_REQUEST_BODY_CURLPOST             2
22555 +#define HTTP_REQUEST_BODY_UPLOADFILE   3
22556 +typedef struct _http_request_body_t {
22557 +       void *data;
22558 +       size_t size;
22559 +       uint type:3;
22560 +       uint free:1;
22561 +       uint priv:28;
22562 +} http_request_body;
22563 +
22564 +
22565 +#define http_request_body_new() http_request_body_init(NULL)
22566 +#define http_request_body_init(b) http_request_body_init_ex((b), 0, NULL, 0, 0)
22567 +#define http_request_body_init_ex(b, t, d, l, f) _http_request_body_init_ex((b), (t), (d), (l), (f) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
22568 +#define http_request_body_init_rel(b, t, d, l, f) _http_request_body_init_ex((b), (t), (d), (l), (f) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC TSRMLS_CC)
22569 +PHP_HTTP_API http_request_body *_http_request_body_init_ex(http_request_body *body, int type, void *data, size_t len, zend_bool free ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
22570 +
22571 +#define http_request_body_fill(b, fields, files) _http_request_body_fill((b), (fields), (files) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
22572 +PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC);
22573 +
22574 +#define http_request_body_encode(b, s, l) _http_request_body_encode((b), (s), (l) TSRMLS_CC)
22575 +PHP_HTTP_API STATUS  _http_request_body_encode(http_request_body *body, char **buf, size_t *len TSRMLS_DC);
22576 +
22577 +#define http_request_body_dtor(b) _http_request_body_dtor((b) TSRMLS_CC)
22578 +PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC);
22579 +
22580 +#define http_request_body_free(b) _http_request_body_free((b) TSRMLS_CC)
22581 +PHP_HTTP_API void _http_request_body_free(http_request_body **body TSRMLS_DC);
22582 +
22583 +#endif
22584 +#endif
22585 +
22586 +/*
22587 + * Local variables:
22588 + * tab-width: 4
22589 + * c-basic-offset: 4
22590 + * End:
22591 + * vim600: noet sw=4 ts=4 fdm=marker
22592 + * vim<600: noet sw=4 ts=4
22593 + */
22594 +
22595 --- /dev/null
22596 +++ b/ext/http/php_http_request_datashare_api.h
22597 @@ -0,0 +1,88 @@
22598 +/*
22599 +    +--------------------------------------------------------------------+
22600 +    | PECL :: http                                                       |
22601 +    +--------------------------------------------------------------------+
22602 +    | Redistribution and use in source and binary forms, with or without |
22603 +    | modification, are permitted provided that the conditions mentioned |
22604 +    | in the accompanying LICENSE file are met.                          |
22605 +    +--------------------------------------------------------------------+
22606 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22607 +    +--------------------------------------------------------------------+
22608 +*/
22609 +
22610 +/* $Id: php_http_request_datashare_api.h 292841 2009-12-31 08:48:57Z mike $ */
22611 +
22612 +#ifndef PHP_HTTP_REQUEST_DATASHARE_API_H
22613 +#define PHP_HTTP_REQUEST_DATASHARE_API_H
22614 +#ifdef HTTP_HAVE_CURL
22615 +#ifdef ZEND_ENGINE_2
22616 +
22617 +#ifdef ZTS
22618 +typedef struct _http_request_datashare_lock_t {
22619 +       CURL *ch;
22620 +       MUTEX_T mx;
22621 +} http_request_datashare_lock;
22622 +
22623 +typedef union _http_request_datashare_handle_t {
22624 +       zend_llist *list;
22625 +       http_request_datashare_lock *locks;
22626 +} http_request_datashare_handle;
22627 +#else
22628 +typedef struct _http_request_datashare_handle_t {
22629 +       zend_llist *list;
22630 +} http_request_datashare_handle;
22631 +#endif
22632 +
22633 +typedef struct _http_request_datashare_t {
22634 +       CURLSH *ch;
22635 +       zend_bool persistent;
22636 +       http_request_datashare_handle handle;
22637 +} http_request_datashare;
22638 +
22639 +#define HTTP_RSHARE_HANDLES(s) ((s)->persistent ? &HTTP_G->request.datashare.handles : (s)->handle.list)
22640 +
22641 +#define http_request_datashare_global_get _http_request_datashare_global_get
22642 +extern http_request_datashare *_http_request_datashare_global_get(void);
22643 +
22644 +extern PHP_MINIT_FUNCTION(http_request_datashare);
22645 +extern PHP_MSHUTDOWN_FUNCTION(http_request_datashare);
22646 +extern PHP_RINIT_FUNCTION(http_request_datashare);
22647 +extern PHP_RSHUTDOWN_FUNCTION(http_request_datashare);
22648 +
22649 +#define http_request_datashare_new() _http_request_datashare_init_ex(NULL, 0 TSRMLS_CC)
22650 +#define http_request_datashare_init(s) _http_request_datashare_init_ex((s), 0 TSRMLS_CC)
22651 +#define http_request_datashare_init_ex(s, p) _http_request_datashare_init_ex((s), (p) TSRMLS_CC)
22652 +PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC);
22653 +
22654 +#define http_request_datashare_attach(s, r) _http_request_datashare_attach((s), (r) TSRMLS_CC)
22655 +PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC);
22656 +
22657 +#define http_request_datashare_detach(s, r) _http_request_datashare_detach((s), (r) TSRMLS_CC)
22658 +PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC);
22659 +
22660 +#define http_request_datashare_detach_all(s) _http_request_datashare_detach_all((s) TSRMLS_CC)
22661 +PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC);
22662 +
22663 +#define http_request_datashare_dtor(s) _http_request_datashare_dtor((s) TSRMLS_CC)
22664 +PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC);
22665 +
22666 +#define http_request_datashare_free(s) _http_request_datashare_free((s) TSRMLS_CC)
22667 +PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC);
22668 +
22669 +#define http_request_datashare_set(s, o, l, e) _http_request_datashare_set((s), (o), (l), (e) TSRMLS_CC)
22670 +PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC);
22671 +
22672 +
22673 +#endif
22674 +#endif
22675 +#endif
22676 +
22677 +/*
22678 + * Local variables:
22679 + * tab-width: 4
22680 + * c-basic-offset: 4
22681 + * End:
22682 + * vim600: noet sw=4 ts=4 fdm=marker
22683 + * vim<600: noet sw=4 ts=4
22684 + */
22685 +
22686 --- /dev/null
22687 +++ b/ext/http/php_http_request_int.h
22688 @@ -0,0 +1,72 @@
22689 +/*
22690 +    +--------------------------------------------------------------------+
22691 +    | PECL :: http                                                       |
22692 +    +--------------------------------------------------------------------+
22693 +    | Redistribution and use in source and binary forms, with or without |
22694 +    | modification, are permitted provided that the conditions mentioned |
22695 +    | in the accompanying LICENSE file are met.                          |
22696 +    +--------------------------------------------------------------------+
22697 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22698 +    +--------------------------------------------------------------------+
22699 +*/
22700 +
22701 +/* $Id: php_http_request_int.h 292841 2009-12-31 08:48:57Z mike $ */
22702 +
22703 +#if defined(ZTS) && defined(HTTP_HAVE_SSL)
22704 +#      ifdef PHP_WIN32
22705 +#              define HTTP_NEED_OPENSSL_TSL
22706 +#              include <openssl/crypto.h>
22707 +#      else /* !PHP_WIN32 */
22708 +#              if defined(HTTP_HAVE_OPENSSL)
22709 +#                      define HTTP_NEED_OPENSSL_TSL
22710 +#                      include <openssl/crypto.h>
22711 +#              elif defined(HTTP_HAVE_GNUTLS)
22712 +#                      define HTTP_NEED_GNUTLS_TSL
22713 +#                      include <gcrypt.h>
22714 +#              else
22715 +#                      warning \
22716 +                               "libcurl was compiled with SSL support, but configure could not determine which" \
22717 +                               "library was used; thus no SSL crypto locking callbacks will be set, which may " \
22718 +                               "cause random crashes on SSL requests"
22719 +#              endif /* HTTP_HAVE_OPENSSL || HTTP_HAVE_GNUTLS */
22720 +#      endif /* PHP_WIN32 */
22721 +#endif /* ZTS && HTTP_HAVE_SSL */
22722 +
22723 +#define HTTP_CURL_OPT(OPTION, p) curl_easy_setopt((request->ch), OPTION, (p))
22724 +
22725 +#define HTTP_CURL_OPT_STRING(OPTION, ldiff, obdc) \
22726 +       { \
22727 +               char *K = #OPTION; \
22728 +               HTTP_CURL_OPT_STRING_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION, obdc); \
22729 +       }
22730 +#define HTTP_CURL_OPT_STRING_EX(keyname, optname, obdc) \
22731 +       if (!strcasecmp(key.str, keyname)) { \
22732 +               zval *copy = http_request_option_cache_ex(request, keyname, strlen(keyname)+1, 0, http_zsep(IS_STRING, *param)); \
22733 +               if (obdc) { \
22734 +                       HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(copy), return FAILURE); \
22735 +               } \
22736 +               HTTP_CURL_OPT(optname, Z_STRVAL_P(copy)); \
22737 +               zval_ptr_dtor(&copy); \
22738 +               continue; \
22739 +       }
22740 +#define HTTP_CURL_OPT_LONG(OPTION, ldiff) \
22741 +       { \
22742 +               char *K = #OPTION; \
22743 +               HTTP_CURL_OPT_LONG_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION); \
22744 +       }
22745 +#define HTTP_CURL_OPT_LONG_EX(keyname, optname) \
22746 +       if (!strcasecmp(key.str, keyname)) { \
22747 +               zval *copy = http_zsep(IS_LONG, *param); \
22748 +               HTTP_CURL_OPT(optname, Z_LVAL_P(copy)); \
22749 +               zval_ptr_dtor(&copy); \
22750 +               continue; \
22751 +       }
22752 +
22753 +/*
22754 + * Local variables:
22755 + * tab-width: 4
22756 + * c-basic-offset: 4
22757 + * End:
22758 + * vim600: noet sw=4 ts=4 fdm=marker
22759 + * vim<600: noet sw=4 ts=4
22760 + */
22761 --- /dev/null
22762 +++ b/ext/http/php_http_request_method_api.h
22763 @@ -0,0 +1,85 @@
22764 +/*
22765 +    +--------------------------------------------------------------------+
22766 +    | PECL :: http                                                       |
22767 +    +--------------------------------------------------------------------+
22768 +    | Redistribution and use in source and binary forms, with or without |
22769 +    | modification, are permitted provided that the conditions mentioned |
22770 +    | in the accompanying LICENSE file are met.                          |
22771 +    +--------------------------------------------------------------------+
22772 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22773 +    +--------------------------------------------------------------------+
22774 +*/
22775 +
22776 +/* $Id: php_http_request_method_api.h 292841 2009-12-31 08:48:57Z mike $ */
22777 +
22778 +#ifndef PHP_HTTP_REQUEST_METHOD_API_H
22779 +#define PHP_HTTP_REQUEST_METHOD_API_H
22780 +
22781 +typedef enum _http_request_method_t {
22782 +       /* force the enum to be signed */
22783 +       HTTP_NEG_REQUEST_METHOD =-1,
22784 +       HTTP_NO_REQUEST_METHOD  = 0,
22785 +       /* HTTP/1.1 */
22786 +       HTTP_GET                                = 1,
22787 +       HTTP_HEAD                               = 2,
22788 +       HTTP_POST                               = 3,
22789 +       HTTP_PUT                                = 4,
22790 +       HTTP_DELETE                             = 5,
22791 +       HTTP_OPTIONS                    = 6,
22792 +       HTTP_TRACE                              = 7,
22793 +       HTTP_CONNECT                    = 8,
22794 +       /* WebDAV - RFC 2518 */
22795 +       HTTP_PROPFIND                   = 9,
22796 +       HTTP_PROPPATCH                  = 10,
22797 +       HTTP_MKCOL                              = 11,
22798 +       HTTP_COPY                               = 12,
22799 +       HTTP_MOVE                               = 13,
22800 +       HTTP_LOCK                               = 14,
22801 +       HTTP_UNLOCK                             = 15,
22802 +       /* WebDAV Versioning - RFC 3253 */
22803 +       HTTP_VERSION_CONTROL    = 16,
22804 +       HTTP_REPORT                             = 17,
22805 +       HTTP_CHECKOUT                   = 18,
22806 +       HTTP_CHECKIN                    = 19,
22807 +       HTTP_UNCHECKOUT                 = 20,
22808 +       HTTP_MKWORKSPACE                = 21,
22809 +       HTTP_UPDATE                             = 22,
22810 +       HTTP_LABEL                              = 23,
22811 +       HTTP_MERGE                              = 24,
22812 +       HTTP_BASELINE_CONTROL   = 25,
22813 +       HTTP_MKACTIVITY                 = 26,
22814 +       /* WebDAV Access Control - RFC 3744 */
22815 +       HTTP_ACL                                = 27,
22816 +       HTTP_MAX_REQUEST_METHOD = 28
22817 +} http_request_method;
22818 +
22819 +#define HTTP_MIN_REQUEST_METHOD (HTTP_NO_REQUEST_METHOD + 1)
22820 +#define HTTP_STD_REQUEST_METHOD(m) ((m > HTTP_NO_REQUEST_METHOD) && (m < HTTP_MAX_REQUEST_METHOD))
22821 +
22822 +extern PHP_MINIT_FUNCTION(http_request_method);
22823 +extern PHP_RINIT_FUNCTION(http_request_method);
22824 +extern PHP_RSHUTDOWN_FUNCTION(http_request_method);
22825 +
22826 +#define http_request_method_name(m) _http_request_method_name((m) TSRMLS_CC)
22827 +PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC);
22828 +
22829 +#define http_request_method_exists(u, l, c) _http_request_method_exists((u), (l), (c) TSRMLS_CC)
22830 +PHP_HTTP_API int _http_request_method_exists(int by_name, http_request_method id, const char *name TSRMLS_DC);
22831 +
22832 +#define http_request_method_register(m, l) _http_request_method_register((m), (l) TSRMLS_CC)
22833 +PHP_HTTP_API int _http_request_method_register(const char *method, int method_name_len TSRMLS_DC);
22834 +
22835 +#define http_request_method_unregister(mn) _http_request_method_unregister((mn) TSRMLS_CC)
22836 +PHP_HTTP_API STATUS _http_request_method_unregister(int method TSRMLS_DC);
22837 +
22838 +#endif
22839 +
22840 +/*
22841 + * Local variables:
22842 + * tab-width: 4
22843 + * c-basic-offset: 4
22844 + * End:
22845 + * vim600: noet sw=4 ts=4 fdm=marker
22846 + * vim<600: noet sw=4 ts=4
22847 + */
22848 +
22849 --- /dev/null
22850 +++ b/ext/http/php_http_request_object.h
22851 @@ -0,0 +1,118 @@
22852 +/*
22853 +    +--------------------------------------------------------------------+
22854 +    | PECL :: http                                                       |
22855 +    +--------------------------------------------------------------------+
22856 +    | Redistribution and use in source and binary forms, with or without |
22857 +    | modification, are permitted provided that the conditions mentioned |
22858 +    | in the accompanying LICENSE file are met.                          |
22859 +    +--------------------------------------------------------------------+
22860 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22861 +    +--------------------------------------------------------------------+
22862 +*/
22863 +
22864 +/* $Id: php_http_request_object.h 292841 2009-12-31 08:48:57Z mike $ */
22865 +
22866 +#ifndef PHP_HTTP_REQUEST_OBJECT_H
22867 +#define PHP_HTTP_REQUEST_OBJECT_H
22868 +#ifdef HTTP_HAVE_CURL
22869 +#ifdef ZEND_ENGINE_2
22870 +
22871 +#include "php_http_request_api.h"
22872 +#include "php_http_request_pool_api.h"
22873 +#include "php_http_request_datashare_api.h"
22874 +
22875 +typedef struct _http_request_object_t {
22876 +       zend_object zo;
22877 +       http_request *request;
22878 +       http_request_pool *pool;
22879 +       http_request_datashare *share;
22880 +} http_request_object;
22881 +
22882 +extern zend_class_entry *http_request_object_ce;
22883 +extern zend_function_entry http_request_object_fe[];
22884 +
22885 +extern PHP_MINIT_FUNCTION(http_request_object);
22886 +
22887 +#define http_request_object_new(ce) _http_request_object_new((ce) TSRMLS_CC)
22888 +extern zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC);
22889 +#define http_request_object_new_ex(ce, ch, ptr) _http_request_object_new_ex((ce), (ch), (ptr) TSRMLS_CC)
22890 +extern zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL *ch, http_request_object **ptr TSRMLS_DC);
22891 +#define http_request_object_clone(zv) _http_request_object_clone_obj((zv) TSRMLS_CC)
22892 +extern zend_object_value _http_request_object_clone_obj(zval *zobject TSRMLS_DC);
22893 +#define http_request_object_free(o) _http_request_object_free((o) TSRMLS_CC)
22894 +extern void _http_request_object_free(zend_object *object TSRMLS_DC);
22895 +
22896 +#define http_request_object_requesthandler(req, this) _http_request_object_requesthandler((req), (this) TSRMLS_CC)
22897 +extern STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr TSRMLS_DC);
22898 +#define http_request_object_responsehandler(req, this) _http_request_object_responsehandler((req), (this) TSRMLS_CC)
22899 +extern STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr TSRMLS_DC);
22900 +
22901 +PHP_METHOD(HttpRequest, __construct);
22902 +PHP_METHOD(HttpRequest, setOptions);
22903 +PHP_METHOD(HttpRequest, getOptions);
22904 +PHP_METHOD(HttpRequest, addSslOptions);
22905 +PHP_METHOD(HttpRequest, setSslOptions);
22906 +PHP_METHOD(HttpRequest, getSslOptions);
22907 +PHP_METHOD(HttpRequest, addHeaders);
22908 +PHP_METHOD(HttpRequest, getHeaders);
22909 +PHP_METHOD(HttpRequest, setHeaders);
22910 +PHP_METHOD(HttpRequest, addCookies);
22911 +PHP_METHOD(HttpRequest, getCookies);
22912 +PHP_METHOD(HttpRequest, setCookies);
22913 +PHP_METHOD(HttpRequest, enableCookies);
22914 +PHP_METHOD(HttpRequest, resetCookies);
22915 +PHP_METHOD(HttpRequest, flushCookies);
22916 +PHP_METHOD(HttpRequest, setMethod);
22917 +PHP_METHOD(HttpRequest, getMethod);
22918 +PHP_METHOD(HttpRequest, setUrl);
22919 +PHP_METHOD(HttpRequest, getUrl);
22920 +PHP_METHOD(HttpRequest, setContentType);
22921 +PHP_METHOD(HttpRequest, getContentType);
22922 +PHP_METHOD(HttpRequest, setQueryData);
22923 +PHP_METHOD(HttpRequest, getQueryData);
22924 +PHP_METHOD(HttpRequest, addQueryData);
22925 +PHP_METHOD(HttpRequest, setPostFields);
22926 +PHP_METHOD(HttpRequest, getPostFields);
22927 +PHP_METHOD(HttpRequest, addPostFields);
22928 +PHP_METHOD(HttpRequest, getBody);
22929 +PHP_METHOD(HttpRequest, setBody);
22930 +PHP_METHOD(HttpRequest, addBody);
22931 +PHP_METHOD(HttpRequest, addPostFile);
22932 +PHP_METHOD(HttpRequest, setPostFiles);
22933 +PHP_METHOD(HttpRequest, getPostFiles);
22934 +PHP_METHOD(HttpRequest, setPutFile);
22935 +PHP_METHOD(HttpRequest, getPutFile);
22936 +PHP_METHOD(HttpRequest, getPutData);
22937 +PHP_METHOD(HttpRequest, setPutData);
22938 +PHP_METHOD(HttpRequest, addPutData);
22939 +PHP_METHOD(HttpRequest, send);
22940 +PHP_METHOD(HttpRequest, getResponseData);
22941 +PHP_METHOD(HttpRequest, getResponseHeader);
22942 +PHP_METHOD(HttpRequest, getResponseCookies);
22943 +PHP_METHOD(HttpRequest, getResponseCode);
22944 +PHP_METHOD(HttpRequest, getResponseStatus);
22945 +PHP_METHOD(HttpRequest, getResponseBody);
22946 +PHP_METHOD(HttpRequest, getResponseInfo);
22947 +PHP_METHOD(HttpRequest, getResponseMessage);
22948 +PHP_METHOD(HttpRequest, getRawResponseMessage);
22949 +PHP_METHOD(HttpRequest, getRequestMessage);
22950 +PHP_METHOD(HttpRequest, getRawRequestMessage);
22951 +PHP_METHOD(HttpRequest, getHistory);
22952 +PHP_METHOD(HttpRequest, clearHistory);
22953 +PHP_METHOD(HttpRequest, getMessageClass);
22954 +PHP_METHOD(HttpRequest, setMessageClass);
22955 +PHP_METHOD(HttpRequest, factory);
22956 +
22957 +#endif
22958 +#endif
22959 +#endif
22960 +
22961 +/*
22962 + * Local variables:
22963 + * tab-width: 4
22964 + * c-basic-offset: 4
22965 + * End:
22966 + * vim600: noet sw=4 ts=4 fdm=marker
22967 + * vim<600: noet sw=4 ts=4
22968 + */
22969 +
22970 --- /dev/null
22971 +++ b/ext/http/php_http_request_pool_api.h
22972 @@ -0,0 +1,97 @@
22973 +/*
22974 +    +--------------------------------------------------------------------+
22975 +    | PECL :: http                                                       |
22976 +    +--------------------------------------------------------------------+
22977 +    | Redistribution and use in source and binary forms, with or without |
22978 +    | modification, are permitted provided that the conditions mentioned |
22979 +    | in the accompanying LICENSE file are met.                          |
22980 +    +--------------------------------------------------------------------+
22981 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
22982 +    +--------------------------------------------------------------------+
22983 +*/
22984 +
22985 +/* $Id: php_http_request_pool_api.h 292841 2009-12-31 08:48:57Z mike $ */
22986 +
22987 +#ifndef PHP_HTTP_REQUEST_POOL_API_H
22988 +#define PHP_HTTP_REQUEST_POOL_API_H
22989 +#ifdef HTTP_HAVE_CURL
22990 +#ifdef ZEND_ENGINE_2
22991 +
22992 +typedef struct _http_request_pool_t {
22993 +       CURLM *ch;
22994 +       zend_llist finished;
22995 +       zend_llist handles;
22996 +       int unfinished;
22997 +#ifdef ZTS
22998 +       void ***tsrm_ls;
22999 +#endif
23000 +#ifdef HTTP_HAVE_EVENT
23001 +       struct event *timeout;
23002 +       unsigned useevents:1;
23003 +       unsigned runsocket:1;
23004 +#endif
23005 +} http_request_pool;
23006 +
23007 +typedef int (*http_request_pool_apply_func)(http_request_pool *pool, zval *request);
23008 +typedef int (*http_request_pool_apply_with_arg_func)(http_request_pool *pool, zval *request, void *arg);
23009 +
23010 +PHP_MINIT_FUNCTION(http_request_pool);
23011 +#ifdef HTTP_HAVE_EVENT
23012 +PHP_RINIT_FUNCTION(http_request_pool);
23013 +#endif
23014 +
23015 +#define http_request_pool_timeout _http_request_pool_timeout
23016 +extern struct timeval *_http_request_pool_timeout(http_request_pool *pool, struct timeval *timeout);
23017 +
23018 +#define http_request_pool_responsehandler _http_request_pool_responsehandler
23019 +extern void _http_request_pool_responsehandler(http_request_pool *pool);
23020 +
23021 +#define http_request_pool_apply_responsehandler _http_request_pool_responsehandler
23022 +extern int _http_request_pool_apply_responsehandler(http_request_pool *pool, zval *req, void *ch);
23023 +
23024 +#define http_request_pool_init(p) _http_request_pool_init((p) TSRMLS_CC)
23025 +PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC);
23026 +
23027 +#define http_request_pool_attach(p, r) _http_request_pool_attach((p), (r))
23028 +PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request);
23029 +
23030 +#define http_request_pool_detach(p, r) _http_request_pool_detach((p), (r))
23031 +PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request);
23032 +
23033 +#define http_request_pool_apply(p, f) _http_request_pool_apply((p), (f))
23034 +PHP_HTTP_API void _http_request_pool_apply(http_request_pool *pool, http_request_pool_apply_func cb);
23035 +
23036 +#define http_request_pool_apply_with_arg(p, f, a) _http_request_pool_apply_with_arg((p), (f), (a))
23037 +PHP_HTTP_API void _http_request_pool_apply_with_arg(http_request_pool *pool, http_request_pool_apply_with_arg_func cb, void *arg);
23038 +
23039 +#define http_request_pool_detach_all(p) _http_request_pool_detach_all((p))
23040 +PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool);
23041 +
23042 +#define http_request_pool_send(p) _http_request_pool_send((p))
23043 +PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool);
23044 +
23045 +#define http_request_pool_select _http_request_pool_select
23046 +PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool);
23047 +
23048 +#define http_request_pool_select_ex _http_request_pool_select_ex
23049 +PHP_HTTP_API STATUS _http_request_pool_select_ex(http_request_pool *pool, struct timeval *custom_timeout);
23050 +
23051 +#define http_request_pool_perform(p) _http_request_pool_perform((p))
23052 +PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool);
23053 +
23054 +#define http_request_pool_dtor(p) _http_request_pool_dtor((p))
23055 +PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool);
23056 +
23057 +#endif
23058 +#endif
23059 +#endif
23060 +
23061 +/*
23062 + * Local variables:
23063 + * tab-width: 4
23064 + * c-basic-offset: 4
23065 + * End:
23066 + * vim600: noet sw=4 ts=4 fdm=marker
23067 + * vim<600: noet sw=4 ts=4
23068 + */
23069 +
23070 --- /dev/null
23071 +++ b/ext/http/php_http_requestdatashare_object.h
23072 @@ -0,0 +1,59 @@
23073 +/*
23074 +    +--------------------------------------------------------------------+
23075 +    | PECL :: http                                                       |
23076 +    +--------------------------------------------------------------------+
23077 +    | Redistribution and use in source and binary forms, with or without |
23078 +    | modification, are permitted provided that the conditions mentioned |
23079 +    | in the accompanying LICENSE file are met.                          |
23080 +    +--------------------------------------------------------------------+
23081 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
23082 +    +--------------------------------------------------------------------+
23083 +*/
23084 +
23085 +/* $Id: php_http_requestdatashare_object.h 292841 2009-12-31 08:48:57Z mike $ */
23086 +
23087 +#ifndef PHP_HTTP_REQUEST_DATASHARE_OBJECT_H
23088 +#define PHP_HTTP_REQUEST_DATASHARE_OBJECT_H
23089 +#ifdef HTTP_HAVE_CURL
23090 +#ifdef ZEND_ENGINE_2
23091 +
23092 +typedef struct _http_requestdatashare_object_t {
23093 +       zend_object zo;
23094 +       http_request_datashare *share;
23095 +} http_requestdatashare_object;
23096 +
23097 +extern zend_class_entry *http_requestdatashare_object_ce;
23098 +extern zend_function_entry http_requestdatashare_object_fe[];
23099 +
23100 +extern PHP_MINIT_FUNCTION(http_requestdatashare_object);
23101 +
23102 +#define http_requestdatashare_object_new(ce) _http_requestdatashare_object_new((ce) TSRMLS_CC)
23103 +extern zend_object_value _http_requestdatashare_object_new(zend_class_entry *ce TSRMLS_DC);
23104 +#define http_requestdatashare_object_new_ex(ce, s, ptr) _http_requestdatashare_object_new_ex((ce), (s), (ptr) TSRMLS_CC)
23105 +extern zend_object_value _http_requestdatashare_object_new_ex(zend_class_entry *ce, http_request_datashare *share, http_requestdatashare_object **ptr TSRMLS_DC);
23106 +#define http_requestdatashare_object_free(o) _http_requestdatashare_object_free((o) TSRMLS_CC)
23107 +extern void _http_requestdatashare_object_free(zend_object *object TSRMLS_DC);
23108 +
23109 +PHP_METHOD(HttpRequestDataShare, __destruct);
23110 +PHP_METHOD(HttpRequestDataShare, count);
23111 +PHP_METHOD(HttpRequestDataShare, attach);
23112 +PHP_METHOD(HttpRequestDataShare, detach);
23113 +PHP_METHOD(HttpRequestDataShare, reset);
23114 +PHP_METHOD(HttpRequestDataShare, factory);
23115 +#ifndef WONKY
23116 +PHP_METHOD(HttpRequestDataShare, singleton);
23117 +#endif
23118 +
23119 +#endif
23120 +#endif
23121 +#endif
23122 +
23123 +/*
23124 + * Local variables:
23125 + * tab-width: 4
23126 + * c-basic-offset: 4
23127 + * End:
23128 + * vim600: noet sw=4 ts=4 fdm=marker
23129 + * vim<600: noet sw=4 ts=4
23130 + */
23131 +
23132 --- /dev/null
23133 +++ b/ext/http/php_http_requestpool_object.h
23134 @@ -0,0 +1,69 @@
23135 +/*
23136 +    +--------------------------------------------------------------------+
23137 +    | PECL :: http                                                       |
23138 +    +--------------------------------------------------------------------+
23139 +    | Redistribution and use in source and binary forms, with or without |
23140 +    | modification, are permitted provided that the conditions mentioned |
23141 +    | in the accompanying LICENSE file are met.                          |
23142 +    +--------------------------------------------------------------------+
23143 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
23144 +    +--------------------------------------------------------------------+
23145 +*/
23146 +
23147 +/* $Id: php_http_requestpool_object.h 292841 2009-12-31 08:48:57Z mike $ */
23148 +
23149 +#ifndef PHP_HTTP_REQUESTPOOL_OBJECT_H
23150 +#define PHP_HTTP_REQUESTPOOL_OBJECT_H
23151 +#ifdef HTTP_HAVE_CURL
23152 +#ifdef ZEND_ENGINE_2
23153 +
23154 +typedef struct _http_requestpool_object_t {
23155 +       zend_object zo;
23156 +       http_request_pool pool;
23157 +       struct {
23158 +               long pos;
23159 +       } iterator;
23160 +} http_requestpool_object;
23161 +
23162 +extern zend_class_entry *http_requestpool_object_ce;
23163 +extern zend_function_entry http_requestpool_object_fe[];
23164 +
23165 +extern PHP_MINIT_FUNCTION(http_requestpool_object);
23166 +
23167 +#define http_requestpool_object_new(ce) _http_requestpool_object_new(ce TSRMLS_CC)
23168 +extern zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC);
23169 +#define http_requestpool_object_free(o) _http_requestpool_object_free(o TSRMLS_CC)
23170 +extern void _http_requestpool_object_free(zend_object *object TSRMLS_DC);
23171 +
23172 +PHP_METHOD(HttpRequestPool, __construct);
23173 +PHP_METHOD(HttpRequestPool, __destruct);
23174 +PHP_METHOD(HttpRequestPool, attach);
23175 +PHP_METHOD(HttpRequestPool, detach);
23176 +PHP_METHOD(HttpRequestPool, send);
23177 +PHP_METHOD(HttpRequestPool, reset);
23178 +PHP_METHOD(HttpRequestPool, socketPerform);
23179 +PHP_METHOD(HttpRequestPool, socketSelect);
23180 +PHP_METHOD(HttpRequestPool, valid);
23181 +PHP_METHOD(HttpRequestPool, current);
23182 +PHP_METHOD(HttpRequestPool, key);
23183 +PHP_METHOD(HttpRequestPool, next);
23184 +PHP_METHOD(HttpRequestPool, rewind);
23185 +PHP_METHOD(HttpRequestPool, count);
23186 +PHP_METHOD(HttpRequestPool, getAttachedRequests);
23187 +PHP_METHOD(HttpRequestPool, getFinishedRequests);
23188 +PHP_METHOD(HttpRequestPool, enablePipelining);
23189 +PHP_METHOD(HttpRequestPool, enableEvents);
23190 +
23191 +#endif
23192 +#endif
23193 +#endif
23194 +
23195 +/*
23196 + * Local variables:
23197 + * tab-width: 4
23198 + * c-basic-offset: 4
23199 + * End:
23200 + * vim600: noet sw=4 ts=4 fdm=marker
23201 + * vim<600: noet sw=4 ts=4
23202 + */
23203 +
23204 --- /dev/null
23205 +++ b/ext/http/php_http_response_object.h
23206 @@ -0,0 +1,67 @@
23207 +/*
23208 +    +--------------------------------------------------------------------+
23209 +    | PECL :: http                                                       |
23210 +    +--------------------------------------------------------------------+
23211 +    | Redistribution and use in source and binary forms, with or without |
23212 +    | modification, are permitted provided that the conditions mentioned |
23213 +    | in the accompanying LICENSE file are met.                          |
23214 +    +--------------------------------------------------------------------+
23215 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
23216 +    +--------------------------------------------------------------------+
23217 +*/
23218 +
23219 +/* $Id: php_http_response_object.h 292841 2009-12-31 08:48:57Z mike $ */
23220 +
23221 +#ifndef PHP_HTTP_RESPONSE_OBJECT_H
23222 +#define PHP_HTTP_RESPONSE_OBJECT_H
23223 +#ifdef ZEND_ENGINE_2
23224 +#ifndef WONKY
23225 +
23226 +extern zend_class_entry *http_response_object_ce;
23227 +extern zend_function_entry http_response_object_fe[];
23228 +
23229 +extern PHP_MINIT_FUNCTION(http_response_object);
23230 +
23231 +PHP_METHOD(HttpResponse, setHeader);
23232 +PHP_METHOD(HttpResponse, getHeader);
23233 +PHP_METHOD(HttpResponse, setETag);
23234 +PHP_METHOD(HttpResponse, getETag);
23235 +PHP_METHOD(HttpResponse, setLastModified);
23236 +PHP_METHOD(HttpResponse, getLastModified);
23237 +PHP_METHOD(HttpResponse, setContentDisposition);
23238 +PHP_METHOD(HttpResponse, getContentDisposition);
23239 +PHP_METHOD(HttpResponse, setContentType);
23240 +PHP_METHOD(HttpResponse, getContentType);
23241 +PHP_METHOD(HttpResponse, guessContentType);
23242 +PHP_METHOD(HttpResponse, setCache);
23243 +PHP_METHOD(HttpResponse, getCache);
23244 +PHP_METHOD(HttpResponse, setCacheControl);
23245 +PHP_METHOD(HttpResponse, getCacheControl);
23246 +PHP_METHOD(HttpResponse, setGzip);
23247 +PHP_METHOD(HttpResponse, getGzip);
23248 +PHP_METHOD(HttpResponse, setThrottleDelay);
23249 +PHP_METHOD(HttpResponse, getThrottleDelay);
23250 +PHP_METHOD(HttpResponse, setBufferSize);
23251 +PHP_METHOD(HttpResponse, getBufferSize);
23252 +PHP_METHOD(HttpResponse, setData);
23253 +PHP_METHOD(HttpResponse, getData);
23254 +PHP_METHOD(HttpResponse, setFile);
23255 +PHP_METHOD(HttpResponse, getFile);
23256 +PHP_METHOD(HttpResponse, setStream);
23257 +PHP_METHOD(HttpResponse, getStream);
23258 +PHP_METHOD(HttpResponse, send);
23259 +PHP_METHOD(HttpResponse, capture);
23260 +
23261 +#endif
23262 +#endif
23263 +#endif
23264 +
23265 +/*
23266 + * Local variables:
23267 + * tab-width: 4
23268 + * c-basic-offset: 4
23269 + * End:
23270 + * vim600: noet sw=4 ts=4 fdm=marker
23271 + * vim<600: noet sw=4 ts=4
23272 + */
23273 +
23274 --- /dev/null
23275 +++ b/ext/http/php_http_send_api.h
23276 @@ -0,0 +1,91 @@
23277 +/*
23278 +    +--------------------------------------------------------------------+
23279 +    | PECL :: http                                                       |
23280 +    +--------------------------------------------------------------------+
23281 +    | Redistribution and use in source and binary forms, with or without |
23282 +    | modification, are permitted provided that the conditions mentioned |
23283 +    | in the accompanying LICENSE file are met.                          |
23284 +    +--------------------------------------------------------------------+
23285 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
23286 +    +--------------------------------------------------------------------+
23287 +*/
23288 +
23289 +/* $Id: php_http_send_api.h 292841 2009-12-31 08:48:57Z mike $ */
23290 +
23291 +#ifndef PHP_HTTP_SEND_API_H
23292 +#define PHP_HTTP_SEND_API_H
23293 +
23294 +typedef enum _http_send_mode_t {
23295 +       SEND_DATA,
23296 +       SEND_RSRC
23297 +} http_send_mode;
23298 +
23299 +#define HTTP_REDIRECT            0L
23300 +#define HTTP_REDIRECT_PERM     301L
23301 +#define HTTP_REDIRECT_FOUND    302L
23302 +#define HTTP_REDIRECT_POST     303L
23303 +#define HTTP_REDIRECT_PROXY    305L
23304 +#define HTTP_REDIRECT_TEMP     307L
23305 +
23306 +extern PHP_MINIT_FUNCTION(http_send);
23307 +
23308 +#define http_send_status(s) sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (long) (s) TSRMLS_CC)
23309 +#define http_send_header(n, v, r) _http_send_header_ex((n), strlen(n), (v), strlen(v), (r), NULL TSRMLS_CC)
23310 +#define http_send_header_ex(n, nl, v, vl, r, s) _http_send_header_ex((n), (nl), (v), (vl), (r), (s) TSRMLS_CC)
23311 +PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC);
23312 +#define http_send_header_string(h) _http_send_status_header_ex(0, (h), strlen(h), 1 TSRMLS_CC)
23313 +#define http_send_header_string_ex(h, l, r) _http_send_status_header_ex(0, (h), (l), (r) TSRMLS_CC)
23314 +#define http_send_status_header(s, h) _http_send_status_header_ex((s), (h), (h)?strlen(h):0, 1 TSRMLS_CC)
23315 +#define http_send_status_header_ex(s, h, l, r) _http_send_status_header_ex((s), (h), (l), (r) TSRMLS_CC)
23316 +PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header, size_t header_len, zend_bool replace TSRMLS_DC);
23317 +
23318 +#define http_send_header_zval(n, z, r) http_send_header_zval_ex((n), strlen(n), (z), (r))
23319 +#define http_send_header_zval_ex(n, l, z, r) _http_send_header_zval_ex((n), (l), (z), (r) TSRMLS_CC)
23320 +PHP_HTTP_API void _http_send_header_zval_ex(const char *name, size_t name_len, zval **val, zend_bool replace TSRMLS_DC);
23321 +
23322 +#define http_hide_header(h) http_hide_header_ex((h), strlen(h))
23323 +#define http_hide_header_ex(h, l) _http_hide_header_ex((h), (l) TSRMLS_CC)
23324 +PHP_HTTP_API void _http_hide_header_ex(const char *name, size_t name_len TSRMLS_DC);
23325 +
23326 +#define http_send_last_modified(t) _http_send_last_modified_ex((t), NULL TSRMLS_CC)
23327 +#define http_send_last_modified_ex(t, s) _http_send_last_modified_ex((t), (s) TSRMLS_CC)
23328 +PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC);
23329 +
23330 +#define http_send_etag(e, l) _http_send_etag_ex((e), (l), NULL TSRMLS_CC)
23331 +#define http_send_etag_ex(e, l, s) _http_send_etag_ex((e), (l), (s) TSRMLS_CC)
23332 +PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC);
23333 +
23334 +#define http_send_cache_control(cc, cl) http_send_header_ex("Cache-Control", lenof("Cache-Control"), (cc), (cl), 1, NULL)
23335 +
23336 +#define http_send_content_type(c, l) _http_send_content_type((c), (l) TSRMLS_CC)
23337 +PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_len TSRMLS_DC);
23338 +
23339 +#define http_send_content_disposition(f, l, i) _http_send_content_disposition((f), (l), (i) TSRMLS_CC)
23340 +PHP_HTTP_API STATUS _http_send_content_disposition(const char *filename, size_t f_len, zend_bool send_inline TSRMLS_DC);
23341 +
23342 +#define http_send_data(d, l) http_send((d), (l), SEND_DATA)
23343 +#define http_send_data_ex(d, l, nc) http_send_ex((d), (l), SEND_DATA, (nc))
23344 +#define http_send(d, s, m) _http_send_ex((d), (s), (m), 0 TSRMLS_CC)
23345 +#define http_send_ex(d, s, m, nc) _http_send_ex((d), (s), (m), (nc) TSRMLS_CC)
23346 +PHP_HTTP_API STATUS _http_send_ex(const void *data, size_t data_size, http_send_mode mode, zend_bool no_cache TSRMLS_DC);
23347 +
23348 +#define http_send_file(f) http_send_stream_ex(php_stream_open_wrapper_ex(f, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT), 1, 0)
23349 +#define http_send_file_ex(f, nc) http_send_stream_ex(php_stream_open_wrapper_ex(f, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT), 1, (nc))
23350 +#define http_send_stream(s) http_send_stream_ex((s), 0, 0)
23351 +#define http_send_stream_ex(s, c, nc) _http_send_stream_ex((s), (c), (nc) TSRMLS_CC)
23352 +PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *s, zend_bool close_stream, zend_bool no_cache TSRMLS_DC);
23353 +
23354 +#define http_guess_content_type(mf, mm, d, l, m) _http_guess_content_type((mf), (mm), (d), (l), (m) TSRMLS_CC)
23355 +PHP_HTTP_API char *_http_guess_content_type(const char *magic_file, long magic_mode, void *data_ptr, size_t data_len, http_send_mode mode TSRMLS_DC);
23356 +
23357 +#endif
23358 +
23359 +/*
23360 + * Local variables:
23361 + * tab-width: 4
23362 + * c-basic-offset: 4
23363 + * End:
23364 + * vim600: noet sw=4 ts=4 fdm=marker
23365 + * vim<600: noet sw=4 ts=4
23366 + */
23367 +
23368 --- /dev/null
23369 +++ b/ext/http/php_http_std_defs.h
23370 @@ -0,0 +1,406 @@
23371 +/*
23372 +    +--------------------------------------------------------------------+
23373 +    | PECL :: http                                                       |
23374 +    +--------------------------------------------------------------------+
23375 +    | Redistribution and use in source and binary forms, with or without |
23376 +    | modification, are permitted provided that the conditions mentioned |
23377 +    | in the accompanying LICENSE file are met.                          |
23378 +    +--------------------------------------------------------------------+
23379 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
23380 +    +--------------------------------------------------------------------+
23381 +*/
23382 +
23383 +/* $Id: php_http_std_defs.h 310777 2011-05-05 06:43:10Z mike $ */
23384 +
23385 +#ifndef PHP_HTTP_STD_DEFS_H
23386 +#define PHP_HTTP_STD_DEFS_H
23387 +
23388 +#if defined(PHP_WIN32)
23389 +#      if defined(HTTP_EXPORTS)
23390 +#              define PHP_HTTP_API __declspec(dllexport)
23391 +#      elif defined(COMPILE_DL_HTTP)
23392 +#              define PHP_HTTP_API __declspec(dllimport)
23393 +#      else
23394 +#              define PHP_HTTP_API
23395 +#      endif
23396 +#else
23397 +#      define PHP_HTTP_API
23398 +#endif
23399 +
23400 +/* make functions that return SUCCESS|FAILURE more obvious */
23401 +typedef int STATUS;
23402 +
23403 +/* lenof() */
23404 +#define lenof(S) (sizeof(S) - 1)
23405 +
23406 +#ifndef MIN
23407 +#      define MIN(a,b) (a<b?a:b)
23408 +#endif
23409 +#ifndef MAX
23410 +#      define MAX(a,b) (a>b?a:b)
23411 +#endif
23412 +
23413 +/* STR_SET() */
23414 +#ifndef STR_SET
23415 +#      define STR_SET(STR, SET) \
23416 +       { \
23417 +               STR_FREE(STR); \
23418 +               STR = SET; \
23419 +       }
23420 +#endif
23421 +
23422 +#define STR_PTR(s) (s?s:"")
23423 +
23424 +#define INIT_ZARR(zv, ht) \
23425 +       { \
23426 +               INIT_PZVAL(&(zv)); \
23427 +               Z_TYPE(zv) = IS_ARRAY; \
23428 +               Z_ARRVAL(zv) = (ht); \
23429 +       }
23430 +
23431 +/* return bool (v == SUCCESS) */
23432 +#define RETVAL_SUCCESS(v) RETVAL_BOOL(SUCCESS == (v))
23433 +#define RETURN_SUCCESS(v) RETURN_BOOL(SUCCESS == (v))
23434 +/* return object(values) */
23435 +#define RETVAL_OBJECT(o, addref) \
23436 +       RETVAL_OBJVAL((o)->value.obj, addref)
23437 +#define RETURN_OBJECT(o, addref) \
23438 +       RETVAL_OBJECT(o, addref); \
23439 +       return
23440 +#define RETVAL_OBJVAL(ov, addref) \
23441 +       ZVAL_OBJVAL(return_value, ov, addref)
23442 +#define RETURN_OBJVAL(ov, addref) \
23443 +       RETVAL_OBJVAL(ov, addref); \
23444 +       return
23445 +#define ZVAL_OBJVAL(zv, ov, addref) \
23446 +       (zv)->type = IS_OBJECT; \
23447 +       (zv)->value.obj = (ov);\
23448 +       if (addref && Z_OBJ_HT_P(zv)->add_ref) { \
23449 +               Z_OBJ_HT_P(zv)->add_ref((zv) TSRMLS_CC); \
23450 +       }
23451 +/* return property */
23452 +#define RETVAL_PROP(n) RETVAL_PROP_EX(getThis(), n)
23453 +#define RETURN_PROP(n) RETURN_PROP_EX(getThis(), n)
23454 +#define RETVAL_PROP_EX(this, n) \
23455 +       { \
23456 +               zval *__prop = zend_read_property(THIS_CE, this, ZEND_STRS(#n)-1, 0 TSRMLS_CC); \
23457 +               RETVAL_ZVAL(__prop, 1, 0); \
23458 +       }
23459 +#define RETURN_PROP_EX(this, n) \
23460 +       { \
23461 +               zval *__prop = zend_read_property(THIS_CE, this, ZEND_STRS(#n)-1, 0 TSRMLS_CC); \
23462 +               RETURN_ZVAL(__prop, 1, 0); \
23463 +       }
23464 +
23465 +/* function accepts no args */
23466 +#define NO_ARGS zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "");
23467 +
23468 +/* CR LF */
23469 +#define HTTP_CRLF "\r\n"
23470 +
23471 +/* default cache control */
23472 +#define HTTP_DEFAULT_CACHECONTROL "private, must-revalidate, max-age=0"
23473 +
23474 +/* max URL length */
23475 +#define HTTP_URL_MAXLEN 4096
23476 +
23477 +/* max request method length */
23478 +#define HTTP_REQUEST_METHOD_MAXLEN 31
23479 +
23480 +/* def URL arg separator */
23481 +#define HTTP_URL_ARGSEP "&"
23482 +
23483 +/* send buffer size */
23484 +#define HTTP_SENDBUF_SIZE 40960
23485 +
23486 +/* CURL buffer size */
23487 +#define HTTP_CURLBUF_SIZE 16384
23488 +
23489 +/* known methods */
23490 +#define HTTP_KNOWN_METHODS \
23491 +               /* HTTP 1.1 */ \
23492 +               "GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE, CONNECT, " \
23493 +               /* WebDAV - RFC 2518 */ \
23494 +               "PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, " \
23495 +               /* WebDAV Versioning - RFC 3253 */ \
23496 +               "VERSION-CONTROL, REPORT, CHECKOUT, CHECKIN, UNCHECKOUT, " \
23497 +               "MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE-CONTROL, MKACTIVITY, " \
23498 +               /* WebDAV Access Control - RFC 3744 */ \
23499 +               "ACL, " \
23500 +               /* END */
23501 +
23502 +#ifdef ZEND_ENGINE_2
23503 +#      include "ext/standard/file.h"
23504 +#      define HTTP_DEFAULT_STREAM_CONTEXT FG(default_context)
23505 +#else
23506 +#      define HTTP_DEFAULT_STREAM_CONTEXT NULL
23507 +#endif
23508 +
23509 +#define HTTP_PHP_INI_ENTRY(entry, default, scope, updater, global) \
23510 +       STD_PHP_INI_ENTRY(entry, default, scope, updater, global, zend_http_globals, http_globals)
23511 +#define HTTP_PHP_INI_ENTRY_EX(entry, default, scope, updater, displayer, global) \
23512 +       STD_PHP_INI_ENTRY_EX(entry, default, scope, updater, global, zend_http_globals, http_globals, displayer)
23513 +
23514 +
23515 +#define HTTP_LONG_CONSTANT(name, const) REGISTER_LONG_CONSTANT(name, const, CONST_CS | CONST_PERSISTENT)
23516 +
23517 +/* {{{ objects & properties */
23518 +#ifdef ZEND_ENGINE_2
23519 +
23520 +#      define HTTP_STATIC_ME_ALIAS(me, al, ai) ZEND_FENTRY(me, ZEND_FN(al), ai, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
23521 +
23522 +#      define HTTP_REGISTER_CLASS_EX(classname, name, parent, flags) \
23523 +       { \
23524 +               zend_class_entry ce; \
23525 +               memset(&ce, 0, sizeof(zend_class_entry)); \
23526 +               INIT_CLASS_ENTRY(ce, #classname, name## _fe); \
23527 +               ce.create_object = _ ##name## _new; \
23528 +               name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
23529 +               name## _ce->ce_flags |= flags;  \
23530 +               memcpy(& name## _handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
23531 +       }
23532 +
23533 +#      define HTTP_REGISTER_CLASS(classname, name, parent, flags) \
23534 +       { \
23535 +               zend_class_entry ce; \
23536 +               memset(&ce, 0, sizeof(zend_class_entry)); \
23537 +               INIT_CLASS_ENTRY(ce, #classname, name## _fe); \
23538 +               ce.create_object = NULL; \
23539 +               name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
23540 +               name## _ce->ce_flags |= flags;  \
23541 +       }
23542 +
23543 +#      define HTTP_REGISTER_EXCEPTION(classname, cename, parent) \
23544 +       { \
23545 +               zend_class_entry ce; \
23546 +               memset(&ce, 0, sizeof(zend_class_entry)); \
23547 +               INIT_CLASS_ENTRY(ce, #classname, NULL); \
23548 +               ce.create_object = NULL; \
23549 +               cename = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
23550 +       }
23551 +
23552 +#      define getObject(t, o) getObjectEx(t, o, getThis())
23553 +#      define getObjectEx(t, o, v) t * o = ((t *) zend_object_store_get_object(v TSRMLS_CC))
23554 +#      define putObject(t, o) zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) _ ##t## _free, NULL TSRMLS_CC);
23555 +#      ifndef WONKY
23556 +#              define freeObject(o) \
23557 +                       if (OBJ_GUARDS(o)) { \
23558 +                               zend_hash_destroy(OBJ_GUARDS(o)); \
23559 +                               FREE_HASHTABLE(OBJ_GUARDS(o)); \
23560 +                       } \
23561 +                       if (OBJ_PROP(o)) { \
23562 +                               zend_hash_destroy(OBJ_PROP(o)); \
23563 +                               FREE_HASHTABLE(OBJ_PROP(o)); \
23564 +                       } \
23565 +                       efree(o);
23566 +#      else
23567 +#              define freeObject(o) \
23568 +                       if (OBJ_PROP(o)) { \
23569 +                               zend_hash_destroy(OBJ_PROP(o)); \
23570 +                               FREE_HASHTABLE(OBJ_PROP(o)); \
23571 +                       } \
23572 +                       efree(o);
23573 +#      endif
23574 +#      define OBJ_PROP(o) (o)->zo.properties
23575 +#      define OBJ_GUARDS(o) (o)->zo.guards
23576 +
23577 +#      define ACC_PROP_PRIVATE(ce, flags)              ((flags & ZEND_ACC_PRIVATE) && (EG(scope) && ce == EG(scope))
23578 +#      define ACC_PROP_PROTECTED(ce, flags)    ((flags & ZEND_ACC_PROTECTED) && (zend_check_protected(ce, EG(scope))))
23579 +#      define ACC_PROP_PUBLIC(flags)                   (flags & ZEND_ACC_PUBLIC)
23580 +#      define ACC_PROP(ce, flags)                              (ACC_PROP_PUBLIC(flags) || ACC_PROP_PRIVATE(ce, flags) || ACC_PROP_PROTECTED(ce, flags))
23581 +
23582 +#      define SET_EH_THROW_HTTP() SET_EH_THROW_EX(http_exception_get_default())
23583 +#      define SET_EH_THROW_EX(ex) php_set_error_handling(EH_THROW, ex TSRMLS_CC)
23584 +#      define SET_EH_NORMAL() php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC)
23585 +
23586 +#endif /* ZEND_ENGINE_2 */
23587 +/* }}} */
23588 +
23589 +#ifdef ZEND_ENGINE_2
23590 +#      define with_error_handling(eh, ec) \
23591 +       { \
23592 +               error_handling_t __eh = GLOBAL_ERROR_HANDLING; \
23593 +               zend_class_entry *__ec= GLOBAL_EXCEPTION_CLASS; \
23594 +               php_set_error_handling(eh, ec TSRMLS_CC);
23595 +#      define end_error_handling() \
23596 +               php_set_error_handling(__eh, __ec TSRMLS_CC); \
23597 +       }
23598 +#else
23599 +#      define with_error_handling(eh, ec)
23600 +#      define end_error_handling()
23601 +#endif
23602 +
23603 +#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 2) || PHP_MAJOR_VERSION > 5
23604 +#      define  ZEND_EXCEPTION_GET_DEFAULT() zend_exception_get_default(TSRMLS_C)
23605 +#else
23606 +#      define  ZEND_EXCEPTION_GET_DEFAULT() zend_exception_get_default()
23607 +#endif
23608 +
23609 +#ifndef E_THROW
23610 +#      define E_THROW 0
23611 +#endif
23612 +#ifdef ZEND_ENGINE_2
23613 +#      define HE_THROW         E_THROW TSRMLS_CC
23614 +#      define HE_NOTICE        (HTTP_G->only_exceptions ? E_THROW : E_NOTICE) TSRMLS_CC
23615 +#      define HE_WARNING       (HTTP_G->only_exceptions ? E_THROW : E_WARNING) TSRMLS_CC
23616 +#      define HE_ERROR         (HTTP_G->only_exceptions ? E_THROW : E_ERROR) TSRMLS_CC
23617 +#else
23618 +#      define HE_THROW         E_WARNING TSRMLS_CC
23619 +#      define HE_NOTICE        E_NOTICE TSRMLS_CC
23620 +#      define HE_WARNING       E_WARNING TSRMLS_CC
23621 +#      define HE_ERROR         E_ERROR TSRMLS_CC
23622 +#endif
23623 +
23624 +#define HTTP_E_RUNTIME                         1L
23625 +#define HTTP_E_INVALID_PARAM           2L
23626 +#define HTTP_E_HEADER                          3L
23627 +#define HTTP_E_MALFORMED_HEADERS       4L
23628 +#define HTTP_E_REQUEST_METHOD          5L
23629 +#define HTTP_E_MESSAGE_TYPE                    6L
23630 +#define HTTP_E_ENCODING                                7L
23631 +#define HTTP_E_REQUEST                         8L
23632 +#define HTTP_E_REQUEST_POOL                    9L
23633 +#define HTTP_E_SOCKET                          10L
23634 +#define HTTP_E_RESPONSE                                11L
23635 +#define HTTP_E_URL                                     12L
23636 +#define HTTP_E_QUERYSTRING                     13L
23637 +
23638 +#ifdef ZEND_ENGINE_2
23639 +#      define HTTP_BEGIN_ARGS_EX(class, method, ret_ref, req_args)     HTTP_STATIC_ARG_INFO ZEND_BEGIN_ARG_INFO_EX(args_for_ ##class## _ ##method , 0, ret_ref, req_args)
23640 +#      define HTTP_BEGIN_ARGS_AR(class, method, ret_ref, req_args)     HTTP_STATIC_ARG_INFO ZEND_BEGIN_ARG_INFO_EX(args_for_ ##class## _ ##method , 1, ret_ref, req_args)
23641 +#      define HTTP_END_ARGS                                                                            }
23642 +#      define HTTP_EMPTY_ARGS_EX(class, method, ret_ref)                       HTTP_BEGIN_ARGS_EX(class, method, ret_ref, 0) HTTP_END_ARGS
23643 +#      define HTTP_ARGS(class, method)                                                         args_for_ ##class## _ ##method
23644 +#      define HTTP_ARG_VAL(name, pass_ref)                                                     ZEND_ARG_INFO(pass_ref, name)
23645 +#      define HTTP_ARG_OBJ(class, name, allow_null)                            ZEND_ARG_OBJ_INFO(0, name, class, allow_null)
23646 +#endif
23647 +
23648 +#ifdef ZEND_ENGINE_2
23649 +#      define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL, 0, 0}
23650 +#else
23651 +#      define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL}
23652 +#endif
23653 +
23654 +#ifdef HTTP_HAVE_CURL
23655 +#      ifdef ZEND_ENGINE_2
23656 +#              define HTTP_DECLARE_ARG_PASS_INFO() \
23657 +                       HTTP_STATIC_ARG_INFO \
23658 +                       ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_2, 0) \
23659 +                               ZEND_ARG_PASS_INFO(0) \
23660 +                               ZEND_ARG_PASS_INFO(1) \
23661 +                       ZEND_END_ARG_INFO(); \
23662 + \
23663 +                       HTTP_STATIC_ARG_INFO \
23664 +                       ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_3, 0) \
23665 +                               ZEND_ARG_PASS_INFO(0) \
23666 +                               ZEND_ARG_PASS_INFO(0) \
23667 +                               ZEND_ARG_PASS_INFO(1) \
23668 +                       ZEND_END_ARG_INFO(); \
23669 + \
23670 +                       HTTP_STATIC_ARG_INFO \
23671 +                       ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_4, 0) \
23672 +                               ZEND_ARG_PASS_INFO(0) \
23673 +                               ZEND_ARG_PASS_INFO(0) \
23674 +                               ZEND_ARG_PASS_INFO(0) \
23675 +                               ZEND_ARG_PASS_INFO(1) \
23676 +                       ZEND_END_ARG_INFO(); \
23677 + \
23678 +                       HTTP_STATIC_ARG_INFO \
23679 +                       ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_5, 0) \
23680 +                               ZEND_ARG_PASS_INFO(0) \
23681 +                               ZEND_ARG_PASS_INFO(0) \
23682 +                               ZEND_ARG_PASS_INFO(0) \
23683 +                               ZEND_ARG_PASS_INFO(0) \
23684 +                               ZEND_ARG_PASS_INFO(1) \
23685 +                       ZEND_END_ARG_INFO();
23686 +
23687 +#      else
23688 +#              define HTTP_DECLARE_ARG_PASS_INFO() \
23689 +                       static unsigned char http_arg_pass_ref_2[] = {2, BYREF_NONE, BYREF_FORCE}; \
23690 +                       static unsigned char http_arg_pass_ref_3[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; \
23691 +                       static unsigned char http_arg_pass_ref_4[] = {4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; \
23692 +                       static unsigned char http_arg_pass_ref_5[] = {5, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
23693 +#      endif /* ZEND_ENGINE_2 */
23694 +#else
23695 +#      ifdef ZEND_ENGINE_2
23696 +#              define HTTP_DECLARE_ARG_PASS_INFO() \
23697 +                       HTTP_STATIC_ARG_INFO \
23698 +                       ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_2, 0) \
23699 +                               ZEND_ARG_PASS_INFO(0) \
23700 +                               ZEND_ARG_PASS_INFO(1) \
23701 +                       ZEND_END_ARG_INFO(); \
23702 +\
23703 +                       HTTP_STATIC_ARG_INFO \
23704 +                       ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_3, 0) \
23705 +                               ZEND_ARG_PASS_INFO(0) \
23706 +                               ZEND_ARG_PASS_INFO(0) \
23707 +                               ZEND_ARG_PASS_INFO(1) \
23708 +                       ZEND_END_ARG_INFO(); \
23709 +\
23710 +                       HTTP_STATIC_ARG_INFO \
23711 +                       ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_4, 0) \
23712 +                               ZEND_ARG_PASS_INFO(0) \
23713 +                               ZEND_ARG_PASS_INFO(0) \
23714 +                               ZEND_ARG_PASS_INFO(0) \
23715 +                               ZEND_ARG_PASS_INFO(1) \
23716 +                       ZEND_END_ARG_INFO();
23717 +#      else
23718 +#              define HTTP_DECLARE_ARG_PASS_INFO() \
23719 +                       static unsigned char http_arg_pass_ref_2[] = {2, BYREF_NONE, BYREF_FORCE}; \
23720 +                       static unsigned char http_arg_pass_ref_3[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; \
23721 +                       static unsigned char http_arg_pass_ref_4[] = {4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
23722 +#      endif /* ZEND_ENGINE_2 */
23723 +#endif /* HTTP_HAVE_CURL */
23724 +
23725 +
23726 +#ifndef HAVE_CURL_SHARE_STRERROR
23727 +#      define curl_share_strerror(dummy) "unknown error"
23728 +#endif
23729 +#ifndef HAVE_CURL_EASY_STRERROR
23730 +#      define curl_easy_strerror(dummy) "unknown error"
23731 +#endif
23732 +#ifndef HAVE_CURL_MULTI_STRERROR
23733 +#      define curl_multi_strerror(dummy) "unknown error"
23734 +#endif
23735 +
23736 +#define PHP_MINIT_CALL(func) PHP_MINIT(func)(INIT_FUNC_ARGS_PASSTHRU)
23737 +#define PHP_RINIT_CALL(func) PHP_RINIT(func)(INIT_FUNC_ARGS_PASSTHRU)
23738 +#define PHP_MSHUTDOWN_CALL(func) PHP_MSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU)
23739 +#define PHP_RSHUTDOWN_CALL(func) PHP_RSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU)
23740 +
23741 +#define Z_OBJ_DELREF(z) \
23742 +       if (Z_OBJ_HT(z)->del_ref) { \
23743 +               Z_OBJ_HT(z)->del_ref(&(z) TSRMLS_CC); \
23744 +       }
23745 +#define Z_OBJ_ADDREF(z) \
23746 +       if (Z_OBJ_HT(z)->add_ref) { \
23747 +               Z_OBJ_HT(z)->add_ref(&(z) TSRMLS_CC); \
23748 +       }
23749 +#define Z_OBJ_DELREF_P(z) \
23750 +       if (Z_OBJ_HT_P(z)->del_ref) { \
23751 +               Z_OBJ_HT_P(z)->del_ref((z) TSRMLS_CC); \
23752 +       }
23753 +#define Z_OBJ_ADDREF_P(z) \
23754 +       if (Z_OBJ_HT_P(z)->add_ref) { \
23755 +               Z_OBJ_HT_P(z)->add_ref((z) TSRMLS_CC); \
23756 +       }
23757 +#define Z_OBJ_DELREF_PP(z) \
23758 +       if (Z_OBJ_HT_PP(z)->del_ref) { \
23759 +               Z_OBJ_HT_PP(z)->del_ref(*(z) TSRMLS_CC); \
23760 +       }
23761 +#define Z_OBJ_ADDREF_PP(z) \
23762 +       if (Z_OBJ_HT_PP(z)->add_ref) { \
23763 +               Z_OBJ_HT_PP(z)->add_ref(*(z) TSRMLS_CC); \
23764 +       }
23765 +
23766 +#endif /* PHP_HTTP_STD_DEFS_H */
23767 +
23768 +/*
23769 + * Local variables:
23770 + * tab-width: 4
23771 + * c-basic-offset: 4
23772 + * End:
23773 + * vim600: noet sw=4 ts=4 fdm=marker
23774 + * vim<600: noet sw=4 ts=4
23775 + */
23776 +
23777 --- /dev/null
23778 +++ b/ext/http/php_http_url_api.h
23779 @@ -0,0 +1,165 @@
23780 +/*
23781 +    +--------------------------------------------------------------------+
23782 +    | PECL :: http                                                       |
23783 +    +--------------------------------------------------------------------+
23784 +    | Redistribution and use in source and binary forms, with or without |
23785 +    | modification, are permitted provided that the conditions mentioned |
23786 +    | in the accompanying LICENSE file are met.                          |
23787 +    +--------------------------------------------------------------------+
23788 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
23789 +    +--------------------------------------------------------------------+
23790 +*/
23791 +
23792 +/* $Id: php_http_url_api.h 292841 2009-12-31 08:48:57Z mike $ */
23793 +
23794 +#ifndef PHP_HTTP_URL_API_H
23795 +#define PHP_HTTP_URL_API_H
23796 +
23797 +#include "ext/standard/url.h"
23798 +
23799 +extern PHP_MINIT_FUNCTION(http_url);
23800 +
23801 +#define http_absolute_url(u) _http_absolute_url_ex((u), HTTP_URL_REPLACE TSRMLS_CC)
23802 +#define http_absolute_url_ex(u, f) _http_absolute_url_ex((u), (f) TSRMLS_CC)
23803 +PHP_HTTP_API char *_http_absolute_url_ex(const char *url, int flags TSRMLS_DC);
23804 +
23805 +#define HTTP_URL_REPLACE               0x000
23806 +#define HTTP_URL_JOIN_PATH             0x001
23807 +#define HTTP_URL_JOIN_QUERY            0x002
23808 +#define HTTP_URL_STRIP_USER            0x004
23809 +#define HTTP_URL_STRIP_PASS            0x008
23810 +#define HTTP_URL_STRIP_AUTH            (HTTP_URL_STRIP_USER|HTTP_URL_STRIP_PASS)
23811 +#define HTTP_URL_STRIP_PORT            0x020
23812 +#define HTTP_URL_STRIP_PATH            0x040
23813 +#define HTTP_URL_STRIP_QUERY   0x080
23814 +#define HTTP_URL_STRIP_FRAGMENT        0x100
23815 +#define HTTP_URL_STRIP_ALL ( \
23816 +       HTTP_URL_STRIP_AUTH | \
23817 +       HTTP_URL_STRIP_PORT | \
23818 +       HTTP_URL_STRIP_PATH | \
23819 +       HTTP_URL_STRIP_QUERY | \
23820 +       HTTP_URL_STRIP_FRAGMENT \
23821 +)
23822 +#define HTTP_URL_FROM_ENV              0x1000
23823 +
23824 +#define http_build_url(f, o, n, p, s, l) _http_build_url((f), (o), (n), (p), (s), (l) TSRMLS_CC)
23825 +PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC);
23826 +
23827 +#define http_urlencode_hash(h, q) _http_urlencode_hash_ex((h), 1, NULL, 0, (q), NULL TSRMLS_CC)
23828 +#define http_urlencode_hash_ex(h, o, p, pl, q, ql) _http_urlencode_hash_ex((h), (o), (p), (pl), (q), (ql) TSRMLS_CC)
23829 +PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep, char *pre_encoded_data, size_t pre_encoded_len, char **encoded_data, size_t *encoded_len TSRMLS_DC);
23830 +
23831 +#define http_urlencode_hash_recursive(ht, s, as, al, pr, pl) _http_urlencode_hash_recursive((ht), (s), (as), (al), (pr), (pl) TSRMLS_CC)
23832 +PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC);
23833 +
23834 +#define http_url_from_struct(u, ht) _http_url_from_struct((u), (ht) TSRMLS_CC)
23835 +static inline php_url *_http_url_from_struct(php_url *url, HashTable *ht TSRMLS_DC)
23836 +{
23837 +       zval **e;
23838 +       
23839 +       if (!url) {
23840 +               url = ecalloc(1, sizeof(php_url));
23841 +       }
23842 +       
23843 +       if ((SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e))
23844 +                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
23845 +               url->scheme = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
23846 +       }
23847 +       if ((SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e))
23848 +                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
23849 +               url->user = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
23850 +       }
23851 +       if ((SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e))
23852 +                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
23853 +               url->pass = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
23854 +       }
23855 +       if ((SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e))
23856 +                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
23857 +               url->host = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
23858 +       }
23859 +       if ((SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e))
23860 +                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
23861 +               url->path = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
23862 +       }
23863 +       if ((SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e))
23864 +                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
23865 +               url->query = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
23866 +       }
23867 +       if ((SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e))
23868 +                       && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) {
23869 +               url->fragment = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e));
23870 +       }
23871 +       if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) {
23872 +               if (Z_TYPE_PP(e) == IS_LONG) {
23873 +                       url->port = (unsigned short) Z_LVAL_PP(e);
23874 +               } else {
23875 +                       zval *o = http_zsep(IS_LONG, *e);
23876 +                       
23877 +                       url->port = (unsigned short) Z_LVAL_P(o);
23878 +                       zval_ptr_dtor(&o);
23879 +               }
23880 +       }
23881 +       
23882 +       return url;
23883 +}
23884 +
23885 +#define http_url_tostruct(u, strct) _http_url_tostruct((u), (strct) TSRMLS_CC)
23886 +static inline HashTable *_http_url_tostruct(php_url *url, zval *strct TSRMLS_DC)
23887 +{
23888 +       zval arr;
23889 +       
23890 +       if (strct) {
23891 +               switch (Z_TYPE_P(strct)) {
23892 +                       default:
23893 +                               zval_dtor(strct);
23894 +                               array_init(strct);
23895 +                       case IS_ARRAY:
23896 +                       case IS_OBJECT:
23897 +                               INIT_ZARR(arr, HASH_OF(strct));
23898 +               }
23899 +       } else {
23900 +               INIT_PZVAL(&arr);
23901 +               array_init(&arr);
23902 +       }
23903 +       
23904 +       if (url) {
23905 +               if (url->scheme) {
23906 +                       add_assoc_string(&arr, "scheme", url->scheme, 1);
23907 +               }
23908 +               if (url->user) {
23909 +                       add_assoc_string(&arr, "user", url->user, 1);
23910 +               }
23911 +               if (url->pass) {
23912 +                       add_assoc_string(&arr, "pass", url->pass, 1);
23913 +               }
23914 +               if (url->host) {
23915 +                       add_assoc_string(&arr, "host", url->host, 1);
23916 +               }
23917 +               if (url->port) {
23918 +                       add_assoc_long(&arr, "port", (long) url->port);
23919 +               }
23920 +               if (url->path) {
23921 +                       add_assoc_string(&arr, "path", url->path, 1);
23922 +               }
23923 +               if (url->query) {
23924 +                       add_assoc_string(&arr, "query", url->query, 1);
23925 +               }
23926 +               if (url->fragment) {
23927 +                       add_assoc_string(&arr, "fragment", url->fragment, 1);
23928 +               }
23929 +       }
23930 +       
23931 +       return Z_ARRVAL(arr);
23932 +}
23933 +
23934 +#endif
23935 +
23936 +/*
23937 + * Local variables:
23938 + * tab-width: 4
23939 + * c-basic-offset: 4
23940 + * End:
23941 + * vim600: noet sw=4 ts=4 fdm=marker
23942 + * vim<600: noet sw=4 ts=4
23943 + */
23944 +
23945 --- /dev/null
23946 +++ b/ext/http/php_http_util_object.h
23947 @@ -0,0 +1,35 @@
23948 +/*
23949 +    +--------------------------------------------------------------------+
23950 +    | PECL :: http                                                       |
23951 +    +--------------------------------------------------------------------+
23952 +    | Redistribution and use in source and binary forms, with or without |
23953 +    | modification, are permitted provided that the conditions mentioned |
23954 +    | in the accompanying LICENSE file are met.                          |
23955 +    +--------------------------------------------------------------------+
23956 +    | Copyright (c) 2004-2010, Michael Wallner <mike@php.net>            |
23957 +    +--------------------------------------------------------------------+
23958 +*/
23959 +
23960 +/* $Id: php_http_util_object.h 292841 2009-12-31 08:48:57Z mike $ */
23961 +
23962 +#ifndef PHP_HTTP_UTIL_OBJECT_H
23963 +#define PHP_HTTP_UTIL_OBJECT_H
23964 +#ifdef ZEND_ENGINE_2
23965 +
23966 +extern zend_class_entry *http_util_object_ce;
23967 +extern zend_function_entry http_util_object_fe[];
23968 +
23969 +extern PHP_MINIT_FUNCTION(http_util_object);
23970 +
23971 +#endif
23972 +#endif
23973 +
23974 +/*
23975 + * Local variables:
23976 + * tab-width: 4
23977 + * c-basic-offset: 4
23978 + * End:
23979 + * vim600: noet sw=4 ts=4 fdm=marker
23980 + * vim<600: noet sw=4 ts=4
23981 + */
23982 +
23983 --- /dev/null
23984 +++ b/ext/http/phpstr/phpstr.c
23985 @@ -0,0 +1,379 @@
23986 +
23987 +/* $Id: phpstr.c 211942 2006-04-24 17:17:09Z mike $ */
23988 +
23989 +#include "php.h"
23990 +#include "phpstr.h"
23991 +
23992 +PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int flags)
23993 +{
23994 +       if (!buf) {
23995 +               buf = pemalloc(sizeof(phpstr), flags & PHPSTR_INIT_PERSISTENT);
23996 +       }
23997 +
23998 +       if (buf) {
23999 +               buf->size = (chunk_size) ? chunk_size : PHPSTR_DEFAULT_SIZE;
24000 +               buf->pmem = (flags & PHPSTR_INIT_PERSISTENT) ? 1 : 0;
24001 +               buf->data = (flags & PHPSTR_INIT_PREALLOC) ? pemalloc(buf->size, buf->pmem) : NULL;
24002 +               buf->free = (flags & PHPSTR_INIT_PREALLOC) ? buf->size : 0;
24003 +               buf->used = 0;
24004 +       }
24005 +       
24006 +       return buf;
24007 +}
24008 +
24009 +PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, const char *string, size_t length)
24010 +{
24011 +       if ((buf = phpstr_init(buf))) {
24012 +               if (PHPSTR_NOMEM == phpstr_append(buf, string, length)) {
24013 +                       pefree(buf, buf->pmem);
24014 +                       buf = NULL;
24015 +               }
24016 +       }
24017 +       return buf;
24018 +}
24019 +
24020 +PHPSTR_API size_t phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size, int allow_error)
24021 +{
24022 +       char *ptr = NULL;
24023 +#if 0
24024 +       fprintf(stderr, "RESIZE: size=%lu, used=%lu, free=%lu\n", buf->size, buf->used, buf->free);
24025 +#endif
24026 +       if (buf->free < len) {
24027 +               size_t size = override_size ? override_size : buf->size;
24028 +               
24029 +               while ((size + buf->free) < len) {
24030 +                       size <<= 1;
24031 +               }
24032 +               
24033 +               if (allow_error) {
24034 +                       ptr = perealloc_recoverable(buf->data, buf->used + buf->free + size, buf->pmem);
24035 +               } else {
24036 +                       ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem);
24037 +               }
24038 +               
24039 +               if (ptr) {
24040 +                       buf->data = ptr;
24041 +               } else {
24042 +                       return PHPSTR_NOMEM;
24043 +               }
24044 +               
24045 +               buf->free += size;
24046 +               return size;
24047 +       }
24048 +       return 0;
24049 +}
24050 +
24051 +PHPSTR_API size_t phpstr_shrink(phpstr *buf)
24052 +{
24053 +       /* avoid another realloc on fixation */
24054 +       if (buf->free > 1) {
24055 +               char *ptr = perealloc(buf->data, buf->used + 1, buf->pmem);
24056 +               
24057 +               if (ptr) {
24058 +                       buf->data = ptr;
24059 +               } else {
24060 +                       return PHPSTR_NOMEM;
24061 +               }
24062 +               buf->free = 1;
24063 +       }
24064 +       return buf->used;
24065 +}
24066 +
24067 +PHPSTR_API size_t phpstr_append(phpstr *buf, const char *append, size_t append_len)
24068 +{
24069 +       if (PHPSTR_NOMEM == phpstr_resize(buf, append_len)) {
24070 +               return PHPSTR_NOMEM;
24071 +       }
24072 +       memcpy(buf->data + buf->used, append, append_len);
24073 +       buf->used += append_len;
24074 +       buf->free -= append_len;
24075 +       return append_len;
24076 +}
24077 +
24078 +PHPSTR_API size_t phpstr_appendf(phpstr *buf, const char *format, ...)
24079 +{
24080 +       va_list argv;
24081 +       char *append;
24082 +       size_t append_len, alloc;
24083 +
24084 +       va_start(argv, format);
24085 +       append_len = vspprintf(&append, 0, format, argv);
24086 +       va_end(argv);
24087 +
24088 +       alloc = phpstr_append(buf, append, append_len);
24089 +       efree(append);
24090 +
24091 +       if (PHPSTR_NOMEM == alloc) {
24092 +               return PHPSTR_NOMEM;
24093 +       }
24094 +       return append_len;
24095 +}
24096 +
24097 +PHPSTR_API size_t phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset)
24098 +{
24099 +       if (PHPSTR_NOMEM == phpstr_resize(buf, insert_len)) {
24100 +               return PHPSTR_NOMEM;
24101 +       }
24102 +       memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
24103 +       memcpy(buf->data + offset, insert, insert_len);
24104 +       buf->used += insert_len;
24105 +       buf->free -= insert_len;
24106 +       return insert_len;
24107 +}
24108 +
24109 +PHPSTR_API size_t phpstr_insertf(phpstr *buf, size_t offset, const char *format, ...)
24110 +{
24111 +       va_list argv;
24112 +       char *insert;
24113 +       size_t insert_len, alloc;
24114 +
24115 +       va_start(argv, format);
24116 +       insert_len = vspprintf(&insert, 0, format, argv);
24117 +       va_end(argv);
24118 +
24119 +       alloc = phpstr_insert(buf, insert, insert_len, offset);
24120 +       efree(insert);
24121 +
24122 +       if (PHPSTR_NOMEM == alloc) {
24123 +               return PHPSTR_NOMEM;
24124 +       }
24125 +       return insert_len;
24126 +}
24127 +
24128 +PHPSTR_API size_t phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len)
24129 +{
24130 +       if (PHPSTR_NOMEM == phpstr_resize(buf, prepend_len)) {
24131 +               return PHPSTR_NOMEM;
24132 +       }
24133 +       memmove(buf->data + prepend_len, buf->data, buf->used);
24134 +       memcpy(buf->data, prepend, prepend_len);
24135 +       buf->used += prepend_len;
24136 +       buf->free -= prepend_len;
24137 +       return prepend_len;
24138 +}
24139 +
24140 +PHPSTR_API size_t phpstr_prependf(phpstr *buf, const char *format, ...)
24141 +{
24142 +       va_list argv;
24143 +       char *prepend;
24144 +       size_t prepend_len, alloc;
24145 +
24146 +       va_start(argv, format);
24147 +       prepend_len = vspprintf(&prepend, 0, format, argv);
24148 +       va_end(argv);
24149 +
24150 +       alloc = phpstr_prepend(buf, prepend, prepend_len);
24151 +       efree(prepend);
24152 +
24153 +       if (PHPSTR_NOMEM == alloc) {
24154 +               return PHPSTR_NOMEM;
24155 +       }
24156 +       return prepend_len;
24157 +}
24158 +
24159 +PHPSTR_API char *phpstr_data(const phpstr *buf, char **into, size_t *len)
24160 +{
24161 +       char *copy = ecalloc(1, buf->used + 1);
24162 +       memcpy(copy, buf->data, buf->used);
24163 +       if (into) {
24164 +               *into = copy;
24165 +       }
24166 +       if (len) {
24167 +               *len = buf->used;
24168 +       }
24169 +       return copy;
24170 +}
24171 +
24172 +PHPSTR_API phpstr *phpstr_dup(const phpstr *buf)
24173 +{
24174 +       phpstr *dup = phpstr_clone(buf);
24175 +       if (PHPSTR_NOMEM == phpstr_append(dup, buf->data, buf->used)) {
24176 +               phpstr_free(&dup);
24177 +       }
24178 +       return dup;
24179 +}
24180 +
24181 +PHPSTR_API size_t phpstr_cut(phpstr *buf, size_t offset, size_t length)
24182 +{
24183 +       if (offset >= buf->used) {
24184 +               return 0;
24185 +       }
24186 +       if (offset + length > buf->used) {
24187 +               length = buf->used - offset;
24188 +       }
24189 +       memmove(buf->data + offset, buf->data + offset + length, buf->used - length);
24190 +       buf->used -= length;
24191 +       buf->free += length;
24192 +       return length;
24193 +}
24194 +
24195 +PHPSTR_API phpstr *phpstr_sub(const phpstr *buf, size_t offset, size_t length)
24196 +{
24197 +       if (offset >= buf->used) {
24198 +               return NULL;
24199 +       } else {
24200 +               size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset));
24201 +               phpstr *sub = phpstr_init_ex(NULL, need, PHPSTR_INIT_PREALLOC | (buf->pmem ? PHPSTR_INIT_PERSISTENT:0));
24202 +               if (sub) {
24203 +                       if (PHPSTR_NOMEM == phpstr_append(sub, buf->data + offset, need)) {
24204 +                               phpstr_free(&sub);
24205 +                       } else {
24206 +                               sub->size = buf->size;
24207 +                       }
24208 +               }
24209 +               return sub;
24210 +       }
24211 +}
24212 +
24213 +PHPSTR_API phpstr *phpstr_right(const phpstr *buf, size_t length)
24214 +{
24215 +       if (length < buf->used) {
24216 +               return phpstr_sub(buf, buf->used - length, length);
24217 +       } else {
24218 +               return phpstr_sub(buf, 0, buf->used);
24219 +       }
24220 +}
24221 +
24222 +
24223 +PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv)
24224 +{
24225 +       unsigned i = 0;
24226 +       buf = phpstr_init(buf);
24227 +
24228 +       if (buf) {
24229 +               while (argc > i++) {
24230 +                       phpstr_free_t f = va_arg(argv, phpstr_free_t);
24231 +                       phpstr *current = va_arg(argv, phpstr *);
24232 +                       phpstr_append(buf, current->data, current->used);
24233 +                       FREE_PHPSTR(f, current);
24234 +               }
24235 +       }
24236 +
24237 +       return buf;
24238 +}
24239 +
24240 +PHPSTR_API phpstr *phpstr_merge_ex(phpstr *buf, unsigned argc, ...)
24241 +{
24242 +       va_list argv;
24243 +       phpstr *ret;
24244 +
24245 +       va_start(argv, argc);
24246 +       ret = phpstr_merge_va(buf, argc, argv);
24247 +       va_end(argv);
24248 +       return ret;
24249 +}
24250 +
24251 +PHPSTR_API phpstr *phpstr_merge(unsigned argc, ...)
24252 +{
24253 +       va_list argv;
24254 +       phpstr *ret;
24255 +
24256 +       va_start(argv, argc);
24257 +       ret = phpstr_merge_va(NULL, argc, argv);
24258 +       va_end(argv);
24259 +       return ret;
24260 +}
24261 +
24262 +PHPSTR_API phpstr *phpstr_fix(phpstr *buf)
24263 +{
24264 +       if (PHPSTR_NOMEM == phpstr_resize_ex(buf, 1, 1, 0)) {
24265 +               return NULL;
24266 +       }
24267 +       buf->data[buf->used] = '\0';
24268 +       return buf;
24269 +}
24270 +
24271 +PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right)
24272 +{
24273 +       if (left->used > right->used) {
24274 +               return -1;
24275 +       } else if (right->used > left->used) {
24276 +               return 1;
24277 +       } else {
24278 +               return memcmp(left->data, right->data, left->used);
24279 +       }
24280 +}
24281 +
24282 +PHPSTR_API void phpstr_reset(phpstr *buf)
24283 +{
24284 +       buf->free += buf->used;
24285 +       buf->used = 0;
24286 +}
24287 +
24288 +PHPSTR_API void phpstr_dtor(phpstr *buf)
24289 +{
24290 +       if (buf->data) {
24291 +               pefree(buf->data, buf->pmem);
24292 +               buf->data = NULL;
24293 +       }
24294 +       buf->used = 0;
24295 +       buf->free = 0;
24296 +}
24297 +
24298 +PHPSTR_API void phpstr_free(phpstr **buf)
24299 +{
24300 +       if (*buf) {
24301 +               phpstr_dtor(*buf);
24302 +               pefree(*buf, (*buf)->pmem);
24303 +               *buf = NULL;
24304 +       }
24305 +}
24306 +
24307 +PHPSTR_API size_t phpstr_chunk_buffer(phpstr **s, const char *data, size_t data_len, char **chunk, size_t chunk_size)
24308 +{
24309 +       phpstr *storage;
24310 +       
24311 +       *chunk = NULL;
24312 +       
24313 +       if (!*s) {
24314 +               *s = phpstr_init_ex(NULL, chunk_size << 1, chunk_size ? PHPSTR_INIT_PREALLOC : 0);
24315 +       }
24316 +       storage = *s;
24317 +       
24318 +       if (data_len) {
24319 +               phpstr_append(storage, data, data_len);
24320 +       }
24321 +       
24322 +       if (!chunk_size) {
24323 +               phpstr_data(storage, chunk, &chunk_size);
24324 +               phpstr_free(s);
24325 +               return chunk_size;
24326 +       }
24327 +       
24328 +       if (storage->used >= (chunk_size = storage->size >> 1)) {
24329 +               *chunk = estrndup(storage->data, chunk_size);
24330 +               phpstr_cut(storage, 0, chunk_size);
24331 +               return chunk_size;
24332 +       }
24333 +       
24334 +       return 0;
24335 +}
24336 +
24337 +PHPSTR_API void phpstr_chunked_output(phpstr **s, const char *data, size_t data_len, size_t chunk_len, phpstr_passthru_func passthru, void *opaque TSRMLS_DC)
24338 +{
24339 +       char *chunk = NULL;
24340 +       size_t got = 0;
24341 +       
24342 +       while ((got = phpstr_chunk_buffer(s, data, data_len, &chunk, chunk_len))) {
24343 +               passthru(opaque, chunk, got TSRMLS_CC);
24344 +               if (!chunk_len) {
24345 +                       /*      we already got the last chunk,
24346 +                               and freed all resources */
24347 +                       break;
24348 +               }
24349 +               data = NULL;
24350 +               data_len = 0;
24351 +               STR_SET(chunk, NULL);
24352 +       }
24353 +       STR_FREE(chunk);
24354 +}
24355 +
24356 +/*
24357 + * Local variables:
24358 + * tab-width: 4
24359 + * c-basic-offset: 4
24360 + * End:
24361 + * vim600: sw=4 ts=4 fdm=marker
24362 + * vim<600: sw=4 ts=4
24363 + */
24364 +
24365 --- /dev/null
24366 +++ b/ext/http/phpstr/phpstr.h
24367 @@ -0,0 +1,224 @@
24368 +
24369 +/* $Id: phpstr.h 229282 2007-02-07 15:31:50Z mike $ */
24370 +
24371 +#ifndef _PHPSTR_H_
24372 +#define _PHPSTR_H_
24373 +
24374 +#ifndef PHPSTR_DEFAULT_SIZE
24375 +#      define PHPSTR_DEFAULT_SIZE 256
24376 +#endif
24377 +
24378 +#define PHPSTR_NOMEM ((size_t) -1)
24379 +
24380 +#ifndef STR_FREE
24381 +#      define STR_FREE(STR) \
24382 +       { \
24383 +               if (STR) { \
24384 +                       efree(STR); \
24385 +               } \
24386 +       }
24387 +#endif
24388 +#ifndef STR_SET
24389 +#      define STR_SET(STR, SET) \
24390 +       { \
24391 +               STR_FREE(STR); \
24392 +               STR = SET; \
24393 +       }
24394 +#endif
24395 +#ifndef TSRMLS_D
24396 +#      define TSRMLS_D
24397 +#      define TSRMLS_DC
24398 +#      define TSRMLS_CC
24399 +#      define TSRMLS_C
24400 +#endif
24401 +#ifdef PHP_ATTRIBUTE_FORMAT
24402 +#      define PHPSTR_ATTRIBUTE_FORMAT(f, a, b) PHP_ATTRIBUTE_FORMAT(f, a, b)
24403 +#else
24404 +#      define PHPSTR_ATTRIBUTE_FORMAT(f, a, b)
24405 +#endif
24406 +#ifndef pemalloc
24407 +#      define pemalloc(s,p)    malloc(s)
24408 +#      define pefree(x,p)              free(x)
24409 +#      define perealloc(x,s,p) realloc(x,s)
24410 +#      define perealloc_recoverable perealloc
24411 +#      define ecalloc calloc
24412 +static inline void *estrndup(void *p, size_t s)
24413 +{
24414 +       char *r = (char *) malloc(s+1);
24415 +       if (r) memcpy((void *) r, p, s), r[s] = '\0';
24416 +       return (void *) r;
24417 +}
24418 +#endif
24419 +
24420 +#if defined(PHP_WIN32)
24421 +#      if defined(PHPSTR_EXPORTS)
24422 +#              define PHPSTR_API __declspec(dllexport)
24423 +#      elif defined(COMPILE_DL_PHPSTR)
24424 +#              define PHPSTR_API __declspec(dllimport)
24425 +#      else
24426 +#              define PHPSTR_API
24427 +#      endif
24428 +#else
24429 +#      define PHPSTR_API
24430 +#endif
24431 +
24432 +#define PHPSTR(p) ((phpstr *) (p))
24433 +#define PHPSTR_VAL(p) (PHPSTR(p))->data
24434 +#define PHPSTR_LEN(p) (PHPSTR(p))->used
24435 +
24436 +#define FREE_PHPSTR_PTR(STR) pefree(STR, STR->pmem)
24437 +#define FREE_PHPSTR_VAL(STR) phpstr_dtor(STR)
24438 +#define FREE_PHPSTR_ALL(STR) phpstr_free(&(STR))
24439 +#define FREE_PHPSTR(free, STR) \
24440 +       switch (free) \
24441 +       { \
24442 +               case PHPSTR_FREE_NOT:                                                   break; \
24443 +               case PHPSTR_FREE_PTR:   pefree(STR, STR->pmem); break; \
24444 +               case PHPSTR_FREE_VAL:   phpstr_dtor(STR);               break; \
24445 +               case PHPSTR_FREE_ALL: \
24446 +               { \
24447 +                       phpstr *PTR = (STR); \
24448 +                       phpstr_free(&PTR); \
24449 +               } \
24450 +               break; \
24451 +               default:                                                                                break; \
24452 +       }
24453 +
24454 +#define RETURN_PHPSTR_PTR(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_PTR, 0)
24455 +#define RETURN_PHPSTR_VAL(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_NOT, 0)
24456 +#define RETURN_PHPSTR_DUP(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_NOT, 1)
24457 +#define RETVAL_PHPSTR_PTR(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_PTR, 0)
24458 +#define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 0)
24459 +#define RETVAL_PHPSTR_DUP(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 1)
24460 +/* RETURN_PHPSTR(buf, PHPSTR_FREE_PTR, 0) */
24461 +#define RETURN_PHPSTR(STR, free, dup) \
24462 +       RETVAL_PHPSTR((STR), (free), (dup)); \
24463 +       return;
24464 +
24465 +#define RETVAL_PHPSTR(STR, free, dup) \
24466 +       phpstr_fix(STR); \
24467 +       RETVAL_STRINGL((STR)->data, (STR)->used, (dup)); \
24468 +       FREE_PHPSTR((free), (STR));
24469 +
24470 +typedef struct _phpstr_t {
24471 +       char  *data;
24472 +       size_t used;
24473 +       size_t free;
24474 +       size_t size;
24475 +       unsigned pmem:1;
24476 +       unsigned reserved:31;
24477 +} phpstr;
24478 +
24479 +typedef enum _phpstr_free_t {
24480 +       PHPSTR_FREE_NOT = 0,
24481 +       PHPSTR_FREE_PTR,        /* pefree() */
24482 +       PHPSTR_FREE_VAL,        /* phpstr_dtor() */
24483 +       PHPSTR_FREE_ALL         /* phpstr_free() */
24484 +} phpstr_free_t;
24485 +
24486 +#define PHPSTR_ALL_FREE(STR) PHPSTR_FREE_ALL,(STR)
24487 +#define PHPSTR_PTR_FREE(STR) PHPSTR_FREE_PTR,(STR)
24488 +#define PHPSTR_VAL_FREE(STR) PHPSTR_FREE_VAL,(STR)
24489 +#define PHPSTR_NOT_FREE(STR) PHPSTR_FREE_NOT,(STR)
24490 +
24491 +#define PHPSTR_INIT_PREALLOC   0x01
24492 +#define PHPSTR_INIT_PERSISTENT 0x02
24493 +
24494 +/* create a new phpstr */
24495 +#define phpstr_new() phpstr_init(NULL)
24496 +#define phpstr_init(b) phpstr_init_ex(b, PHPSTR_DEFAULT_SIZE, 0)
24497 +#define phpstr_clone(phpstr_pointer) phpstr_init_ex(NULL, (phpstr_pointer)->size, (phpstr_pointer)->pmem ? PHPSTR_INIT_PERSISTENT:0)
24498 +PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int flags);
24499 +
24500 +/* create a phpstr from a zval or c-string */
24501 +#define phpstr_from_zval(z) phpstr_from_string(Z_STRVAL(z), Z_STRLEN(z))
24502 +#define phpstr_from_zval_ex(b, z) phpstr_from_string_ex(b, Z_STRVAL(z), Z_STRLEN(z))
24503 +#define phpstr_from_string(s, l) phpstr_from_string_ex(NULL, (s), (l))
24504 +PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, const char *string, size_t length);
24505 +
24506 +/* usually only called from within the internal functions */
24507 +#define phpstr_resize(b, s) phpstr_resize_ex((b), (s), 0, 0)
24508 +PHPSTR_API size_t phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size, int allow_error);
24509 +
24510 +/* shrink memory chunk to actually used size (+1) */
24511 +PHPSTR_API size_t phpstr_shrink(phpstr *buf);
24512 +
24513 +/* append data to the phpstr */
24514 +#define phpstr_appends(b, a) phpstr_append((b), (a), sizeof(a)-1)
24515 +#define phpstr_appendl(b, a) phpstr_append((b), (a), strlen(a))
24516 +PHPSTR_API size_t phpstr_append(phpstr *buf, const char *append, size_t append_len);
24517 +PHPSTR_API size_t phpstr_appendf(phpstr *buf, const char *format, ...) PHPSTR_ATTRIBUTE_FORMAT(printf, 2, 3);
24518 +
24519 +/* insert data at a specific position of the phpstr */
24520 +#define phpstr_inserts(b, i, o) phpstr_insert((b), (i), sizeof(i)-1, (o))
24521 +#define phpstr_insertl(b, i, o) phpstr_insert((b), (i), strlen(i), (o))
24522 +PHPSTR_API size_t phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset);
24523 +PHPSTR_API size_t phpstr_insertf(phpstr *buf, size_t offset, const char *format, ...) PHPSTR_ATTRIBUTE_FORMAT(printf, 3, 4);
24524 +
24525 +/* prepend data */
24526 +#define phpstr_prepends(b, p) phpstr_prepend((b), (p), sizeof(p)-1)
24527 +#define phpstr_prependl(b, p) phpstr_prepend((b), (p), strlen(p))
24528 +PHPSTR_API size_t phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len);
24529 +PHPSTR_API size_t phpstr_prependf(phpstr *buf, const char *format, ...) PHPSTR_ATTRIBUTE_FORMAT(printf, 2, 3);
24530 +
24531 +/* get a zero-terminated string */
24532 +PHPSTR_API char *phpstr_data(const phpstr *buf, char **into, size_t *len);
24533 +
24534 +/* get a part of the phpstr */
24535 +#define phpstr_mid(b, o, l) phpstr_sub((b), (o), (l))
24536 +#define phpstr_left(b, l) phpstr_sub((b), 0, (l))
24537 +PHPSTR_API phpstr *phpstr_right(const phpstr *buf, size_t length);
24538 +PHPSTR_API phpstr *phpstr_sub(const phpstr *buf, size_t offset, size_t len);
24539 +
24540 +/* remove a substring */
24541 +PHPSTR_API size_t phpstr_cut(phpstr *buf, size_t offset, size_t length);
24542 +
24543 +/* get a complete phpstr duplicate */
24544 +PHPSTR_API phpstr *phpstr_dup(const phpstr *buf);
24545 +
24546 +/* merge several phpstr objects
24547 +   use like:
24548 +
24549 +       phpstr *final = phpstr_merge(3,
24550 +               PHPSTR_NOT_FREE(&keep),
24551 +               PHPSTR_ALL_FREE(middle_ptr),
24552 +               PHPSTR_VAL_FREE(&local);
24553 +*/
24554 +PHPSTR_API phpstr *phpstr_merge(unsigned argc, ...);
24555 +PHPSTR_API phpstr *phpstr_merge_ex(phpstr *buf, unsigned argc, ...);
24556 +PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv);
24557 +
24558 +/* sets a trailing NUL byte */
24559 +PHPSTR_API phpstr *phpstr_fix(phpstr *buf);
24560 +
24561 +/* memcmp for phpstr objects */
24562 +PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right);
24563 +
24564 +/* reset phpstr object */
24565 +PHPSTR_API void phpstr_reset(phpstr *buf);
24566 +
24567 +/* free a phpstr objects contents */
24568 +PHPSTR_API void phpstr_dtor(phpstr *buf);
24569 +
24570 +/* free a phpstr object completely */
24571 +PHPSTR_API void phpstr_free(phpstr **buf);
24572 +
24573 +/* stores data in a phpstr until it reaches chunk_size */
24574 +PHPSTR_API size_t phpstr_chunk_buffer(phpstr **s, const char *data, size_t data_len, char **chunk, size_t chunk_size);
24575 +
24576 +typedef void (*phpstr_passthru_func)(void *opaque, const char *, size_t TSRMLS_DC);
24577 +
24578 +/* wrapper around phpstr_chunk_buffer, which passes available chunks to passthru() */
24579 +PHPSTR_API void phpstr_chunked_output(phpstr **s, const char *data, size_t data_len, size_t chunk_size, phpstr_passthru_func passthru, void *opaque TSRMLS_DC);
24580 +
24581 +#endif
24582 +
24583 +
24584 +/*
24585 + * Local variables:
24586 + * tab-width: 4
24587 + * c-basic-offset: 4
24588 + * End:
24589 + * vim600: sw=4 ts=4 fdm=marker
24590 + * vim<600: sw=4 ts=4
24591 + */
24592 --- /dev/null
24593 +++ b/ext/http/tests/HttpMessage_001.phpt
24594 @@ -0,0 +1,70 @@
24595 +--TEST--
24596 +HttpMessage
24597 +--SKIPIF--
24598 +<?php
24599 +include 'skip.inc';
24600 +checkmin("5.2.5");
24601 +?>
24602 +--FILE--
24603 +<?php
24604 +echo "-TEST\n";
24605 +$m = new HttpMessage(
24606 +       "HTTP/1.1 301\r\n".
24607 +       "Location: /anywhere\r\n".
24608 +       "HTTP/1.1 302\r\n".
24609 +       "Location: /somewhere\r\n".
24610 +       "HTTP/1.1 206 Partial content\r\n".
24611 +       "Content-Range: bytes=2-3\r\n".
24612 +       "Transfer-Encoding: chunked\r\n".
24613 +       "\r\n".
24614 +       "01\r\n".
24615 +       "X\r\n".
24616 +       "00"
24617 +);
24618 +
24619 +var_dump($m->getResponseStatus());
24620 +
24621 +$x = $m->getParentMessage();
24622 +$x = $m->getParentMessage();
24623 +$x = $m->getParentMessage();
24624 +
24625 +var_dump($m->getBody());
24626 +var_dump(HttpMessage::fromString($m->toString(true))->toString(true));
24627 +try {
24628 +       do {
24629 +               var_dump($m->toString());
24630 +       } while ($m = $m->getParentMessage());
24631 +} catch (HttpException $ex) {
24632 +}
24633 +
24634 +echo "Done\n";
24635 +?>
24636 +--EXPECTF--
24637 +%aTEST
24638 +string(15) "Partial content"
24639 +string(1) "X"
24640 +string(190) "HTTP/1.1 301
24641 +Location: /anywhere
24642 +HTTP/1.1 302
24643 +Location: /somewhere
24644 +HTTP/1.1 206 Partial content
24645 +Content-Range: bytes=2-3
24646 +X-Original-Transfer-Encoding: chunked
24647 +Content-Length: 1
24648 +
24649 +X
24650 +"
24651 +string(119) "HTTP/1.1 206 Partial content
24652 +Content-Range: bytes=2-3
24653 +X-Original-Transfer-Encoding: chunked
24654 +Content-Length: 1
24655 +
24656 +X
24657 +"
24658 +string(36) "HTTP/1.1 302
24659 +Location: /somewhere
24660 +"
24661 +string(35) "HTTP/1.1 301
24662 +Location: /anywhere
24663 +"
24664 +Done
24665 --- /dev/null
24666 +++ b/ext/http/tests/HttpMessage_002.phpt
24667 @@ -0,0 +1,65 @@
24668 +--TEST--
24669 +HttpMessage properties
24670 +--SKIPIF--
24671 +<?php
24672 +include 'skip.inc';
24673 +checkmin("5.2.5");
24674 +checkcls('HttpMessage');
24675 +?>
24676 +--FILE--
24677 +<?php
24678 +class Message extends HttpMessage
24679 +{
24680 +       var $var_property = 'var';
24681 +       public $public_property = 'public';
24682 +       protected $protected_property = 'protected';
24683 +       private $private_property = 'private';
24684 +
24685 +       public function test()
24686 +       {
24687 +               var_dump($this->var_property);
24688 +               var_dump($this->public_property);
24689 +               var_dump($this->protected_property);
24690 +               var_dump($this->private_property);
24691 +               var_dump($this->non_ex_property);
24692 +               $this->var_property.='_property';
24693 +               $this->public_property.='_property';
24694 +               $this->protected_property.='_property';
24695 +               $this->private_property.='_property';
24696 +               $this->non_ex_property = 'non_ex';
24697 +               var_dump($this->var_property);
24698 +               var_dump($this->public_property);
24699 +               var_dump($this->protected_property);
24700 +               var_dump($this->private_property);
24701 +               var_dump($this->non_ex_property);
24702 +
24703 +               print_r($this->headers);
24704 +               $this->headers['Foo'] = 'Bar';
24705 +       }
24706 +}
24707 +
24708 +error_reporting(E_ALL|E_STRICT);
24709 +
24710 +echo "-TEST\n";
24711 +$m = new Message;
24712 +$m->test();
24713 +echo "Done\n";
24714 +?>
24715 +--EXPECTF--
24716 +%aTEST
24717 +string(3) "var"
24718 +string(6) "public"
24719 +string(9) "protected"
24720 +string(7) "private"
24721 +
24722 +Notice: Undefined property: Message::$non_ex_property in %s
24723 +NULL
24724 +string(12) "var_property"
24725 +string(15) "public_property"
24726 +string(18) "protected_property"
24727 +string(16) "private_property"
24728 +string(6) "non_ex"
24729 +Array
24730 +(
24731 +)
24732 +%aFatal error%sCannot access HttpMessage properties by reference or array key/index in%s
24733 --- /dev/null
24734 +++ b/ext/http/tests/HttpMessage_003.phpt
24735 @@ -0,0 +1,70 @@
24736 +--TEST--
24737 +HttpMessage implements Serializable, Countable
24738 +--SKIPIF--
24739 +<?php
24740 +include 'skip.inc';
24741 +checkmin("5.2.5");
24742 +?>
24743 +--FILE--
24744 +<?php
24745 +echo "-TEST\n";
24746 +
24747 +$m = new HttpMessage(
24748 +       "HTTP/1.1 301\r\n".
24749 +       "Location: /anywhere\r\n".
24750 +       "HTTP/1.1 302\r\n".
24751 +       "Location: /somewhere\r\n".
24752 +       "HTTP/1.1 200\r\n".
24753 +       "Transfer-Encoding: chunked\r\n".
24754 +       "\r\n".
24755 +       "01\r\n".
24756 +       "X\r\n".
24757 +       "00"
24758 +);
24759 +
24760 +var_dump($m->count());
24761 +var_dump($m->serialize());
24762 +$m->unserialize("HTTP/1.1 200 Ok\r\nServer: Funky/1.0");
24763 +var_dump($m);
24764 +var_dump($m->count());
24765 +
24766 +echo "Done\n";
24767 +?>
24768 +--EXPECTF--
24769 +%aTEST
24770 +int(3)
24771 +string(148) "HTTP/1.1 301
24772 +Location: /anywhere
24773 +HTTP/1.1 302
24774 +Location: /somewhere
24775 +HTTP/1.1 200
24776 +X-Original-Transfer-Encoding: chunked
24777 +Content-Length: 1
24778 +
24779 +X
24780 +"
24781 +object(HttpMessage)#%d (%d) {
24782 +  ["type%s]=>
24783 +  int(2)
24784 +  ["body%s]=>
24785 +  string(0) ""
24786 +  ["requestMethod%s]=>
24787 +  string(0) ""
24788 +  ["requestUrl%s]=>
24789 +  string(0) ""
24790 +  ["responseStatus%s]=>
24791 +  string(2) "Ok"
24792 +  ["responseCode%s]=>
24793 +  int(200)
24794 +  ["httpVersion%s]=>
24795 +  float(1.1)
24796 +  ["headers%s]=>
24797 +  array(1) {
24798 +    ["Server"]=>
24799 +    string(9) "Funky/1.0"
24800 +  }
24801 +  ["parentMessage%s]=>
24802 +  NULL
24803 +}
24804 +int(1)
24805 +Done
24806 --- /dev/null
24807 +++ b/ext/http/tests/HttpMessage_004.phpt
24808 @@ -0,0 +1,36 @@
24809 +--TEST--
24810 +HttpMessage::detach()
24811 +--SKIPIF--
24812 +<?php
24813 +include 'skip.inc';
24814 +checkver(5);
24815 +?>
24816 +--FILE--
24817 +<?php
24818 +echo "-TEST\n";
24819 +
24820 +$m = new HttpMessage("
24821 +GET / HTTP/1.1
24822 +Host: example.com
24823 +Accept: */*
24824 +Connection: close
24825 +HTTP/1.1 200 ok
24826 +Server: Funky/1.0
24827 +Content-Type: text/plain
24828 +Content-Length: 3
24829 +
24830 +Hi!"
24831 +);
24832 +
24833 +$d = $m->detach();
24834 +$d->addHeaders(array('Server'=>'Funky/2.0'));
24835 +var_dump($d->getHeaders() == $m->getHeaders());
24836 +var_dump($d->getBody());
24837 +
24838 +echo "Done\n";
24839 +?>
24840 +--EXPECTF--
24841 +%aTEST
24842 +bool(false)
24843 +string(3) "Hi!"
24844 +Done
24845 \ No newline at end of file
24846 --- /dev/null
24847 +++ b/ext/http/tests/HttpMessage_005.phpt
24848 @@ -0,0 +1,86 @@
24849 +--TEST--
24850 +HttpMessage::prepend()
24851 +--SKIPIF--
24852 +<?php
24853 +include 'skip.inc';
24854 +checkver(5);
24855 +?>
24856 +--FILE--
24857 +<?php
24858 +echo "-TEST\n";
24859 +
24860 +$m1 = new HttpMessage("
24861 +GET / HTTP/1.1
24862 +Host: example.com
24863 +Accept: */*
24864 +Connection: close
24865 +HTTP/1.1 200 ok
24866 +Server: Funky/1.0
24867 +Content-Type: text/plain
24868 +Content-Length: 3
24869 +
24870 +Hi!"
24871 +);
24872 +
24873 +$m2 = new HttpMessage("
24874 +GET http://example.com/ HTTP/1.0
24875 +HTTP/1.1 200 ok
24876 +Server: Funky/2.0
24877 +Content-Type: text/html
24878 +Content-Length: 9
24879 +
24880 +Hi there!"
24881 +);
24882 +
24883 +$m1->prepend($m2);
24884 +$m2 = NULL;
24885 +echo $m1->toString(true);
24886 +
24887 +$m1->prepend($m1->detach(), false);
24888 +echo $m1->toString(true);
24889 +
24890 +echo "Done\n";
24891 +?>
24892 +--EXPECTF--
24893 +%aTEST
24894 +GET http://example.com/ HTTP/1.0
24895 +HTTP/1.1 200 ok
24896 +Server: Funky/2.0
24897 +Content-Type: text/html
24898 +Content-Length: 9
24899 +
24900 +Hi there!
24901 +GET / HTTP/1.1
24902 +Host: example.com
24903 +Accept: */*
24904 +Connection: close
24905 +HTTP/1.1 200 ok
24906 +Server: Funky/1.0
24907 +Content-Type: text/plain
24908 +Content-Length: 3
24909 +
24910 +Hi!
24911 +GET http://example.com/ HTTP/1.0
24912 +HTTP/1.1 200 ok
24913 +Server: Funky/2.0
24914 +Content-Type: text/html
24915 +Content-Length: 9
24916 +
24917 +Hi there!
24918 +GET / HTTP/1.1
24919 +Host: example.com
24920 +Accept: */*
24921 +Connection: close
24922 +HTTP/1.1 200 ok
24923 +Server: Funky/1.0
24924 +Content-Type: text/plain
24925 +Content-Length: 3
24926 +
24927 +Hi!
24928 +HTTP/1.1 200 ok
24929 +Server: Funky/1.0
24930 +Content-Type: text/plain
24931 +Content-Length: 3
24932 +
24933 +Hi!
24934 +Done
24935 \ No newline at end of file
24936 --- /dev/null
24937 +++ b/ext/http/tests/HttpMessage_006.phpt
24938 @@ -0,0 +1,35 @@
24939 +--TEST--
24940 +HttpMessage iterator
24941 +--SKIPIF--
24942 +<?php
24943 +include 'skip.inc';
24944 +checkver(5);
24945 +?>
24946 +--FILE--
24947 +<?php
24948 +echo "-TEST\n";
24949 +
24950 +$m = new HttpMessage("
24951 +GET / HTTP/1.1
24952 +HTTP/1.1 200 OK
24953 +GET /foo HTTP/1.1
24954 +HTTP/1.1 304 Not Modified
24955 +");
24956 +
24957 +foreach ($m as $msg) {
24958 +       echo "==\n", $msg;
24959 +}
24960 +
24961 +echo "Done\n";
24962 +?>
24963 +--EXPECTF--
24964 +%aTEST
24965 +==
24966 +HTTP/1.1 304 Not Modified
24967 +==
24968 +GET /foo HTTP/1.1
24969 +==
24970 +HTTP/1.1 200 OK
24971 +==
24972 +GET / HTTP/1.1
24973 +Done
24974 \ No newline at end of file
24975 --- /dev/null
24976 +++ b/ext/http/tests/HttpMessage_007.phpt
24977 @@ -0,0 +1,46 @@
24978 +--TEST--
24979 +HttpMessage::reverse()
24980 +--SKIPIF--
24981 +<?php
24982 +include 'skip.inc';
24983 +checkver(5);
24984 +?>
24985 +--FILE--
24986 +<?php
24987 +echo "-TEST\n";
24988 +$s = "GET /first HTTP/1.1\nHTTP/1.1 200 Ok-first\nGET /second HTTP/1.1\nHTTP/1.1 200 Ok-second\nGET /third HTTP/1.1\nHTTP/1.1 200 Ok-third\n";
24989 +echo HttpMessage::fromString($s)->toString(true);
24990 +echo "===\n";
24991 +echo HttpMessage::fromString($s)->reverse()->toString(true);
24992 +
24993 +$m = new HttpMessage($s);
24994 +$r = $m->reverse();
24995 +unset($m);
24996 +var_dump($r->count());
24997 +echo $r->toString(true);
24998 +
24999 +echo "Done\n";
25000 +?>
25001 +--EXPECTF--
25002 +%aTEST
25003 +GET /first HTTP/1.1
25004 +HTTP/1.1 200 Ok-first
25005 +GET /second HTTP/1.1
25006 +HTTP/1.1 200 Ok-second
25007 +GET /third HTTP/1.1
25008 +HTTP/1.1 200 Ok-third
25009 +===
25010 +HTTP/1.1 200 Ok-third
25011 +GET /third HTTP/1.1
25012 +HTTP/1.1 200 Ok-second
25013 +GET /second HTTP/1.1
25014 +HTTP/1.1 200 Ok-first
25015 +GET /first HTTP/1.1
25016 +int(6)
25017 +HTTP/1.1 200 Ok-third
25018 +GET /third HTTP/1.1
25019 +HTTP/1.1 200 Ok-second
25020 +GET /second HTTP/1.1
25021 +HTTP/1.1 200 Ok-first
25022 +GET /first HTTP/1.1
25023 +Done
25024 --- /dev/null
25025 +++ b/ext/http/tests/HttpMessage_008.phpt
25026 @@ -0,0 +1,41 @@
25027 +--TEST--
25028 +HttpMessage::toMessageTypeObject()
25029 +--SKIPIF--
25030 +<?php
25031 +include 'skip.inc';
25032 +checkver(5);
25033 +checkcls('HttpRequest');
25034 +?>
25035 +--FILE--
25036 +<?php
25037 +echo "-TEST\n";
25038 +
25039 +$b = HttpRequest::encodeBody(array("a"=>"b",1=>2),null);
25040 +
25041 +$m = new HttpMessage;
25042 +$m->setType(HttpMessage::TYPE_REQUEST);
25043 +$m->setRequestMethod('POST');
25044 +$m->setRequestUrl("http://www.example.com");
25045 +$m->setHttpVersion('1.1');
25046 +$m->addHeaders(
25047 +       array(
25048 +               "Content-Type"  => "application/x-www-form-urlencoded",
25049 +               "Host"                  => "www.example.com",
25050 +               "Content-Length"=> strlen($b),
25051 +       )
25052 +);
25053 +$m->setBody($b);
25054 +$r = $m->toMessageTypeObject();
25055 +echo $m,"\n";
25056 +echo "Done\n";
25057 +?>
25058 +--EXPECTF--
25059 +%aTEST
25060 +POST http://www.example.com HTTP/1.1
25061 +Content-Type: application/x-www-form-urlencoded
25062 +Host: www.example.com
25063 +Content-Length: 7
25064 +
25065 +a=b&1=2
25066 +
25067 +Done
25068 --- /dev/null
25069 +++ b/ext/http/tests/HttpMessage_009_bug16700.phpt
25070 @@ -0,0 +1,24 @@
25071 +--TEST--
25072 +Bug #16700 - child classes of HttpMessage cannot not have array properties
25073 +--SKIPIF--
25074 +<?php
25075 +include 'skip.inc';
25076 +checkver(5);
25077 +?>
25078 +--FILE--
25079 +<?php
25080 +echo "-TEST\n";
25081 +
25082 +class ChildMessage extends HttpMessage {
25083 +    public $properties = array();
25084 +}
25085 +
25086 +$child = new ChildMessage;
25087 +$child->properties['foo'] = 'bar';
25088 +echo $child->properties['foo'], "\n";
25089 +echo "Done\n";
25090 +?>
25091 +--EXPECTF--
25092 +%aTEST
25093 +bar
25094 +Done
25095 --- /dev/null
25096 +++ b/ext/http/tests/HttpQueryString_001.phpt
25097 @@ -0,0 +1,116 @@
25098 +--TEST--
25099 +HttpQueryString global
25100 +--SKIPIF--
25101 +<?php
25102 +include 'skip.inc';
25103 +checkmin("5.2.5");
25104 +?>
25105 +--FILE--
25106 +<?php
25107 +echo "-TEST\n";
25108 +
25109 +$_GET = array('a'=>'b','c'=>'3.4','r'=>array(1,2,3));
25110 +$_SERVER['QUERY_STRING'] = 'a=b&c=3.4&r[0]=1&r[1]=2&r[2]=3';
25111 +
25112 +var_dump(HttpQueryString::singleton()->get());
25113 +var_dump(HttpQueryString::singleton()->get('n'));
25114 +var_dump(HttpQueryString::singleton()->get('a'));
25115 +var_dump(HttpQueryString::singleton()->get('a', "i", 0, true));
25116 +var_dump(HttpQueryString::singleton()->get('a', "string", 'hi!'));
25117 +var_dump(HttpQueryString::singleton()->get('c'));
25118 +var_dump(HttpQueryString::singleton()->get('c', HttpQueryString::TYPE_INT));
25119 +var_dump(HttpQueryString::singleton()->get('c', HttpQueryString::TYPE_FLOAT));
25120 +var_dump(HttpQueryString::singleton()->get('c', HttpQueryString::TYPE_BOOL));
25121 +var_dump(HttpQueryString::singleton()->get('r'));
25122 +var_dump(HttpQueryString::singleton()->get('r', HttpQueryString::TYPE_ARRAY));
25123 +var_dump(HttpQueryString::singleton()->get('r', HttpQueryString::TYPE_OBJECT));
25124 +
25125 +HttpQueryString::singleton()->set(new HttpQueryString(false, 'z[0]=2'));
25126 +
25127 +HttpQueryString::singleton()->set(array('a'=>'b', 'c'=> "3.4"));
25128 +HttpQueryString::singleton()->set(array('a' => NULL));
25129 +
25130 +var_dump(HttpQueryString::singleton());
25131 +var_dump($_GET);
25132 +var_dump($_SERVER['QUERY_STRING']);
25133 +
25134 +echo "Done\n";
25135 +?>
25136 +--EXPECTF--
25137 +%aTEST
25138 +string(42) "a=b&c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3"
25139 +NULL
25140 +string(1) "b"
25141 +int(0)
25142 +string(3) "hi!"
25143 +string(3) "3.4"
25144 +int(3)
25145 +float(3.4)
25146 +bool(true)
25147 +array(3) {
25148 +  [0]=>
25149 +  int(1)
25150 +  [1]=>
25151 +  int(2)
25152 +  [2]=>
25153 +  int(3)
25154 +}
25155 +array(3) {
25156 +  [0]=>
25157 +  int(1)
25158 +  [1]=>
25159 +  int(2)
25160 +  [2]=>
25161 +  int(3)
25162 +}
25163 +object(stdClass)#%d (%d) {
25164 +  [0]=>
25165 +  int(1)
25166 +  [1]=>
25167 +  int(2)
25168 +  [2]=>
25169 +  int(3)
25170 +}
25171 +object(HttpQueryString)#1 (2) {
25172 +  ["queryArray%s]=>
25173 +  &array(3) {
25174 +    ["c"]=>
25175 +    string(3) "3.4"
25176 +    ["r"]=>
25177 +    array(3) {
25178 +      [0]=>
25179 +      int(1)
25180 +      [1]=>
25181 +      int(2)
25182 +      [2]=>
25183 +      int(3)
25184 +    }
25185 +    ["z"]=>
25186 +    array(1) {
25187 +      [0]=>
25188 +      string(1) "2"
25189 +    }
25190 +  }
25191 +  ["queryString%s]=>
25192 +  &string(49) "c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3&z%5B0%5D=2"
25193 +}
25194 +array(3) {
25195 +  ["c"]=>
25196 +  string(3) "3.4"
25197 +  ["r"]=>
25198 +  array(3) {
25199 +    [0]=>
25200 +    int(1)
25201 +    [1]=>
25202 +    int(2)
25203 +    [2]=>
25204 +    int(3)
25205 +  }
25206 +  ["z"]=>
25207 +  array(1) {
25208 +    [0]=>
25209 +    string(1) "2"
25210 +  }
25211 +}
25212 +string(49) "c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3&z%5B0%5D=2"
25213 +Done
25214 \ No newline at end of file
25215 --- /dev/null
25216 +++ b/ext/http/tests/HttpQueryString_002.phpt
25217 @@ -0,0 +1,108 @@
25218 +--TEST--
25219 +HttpQueryString local
25220 +--SKIPIF--
25221 +<?php
25222 +include 'skip.inc';
25223 +checkmin("5.2.5");
25224 +?>
25225 +--FILE--
25226 +<?php
25227 +echo "-TEST\n";
25228 +
25229 +$q = new HttpQueryString(false, $array = array('a'=>'b','c'=>'3.4','r'=>array(1,2,3)));
25230 +var_dump($q->get());
25231 +var_dump($q->get('n'));
25232 +var_dump($q->get('a'));
25233 +var_dump($q->get('a', "i", 0, true));
25234 +var_dump($q->get('a', "string", 'hi!'));
25235 +var_dump($q->get('c'));
25236 +var_dump($q->get('c', HttpQueryString::TYPE_INT));
25237 +var_dump($q->get('c', HttpQueryString::TYPE_FLOAT));
25238 +var_dump($q->get('c', HttpQueryString::TYPE_BOOL));
25239 +var_dump($q->get('r'));
25240 +var_dump($q->get('r', HttpQueryString::TYPE_ARRAY));
25241 +var_dump($q->get('r', HttpQueryString::TYPE_OBJECT));
25242 +
25243 +$q->set('z[0]=2');
25244 +$q->set(array('a'=>'b', 'c'=> "3.4"));
25245 +$q->set(array('a' => NULL));
25246 +
25247 +var_dump($q);
25248 +var_dump($array);
25249 +
25250 +echo "Done\n";
25251 +?>
25252 +--EXPECTF--
25253 +%aTEST
25254 +string(42) "a=b&c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3"
25255 +NULL
25256 +string(1) "b"
25257 +int(0)
25258 +string(3) "hi!"
25259 +string(3) "3.4"
25260 +int(3)
25261 +float(3.4)
25262 +bool(true)
25263 +array(3) {
25264 +  [0]=>
25265 +  int(1)
25266 +  [1]=>
25267 +  int(2)
25268 +  [2]=>
25269 +  int(3)
25270 +}
25271 +array(3) {
25272 +  [0]=>
25273 +  int(1)
25274 +  [1]=>
25275 +  int(2)
25276 +  [2]=>
25277 +  int(3)
25278 +}
25279 +object(stdClass)#%d (%d) {
25280 +  [0]=>
25281 +  int(1)
25282 +  [1]=>
25283 +  int(2)
25284 +  [2]=>
25285 +  int(3)
25286 +}
25287 +object(HttpQueryString)#1 (2) {
25288 +  ["queryArray%s]=>
25289 +  array(3) {
25290 +    ["c"]=>
25291 +    string(3) "3.4"
25292 +    ["r"]=>
25293 +    array(3) {
25294 +      [0]=>
25295 +      int(1)
25296 +      [1]=>
25297 +      int(2)
25298 +      [2]=>
25299 +      int(3)
25300 +    }
25301 +    ["z"]=>
25302 +    array(1) {
25303 +      [0]=>
25304 +      string(1) "2"
25305 +    }
25306 +  }
25307 +  ["queryString%s]=>
25308 +  string(49) "c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3&z%5B0%5D=2"
25309 +}
25310 +array(3) {
25311 +  ["a"]=>
25312 +  string(1) "b"
25313 +  ["c"]=>
25314 +  string(3) "3.4"
25315 +  ["r"]=>
25316 +  array(3) {
25317 +    [0]=>
25318 +    int(1)
25319 +    [1]=>
25320 +    int(2)
25321 +    [2]=>
25322 +    int(3)
25323 +  }
25324 +}
25325 +Done
25326 \ No newline at end of file
25327 --- /dev/null
25328 +++ b/ext/http/tests/HttpQueryString_003.phpt
25329 @@ -0,0 +1,24 @@
25330 +--TEST--
25331 +HttpQueryString xlate
25332 +--SKIPIF--
25333 +<?php
25334 +include 'skip.inc';
25335 +checkmin("5.2.5");
25336 +checkext('iconv');
25337 +?>
25338 +--FILE--
25339 +<?php
25340 +echo "-TEST\n";
25341 +$qs = new HttpQueryString(false, "ä[0]=ü&ö[a]=ß");
25342 +var_dump($qs->get());
25343 +$qs->xlate("latin1", "utf8");
25344 +var_dump($qs->get());
25345 +$qs->xlate("utf8", "latin1");
25346 +var_dump($qs->get());
25347 +echo "Done\n";
25348 +--EXPECTF--
25349 +%aTEST
25350 +string(29) "%E4%5B0%5D=%FC&%F6%5Ba%5D=%DF"
25351 +string(41) "%C3%A4%5B0%5D=%C3%BC&%C3%B6%5Ba%5D=%C3%9F"
25352 +string(29) "%E4%5B0%5D=%FC&%F6%5Ba%5D=%DF"
25353 +Done
25354 --- /dev/null
25355 +++ b/ext/http/tests/HttpQueryString_004.phpt
25356 @@ -0,0 +1,54 @@
25357 +--TEST--
25358 +HttpQueryString w/ objects
25359 +--SKIPIF--
25360 +<?php
25361 +include 'skip.inc';
25362 +checkmin("5.2.5");
25363 +?>
25364 +--FILE--
25365 +<?php
25366 +echo "-TEST\n";
25367 +class test_props {
25368 +       public $bar;
25369 +       public $baz;
25370 +       protected $dont_show;
25371 +       private $dont_show2;
25372 +       function __construct() {
25373 +               $this->bar = (object) array("baz"=>1);
25374 +               $this->dont_show = 'xxx';
25375 +               $this->dont_show2 = 'zzz';
25376 +       }
25377 +}
25378 +$foo = new test_props;
25379 +var_dump($q = new HttpQueryString(false, $foo));
25380 +$foo->bar->baz = 0;
25381 +var_dump($q->mod($foo));
25382 +echo "Done\n";
25383 +?>
25384 +--EXPECTF--
25385 +%aTEST
25386 +object(HttpQueryString)#3 (2) {
25387 +  ["queryArray%s]=>
25388 +  array(1) {
25389 +    ["bar"]=>
25390 +    array(1) {
25391 +      ["baz"]=>
25392 +      int(1)
25393 +    }
25394 +  }
25395 +  ["queryString%s]=>
25396 +  string(14) "bar%5Bbaz%5D=1"
25397 +}
25398 +object(HttpQueryString)#4 (2) {
25399 +  ["queryArray%s]=>
25400 +  array(1) {
25401 +    ["bar"]=>
25402 +    array(1) {
25403 +      ["baz"]=>
25404 +      int(0)
25405 +    }
25406 +  }
25407 +  ["queryString%s]=>
25408 +  string(14) "bar%5Bbaz%5D=0"
25409 +}
25410 +Done
25411 --- /dev/null
25412 +++ b/ext/http/tests/HttpRequestDataShare_001.phpt
25413 @@ -0,0 +1,38 @@
25414 +--TEST--
25415 +HttpRequestDataShare
25416 +--SKIPIF--
25417 +<?php
25418 +include "skip.inc";
25419 +checkurl("www.google.com");
25420 +checkcls("HttpRequestDataShare");
25421 +?>
25422 +--FILE--
25423 +<?php
25424 +echo "-TEST\n";
25425 +
25426 +$s = new HttpRequestDataShare;
25427 +$s->dns = true;
25428 +$s->cookie = true;
25429 +
25430 +$r1 = new HttpRequest("http://www.google.com/");
25431 +$r2 = new HttpRequest("http://www.google.com/");
25432 +
25433 +$r1->enableCookies();
25434 +$r2->enableCookies();
25435 +
25436 +$s->attach($r1);
25437 +$s->attach($r2);
25438 +
25439 +$r1->send();
25440 +$r2->send();
25441 +
25442 +$s->reset();
25443 +
25444 +var_dump(current($r1->getResponseCookies())->cookies["PREF"] === HttpUtil::parseCookie($r2->getRequestMessage()->getHeader("Cookie"))->cookies["PREF"]);
25445 +
25446 +echo "Done\n";
25447 +?>
25448 +--EXPECTF--
25449 +%aTEST
25450 +bool(true)
25451 +Done
25452 --- /dev/null
25453 +++ b/ext/http/tests/HttpRequestDataShare_002.phpt
25454 @@ -0,0 +1,52 @@
25455 +--TEST--
25456 +HttpRequestDataShare global
25457 +--SKIPIF--
25458 +<?php
25459 +include "skip.inc";
25460 +checkurl("www.google.com");
25461 +checkcls("HttpRequestDataShare");
25462 +?>
25463 +--FILE--
25464 +<?php
25465 +echo "-TEST\n";
25466 +
25467 +$s = HttpRequestDataShare::singleton(true);
25468 +$s->cookie = true;
25469 +var_dump($s);
25470 +
25471 +$r1 = new HttpRequest("http://www.google.com/");
25472 +$r2 = new HttpRequest("http://www.google.com/");
25473 +
25474 +$r1->enableCookies();
25475 +$r2->enableCookies();
25476 +
25477 +$s->attach($r1);
25478 +$s->attach($r2);
25479 +
25480 +$r1->send();
25481 +$r2->send();
25482 +
25483 +$s->reset();
25484 +
25485 +if (current($r1->getResponseCookies())->cookies["PREF"] !== HttpUtil::parseCookie($r2->getRequestMessage()->getHeader("Cookie"))->cookies["PREF"]) {
25486 +       var_dump(
25487 +               current($r1->getResponseCookies())->cookies["PREF"],
25488 +               HttpUtil::parseCookie($r2->getRequestMessage()->getHeader("Cookie"))->cookies["PREF"]
25489 +       );
25490 +}
25491 +
25492 +echo "Done\n";
25493 +?>
25494 +--EXPECTF--
25495 +%aTEST
25496 +object(HttpRequestDataShare)#1 (4) {
25497 +  ["cookie"]=>
25498 +  bool(true)
25499 +  ["dns"]=>
25500 +  bool(true)
25501 +  ["ssl"]=>
25502 +  bool(false)
25503 +  ["connect"]=>
25504 +  bool(false)
25505 +}
25506 +Done
25507 --- /dev/null
25508 +++ b/ext/http/tests/HttpRequestPool_001.phpt
25509 @@ -0,0 +1,51 @@
25510 +--TEST--
25511 +HttpRequestPool
25512 +--SKIPIF--
25513 +<?php
25514 +include 'skip.inc';
25515 +checkmin("5.2.5");
25516 +checkcls('HttpRequestPool');
25517 +checkurl('www.php.net');
25518 +checkurl('dev.iworks.at');
25519 +?>
25520 +--FILE--
25521 +<?php
25522 +echo "-TEST\n";
25523 +$post = new HttpRequest('http://dev.iworks.at/ext-http/.print_request.php', HTTP_METH_POST);
25524 +$post->addPostFields(array('a'=>1,'b'=>2)) ;
25525 +
25526 +$pool = new HttpRequestPool(
25527 +    new HttpRequest('http://www.php.net/', HTTP_METH_HEAD),
25528 +    $post
25529 +);
25530 +
25531 +$pool->send();
25532 +
25533 +foreach ($pool as $req) {
25534 +    echo $req->getUrl(), '=',
25535 +        $req->getResponseCode(), ':',
25536 +        $req->getResponseMessage()->getResponseCode(), "\n";
25537 +}
25538 +
25539 +foreach ($pool as $req) {
25540 +       try {
25541 +               $pool->attach(new HttpRequest('http://foo.bar'));
25542 +       } catch (HttpRequestPoolException $x) {
25543 +               echo ".\n";
25544 +       }
25545 +}
25546 +
25547 +foreach ($pool as $req) {
25548 +       $pool->detach($req);
25549 +}
25550 +
25551 +echo "Done\n";
25552 +?>
25553 +
25554 +--EXPECTF--
25555 +%aTEST
25556 +http://www.php.net/=200:200
25557 +http://dev.iworks.at/ext-http/.print_request.php=200:200
25558 +.
25559 +.
25560 +Done
25561 --- /dev/null
25562 +++ b/ext/http/tests/HttpRequestPool_002.phpt
25563 @@ -0,0 +1,51 @@
25564 +--TEST--
25565 +extending HttpRequestPool
25566 +--SKIPIF--
25567 +<?php
25568 +include 'skip.inc';
25569 +checkcls('HttpRequestPool');
25570 +checkurl('www.php.net');
25571 +?>
25572 +--FILE--
25573 +<?php
25574 +echo "-TEST\n";
25575 +
25576 +class MyPool extends HttpRequestPool
25577 +{
25578 +       public function send()
25579 +       {
25580 +               while ($this->socketPerform()) {
25581 +                       if (!$this->socketSelect()) {
25582 +                               throw new HttpSocketException;
25583 +                       }
25584 +               }
25585 +       }
25586 +       
25587 +       protected final function socketPerform()
25588 +       {
25589 +               $result = parent::socketPerform();
25590 +               
25591 +               echo ".";
25592 +               foreach ($this->getFinishedRequests() as $r) {
25593 +                       echo "=", $r->getResponseCode(), "=";
25594 +                       $this->detach($r);
25595 +               }
25596 +               
25597 +               return $result;
25598 +       }
25599 +}
25600 +
25601 +$pool = new MyPool(
25602 +    new HttpRequest('http://www.php.net/', HTTP_METH_HEAD),
25603 +    new HttpRequest('http://www.php.net/', HTTP_METH_HEAD),
25604 +    new HttpRequest('http://www.php.net/', HTTP_METH_HEAD)
25605 +);
25606 +
25607 +$pool->send();
25608 +
25609 +echo "\nDone\n";
25610 +?>
25611 +--EXPECTREGEX--
25612 +.+TEST
25613 +\.*=200=\.*=200=\.*=200=
25614 +Done
25615 --- /dev/null
25616 +++ b/ext/http/tests/HttpRequestPool_003.phpt
25617 @@ -0,0 +1,175 @@
25618 +--TEST--
25619 +HttpRequestPool chain
25620 +--SKIPIF--
25621 +<?php
25622 +include 'skip.inc';
25623 +checkcls('HttpRequest');
25624 +checkcls('HttpRequestPool');
25625 +?>
25626 +--FILE--
25627 +<?php
25628 +
25629 +echo "-TEST\n";
25630 +
25631 +set_time_limit(0);
25632 +ini_set('error_reporting', E_ALL);
25633 +ini_set('html_errors', 0);
25634 +
25635 +class Pool extends HttpRequestPool
25636 +{
25637 +       private $all;
25638 +       private $rem;
25639 +       private $dir;
25640 +       
25641 +       public final function __construct($urls_file = 'urls.txt', $cache_dir = 'HttpRequestPool_cache')
25642 +       {
25643 +               $this->dir = (is_dir($cache_dir) or @mkdir($cache_dir)) ? $cache_dir : null;
25644 +               
25645 +               foreach (array_map('trim', file($urls_file)) as $url) {
25646 +                       $this->all[$url] = $this->dir ? $this->dir .'/'. md5($url) : null;
25647 +               }
25648 +               
25649 +               $this->send();
25650 +       }
25651 +       
25652 +       public final function send()
25653 +       {
25654 +               if (RMAX) {
25655 +                       $now = array_slice($this->all, 0, RMAX);
25656 +                       $this->rem = array_slice($this->all, RMAX);
25657 +               } else {
25658 +                       $now = $urls;
25659 +                       $this->rem = array();
25660 +               }
25661 +               
25662 +               foreach ($now as $url => $file) {
25663 +                       $this->attach(
25664 +                               new HttpRequest(
25665 +                                       $url,
25666 +                                       HttpRequest::METH_GET,
25667 +                                       array(
25668 +                                               'redirect'      => 5,
25669 +                                               'compress'  => GZIP,
25670 +                                               'timeout'       => TOUT,
25671 +                                               'connecttimeout' => TOUT,
25672 +                                               'lastmodified' => is_file($file)?filemtime($file):0
25673 +                                       )
25674 +                               )
25675 +                       );
25676 +               }
25677 +               
25678 +               while ($this->socketPerform()) {
25679 +                       if (!$this->socketSelect()) {
25680 +                               throw new HttpSocketException;
25681 +                       }
25682 +               }
25683 +       }
25684 +       
25685 +       protected final function socketPerform()
25686 +       {
25687 +               try {
25688 +                       $rc = parent::socketPerform();
25689 +               } catch (HttpRequestException $x) {
25690 +                       // a request may have thrown an exception,
25691 +                       // but it is still save to continue
25692 +                       echo $x->getMessage(), "\n";
25693 +               }
25694 +               
25695 +               foreach ($this->getFinishedRequests() as $r) {
25696 +                       $this->detach($r);
25697 +                       
25698 +                       $u = $r->getUrl();
25699 +                       $c = $r->getResponseCode();
25700 +                       $b = $r->getResponseBody();
25701 +                       
25702 +                       printf("%d %s %d\n", $c, $u, strlen($b));
25703 +                       
25704 +                       if ($c == 200 && $this->dir) {
25705 +                               file_put_contents($this->all[$u], $b);
25706 +                       }
25707 +                       
25708 +                       if ($a = each($this->rem)) {
25709 +                               list($url, $file) = $a;
25710 +                               $this->attach(
25711 +                                       new HttpRequest(
25712 +                                               $url,
25713 +                                               HttpRequest::METH_GET,
25714 +                                               array(
25715 +                                                       'redirect'      => 5,
25716 +                                                       'compress'      => GZIP,
25717 +                                                       'timeout'       => TOUT,
25718 +                                                       'connecttimeout' => TOUT,
25719 +                                                       'lastmodified' => is_file($file)?filemtime($file):0
25720 +                                               )
25721 +                                       )
25722 +                               );
25723 +                       }
25724 +               }
25725 +               return $rc;
25726 +       }
25727 +}
25728 +
25729 +define('GZIP', true);
25730 +define('TOUT', 50);
25731 +define('RMAX', 10);
25732 +chdir(dirname(__FILE__));
25733 +
25734 +$time = microtime(true);
25735 +$pool = new Pool();
25736 +printf("Elapsed: %0.3fs\n", microtime(true)-$time);
25737 +
25738 +echo "Done\n";
25739 +?>
25740 +--EXPECTF--
25741 +%aTEST
25742 +%d %s %d
25743 +%d %s %d
25744 +%d %s %d
25745 +%d %s %d
25746 +%d %s %d
25747 +%d %s %d
25748 +%d %s %d
25749 +%d %s %d
25750 +%d %s %d
25751 +%d %s %d
25752 +%d %s %d
25753 +%d %s %d
25754 +%d %s %d
25755 +%d %s %d
25756 +%d %s %d
25757 +%d %s %d
25758 +%d %s %d
25759 +%d %s %d
25760 +%d %s %d
25761 +%d %s %d
25762 +%d %s %d
25763 +%d %s %d
25764 +%d %s %d
25765 +%d %s %d
25766 +%d %s %d
25767 +%d %s %d
25768 +%d %s %d
25769 +%d %s %d
25770 +%d %s %d
25771 +%d %s %d
25772 +%d %s %d
25773 +%d %s %d
25774 +%d %s %d
25775 +%d %s %d
25776 +%d %s %d
25777 +%d %s %d
25778 +%d %s %d
25779 +%d %s %d
25780 +%d %s %d
25781 +%d %s %d
25782 +%d %s %d
25783 +%d %s %d
25784 +%d %s %d
25785 +%d %s %d
25786 +%d %s %d
25787 +%d %s %d
25788 +%d %s %d
25789 +%d %s %d
25790 +%d %s %d
25791 +Elapsed: %fs
25792 +Done
25793 --- /dev/null
25794 +++ b/ext/http/tests/HttpRequestPool_004.phpt
25795 @@ -0,0 +1,19 @@
25796 +--TEST--
25797 +HttpRequestPool::__destruct() invalid curl handle
25798 +--SKIPIF--
25799 +<?php
25800 +include 'skip.inc';
25801 +checkmin("5.2.5");
25802 +checkcls('HttpRequest');
25803 +checkcls('HttpRequestPool');
25804 +?>
25805 +--FILE--
25806 +<?php
25807 +echo "-TEST\n";
25808 +$p = new HttpRequestPool(new HttpRequest('http://example.com'));
25809 +$p = null;
25810 +echo "Done\n";
25811 +?>
25812 +--EXPECTF--
25813 +%aTEST
25814 +Done
25815 --- /dev/null
25816 +++ b/ext/http/tests/HttpRequestPool_005.phpt
25817 @@ -0,0 +1,46 @@
25818 +--TEST--
25819 +HttpRequestPool exception
25820 +--SKIPIF--
25821 +<?php
25822 +include 'skip.inc';
25823 +checkmin("5.2.5");
25824 +checkcls('HttpRequestPool');
25825 +?>
25826 +--FILE--
25827 +<?php
25828 +echo "-TEST\n";
25829 +
25830 +$p = new HttpRequestPool(new HttpRequest('http://_____'));
25831 +try {
25832 +       $p->send();
25833 +} catch (HttpRequestPoolException $x) {
25834 +       for ($i=0; $x; ++$i, $x = @$x->innerException) {
25835 +               printf("%s%s: %s\n", str_repeat("\t", $i), get_class($x), $x->getMessage());
25836 +       }
25837 +       var_dump($i);
25838 +}
25839 +$p = new HttpRequestPool(new HttpRequest('http://_____'), new HttpRequest('http://_____'));
25840 +try {
25841 +       $p->send();
25842 +} catch (HttpRequestPoolException $x) {
25843 +       for ($i=0; $x; ++$i, $x = @$x->innerException) {
25844 +               printf("%s%s: %s\n", str_repeat("\t", $i), get_class($x),  $x->getMessage());
25845 +       }
25846 +       var_dump($i);
25847 +}
25848 +echo "Done\n";
25849 +?>
25850 +--EXPECTF--
25851 +%aTEST
25852 +HttpRequestPoolException: Exception caused by 2 inner exception(s)
25853 +       HttpInvalidParamException: Empty or too short HTTP message: ''
25854 +               HttpRequestException: %souldn't resolve host name; %s (http://_____/)
25855 +int(3)
25856 +HttpRequestPoolException: Exception caused by 4 inner exception(s)
25857 +       HttpInvalidParamException: Empty or too short HTTP message: ''
25858 +               HttpRequestException: %souldn't resolve host name; %s (http://_____/)
25859 +                       HttpInvalidParamException: Empty or too short HTTP message: ''
25860 +                               HttpRequestException: %souldn't resolve host name; %s (http://_____/)
25861 +int(5)
25862 +Done
25863 +
25864 --- /dev/null
25865 +++ b/ext/http/tests/HttpRequestPool_006.phpt
25866 @@ -0,0 +1,50 @@
25867 +--TEST--
25868 +HttpRequestPool detaching in callbacks
25869 +--SKIPIF--
25870 +<?php
25871 +include 'skip.inc';
25872 +checkcls("HttpRequestPool");
25873 +checkurl("at.php.net");
25874 +checkurl("de.php.net");
25875 +?>
25876 +--FILE--
25877 +<?php
25878 +echo "-TEST\n";
25879 +class r extends HttpRequest {
25880 +       function onProgress() {
25881 +               static $i = array();
25882 +               if (empty($i[$this->getUrl()])) {
25883 +                       $i[$this->getUrl()] = true;
25884 +                       try {
25885 +                               $GLOBALS['p']->detach($this);
25886 +                       } catch (Exception $ex) {
25887 +                               echo $ex, "\n";
25888 +                       }
25889 +               }
25890 +       }
25891 +       function onFinish() {
25892 +               $GLOBALS['p']->detach($this);
25893 +       }
25894 +}
25895 +$p = new HttpRequestPool(new r("http://at.php.net"), new r("http://de.php.net"));
25896 +$p->send();
25897 +var_dump($p->getAttachedRequests());
25898 +echo "Done\n";
25899 +?>
25900 +--EXPECTF--
25901 +%aTEST
25902 +exception 'HttpRequestPoolException' with message 'HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback' in %aHttpRequestPool_006.php:%d
25903 +Stack trace:
25904 +#0 %aHttpRequestPool_006.php(%d): HttpRequestPool->detach(Object(r))
25905 +#1 [internal function]: r->onProgress(Array)
25906 +#2 %aHttpRequestPool_006.php(%d): HttpRequestPool->send()
25907 +#3 {main}
25908 +exception 'HttpRequestPoolException' with message 'HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback' in %aHttpRequestPool_006.php:%d
25909 +Stack trace:
25910 +#0 %aHttpRequestPool_006.php(%d): HttpRequestPool->detach(Object(r))
25911 +#1 [internal function]: r->onProgress(Array)
25912 +#2 %aHttpRequestPool_006.php(%d): HttpRequestPool->send()
25913 +#3 {main}
25914 +array(0) {
25915 +}
25916 +Done
25917 --- /dev/null
25918 +++ b/ext/http/tests/HttpRequest_001.phpt
25919 @@ -0,0 +1,51 @@
25920 +--TEST--
25921 +HttpRequest options
25922 +--SKIPIF--
25923 +<?php
25924 +include 'skip.inc';
25925 +checkmin("5.2.5");
25926 +checkcls('HttpRequest');
25927 +?>
25928 +--FILE--
25929 +<?php
25930 +echo "-TEST\n";
25931 +$r1 = new HttpRequest(null, 0, array('redirect'=>11, 'headers'=>array('X-Foo'=>'Bar')));
25932 +$r2 = new HttpRequest;
25933 +$r2->setOptions(array('redirect'=>99, 'headers'=>array('X-Bar'=>'Foo')));
25934 +$o1 = $r1->getOptions();
25935 +$o2 = $r2->getOptions();
25936 +$r1->setOptions($o2);
25937 +$r2->setOptions($o1);
25938 +print_r(array($o1, $o2));
25939 +var_dump(serialize($r1->getOptions()) === serialize($r2->getOptions()));
25940 +$r1 = null;
25941 +$r2 = null;
25942 +?>
25943 +--EXPECTF--
25944 +%aTEST
25945 +Array
25946 +(
25947 +    [0] => Array
25948 +        (
25949 +            [headers] => Array
25950 +                (
25951 +                    [X-Foo] => Bar
25952 +                    [X-Bar] => Foo
25953 +                )
25954 +
25955 +            [redirect] => 11
25956 +        )
25957 +
25958 +    [1] => Array
25959 +        (
25960 +            [headers] => Array
25961 +                (
25962 +                    [X-Bar] => Foo
25963 +                    [X-Foo] => Bar
25964 +                )
25965 +
25966 +            [redirect] => 99
25967 +        )
25968 +
25969 +)
25970 +bool(false)
25971 --- /dev/null
25972 +++ b/ext/http/tests/HttpRequest_002.phpt
25973 @@ -0,0 +1,86 @@
25974 +--TEST--
25975 +HttpRequest GET/POST
25976 +--SKIPIF--
25977 +<?php
25978 +include 'skip.inc';
25979 +checkmin("5.2.5");
25980 +checkcls('HttpRequest');
25981 +checkurl('www.google.com');
25982 +checkurl('dev.iworks.at');
25983 +?>
25984 +--FILE--
25985 +<?php
25986 +echo "-TEST\n";
25987 +
25988 +$r = new HttpRequest('http://www.google.com', HttpRequest::METH_GET);
25989 +$r->send();
25990 +print_r($r->getResponseInfo());
25991 +
25992 +$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_request.php', HTTP_METH_POST);
25993 +$r->addCookies(array('MyCookie' => 'foobar'));
25994 +$r->addQueryData(array('gq'=>'foobar','gi'=>10));
25995 +$r->addPostFields(array('pq'=>'foobar','pi'=>10));
25996 +$r->addPostFile('upload', dirname(__FILE__).'/data.txt', 'text/plain');
25997 +$r->send();
25998 +echo $r->getResponseBody();
25999 +var_dump($r->getResponseMessage()->getResponseCode());
26000 +
26001 +echo "Done";
26002 +?>
26003 +--EXPECTF--
26004 +%aTEST
26005 +Array
26006 +(
26007 +    [effective_url] => http://www.google.com/
26008 +    [response_code] => 302
26009 +    [total_time] => %f
26010 +    [namelookup_time] => %f
26011 +    [connect_time] => %f
26012 +    [pretransfer_time] => %f
26013 +    [size_upload] => %d
26014 +    [size_download] => %d
26015 +    [speed_download] => %d
26016 +    [speed_upload] => %d
26017 +    [header_size] => %d
26018 +    [request_size] => %d
26019 +    [ssl_verifyresult] => %d
26020 +    [filetime] => -1
26021 +    [content_length_download] => %d
26022 +    [content_length_upload] => %d
26023 +    [starttransfer_time] => %f
26024 +    [content_type] => %s
26025 +    [redirect_time] => %d
26026 +    [redirect_count] => %d
26027 +    [connect_code] => %d
26028 +    [httpauth_avail] => %d
26029 +    [proxyauth_avail] => %d
26030 +    [os_errno] => %d
26031 +    [num_connects] => %d
26032 +    [ssl_engines] => Array
26033 +    %a
26034 +    [cookies] => Array
26035 +    %a
26036 +    [error] => 
26037 +)
26038 +Array
26039 +(
26040 +    [gq] => foobar
26041 +    [gi] => 10
26042 +    [pq] => foobar
26043 +    [pi] => 10
26044 +    [MyCookie] => foobar
26045 +)
26046 +Array
26047 +(
26048 +    [upload] => Array
26049 +        (
26050 +            [name] => data.txt
26051 +            [type] => text/plain
26052 +            [tmp_name] => %a
26053 +            [error] => 0
26054 +            [size] => 1010
26055 +        )
26056 +
26057 +)
26058 +int(200)
26059 +Done
26060 --- /dev/null
26061 +++ b/ext/http/tests/HttpRequest_003.phpt
26062 @@ -0,0 +1,54 @@
26063 +--TEST--
26064 +HttpRequest SSL
26065 +--SKIPIF--
26066 +<?php
26067 +include 'skip.inc';
26068 +checkmin("5.2.5");
26069 +checkurl('arweb.info');
26070 +skipif(!http_support(HTTP_SUPPORT_SSLREQUESTS), 'need ssl-request support')
26071 +?>
26072 +--FILE--
26073 +<?php
26074 +echo "-TEST\n";
26075 +$o = array('redirect' => '3', 'ssl' => array('version' => '3', 'verifyhost' => '1'));
26076 +$r = new HttpRequest('https://ssl.irmler.at/iworks/data.txt');
26077 +$r->setOptions($o);
26078 +$r->send();
26079 +var_dump($r->getResponseBody());
26080 +var_dump(is_object($r->getResponseMessage()));
26081 +var_dump(is_object($r->getResponseMessage()));
26082 +var_dump(is_object($r->getResponseMessage()));
26083 +var_dump($o);
26084 +$r->setOptions($o);
26085 +$r->send();
26086 +var_dump($o);
26087 +?>
26088 +--EXPECTF--
26089 +%aTEST
26090 +string(10) "1234567890"
26091 +bool(true)
26092 +bool(true)
26093 +bool(true)
26094 +array(2) {
26095 +  ["redirect"]=>
26096 +  string(1) "3"
26097 +  ["ssl"]=>
26098 +  array(2) {
26099 +    ["version"]=>
26100 +    string(1) "3"
26101 +    ["verifyhost"]=>
26102 +    string(1) "1"
26103 +  }
26104 +}
26105 +array(2) {
26106 +  ["redirect"]=>
26107 +  string(1) "3"
26108 +  ["ssl"]=>
26109 +  array(2) {
26110 +    ["version"]=>
26111 +    string(1) "3"
26112 +    ["verifyhost"]=>
26113 +    string(1) "1"
26114 +  }
26115 +}
26116 +
26117 --- /dev/null
26118 +++ b/ext/http/tests/HttpRequest_004.phpt
26119 @@ -0,0 +1,162 @@
26120 +--TEST--
26121 +HttpRequest multiple posts
26122 +--SKIPIF--
26123 +<?php
26124 +include 'skip.inc';
26125 +checkcls('HttpRequest');
26126 +?>
26127 +--FILE--
26128 +<?php
26129 +echo "-TEST\n";
26130 +
26131 +$fields = array(
26132 +       array('int' => 1, 'dbl' => M_PI),
26133 +       array('str' => 'something', 'nil' => null)
26134 +);
26135 +
26136 +echo "\nFirst Request\n";
26137 +$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_request.php', HttpRequest::METH_POST);
26138 +$r->setPostFields($fields[0]);
26139 +$r->addPostFields($fields[1]);
26140 +var_dump($r->send()->getBody());
26141 +var_dump($fields);
26142 +
26143 +echo "\nSecond Request\n";
26144 +$r->setPostFields($fields);
26145 +var_dump($r->send()->getBody());
26146 +var_dump($fields);
26147 +
26148 +echo "\nThird Request\n";
26149 +$r->addPostFields(array('x' => 'X'));
26150 +var_dump($r->send()->getBody());
26151 +var_dump($fields);
26152 +
26153 +echo "\nFourth Request\n";
26154 +$r->setPostFields(array());
26155 +var_dump($r->send()->getBody());
26156 +var_dump($fields);
26157 +
26158 +echo "Done\n";
26159 +?>
26160 +--EXPECTF--
26161 +%aTEST
26162 +
26163 +First Request
26164 +string(%d) "Array
26165 +(
26166 +    [int] => 1
26167 +    [dbl] => 3.1415926535898
26168 +    [str] => something
26169 +    [nil] => 
26170 +)
26171 +string(44) "int=1&dbl=3.1415926535898&str=something&nil="
26172 +"
26173 +array(2) {
26174 +  [0]=>
26175 +  array(2) {
26176 +    ["int"]=>
26177 +    int(1)
26178 +    ["dbl"]=>
26179 +    float(3.1415926535898)
26180 +  }
26181 +  [1]=>
26182 +  array(2) {
26183 +    ["str"]=>
26184 +    string(9) "something"
26185 +    ["nil"]=>
26186 +    NULL
26187 +  }
26188 +}
26189 +
26190 +Second Request
26191 +string(%d) "Array
26192 +(
26193 +    [0] => Array
26194 +        (
26195 +            [int] => 1
26196 +            [dbl] => 3.1415926535898
26197 +        )
26198 +
26199 +    [1] => Array
26200 +        (
26201 +            [str] => something
26202 +            [nil] => 
26203 +        )
26204 +
26205 +)
26206 +string(72) "0%5Bint%5D=1&0%5Bdbl%5D=3.1415926535898&1%5Bstr%5D=something&1%5Bnil%5D="
26207 +"
26208 +array(2) {
26209 +  [0]=>
26210 +  array(2) {
26211 +    ["int"]=>
26212 +    int(1)
26213 +    ["dbl"]=>
26214 +    float(3.1415926535898)
26215 +  }
26216 +  [1]=>
26217 +  array(2) {
26218 +    ["str"]=>
26219 +    string(9) "something"
26220 +    ["nil"]=>
26221 +    NULL
26222 +  }
26223 +}
26224 +
26225 +Third Request
26226 +string(%d) "Array
26227 +(
26228 +    [0] => Array
26229 +        (
26230 +            [int] => 1
26231 +            [dbl] => 3.1415926535898
26232 +        )
26233 +
26234 +    [1] => Array
26235 +        (
26236 +            [str] => something
26237 +            [nil] => 
26238 +        )
26239 +
26240 +    [x] => X
26241 +)
26242 +string(76) "0%5Bint%5D=1&0%5Bdbl%5D=3.1415926535898&1%5Bstr%5D=something&1%5Bnil%5D=&x=X"
26243 +"
26244 +array(2) {
26245 +  [0]=>
26246 +  array(2) {
26247 +    ["int"]=>
26248 +    int(1)
26249 +    ["dbl"]=>
26250 +    float(3.1415926535898)
26251 +  }
26252 +  [1]=>
26253 +  array(2) {
26254 +    ["str"]=>
26255 +    string(9) "something"
26256 +    ["nil"]=>
26257 +    NULL
26258 +  }
26259 +}
26260 +
26261 +Fourth Request
26262 +string(13) "string(0) ""
26263 +"
26264 +array(2) {
26265 +  [0]=>
26266 +  array(2) {
26267 +    ["int"]=>
26268 +    int(1)
26269 +    ["dbl"]=>
26270 +    float(3.1415926535898)
26271 +  }
26272 +  [1]=>
26273 +  array(2) {
26274 +    ["str"]=>
26275 +    string(9) "something"
26276 +    ["nil"]=>
26277 +    NULL
26278 +  }
26279 +}
26280 +Done
26281 +
26282 --- /dev/null
26283 +++ b/ext/http/tests/HttpRequest_005.phpt
26284 @@ -0,0 +1,24 @@
26285 +--TEST--
26286 +HttpRequest accessors
26287 +--SKIPIF--
26288 +<?php
26289 +include 'skip.inc';
26290 +checkcls('HttpRequest');
26291 +?>
26292 +--FILE--
26293 +<?php
26294 +echo "-TEST\n";
26295 +error_reporting(0);
26296 +$r = new HttpRequest;
26297 +foreach (get_class_methods('HttpRequest') as $method) {
26298 +       try {
26299 +               if (strlen($method) > 3 && substr($method, 0, 3) == 'get')
26300 +                       $x = $r->$method();
26301 +       } catch (HttpException $e) {
26302 +       }
26303 +}
26304 +echo "Done\n";
26305 +?>
26306 +--EXPECTF--
26307 +%aTEST
26308 +Done
26309 --- /dev/null
26310 +++ b/ext/http/tests/HttpRequest_006.phpt
26311 @@ -0,0 +1,147 @@
26312 +--TEST--
26313 +HttpRequest XMLRPC
26314 +--SKIPIF--
26315 +<?php
26316 +include 'skip.inc';
26317 +checkext('xmlrpc');
26318 +checkcls('HttpRequest');
26319 +?>
26320 +--FILE--
26321 +<?php
26322 +echo "-TEST\n";
26323 +
26324 +$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_request.php', HTTP_METH_POST);
26325 +$r->setContentType('text/xml');
26326 +$r->setBody(xmlrpc_encode_request('testMethod', array('foo' => 'bar')));
26327 +var_dump($r->send());
26328 +var_dump($r->send());
26329 +var_dump($r->send());
26330 +
26331 +echo "Done\n";
26332 +?>
26333 +--EXPECTF--
26334 +%aTEST
26335 +object(HttpMessage)#%d (%d) {
26336 +  ["type:protected"]=>
26337 +  int(2)
26338 +  ["body:protected"]=>
26339 +  string(309) "string(294) "<?xml version="1.0" encoding="iso-8859-1%s]>
26340 +<methodCall>
26341 +<methodName>testMethod</methodName>
26342 +<params>
26343 + <param>
26344 +  <value>
26345 +   <struct>
26346 +    <member>
26347 +     <name>foo</name>
26348 +     <value>
26349 +      <string>bar</string>
26350 +     </value>
26351 +    </member>
26352 +   </struct>
26353 +  </value>
26354 + </param>
26355 +</params>
26356 +</methodCall>
26357 +"
26358 +"
26359 +  ["requestMethod:protected"]=>
26360 +  string(0) ""
26361 +  ["requestUrl:protected"]=>
26362 +  string(0) ""
26363 +  ["responseStatus:protected"]=>
26364 +  string(2) "OK"
26365 +  ["responseCode:protected"]=>
26366 +  int(200)
26367 +  ["httpVersion:protected"]=>
26368 +  float(1.1)
26369 +  ["headers:protected"]=>
26370 +  array(6) {
26371 +    %a
26372 +  }
26373 +  ["parentMessage:protected"]=>
26374 +  NULL
26375 +}
26376 +object(HttpMessage)#%d (%d) {
26377 +  ["type:protected"]=>
26378 +  int(2)
26379 +  ["body:protected"]=>
26380 +  string(309) "string(294) "<?xml version="1.0" encoding="iso-8859-1%s]>
26381 +<methodCall>
26382 +<methodName>testMethod</methodName>
26383 +<params>
26384 + <param>
26385 +  <value>
26386 +   <struct>
26387 +    <member>
26388 +     <name>foo</name>
26389 +     <value>
26390 +      <string>bar</string>
26391 +     </value>
26392 +    </member>
26393 +   </struct>
26394 +  </value>
26395 + </param>
26396 +</params>
26397 +</methodCall>
26398 +"
26399 +"
26400 +  ["requestMethod:protected"]=>
26401 +  string(0) ""
26402 +  ["requestUrl:protected"]=>
26403 +  string(0) ""
26404 +  ["responseStatus:protected"]=>
26405 +  string(2) "OK"
26406 +  ["responseCode:protected"]=>
26407 +  int(200)
26408 +  ["httpVersion:protected"]=>
26409 +  float(1.1)
26410 +  ["headers:protected"]=>
26411 +  array(6) {
26412 +    %a
26413 +  }
26414 +  ["parentMessage:protected"]=>
26415 +  NULL
26416 +}
26417 +object(HttpMessage)#%d (%d) {
26418 +  ["type:protected"]=>
26419 +  int(2)
26420 +  ["body:protected"]=>
26421 +  string(309) "string(294) "<?xml version="1.0" encoding="iso-8859-1%s]>
26422 +<methodCall>
26423 +<methodName>testMethod</methodName>
26424 +<params>
26425 + <param>
26426 +  <value>
26427 +   <struct>
26428 +    <member>
26429 +     <name>foo</name>
26430 +     <value>
26431 +      <string>bar</string>
26432 +     </value>
26433 +    </member>
26434 +   </struct>
26435 +  </value>
26436 + </param>
26437 +</params>
26438 +</methodCall>
26439 +"
26440 +"
26441 +  ["requestMethod:protected"]=>
26442 +  string(0) ""
26443 +  ["requestUrl:protected"]=>
26444 +  string(0) ""
26445 +  ["responseStatus:protected"]=>
26446 +  string(2) "OK"
26447 +  ["responseCode:protected"]=>
26448 +  int(200)
26449 +  ["httpVersion:protected"]=>
26450 +  float(1.1)
26451 +  ["headers:protected"]=>
26452 +  array(6) {
26453 +    %a
26454 +  }
26455 +  ["parentMessage:protected"]=>
26456 +  NULL
26457 +}
26458 +Done
26459 --- /dev/null
26460 +++ b/ext/http/tests/HttpRequest_007.phpt
26461 @@ -0,0 +1,64 @@
26462 +--TEST--
26463 +HttpRequest PUT
26464 +--SKIPIF--
26465 +<?php
26466 +include 'skip.inc';
26467 +checkcls('HttpRequest');
26468 +?>
26469 +--FILE--
26470 +<?php
26471 +echo "-TEST\n";
26472 +
26473 +$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_put.php5', HTTP_METH_PUT);
26474 +$r->recordHistory = true;
26475 +$r->addHeaders(array('content-type' => 'text/plain'));
26476 +$r->setPutFile(__FILE__);
26477 +$r->send();
26478 +var_dump($r->getHistory()->toString(true));
26479 +echo "Done\n";
26480 +?>
26481 +--EXPECTF--
26482 +%aTEST
26483 +string(%d) "PUT /ext-http/.print_put.php5 HTTP/1.1
26484 +User-Agent: PECL::HTTP/%a
26485 +Host: dev.iworks.at
26486 +Accept: */*
26487 +Content-Type: text/plain
26488 +Content-Length: %d
26489 +Expect: 100-continue
26490 +
26491 +<?php
26492 +echo "-TEST\n";
26493 +
26494 +$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_put.php5', HTTP_METH_PUT);
26495 +$r->recordHistory = true;
26496 +$r->addHeaders(array('content-type' => 'text/plain'));
26497 +$r->setPutFile(__FILE__);
26498 +$r->send();
26499 +var_dump($r->getHistory()->toString(true));
26500 +echo "Done\n";
26501 +?>
26502 +
26503 +HTTP/1.1 100 Continue
26504 +HTTP/1.1 200 OK
26505 +Date: %a
26506 +Server: %a
26507 +X-Powered-By: %a
26508 +Vary: Accept-Encoding
26509 +Content-Length: %d
26510 +Content-Type: text/html
26511 +
26512 +<?php
26513 +echo "-TEST\n";
26514 +
26515 +$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_put.php5', HTTP_METH_PUT);
26516 +$r->recordHistory = true;
26517 +$r->addHeaders(array('content-type' => 'text/plain'));
26518 +$r->setPutFile(__FILE__);
26519 +$r->send();
26520 +var_dump($r->getHistory()->toString(true));
26521 +echo "Done\n";
26522 +?>
26523 +
26524 +"
26525 +Done
26526 --- /dev/null
26527 +++ b/ext/http/tests/HttpRequest_008.phpt
26528 @@ -0,0 +1,32 @@
26529 +--TEST--
26530 +HttpRequest custom request method
26531 +--SKIPIF--
26532 +<?php
26533 +include 'skip.inc';
26534 +checkcls('HttpRequest');
26535 +?>
26536 +--FILE--
26537 +<?php
26538 +echo "-TEST\n";
26539 +
26540 +HttpRequest::methodRegister('foobar');
26541 +$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_request.php', HttpRequest::METH_FOOBAR);
26542 +$r->setContentType('text/plain');
26543 +$r->setBody('Yep, this is FOOBAR!');
26544 +var_dump($r->send()->getResponseCode());
26545 +var_dump($r->getRawRequestMessage());
26546 +
26547 +echo "Done\n";
26548 +?>
26549 +--EXPECTF--
26550 +%aTEST
26551 +int(200)
26552 +string(%d) "FOOBAR /ext-http/.print_request.php HTTP/1.1
26553 +User-Agent: %a
26554 +Host: dev.iworks.at
26555 +Accept: */*
26556 +Content-Type: text/plain
26557 +Content-Length: 20
26558 +
26559 +Yep, this is FOOBAR!"
26560 +Done
26561 --- /dev/null
26562 +++ b/ext/http/tests/HttpRequest_009.phpt
26563 @@ -0,0 +1,48 @@
26564 +--TEST--
26565 +HttpRequest callbacks
26566 +--SKIPIF--
26567 +<?php
26568 +include 'skip.inc';
26569 +checkcls('HttpRequest');
26570 +?>
26571 +--FILE--
26572 +<?php
26573 +echo "-TEST\n";
26574 +
26575 +class _R extends HttpRequest
26576 +{
26577 +       function onProgress($progress)
26578 +       {
26579 +               print_r($progress);
26580 +       }
26581 +       
26582 +       function onFinish()
26583 +       {
26584 +               var_dump($this->getResponseCode());
26585 +       }
26586 +}
26587 +
26588 +$r = new _R('http://dev.iworks.at/ext-http/.print_request.php', HTTP_METH_POST);
26589 +$r->addPostFile('upload', __FILE__, 'text/plain');
26590 +$r->send();
26591 +
26592 +echo "Done\n";
26593 +?>
26594 +--EXPECTF--
26595 +%aTEST
26596 +Array
26597 +(
26598 +    [dltotal] => %f
26599 +    [dlnow] => %f
26600 +    [ultotal] => %f
26601 +    [ulnow] => %f
26602 +)
26603 +%array
26604 +(
26605 +    [dltotal] => %f
26606 +    [dlnow] => %f
26607 +    [ultotal] => %f
26608 +    [ulnow] => %f
26609 +)
26610 +int(200)
26611 +Done
26612 --- /dev/null
26613 +++ b/ext/http/tests/HttpRequest_010.phpt
26614 @@ -0,0 +1,48 @@
26615 +--TEST--
26616 +HttpRequest cookie API
26617 +--SKIPIF--
26618 +<?php
26619 +include 'skip.inc';
26620 +checkmin("5.2.5");
26621 +checkcls("HttpRequest");
26622 +?>
26623 +--FILE--
26624 +<?php
26625 +echo "-TEST\n";
26626 +
26627 +$r = new HttpRequest("http://dev.iworks.at/ext-http/.cookie.php");
26628 +
26629 +$r->send();
26630 +$c[0] = $r->getResponseInfo("cookies");
26631 +if (!empty($c[0])) {
26632 +       var_dump('$c[0]', $c[0]);
26633 +}
26634 +
26635 +var_dump($r->enableCookies());
26636 +$r->send();
26637 +
26638 +$c[1] = $r->getResponseInfo("cookies");
26639 +if (empty($c[1])) {
26640 +       var_dump('$c[1]', $c[1]);
26641 +}
26642 +
26643 +var_dump($r->resetCookies());
26644 +$r->send();
26645 +
26646 +$c[2] = $r->getResponseInfo("cookies");
26647 +if ($c[1] === $c[2]) {
26648 +       var_dump('$c[1]', $c[1], '$c[2]', $c[2]);
26649 +}
26650 +
26651 +$r->send();
26652 +$c[3] = $r->getResponseInfo("cookies");
26653 +if ($c[2] !== $c[3]) {
26654 +       var_dump('$c[2]', $c[2], '$c[3]', $c[3]);
26655 +}
26656 +
26657 +echo "Done\n";
26658 +--EXPECTF--
26659 +%aTEST
26660 +bool(true)
26661 +bool(true)
26662 +Done
26663 --- /dev/null
26664 +++ b/ext/http/tests/HttpResponse_001.phpt
26665 @@ -0,0 +1,25 @@
26666 +--TEST--
26667 +HttpResponse - send data with caching headers
26668 +--SKIPIF--
26669 +<?php 
26670 +include 'skip.inc';
26671 +checkmin("5.2.5");
26672 +checkcgi();
26673 +?>
26674 +--FILE--
26675 +<?php
26676 +HttpResponse::setCache(true);
26677 +HttpResponse::setCacheControl('public', 3600);
26678 +HttpResponse::setData('foobar');
26679 +HttpResponse::send();
26680 +?>
26681 +--EXPECTF--
26682 +X-Powered-By: PHP/%a
26683 +Cache-Control: public, must-revalidate, max-age=3600
26684 +Last-Modified: %a, %d %a 20%d %d:%d:%d GMT
26685 +Content-Type: %a
26686 +Accept-Ranges: bytes
26687 +ETag: "3858f62230ac3c915f300c664312c63f"
26688 +Content-Length: 6
26689 +
26690 +foobar
26691 --- /dev/null
26692 +++ b/ext/http/tests/HttpResponse_002.phpt
26693 @@ -0,0 +1,25 @@
26694 +--TEST--
26695 +HttpResponse - send gzipped file
26696 +--SKIPIF--
26697 +<?php
26698 +include 'skip.inc';
26699 +checkmin("5.2.5");
26700 +checkcgi();
26701 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib support");
26702 +?>
26703 +--ENV--
26704 +HTTP_ACCEPT_ENCODING=gzip
26705 +--FILE--
26706 +<?php
26707 +HttpResponse::setGzip(true);
26708 +HttpResponse::setFile(__FILE__);
26709 +HttpResponse::send();
26710 +?>
26711 +--EXPECTF--
26712 +X-Powered-By: PHP/%a
26713 +Content-Type: %a
26714 +Accept-Ranges: bytes
26715 +Content-Encoding: gzip
26716 +Vary: Accept-Encoding
26717 +
26718 +%a
26719 --- /dev/null
26720 +++ b/ext/http/tests/HttpResponse_003.phpt
26721 @@ -0,0 +1,30 @@
26722 +--TEST--
26723 +HttpResponse - send gzipped file with caching headers
26724 +--SKIPIF--
26725 +<?php 
26726 +include 'skip.inc';
26727 +checkmin("5.2.5");
26728 +checkcgi();
26729 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib support");
26730 +?>
26731 +--ENV--
26732 +HTTP_ACCEPT_ENCODING=gzip
26733 +--FILE--
26734 +<?php
26735 +HttpResponse::setGzip(true);
26736 +HttpResponse::setCache(true);
26737 +HttpResponse::setCacheControl('public', 3600);
26738 +HttpResponse::setFile(__FILE__);
26739 +HttpResponse::send();
26740 +?>
26741 +--EXPECTF--
26742 +X-Powered-By: PHP/%a
26743 +Cache-Control: public, must-revalidate, max-age=3600
26744 +Last-Modified: %a, %d %a 20%d %d:%d:%d GMT
26745 +Content-Type: %a
26746 +Accept-Ranges: bytes
26747 +ETag: "%a"
26748 +Content-Encoding: gzip
26749 +Vary: Accept-Encoding
26750 +
26751 +%a
26752 --- /dev/null
26753 +++ b/ext/http/tests/HttpResponse_004.phpt
26754 @@ -0,0 +1,27 @@
26755 +--TEST--
26756 +HttpResponse - send cached gzipped data
26757 +--SKIPIF--
26758 +<?php 
26759 +include 'skip.inc';
26760 +checkcgi();
26761 +checkmin("5.2.7");
26762 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib support");
26763 +?>
26764 +--ENV--
26765 +HTTP_IF_NONE_MATCH="900150983cd24fb0d6963f7d28e17f72"
26766 +HTTP_ACCEPT_ENCODING=gzip
26767 +--FILE--
26768 +<?php
26769 +HttpResponse::setGzip(true);
26770 +HttpResponse::setCache(true);
26771 +HttpResponse::setCacheControl('public', 3600);
26772 +HttpResponse::setData("abc");
26773 +HttpResponse::send();
26774 +?>
26775 +--EXPECTF--
26776 +Status: 304%s
26777 +X-Powered-By: PHP/%s
26778 +Cache-Control: public, must-revalidate, max-age=3600
26779 +Last-Modified: %s
26780 +Accept-Ranges: bytes
26781 +ETag: "900150983cd24fb0d6963f7d28e17f72"
26782 --- /dev/null
26783 +++ b/ext/http/tests/HttpResponse_005.phpt
26784 @@ -0,0 +1,24 @@
26785 +--TEST--
26786 +HttpResponse file not found
26787 +--SKIPIF--
26788 +<?php
26789 +include 'skip.inc';
26790 +checkcgi();
26791 +checkmin("5.2.5");
26792 +?>
26793 +--FILE--
26794 +<?php
26795 +ini_set("error_reporting", 0);
26796 +ini_set("default_mimetype", "text/plain");
26797 +
26798 +HttpResponse::setContentType("application/pdf");
26799 +HttpResponse::setContentDisposition("doc.pdf");
26800 +HttpResponse::setFile("__nonexistant__.pdf");
26801 +HttpResponse::send();
26802 +?>
26803 +--EXPECTF--
26804 +Status: 404%s
26805 +X-Powered-By: PHP/%s
26806 +Content-Type: text/plain
26807 +
26808 +File not found
26809 --- /dev/null
26810 +++ b/ext/http/tests/allowed_methods_002.phpt
26811 @@ -0,0 +1,21 @@
26812 +--TEST--
26813 +allowed methods
26814 +--SKIPIF--
26815 +<?php
26816 +include 'skip.inc';
26817 +checkcgi();
26818 +checkmin("5.2.5");
26819 +?>
26820 +--FILE--
26821 +<?php
26822 +include 'log.inc';
26823 +log_prepare(_AMETH_LOG);
26824 +ini_set('http.request.methods.allowed', 'POST');
26825 +echo "Done\n";
26826 +?>
26827 +--EXPECTF--
26828 +Status: 405%s
26829 +X-Powered-By: PHP/%a
26830 +Allow: POST
26831 +Content-type: %a
26832 +
26833 --- /dev/null
26834 +++ b/ext/http/tests/allowed_methods_002_logging.phpt
26835 @@ -0,0 +1,21 @@
26836 +--TEST--
26837 +logging allowed methods
26838 +--SKIPIF--
26839 +<?php
26840 +include 'skip.inc';
26841 +checkcgi();
26842 +checkmin("5.2.5");
26843 +?>
26844 +--ENV--
26845 +HTTP_HOST=example.com
26846 +--FILE--
26847 +<?php
26848 +echo "-TEST\n";
26849 +include 'log.inc';
26850 +log_content(_AMETH_LOG);
26851 +echo "Done";
26852 +?>
26853 +--EXPECTF--
26854 +%aTEST
26855 +%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d      [405-ALLOWED]   Allow: POST     <%a>
26856 +Done
26857 --- /dev/null
26858 +++ b/ext/http/tests/bug_15800.phpt
26859 @@ -0,0 +1,49 @@
26860 +--TEST--
26861 +Bug #15800 Double free when zval is separated in convert_to_*
26862 +--SKIPIF--
26863 +<?php
26864 +include 'skip.inc';
26865 +checkmin("5.2.5");
26866 +checkcls('HttpRequest');
26867 +skipif(!function_exists('debug_zval_dump'), "need DEBUG version of PHP");
26868 +?>
26869 +--FILE--
26870 +<?php
26871 +echo "-TEST\n";
26872 +$o = array('ssl' => array('verifypeer'=>'1'));
26873 +debug_zval_dump($o);
26874 +
26875 +$r = new HttpRequest('http://www.google.com');
26876 +$r->setOptions($o);
26877 +$r->send();
26878 +debug_zval_dump($o);
26879 +
26880 +unset($r);
26881 +debug_zval_dump($o);
26882 +
26883 +echo "Done\n";
26884 +?>
26885 +--EXPECTF--
26886 +%aTEST
26887 +array(1) refcount(2){
26888 +  ["ssl"]=>
26889 +  array(1) refcount(1){
26890 +    ["verifypeer"]=>
26891 +    string(1) "1" refcount(1)
26892 +  }
26893 +}
26894 +array(1) refcount(2){
26895 +  ["ssl"]=>
26896 +  array(1) refcount(1){
26897 +    ["verifypeer"]=>
26898 +    string(1) "1" refcount(2)
26899 +  }
26900 +}
26901 +array(1) refcount(2){
26902 +  ["ssl"]=>
26903 +  array(1) refcount(1){
26904 +    ["verifypeer"]=>
26905 +    string(1) "1" refcount(1)
26906 +  }
26907 +}
26908 +Done
26909 --- /dev/null
26910 +++ b/ext/http/tests/build_str_001.phpt
26911 @@ -0,0 +1,30 @@
26912 +--TEST--
26913 +http_build_str
26914 +--SKIPIF--
26915 +<?php
26916 +include 'skip.inc';
26917 +?>
26918 +--FILE--
26919 +<?php
26920 +echo "-TEST\n";
26921 +
26922 +parse_str("a=b", $q);
26923 +echo http_build_str($q, null, "&"), "\n";
26924 +
26925 +parse_str("a=b&c[0]=1", $q);
26926 +echo http_build_str($q, null, "&"), "\n";
26927 +
26928 +parse_str("a=b&c[0]=1&d[e]=f", $q);
26929 +echo http_build_str($q, null, "&"), "\n";
26930 +
26931 +echo http_build_str(array(1,2,array(3)), "foo", "&"), "\n";
26932 +
26933 +echo "Done\n";
26934 +?>
26935 +--EXPECTF--
26936 +%aTEST
26937 +a=b
26938 +a=b&c%5B0%5D=1
26939 +a=b&c%5B0%5D=1&d%5Be%5D=f
26940 +foo%5B0%5D=1&foo%5B1%5D=2&foo%5B2%5D%5B0%5D=3
26941 +Done
26942 --- /dev/null
26943 +++ b/ext/http/tests/build_url_001.phpt
26944 @@ -0,0 +1,18 @@
26945 +--TEST--
26946 +http_build_url() with relative paths
26947 +--SKIPIF--
26948 +<?php
26949 +include 'skip.inc';
26950 +?>
26951 +--FILE--
26952 +<?php
26953 +echo "-TEST\n";
26954 +echo http_build_url('page'), "\n";
26955 +echo http_build_url('with/some/path/'), "\n";
26956 +echo "Done\n";
26957 +?>
26958 +--EXPECTF--
26959 +%aTEST
26960 +http://%a/page
26961 +http://%a/with/some/path/
26962 +Done
26963 --- /dev/null
26964 +++ b/ext/http/tests/build_url_002.phpt
26965 @@ -0,0 +1,30 @@
26966 +--TEST--
26967 +http_build_url() with parse_url()
26968 +--SKIPIF--
26969 +<?php
26970 +include 'skip.inc';
26971 +?>
26972 +--FILE--
26973 +<?php
26974 +echo "-TEST\n";
26975 +echo http_build_url(parse_url("http://example.org/orig?q=1#f"), 
26976 +       parse_url("https://www.example.com:9999/replaced#n")), "\n";
26977 +echo http_build_url(("http://example.org/orig?q=1#f"), 
26978 +       ("https://www.example.com:9999/replaced#n"), 0, $u), "\n";
26979 +print_r($u);
26980 +echo "Done\n";
26981 +?>
26982 +--EXPECTF--
26983 +%aTEST
26984 +https://www.example.com:9999/replaced?q=1#n
26985 +https://www.example.com:9999/replaced?q=1#n
26986 +Array
26987 +(
26988 +    [scheme] => https
26989 +    [host] => www.example.com
26990 +    [port] => 9999
26991 +    [path] => /replaced
26992 +    [query] => q=1
26993 +    [fragment] => n
26994 +)
26995 +Done
26996 --- /dev/null
26997 +++ b/ext/http/tests/build_url_003.phpt
26998 @@ -0,0 +1,26 @@
26999 +--TEST--
27000 +http_build_url()
27001 +--SKIPIF--
27002 +<?php
27003 +include 'skip.inc';
27004 +checkmin("5.2.5");
27005 +?>
27006 +--ENV--
27007 +HTTP_HOST=www.example.com
27008 +--FILE--
27009 +<?php
27010 +$url = '/path/?query#anchor';
27011 +echo "-TEST\n";
27012 +printf("-%s-\n", http_build_url($url));
27013 +printf("-%s-\n", http_build_url($url, array('scheme' => 'https')));
27014 +printf("-%s-\n", http_build_url($url, array('scheme' => 'https', 'host' => 'ssl.example.com')));
27015 +printf("-%s-\n", http_build_url($url, array('scheme' => 'ftp', 'host' => 'ftp.example.com', 'port' => 21)));
27016 +echo "Done\n";
27017 +?>
27018 +--EXPECTF--
27019 +%aTEST
27020 +-http://www.example.com/path/?query#anchor-
27021 +-https://www.example.com/path/?query#anchor-
27022 +-https://ssl.example.com/path/?query#anchor-
27023 +-ftp://ftp.example.com/path/?query#anchor-
27024 +Done
27025 --- /dev/null
27026 +++ b/ext/http/tests/build_url_004.phpt
27027 @@ -0,0 +1,22 @@
27028 +--TEST--
27029 +http_build_url flags
27030 +--SKPIF--
27031 +<?php
27032 +include 'skip.inc';
27033 +?>
27034 +--FILE--
27035 +<?php
27036 +echo "-TEST\n";
27037 +echo http_build_url("http://mike@www.example.com/foo/bar", "./baz", HTTP_URL_STRIP_AUTH|HTTP_URL_JOIN_PATH), "\n";
27038 +echo http_build_url("http://mike@www.example.com/foo/bar/", "../baz", HTTP_URL_STRIP_USER|HTTP_URL_JOIN_PATH), "\n";
27039 +echo http_build_url("http://mike:1234@www.example.com/foo/bar/", "./../baz", HTTP_URL_STRIP_PASS|HTTP_URL_JOIN_PATH), "\n";
27040 +echo http_build_url("http://www.example.com:8080/foo?a[0]=b#frag", "?a[0]=1&b=c&a[1]=b", HTTP_URL_JOIN_QUERY|HTTP_URL_STRIP_PORT|HTTP_URL_STRIP_FRAGMENT|HTTP_URL_STRIP_PATH), "\n";
27041 +echo "Done\n";
27042 +?>
27043 +--EXPECTF--
27044 +%aTEST
27045 +http://www.example.com/foo/baz
27046 +http://www.example.com/foo/baz
27047 +http://mike@www.example.com/foo/baz
27048 +http://www.example.com/?a%5B0%5D=1&a%5B1%5D=b&b=c
27049 +Done
27050 --- /dev/null
27051 +++ b/ext/http/tests/chunked_decode_001.phpt
27052 @@ -0,0 +1,25 @@
27053 +--TEST--
27054 +http_chunked_decode() "\r\n"
27055 +--SKIPIF--
27056 +<?php
27057 +include 'skip.inc';
27058 +?>
27059 +--FILE--
27060 +<?php
27061 +echo "-TEST\n";
27062 +$data =
27063 +"02\r\n".
27064 +"ab\r\n".
27065 +"04\r\n".
27066 +"ra\nc\r\n".
27067 +"06\r\n".
27068 +"adabra\r\n".
27069 +"0\r\n".
27070 +"nothing\n";
27071 +var_dump(http_chunked_decode($data));
27072 +?>
27073 +--EXPECTF--
27074 +%aTEST
27075 +string(12) "abra
27076 +cadabra"
27077 +
27078 --- /dev/null
27079 +++ b/ext/http/tests/chunked_decode_002.phpt
27080 @@ -0,0 +1,25 @@
27081 +--TEST--
27082 +http_chunked_decode() "\n"
27083 +--SKIPIF--
27084 +<?php
27085 +include 'skip.inc';
27086 +?>
27087 +--FILE--
27088 +<?php
27089 +echo "-TEST\n";
27090 +$data =
27091 +"02\n".
27092 +"ab\n".
27093 +"04\n".
27094 +"ra\nc\n".
27095 +"06\n".
27096 +"adabra\n".
27097 +"0\n".
27098 +"hidden\n";
27099 +var_dump(http_chunked_decode($data));
27100 +?>
27101 +--EXPECTF--
27102 +%aTEST
27103 +string(12) "abra
27104 +cadabra"
27105 +
27106 --- /dev/null
27107 +++ b/ext/http/tests/chunked_decode_003.phpt
27108 @@ -0,0 +1,27 @@
27109 +--TEST--
27110 +http_chunked_decode() truncated message
27111 +--SKIPIF--
27112 +<?php
27113 +include 'skip.inc';
27114 +?>
27115 +--FILE--
27116 +<?php
27117 +echo "-TEST\n";
27118 +$data =
27119 +"02\r\n".
27120 +"ab\r\n".
27121 +"04\r\n".
27122 +"ra\nc\r\n".
27123 +"06\r\n".
27124 +"adabra\r\n".
27125 +"ff\r\n".
27126 +"\nall we got\n";
27127 +var_dump(http_chunked_decode($data));
27128 +?>
27129 +--EXPECTF--
27130 +%aTEST
27131 +%aWarning%ahttp_chunked_decode()%aTruncated message: chunk size 255 exceeds remaining data size 12 at pos 34 of 46 in%a
27132 +string(24) "abra
27133 +cadabra
27134 +all we got
27135 +"
27136 --- /dev/null
27137 +++ b/ext/http/tests/chunked_decode_004.phpt
27138 @@ -0,0 +1,26 @@
27139 +--TEST--
27140 +http_chunked_decode() truncated message ending with NUL after a chunk
27141 +--SKIPIF--
27142 +<?php
27143 +include 'skip.inc';
27144 +?>
27145 +--FILE--
27146 +<?php
27147 +echo "-TEST\n";
27148 +$data =
27149 +"02\r\n".
27150 +"ab\r\n".
27151 +"04\r\n".
27152 +"ra\nc\r\n".
27153 +"06\r\n".
27154 +"adabra\r\n".
27155 +"0c\r\n".
27156 +"\nall we got\n";
27157 +var_dump(http_chunked_decode($data));
27158 +?>
27159 +--EXPECTF--
27160 +%aTEST
27161 +string(24) "abra
27162 +cadabra
27163 +all we got
27164 +"
27165 --- /dev/null
27166 +++ b/ext/http/tests/cloning_001.phpt
27167 @@ -0,0 +1,29 @@
27168 +--TEST--
27169 +cloning
27170 +--SKIPIF--
27171 +<?php
27172 +include 'skip.inc';
27173 +checkmin("5.2.5");
27174 +checkcls('HttpRequest');
27175 +?>
27176 +--FILE--
27177 +<?php
27178 +echo "-TEST\n";
27179 +
27180 +$r1 = new HttpRequest;
27181 +$r2 = clone $r1;
27182 +$r1->setOptions(array('redirect' => 3));
27183 +var_dump($r1->getOptions() == $r2->getOptions());
27184 +$r1->setUrl('http://www.google.com/');
27185 +var_dump($r1->getUrl() == $r2->getUrl());
27186 +$r1->send();
27187 +var_dump($r1->getResponseInfo() == $r2->getResponseInfo());
27188 +
27189 +echo "Done\n";
27190 +?>
27191 +--EXPECTF--
27192 +%aTEST
27193 +bool(false)
27194 +bool(false)
27195 +bool(false)
27196 +Done
27197 --- /dev/null
27198 +++ b/ext/http/tests/data.txt
27199 @@ -0,0 +1,10 @@
27200 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27201 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27202 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27203 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27204 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27205 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27206 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27207 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27208 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27209 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
27210 --- /dev/null
27211 +++ b/ext/http/tests/date_001.phpt
27212 @@ -0,0 +1,17 @@
27213 +--TEST--
27214 +http_date() with timestamp
27215 +--SKIPIF--
27216 +<?php
27217 +include 'skip.inc';
27218 +?>
27219 +--FILE--
27220 +<?php
27221 +echo "-TEST\n";
27222 +echo http_date(1), "\n";
27223 +echo http_date(1234567890), "\n";
27224 +?>
27225 +--EXPECTF--
27226 +%aTEST
27227 +Thu, 01 Jan 1970 00:00:01 GMT
27228 +Fri, 13 Feb 2009 23:31:30 GMT
27229 +
27230 --- /dev/null
27231 +++ b/ext/http/tests/date_002.phpt
27232 @@ -0,0 +1,21 @@
27233 +--TEST--
27234 +http_date() without timestamp
27235 +--SKIPIF--
27236 +<?php
27237 +include 'skip.inc';
27238 +?>
27239 +--FILE--
27240 +<?php
27241 +echo "-TEST\n";
27242 +ini_set('date.timezone', 'GMT');
27243 +$d = http_date();
27244 +$t = strtotime($d);
27245 +var_dump($t > 1);
27246 +echo "$t\n$d\nDone\n";
27247 +?>
27248 +--EXPECTF--
27249 +%aTEST
27250 +bool(true)
27251 +%d
27252 +%a, %d %a %d %d:%d:%d GMT
27253 +Done
27254 --- /dev/null
27255 +++ b/ext/http/tests/encoding_objects_001.phpt
27256 @@ -0,0 +1,35 @@
27257 +--TEST--
27258 +encoding stream objects
27259 +--SKIPIF--
27260 +<?php
27261 +include 'skip.inc';
27262 +checkver(5);
27263 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib");
27264 +?>
27265 +--FILE--
27266 +<?php
27267 +echo "-TEST\n";
27268 +$d = new HttpDeflateStream;
27269 +$i = new HttpInflateStream;
27270 +echo $i->flush($d->flush("Hi "));
27271 +echo $i->finish($d->finish("there!\n"));
27272 +echo $i->finish($d->finish("Yo...\n"));
27273 +
27274 +$id = $i->update($d->update($pd = file_get_contents(__FILE__)));
27275 +foreach (glob('*.phpt') as $f) {
27276 +       $id .= $i->update($d->update($tmp = file_get_contents($f)));
27277 +       $pd .= $tmp;
27278 +}
27279 +$id .= $i->finish($d->finish());
27280 +
27281 +var_dump($id == $pd);
27282 +
27283 +echo "Done\n";
27284 +?>
27285 +--EXPECTF--
27286 +%aTEST
27287 +Hi there!
27288 +Yo...
27289 +bool(true)
27290 +Done
27291 +
27292 --- /dev/null
27293 +++ b/ext/http/tests/encodings.phpt
27294 @@ -0,0 +1,44 @@
27295 +--TEST--
27296 +encodings
27297 +--SKIPIF--
27298 +<?php
27299 +include 'skip.inc';
27300 +skipif(!function_exists('http_deflate'), 'need zlib');
27301 +?>
27302 +--FILE--
27303 +<?php
27304 +echo "-TEST\n";
27305 +
27306 +set_time_limit(0);
27307 +error_reporting(E_ALL);
27308 +
27309 +$s = '';
27310 +
27311 +for ($i = 0; $i < 5000; ++$i) {
27312 +       $s .= chr(rand(0,255));
27313 +}
27314 +
27315 +var_dump($s == http_inflate(http_deflate($s, HTTP_DEFLATE_TYPE_ZLIB)));
27316 +var_dump($s == http_inflate(http_deflate($s, HTTP_DEFLATE_TYPE_GZIP)));
27317 +var_dump($s == http_inflate(http_deflate($s, HTTP_DEFLATE_TYPE_RAW)));
27318 +
27319 +if (extension_loaded('zlib')) {
27320 +       
27321 +       $s = "A simple test string, which won't blow up ext/zlib.\n";
27322 +       
27323 +       ($s == http_inflate(gzencode($s))) or print "GZIP Failed\n";
27324 +       ($s == http_inflate(gzdeflate($s))) or print "DEFLATE Failed\n";
27325 +       ($s == http_inflate(gzcompress($s))) or print "COMPRESS Failed\n";
27326 +       
27327 +       ($s == gzinflate(http_deflate($s, HTTP_DEFLATE_TYPE_RAW))) or print "INFLATE Failed\n";
27328 +       ($s == gzuncompress(http_deflate($s, HTTP_DEFLATE_TYPE_ZLIB))) or print "UNCOMPRESS Failed\n";
27329 +}
27330 +
27331 +echo "Done\n";
27332 +?>
27333 +--EXPECTF--
27334 +%aTEST
27335 +bool(true)
27336 +bool(true)
27337 +bool(true)
27338 +Done
27339 --- /dev/null
27340 +++ b/ext/http/tests/etag_mode_031.phpt
27341 @@ -0,0 +1,23 @@
27342 +--TEST--
27343 +crc32 etag (may fail because PHPs crc32 is actually crc32b)
27344 +--SKIPIF--
27345 +<?php
27346 +include 'skip.inc';
27347 +checkcgi();
27348 +checkmin("5.2.5");
27349 +?>
27350 +--FILE--
27351 +<?php
27352 +ini_set('http.etag.mode', extension_loaded('hash')?'crc32b':'crc32');
27353 +http_cache_etag();
27354 +http_send_data("abc\n");
27355 +?>
27356 +--EXPECTF--
27357 +X-Powered-By: PHP/%a
27358 +Cache-Control: private, must-revalidate, max-age=0
27359 +Accept-Ranges: bytes
27360 +ETag: "4e818847"
27361 +Content-Length: 4
27362 +Content-type: %a
27363 +
27364 +abc
27365 --- /dev/null
27366 +++ b/ext/http/tests/etag_mode_032.phpt
27367 @@ -0,0 +1,23 @@
27368 +--TEST--
27369 +sha1 etag
27370 +--SKIPIF--
27371 +<?php
27372 +include 'skip.inc';
27373 +checkcgi();
27374 +checkmin("5.2.5");
27375 +?>
27376 +--FILE--
27377 +<?php
27378 +ini_set('http.etag.mode', 'SHA1');
27379 +http_cache_etag();
27380 +http_send_data("abc\n");
27381 +?>
27382 +--EXPECTF--
27383 +X-Powered-By: PHP/%a
27384 +Cache-Control: private, must-revalidate, max-age=0
27385 +Accept-Ranges: bytes
27386 +ETag: "03cfd743661f07975fa2f1220c5194cbaff48451"
27387 +Content-Length: 4
27388 +Content-type: %a
27389 +
27390 +abc
27391 --- /dev/null
27392 +++ b/ext/http/tests/etag_mode_033.phpt
27393 @@ -0,0 +1,23 @@
27394 +--TEST--
27395 +md5 etag
27396 +--SKIPIF--
27397 +<?php
27398 +include 'skip.inc';
27399 +checkcgi();
27400 +checkmin("5.2.5");
27401 +?>
27402 +--FILE--
27403 +<?php
27404 +ini_set('http.etag.mode', 'MD5');
27405 +http_cache_etag();
27406 +http_send_data("abc\n");
27407 +?>
27408 +--EXPECTF--
27409 +X-Powered-By: PHP/%a
27410 +Cache-Control: private, must-revalidate, max-age=0
27411 +Accept-Ranges: bytes
27412 +ETag: "0bee89b07a248e27c83fc3d5951213c1"
27413 +Content-Length: 4
27414 +Content-type: %a
27415 +
27416 +abc
27417 --- /dev/null
27418 +++ b/ext/http/tests/etag_mode_034.phpt
27419 @@ -0,0 +1,24 @@
27420 +--TEST--
27421 +ext/hash etag
27422 +--SKIPIF--
27423 +<?php
27424 +include 'skip.inc';
27425 +checkcgi();
27426 +checkmin("5.2.5");
27427 +skipif(!extension_loaded('hash'), 'need ext/hash support');
27428 +?>
27429 +--FILE--
27430 +<?php
27431 +ini_set('http.etag.mode', 'sha256');
27432 +http_cache_etag();
27433 +http_send_data("abc\n");
27434 +?>
27435 +--EXPECTF--
27436 +X-Powered-By: PHP/%a
27437 +Cache-Control: private, must-revalidate, max-age=0
27438 +Accept-Ranges: bytes
27439 +ETag: "edeaaff3f1774ad2888673770c6d64097e391bc362d7d6fb34982ddf0efd18cb"
27440 +Content-Length: 4
27441 +Content-type: %a
27442 +
27443 +abc
27444 --- /dev/null
27445 +++ b/ext/http/tests/etag_mode_041.phpt
27446 @@ -0,0 +1,21 @@
27447 +--TEST--
27448 +ob crc32 etag (may fail because PHPs crc32 is actually crc32b)
27449 +--SKIPIF--
27450 +<?php
27451 +include 'skip.inc';
27452 +checkcgi();
27453 +checkmin("5.2.5");
27454 +?>
27455 +--FILE--
27456 +<?php
27457 +ini_set('http.etag.mode', extension_loaded('hash')?'crc32b':'crc32');
27458 +http_cache_etag();
27459 +print("abc\n");
27460 +?>
27461 +--EXPECTF--
27462 +X-Powered-By: PHP/%a
27463 +Cache-Control: private, must-revalidate, max-age=0
27464 +ETag: "4e818847"
27465 +Content-type: %a
27466 +
27467 +abc
27468 --- /dev/null
27469 +++ b/ext/http/tests/etag_mode_042.phpt
27470 @@ -0,0 +1,21 @@
27471 +--TEST--
27472 +ob sha1 etag
27473 +--SKIPIF--
27474 +<?php
27475 +include 'skip.inc';
27476 +checkcgi();
27477 +checkmin("5.2.5");
27478 +?>
27479 +--FILE--
27480 +<?php
27481 +ini_set('http.etag.mode', 'SHA1');
27482 +http_cache_etag();
27483 +print("abc\n");
27484 +?>
27485 +--EXPECTF--
27486 +X-Powered-By: PHP/%a
27487 +Cache-Control: private, must-revalidate, max-age=0
27488 +ETag: "03cfd743661f07975fa2f1220c5194cbaff48451"
27489 +Content-type: %a
27490 +
27491 +abc
27492 --- /dev/null
27493 +++ b/ext/http/tests/etag_mode_043.phpt
27494 @@ -0,0 +1,21 @@
27495 +--TEST--
27496 +ob md5 etag
27497 +--SKIPIF--
27498 +<?php
27499 +include 'skip.inc';
27500 +checkcgi();
27501 +checkmin("5.2.5");
27502 +?>
27503 +--FILE--
27504 +<?php
27505 +ini_set('http.etag.mode', 'bogus');
27506 +http_cache_etag();
27507 +print("abc\n");
27508 +?>
27509 +--EXPECTF--
27510 +X-Powered-By: PHP/%a
27511 +Cache-Control: private, must-revalidate, max-age=0
27512 +ETag: "0bee89b07a248e27c83fc3d5951213c1"
27513 +Content-type: %a
27514 +
27515 +abc
27516 --- /dev/null
27517 +++ b/ext/http/tests/etag_mode_044.phpt
27518 @@ -0,0 +1,22 @@
27519 +--TEST--
27520 +ob ext/hash etag
27521 +--SKIPIF--
27522 +<?php
27523 +include 'skip.inc';
27524 +checkcgi();
27525 +checkmin("5.2.5");
27526 +skipif(!extension_loaded('hash'), 'need ext/hash support');
27527 +?>
27528 +--FILE--
27529 +<?php
27530 +ini_set('http.etag.mode', 'sha256');
27531 +http_cache_etag();
27532 +print("abc\n");
27533 +?>
27534 +--EXPECTF--
27535 +X-Powered-By: PHP/%a
27536 +Cache-Control: private, must-revalidate, max-age=0
27537 +ETag: "edeaaff3f1774ad2888673770c6d64097e391bc362d7d6fb34982ddf0efd18cb"
27538 +Content-type: %a
27539 +
27540 +abc
27541 --- /dev/null
27542 +++ b/ext/http/tests/exceptions.phpt
27543 @@ -0,0 +1,53 @@
27544 +--TEST--
27545 +exceptions
27546 +--SKIPIF--
27547 +<?php
27548 +include 'skip.inc';
27549 +checkmin("5.2.5");
27550 +?>
27551 +--FILE--
27552 +<?php
27553 +echo "-TEST\n";
27554 +
27555 +ini_set('http.only_exceptions', true);
27556 +
27557 +$e = array(
27558 +        HTTP_E_RUNTIME                         => 'Runtime',
27559 +        HTTP_E_INVALID_PARAM           => 'InvalidParam',
27560 +        HTTP_E_HEADER                          => 'Header',
27561 +        HTTP_E_MALFORMED_HEADERS       => 'MalformedHeaders',
27562 +        HTTP_E_REQUEST_METHOD          => 'RequestMethod',
27563 +        HTTP_E_MESSAGE_TYPE            => 'MessageType',
27564 +        HTTP_E_ENCODING                        => 'Encoding',
27565 +        HTTP_E_REQUEST                         => 'Request',
27566 +        HTTP_E_REQUEST_POOL            => 'RequestPool',
27567 +        HTTP_E_SOCKET                          => 'Socket',
27568 +        HTTP_E_RESPONSE                        => 'Response',
27569 +        HTTP_E_URL                                     => 'Url',
27570 +);
27571 +
27572 +foreach ($e as $i => $c) {
27573 +       try {
27574 +               $n = "Http{$c}Exception";
27575 +               throw new $n;
27576 +       } catch (HttpException $x) {
27577 +               printf("%2d: %s\n", $i, get_class($x));
27578 +       }
27579 +}
27580 +echo "Done\n";
27581 +?>
27582 +--EXPECTF--
27583 +%aTEST
27584 + 1: HttpRuntimeException
27585 + 2: HttpInvalidParamException
27586 + 3: HttpHeaderException
27587 + 4: HttpMalformedHeadersException
27588 + 5: HttpRequestMethodException
27589 + 6: HttpMessageTypeException
27590 + 7: HttpEncodingException
27591 + 8: HttpRequestException
27592 + 9: HttpRequestPoolException
27593 +10: HttpSocketException
27594 +11: HttpResponseException
27595 +12: HttpUrlException
27596 +Done
27597 --- /dev/null
27598 +++ b/ext/http/tests/get_request_data_001.phpt
27599 @@ -0,0 +1,40 @@
27600 +--TEST--
27601 +get request data
27602 +--SKIPIF--
27603 +<?php
27604 +include 'skip.inc';
27605 +?>
27606 +--POST--
27607 +a=b&c=d
27608 +--FILE--
27609 +<?php
27610 +echo "-TEST\n";
27611 +
27612 +$_SERVER['HTTP_ACCEPT_CHARSET'] = 'iso-8859-1, *';
27613 +$_SERVER['HTTP_ACCEPT_ENCODING'] = 'none';
27614 +$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0';
27615 +$_SERVER['HTTP_HOST'] = 'localhost';
27616 +
27617 +$h = http_get_request_headers();
27618 +ksort($h);
27619 +print_r($h);
27620 +var_dump(http_get_request_body());
27621 +var_dump(http_get_request_body());
27622 +var_dump(http_get_request_body());
27623 +var_dump(fread(http_get_request_body_stream(), 4096));
27624 +echo "Done\n";
27625 +?>
27626 +--EXPECTF--
27627 +%aTEST
27628 +Array
27629 +(
27630 +    [Accept-Charset] => iso-8859-1, *
27631 +    [Accept-Encoding] => none
27632 +    [Host] => localhost
27633 +    [User-Agent] => Mozilla/5.0
27634 +)
27635 +string(7) "a=b&c=d"
27636 +string(7) "a=b&c=d"
27637 +string(7) "a=b&c=d"
27638 +string(7) "a=b&c=d"
27639 +Done
27640 --- /dev/null
27641 +++ b/ext/http/tests/log.inc
27642 @@ -0,0 +1,23 @@
27643 +<?php
27644 +define('_REDIR_LOG', '__r_log');
27645 +define('_CACHE_LOG', '__c_log');
27646 +define('_AMETH_LOG', '__m_log');
27647 +define('_CMPST_LOG', '__a_log');
27648 +
27649 +function log_prepare($log)
27650 +{
27651 +       is_file($log) and @unlink($log);
27652 +       switch ($log)
27653 +       {
27654 +               case _REDIR_LOG:        ini_set('http.log.redirect', _REDIR_LOG);                       break;
27655 +               case _CACHE_LOG:        ini_set('http.log.cache', _CACHE_LOG);                          break;
27656 +               case _AMETH_LOG:        ini_set('http.log.allowed_methods', _AMETH_LOG);        break;
27657 +               case _CMPTS_LOG:        ini_set('http.log.composite', _CMPST_LOG);                      break;
27658 +       }
27659 +}
27660 +function log_content($log)
27661 +{
27662 +       echo file_get_contents($log);
27663 +       unlink($log);
27664 +}
27665 +?>
27666 --- /dev/null
27667 +++ b/ext/http/tests/match_request_header_001.phpt
27668 @@ -0,0 +1,23 @@
27669 +--TEST--
27670 +http_match_request_header()
27671 +--SKIPIF--
27672 +<?php
27673 +include 'skip.inc';
27674 +checkmin("5.2.5");
27675 +?>
27676 +--ENV--
27677 +HTTP_FOO=bar
27678 +--FILE--
27679 +<?php
27680 +echo "-TEST\n";
27681 +var_dump(http_match_request_header("Foo", "bar", 1));
27682 +var_dump(http_match_request_header("fOO", "BAR", 0));
27683 +var_dump(http_match_request_header("foo", "BAR", 1));
27684 +echo "Done\n";
27685 +?>
27686 +--EXPECTF--
27687 +%aTEST
27688 +bool(true)
27689 +bool(true)
27690 +bool(false)
27691 +Done
27692 --- /dev/null
27693 +++ b/ext/http/tests/negotiation_001.phpt
27694 @@ -0,0 +1,64 @@
27695 +--TEST--
27696 +negotiation
27697 +--SKIPIF--
27698 +<?php
27699 +include 'skip.inc';
27700 +checkmin("5.2.5");
27701 +?>
27702 +--ENV--
27703 +HTTP_ACCEPT=application/xml, application/xhtml+xml, text/html ; q = .8
27704 +HTTP_ACCEPT_LANGUAGE=de-AT,de-DE;q=0.8,en-GB;q=0.3,en-US;q=0.2
27705 +HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7
27706 +--FILE--
27707 +<?php
27708 +echo "-TEST\n";
27709 +$langs = array(
27710 +       array('de', 'en', 'es'),
27711 +);
27712 +$csets = array(
27713 +       array('utf-8', 'iso-8859-1'),
27714 +);
27715 +$ctype = array(
27716 +       array('foo/bar', 'application/xhtml+xml', 'text/html')
27717 +);
27718 +var_dump(http_negotiate_language($langs[0]));
27719 +var_dump(http_negotiate_language($langs[0], $lresult));
27720 +var_dump(http_negotiate_charset($csets[0]));
27721 +var_dump(http_negotiate_charset($csets[0], $cresult));
27722 +var_dump(http_negotiate_content_type($ctype[0]));
27723 +var_dump(http_negotiate_content_type($ctype[0], $tresult));
27724 +var_dump(http_negotiate_language(array("unknown")));
27725 +var_dump(http_negotiate_charset(array("unknown")));
27726 +var_dump(http_negotiate_content_type(array("unknown")));
27727 +print_r($lresult);
27728 +print_r($cresult);
27729 +print_r($tresult);
27730 +echo "Done\n";
27731 +?>
27732 +--EXPECTF--
27733 +%aTEST
27734 +string(2) "de"
27735 +string(2) "de"
27736 +string(10) "iso-8859-1"
27737 +string(10) "iso-8859-1"
27738 +string(21) "application/xhtml+xml"
27739 +string(21) "application/xhtml+xml"
27740 +string(7) "unknown"
27741 +string(7) "unknown"
27742 +string(7) "unknown"
27743 +Array
27744 +(
27745 +    [de] => 900
27746 +    [en] => 0.27
27747 +)
27748 +Array
27749 +(
27750 +    [iso-8859-1] => 1000
27751 +    [utf-8] => 0.7
27752 +)
27753 +Array
27754 +(
27755 +    [application/xhtml+xml] => 999
27756 +    [text/html] => 0.8
27757 +)
27758 +Done
27759 --- /dev/null
27760 +++ b/ext/http/tests/ob_deflatehandler_001.phpt
27761 @@ -0,0 +1,23 @@
27762 +--TEST--
27763 +ob_deflatehandler
27764 +--SKIPIF--
27765 +<?php
27766 +include 'skip.inc';
27767 +checkcgi();
27768 +checkmin("5.2.5");
27769 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib");
27770 +?>
27771 +--ENV--
27772 +HTTP_ACCEPT_ENCODING=gzip
27773 +--FILE--
27774 +<?php
27775 +ob_start('ob_deflatehandler');
27776 +echo "-TEST\n";
27777 +echo "Done\n";
27778 +?>
27779 +--EXPECTF--
27780 +%a
27781 +Content-Encoding: gzip
27782 +Vary: Accept-Encoding
27783 +%a
27784 +
27785 --- /dev/null
27786 +++ b/ext/http/tests/ob_inflatehandler_001.phpt
27787 @@ -0,0 +1,16 @@
27788 +--TEST--
27789 +ob_inflatehandler
27790 +--SKIPIF--
27791 +<?php
27792 +include 'skip.inc';
27793 +checkcgi();
27794 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib");
27795 +?>
27796 +--FILE--
27797 +<?php
27798 +ob_start('ob_inflatehandler');
27799 +echo http_deflate("TEST\n");
27800 +?>
27801 +--EXPECTF--
27802 +%aTEST
27803 +
27804 --- /dev/null
27805 +++ b/ext/http/tests/parse_cookie_001.phpt
27806 @@ -0,0 +1,41 @@
27807 +--TEST--
27808 +parse cookie
27809 +--SKIPIF--
27810 +<?php
27811 +include 'skip.inc';
27812 +?>
27813 +--FILE--
27814 +<?php
27815 +echo "-TEST\n";
27816 +
27817 +var_dump(http_parse_cookie('name="value"; foo="bar\"baz"; hey=got"it ; path=/     ; comment=; expires='.http_date(1).' secure ; httpOnly', 0, array("comment")));
27818 +
27819 +echo "Done\n";
27820 +?>
27821 +--EXPECTF--
27822 +%aTEST
27823 +object(stdClass)%a {
27824 +  ["cookies"]=>
27825 +  array(3) {
27826 +    ["name"]=>
27827 +    string(5) "value"
27828 +    ["foo"]=>
27829 +    string(7) "bar"baz"
27830 +    ["hey"]=>
27831 +    string(6) "got"it"
27832 +  }
27833 +  ["extras"]=>
27834 +  array(1) {
27835 +    ["comment"]=>
27836 +    string(0) ""
27837 +  }
27838 +  ["flags"]=>
27839 +  int(32)
27840 +  ["expires"]=>
27841 +  int(1)
27842 +  ["path"]=>
27843 +  string(1) "/"
27844 +  ["domain"]=>
27845 +  string(0) ""
27846 +}
27847 +Done
27848 --- /dev/null
27849 +++ b/ext/http/tests/parse_cookie_002.phpt
27850 @@ -0,0 +1,80 @@
27851 +--TEST--
27852 +parse cookie
27853 +--SKIPIF--
27854 +<?php
27855 +include 'skip.inc';
27856 +checkmin("5.2.5");
27857 +?>
27858 +--FILE--
27859 +<?php
27860 +echo "-TEST\n";
27861 +
27862 +var_dump(http_parse_cookie('foo')->cookies['foo']);
27863 +var_dump(http_parse_cookie('foo;')->cookies['foo']);
27864 +var_dump(http_parse_cookie('foo ')->cookies['foo']);
27865 +var_dump(http_parse_cookie('foo ;')->cookies['foo']);
27866 +var_dump(http_parse_cookie('foo ; ')->cookies['foo']);
27867 +var_dump(http_parse_cookie('foo=')->cookies['foo']);
27868 +var_dump(http_parse_cookie('foo=;')->cookies['foo']);
27869 +var_dump(http_parse_cookie('foo =')->cookies['foo']);
27870 +var_dump(http_parse_cookie('foo =;')->cookies['foo']);
27871 +var_dump(http_parse_cookie('foo= ')->cookies['foo']);
27872 +var_dump(http_parse_cookie('foo= ;')->cookies['foo']);
27873 +
27874 +var_dump(http_parse_cookie('foo=1')->cookies['foo']);
27875 +var_dump(http_parse_cookie('foo=1;')->cookies['foo']);
27876 +var_dump(http_parse_cookie('foo=1 ;')->cookies['foo']);
27877 +var_dump(http_parse_cookie('foo= 1;')->cookies['foo']);
27878 +var_dump(http_parse_cookie('foo = 1;')->cookies['foo']);
27879 +var_dump(http_parse_cookie('foo = 1 ;')->cookies['foo']);
27880 +var_dump(http_parse_cookie('foo=1')->cookies['foo']);
27881 +var_dump(http_parse_cookie('foo= 1')->cookies['foo']);
27882 +
27883 +var_dump(http_parse_cookie('foo="1"')->cookies['foo']);
27884 +var_dump(http_parse_cookie('foo="1" ')->cookies['foo']);
27885 +var_dump(http_parse_cookie('foo="1";')->cookies['foo']);
27886 +var_dump(http_parse_cookie('foo = "1" ;')->cookies['foo']);
27887 +var_dump(http_parse_cookie('foo= "1" ')->cookies['foo']);
27888 +
27889 +var_dump(http_parse_cookie('foo=""')->cookies['foo']);
27890 +var_dump(http_parse_cookie('foo="\""')->cookies['foo']);
27891 +var_dump(http_parse_cookie('foo=" "')->cookies['foo']);
27892 +var_dump(http_parse_cookie('foo= "')->cookies['foo']);
27893 +var_dump(http_parse_cookie('foo=" ')->cookies['foo']);
27894 +var_dump(http_parse_cookie('foo= " ')->cookies['foo']);
27895 +
27896 +echo "Done\n";
27897 +?>
27898 +--EXPECTF--
27899 +%aTEST
27900 +string(0) ""
27901 +string(0) ""
27902 +string(0) ""
27903 +string(0) ""
27904 +string(0) ""
27905 +string(0) ""
27906 +string(0) ""
27907 +string(0) ""
27908 +string(0) ""
27909 +string(0) ""
27910 +string(0) ""
27911 +string(1) "1"
27912 +string(1) "1"
27913 +string(1) "1"
27914 +string(1) "1"
27915 +string(1) "1"
27916 +string(1) "1"
27917 +string(1) "1"
27918 +string(1) "1"
27919 +string(1) "1"
27920 +string(1) "1"
27921 +string(1) "1"
27922 +string(1) "1"
27923 +string(1) "1"
27924 +string(0) ""
27925 +string(1) """
27926 +string(1) " "
27927 +string(1) """
27928 +string(1) """
27929 +string(1) """
27930 +Done
27931 --- /dev/null
27932 +++ b/ext/http/tests/parse_headers_001.phpt
27933 @@ -0,0 +1,41 @@
27934 +--TEST--
27935 +http_parse_headers()
27936 +--SKIPIF--
27937 +<?php
27938 +include 'skip.inc';
27939 +?>
27940 +--FILE--
27941 +<?php
27942 +echo "-TEST\n";
27943 +print_r(http_parse_headers(
27944 +"Host: localhost\r\n".
27945 +"Host: ambigious\r\n".
27946 +"Nospace:here\r\n".
27947 +"Muchspace:  there   \r\n".
27948 +"Empty:\r\n".
27949 +"Empty2: \r\n".
27950 +"Folded: one\r\n".
27951 +"\ttwo\r\n".
27952 +"  three\r\n\r\n".
27953 +"stop\r\n"
27954 +));
27955 +?>
27956 +--EXPECTF--
27957 +%aTEST
27958 +Array
27959 +(
27960 +    [Host] => Array
27961 +        (
27962 +            [0] => localhost
27963 +            [1] => ambigious
27964 +        )
27965 +
27966 +    [Nospace] => here
27967 +    [Muchspace] => there
27968 +    [Empty] => 
27969 +    [Empty2] => 
27970 +    [Folded] => one
27971 +       two
27972 +  three
27973 +)
27974 +
27975 --- /dev/null
27976 +++ b/ext/http/tests/parse_message_001.phpt
27977 @@ -0,0 +1,18 @@
27978 +--TEST--
27979 +http_parse_message()
27980 +--SKIPIF--
27981 +<?php
27982 +include 'skip.inc';
27983 +checkurl('www.google.com');
27984 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), 'need curl support');
27985 +?>
27986 +--FILE--
27987 +<?php
27988 +echo "-TEST\n";
27989 +$m = http_parse_message(http_get('http://www.google.com'));
27990 +echo $m->body;
27991 +echo "Done\n";
27992 +--EXPECTF--
27993 +%aTEST
27994 +<HTML>%aThe document has moved%a</HTML>
27995 +Done
27996 --- /dev/null
27997 +++ b/ext/http/tests/parse_message_002.phpt
27998 @@ -0,0 +1,39 @@
27999 +--TEST--
28000 +identity encoding trap
28001 +--SKIPIF--
28002 +<?php
28003 +include 'skip.inc';
28004 +?>
28005 +--FILE--
28006 +<?php
28007 +echo "-TEST\n";
28008 +
28009 +$message =
28010 +"HTTP/1.1 200 Ok\n".
28011 +"Transfer-Encoding: identity\n".
28012 +"Content-Length: 3\n".
28013 +"Content-Type: text/plain\n\n".
28014 +"Hi!\n\n\n\n";
28015 +
28016 +print_r(http_parse_message($message));
28017 +
28018 +echo "Done\n";
28019 +--EXPECTF--
28020 +%aTEST
28021 +stdClass Object
28022 +(
28023 +    [type] => 2
28024 +    [httpVersion] => 1.1
28025 +    [responseCode] => 200
28026 +    [responseStatus] => Ok
28027 +    [headers] => Array
28028 +        (
28029 +            [Transfer-Encoding] => identity
28030 +            [Content-Length] => 3
28031 +            [Content-Type] => text/plain
28032 +        )
28033 +
28034 +    [body] => Hi!
28035 +    [parentMessage] => 
28036 +)
28037 +Done
28038 --- /dev/null
28039 +++ b/ext/http/tests/parse_message_003.phpt
28040 @@ -0,0 +1,31 @@
28041 +--TEST--
28042 +content range message
28043 +--SKIPIF--
28044 +<?php
28045 +include 'skip.inc';
28046 +?>
28047 +--FILE--
28048 +<?php
28049 +echo "-TEST\n";
28050 +
28051 +$message = 
28052 +"HTTP/1.1 200 Ok\n".
28053 +"Content-Range: bytes: 0-1/5\n\n".
28054 +"OK\n";
28055 +
28056 +$msg = http_parse_message($message);
28057 +var_dump($msg->body);
28058 +
28059 +$message = 
28060 +"HTTP/1.1 200 Ok\n".
28061 +"Content-Range: bytes 0-1/1\n\n".
28062 +"X\n";
28063 +
28064 +$msg = http_parse_message($message);
28065 +
28066 +echo "Done\n";
28067 +--EXPECTF--
28068 +%aTEST
28069 +string(2) "OK"
28070 +%a Invalid Content-Range header: bytes 0-1/1 in%a
28071 +Done
28072 --- /dev/null
28073 +++ b/ext/http/tests/parse_message_004.phpt
28074 @@ -0,0 +1,115 @@
28075 +--TEST--
28076 +http_parse_message() recursive
28077 +--SKIPIF--
28078 +<?php
28079 +include 'skip.inc';
28080 +?>
28081 +--FILE--
28082 +<?php
28083 +
28084 +echo "-TEST\n";
28085 +$message =
28086 +"HEAD / HTTP/1.1
28087 +Host: www.example.com
28088 +Accept: */*
28089 +HTTP/1.1 200 Ok
28090 +Server: Funky/1.0
28091 +Content-Length: 10
28092 +GET / HTTP/1.1
28093 +Host: www.example.com
28094 +Accept: */*
28095 +HTTP/1.1 200 Ok
28096 +Server: Funky/1.0
28097 +Content-Length: 10
28098 +
28099 +1234567890
28100 +";
28101 +
28102 +var_dump(http_parse_message($message));
28103 +
28104 +echo "Done\n";
28105 +?>
28106 +--EXPECTF--
28107 +%aTEST
28108 +object(stdClass)%a {
28109 +  ["type"]=>
28110 +  int(2)
28111 +  ["httpVersion"]=>
28112 +  float(1.1)
28113 +  ["responseCode"]=>
28114 +  int(200)
28115 +  ["responseStatus"]=>
28116 +  string(2) "Ok"
28117 +  ["headers"]=>
28118 +  array(2) {
28119 +    ["Server"]=>
28120 +    string(9) "Funky/1.0"
28121 +    ["Content-Length"]=>
28122 +    string(2) "10"
28123 +  }
28124 +  ["body"]=>
28125 +  string(10) "1234567890"
28126 +  ["parentMessage"]=>
28127 +  object(stdClass)%a {
28128 +    ["type"]=>
28129 +    int(1)
28130 +    ["httpVersion"]=>
28131 +    float(1.1)
28132 +    ["requestMethod"]=>
28133 +    string(3) "GET"
28134 +    ["requestUrl"]=>
28135 +    string(1) "/"
28136 +    ["headers"]=>
28137 +    array(2) {
28138 +      ["Host"]=>
28139 +      string(15) "www.example.com"
28140 +      ["Accept"]=>
28141 +      string(3) "*/*"
28142 +    }
28143 +    ["body"]=>
28144 +    string(0) ""
28145 +    ["parentMessage"]=>
28146 +    object(stdClass)%a {
28147 +      ["type"]=>
28148 +      int(2)
28149 +      ["httpVersion"]=>
28150 +      float(1.1)
28151 +      ["responseCode"]=>
28152 +      int(200)
28153 +      ["responseStatus"]=>
28154 +      string(2) "Ok"
28155 +      ["headers"]=>
28156 +      array(2) {
28157 +        ["Server"]=>
28158 +        string(9) "Funky/1.0"
28159 +        ["Content-Length"]=>
28160 +        string(2) "10"
28161 +      }
28162 +      ["body"]=>
28163 +      string(0) ""
28164 +      ["parentMessage"]=>
28165 +      object(stdClass)%a {
28166 +        ["type"]=>
28167 +        int(1)
28168 +        ["httpVersion"]=>
28169 +        float(1.1)
28170 +        ["requestMethod"]=>
28171 +        string(4) "HEAD"
28172 +        ["requestUrl"]=>
28173 +        string(1) "/"
28174 +        ["headers"]=>
28175 +        array(2) {
28176 +          ["Host"]=>
28177 +          string(15) "www.example.com"
28178 +          ["Accept"]=>
28179 +          string(3) "*/*"
28180 +        }
28181 +        ["body"]=>
28182 +        string(0) ""
28183 +        ["parentMessage"]=>
28184 +        NULL
28185 +      }
28186 +    }
28187 +  }
28188 +}
28189 +Done
28190 --- /dev/null
28191 +++ b/ext/http/tests/parse_message_005.phpt
28192 @@ -0,0 +1,60 @@
28193 +--TEST--
28194 +http_parse_message() content range header w/(o) =
28195 +--SKIPIF--
28196 +<?php
28197 +include 'skip.inc';
28198 +?>
28199 +--FILE--
28200 +<?php
28201 +echo "-TEST\n";
28202 +print_r(http_parse_message(
28203 +"
28204 +HTTP/1.1 206
28205 +Server: Funky/1.0
28206 +Content-Range: bytes: 0-0/100
28207 +
28208 +1
28209 +
28210 +HTTP/1.1 206
28211 +Server: Funky/1.0
28212 +Content-Range: bytes 0-0/100
28213 +
28214 +1
28215 +
28216 +"
28217 +));
28218 +echo "Done\n";
28219 +?>
28220 +--EXPECTF--
28221 +%aTEST
28222 +stdClass Object
28223 +(
28224 +    [type] => 2
28225 +    [httpVersion] => 1.1
28226 +    [responseCode] => 206
28227 +    [responseStatus] => 
28228 +    [headers] => Array
28229 +        (
28230 +            [Server] => Funky/1.0
28231 +            [Content-Range] => bytes 0-0/100
28232 +        )
28233 +
28234 +    [body] => 1
28235 +    [parentMessage] => stdClass Object
28236 +        (
28237 +            [type] => 2
28238 +            [httpVersion] => 1.1
28239 +            [responseCode] => 206
28240 +            [responseStatus] => 
28241 +            [headers] => Array
28242 +                (
28243 +                    [Server] => Funky/1.0
28244 +                    [Content-Range] => bytes: 0-0/100
28245 +                )
28246 +
28247 +            [body] => 1
28248 +            [parentMessage] => 
28249 +        )
28250 +
28251 +)
28252 +Done
28253 --- /dev/null
28254 +++ b/ext/http/tests/parse_message_006.phpt
28255 @@ -0,0 +1,38 @@
28256 +--TEST--
28257 +mixed EOL trap
28258 +--SKIPIF--
28259 +<?php
28260 +include 'skip.inc';
28261 +?>
28262 +--FILE--
28263 +<?php
28264 +echo "-TEST\n";
28265 +
28266 +$message =
28267 +"HTTP/1.1 200 Ok\n".
28268 +"Header: Value\r\n".
28269 +"Connection: close\r\n".
28270 +"\n".
28271 +"Bug!";
28272 +
28273 +print_r(http_parse_message($message));
28274 +
28275 +echo "Done\n";
28276 +--EXPECTF--
28277 +%aTEST
28278 +stdClass Object
28279 +(
28280 +    [type] => 2
28281 +    [httpVersion] => 1.1
28282 +    [responseCode] => 200
28283 +    [responseStatus] => Ok
28284 +    [headers] => Array
28285 +        (
28286 +            [Header] => Value
28287 +            [Connection] => close
28288 +        )
28289 +
28290 +    [body] => Bug!
28291 +    [parentMessage] => 
28292 +)
28293 +Done
28294 --- /dev/null
28295 +++ b/ext/http/tests/parse_params_001.phpt
28296 @@ -0,0 +1,75 @@
28297 +--TEST--
28298 +http_parse_params
28299 +--SKIPIF--
28300 +<?php
28301 +include 'skip.inc';
28302 +?>
28303 +--FILE--
28304 +<?php
28305 +echo "-TEST\n";
28306 +var_dump(http_parse_params('text/html; charset=iso-8859-1'));
28307 +var_dump(http_parse_params('text/html; charset="iso-8859-1"'));
28308 +var_dump(http_parse_params('attachment; filename="gol;got,a.ext"'));
28309 +var_dump(http_parse_params('public, must-revalidate, max-age=0'));
28310 +$p = http_parse_params('a'); var_dump($p->params[0]);
28311 +$p = http_parse_params('a=b'); var_dump($p->params[0]);
28312 +echo "Done\n";
28313 +?>
28314 +--EXPECTF--
28315 +%aTEST
28316 +object(stdClass)%a {
28317 +  ["params"]=>
28318 +  array(2) {
28319 +    [0]=>
28320 +    string(9) "text/html"
28321 +    [1]=>
28322 +    array(1) {
28323 +      ["charset"]=>
28324 +      string(10) "iso-8859-1"
28325 +    }
28326 +  }
28327 +}
28328 +object(stdClass)%a {
28329 +  ["params"]=>
28330 +  array(2) {
28331 +    [0]=>
28332 +    string(9) "text/html"
28333 +    [1]=>
28334 +    array(1) {
28335 +      ["charset"]=>
28336 +      string(10) "iso-8859-1"
28337 +    }
28338 +  }
28339 +}
28340 +object(stdClass)%a {
28341 +  ["params"]=>
28342 +  array(2) {
28343 +    [0]=>
28344 +    string(10) "attachment"
28345 +    [1]=>
28346 +    array(1) {
28347 +      ["filename"]=>
28348 +      string(13) "gol;got,a.ext"
28349 +    }
28350 +  }
28351 +}
28352 +object(stdClass)%a {
28353 +  ["params"]=>
28354 +  array(3) {
28355 +    [0]=>
28356 +    string(6) "public"
28357 +    [1]=>
28358 +    string(15) "must-revalidate"
28359 +    [2]=>
28360 +    array(1) {
28361 +      ["max-age"]=>
28362 +      string(1) "0"
28363 +    }
28364 +  }
28365 +}
28366 +string(1) "a"
28367 +array(1) {
28368 +  ["a"]=>
28369 +  string(1) "b"
28370 +}
28371 +Done
28372 --- /dev/null
28373 +++ b/ext/http/tests/persistent_handles_001.phpt
28374 @@ -0,0 +1,91 @@
28375 +--TEST--
28376 +persistent handles
28377 +--SKIPIF--
28378 +<?php
28379 +include 'skip.inc';
28380 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), "need request support");
28381 +skipif(!function_exists('zend_thread_id'), "need ZTS build");
28382 +?>
28383 +--INI--
28384 +http.persistent.handles.limit=-1
28385 +http.persistent.handles.ident=GLOBAL
28386 +--FILE--
28387 +<?php
28388 +echo "-TEST\n";
28389 +
28390 +echo "No free handles!\n";
28391 +foreach (http_persistent_handles_count() as $provider => $idents) {
28392 +       foreach ((array)$idents as $ident => $counts) {
28393 +               if (!empty($counts["free"])) {
28394 +                       printf("%a, %a, %a\n", $provider, $ident, $counts["free"]);
28395 +               }
28396 +       }
28397 +}
28398 +
28399 +http_get("http://www.google.com/", null, $info[]);
28400 +
28401 +echo "One free request handle within GLOBAL: ";
28402 +var_dump(http_persistent_handles_count()->http_request["GLOBAL"]["free"]);
28403 +
28404 +echo "Reusing request handle: ";
28405 +http_get("http://www.google.com/", null, $info[]);
28406 +var_dump($info[0]["pretransfer_time"] > 10 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]);
28407 +
28408 +echo "Handles' been cleaned up:\n";
28409 +http_persistent_handles_clean();
28410 +print_r(http_persistent_handles_count());
28411 +
28412 +echo "Done\n";
28413 +?>
28414 +--EXPECTF--
28415 +%aTEST
28416 +No free handles!
28417 +One free request handle within GLOBAL: int(1)
28418 +Reusing request handle: bool(true)
28419 +float(%f)
28420 +float(%f)
28421 +Handles' been cleaned up:
28422 +stdClass Object
28423 +(
28424 +    [http_request] => Array
28425 +        (
28426 +            [GLOBAL] => Array
28427 +                (
28428 +                    [used] => 0
28429 +                    [free] => 0
28430 +                )
28431 +
28432 +        )
28433 +
28434 +    [http_request_datashare] => Array
28435 +        (
28436 +            [GLOBAL] => Array
28437 +                (
28438 +                    [used] => 0
28439 +                    [free] => 0
28440 +                )
28441 +
28442 +        )
28443 +
28444 +    [http_request_datashare_lock] => Array
28445 +        (
28446 +            [GLOBAL] => Array
28447 +                (
28448 +                    [used] => 0
28449 +                    [free] => 0
28450 +                )
28451 +
28452 +        )
28453 +
28454 +    [http_request_pool] => Array
28455 +        (
28456 +            [GLOBAL] => Array
28457 +                (
28458 +                    [used] => 0
28459 +                    [free] => 0
28460 +                )
28461 +
28462 +        )
28463 +
28464 +)
28465 +Done
28466 --- /dev/null
28467 +++ b/ext/http/tests/persistent_handles_002.phpt
28468 @@ -0,0 +1,83 @@
28469 +--TEST--
28470 +persistent handles
28471 +--SKIPIF--
28472 +<?php
28473 +include 'skip.inc';
28474 +checkmin("5.2.5");
28475 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), "need request support");
28476 +skipif(function_exists('zend_thread_id'), "need non-ZTS build");
28477 +?>
28478 +--INI--
28479 +http.persistent.handles.limit=-1
28480 +http.persistent.handles.ident=GLOBAL
28481 +--FILE--
28482 +<?php
28483 +echo "-TEST\n";
28484 +
28485 +echo "No free handles!\n";
28486 +foreach (http_persistent_handles_count() as $provider => $idents) {
28487 +       foreach ((array)$idents as $ident => $counts) {
28488 +               if (!empty($counts["free"])) {
28489 +                       printf("%a, %a, %a\n", $provider, $ident, $counts["free"]);
28490 +               }
28491 +       }
28492 +}
28493 +
28494 +http_get("http://www.google.com/", null, $info[]);
28495 +
28496 +echo "One free request handle within GLOBAL: ";
28497 +$h = http_persistent_handles_count();
28498 +var_dump($h->http_request["GLOBAL"]["free"]);
28499 +
28500 +echo "Reusing request handle: ";
28501 +http_get("http://www.google.com/", null, $info[]);
28502 +var_dump($info[0]["pretransfer_time"] > 10 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]);
28503 +
28504 +echo "Handles' been cleaned up:\n";
28505 +http_persistent_handles_clean();
28506 +print_r(http_persistent_handles_count());
28507 +
28508 +echo "Done\n";
28509 +?>
28510 +--EXPECTF--
28511 +%aTEST
28512 +No free handles!
28513 +One free request handle within GLOBAL: int(1)
28514 +Reusing request handle: bool(true)
28515 +float(%f)
28516 +float(%f)
28517 +Handles' been cleaned up:
28518 +stdClass Object
28519 +(
28520 +    [http_request] => Array
28521 +        (
28522 +            [GLOBAL] => Array
28523 +                (
28524 +                    [used] => 0
28525 +                    [free] => 0
28526 +                )
28527 +
28528 +        )
28529 +
28530 +    [http_request_datashare] => Array
28531 +        (
28532 +            [GLOBAL] => Array
28533 +                (
28534 +                    [used] => 0
28535 +                    [free] => 0
28536 +                )
28537 +
28538 +        )
28539 +
28540 +    [http_request_pool] => Array
28541 +        (
28542 +            [GLOBAL] => Array
28543 +                (
28544 +                    [used] => 0
28545 +                    [free] => 0
28546 +                )
28547 +
28548 +        )
28549 +
28550 +)
28551 +Done
28552 --- /dev/null
28553 +++ b/ext/http/tests/persistent_handles_003.phpt
28554 @@ -0,0 +1,62 @@
28555 +--TEST--
28556 +persistent handles
28557 +--SKIPIF--
28558 +<?php
28559 +include 'skip.inc';
28560 +checkmax(4.4);
28561 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), "need request support");
28562 +?>
28563 +--INI--
28564 +http.persistent.handles.limit=-1
28565 +http.persistent.handles.ident=GLOBAL
28566 +--FILE--
28567 +<?php
28568 +echo "-TEST\n";
28569 +
28570 +echo "No free handles!\n";
28571 +foreach (http_persistent_handles_count() as $provider => $idents) {
28572 +       foreach ((array)$idents as $ident => $counts) {
28573 +               if (!empty($counts["free"])) {
28574 +                       printf("%a, %a, %a\n", $provider, $ident, $counts["free"]);
28575 +               }
28576 +       }
28577 +}
28578 +
28579 +http_get("http://www.google.com/", null, $info[]);
28580 +
28581 +echo "One free request handle within GLOBAL: ";
28582 +$h = http_persistent_handles_count();
28583 +var_dump($h->http_request["GLOBAL"]["free"]);
28584 +
28585 +echo "Reusing request handle: ";
28586 +http_get("http://www.google.com/", null, $info[]);
28587 +var_dump($info[0]["pretransfer_time"] > 10 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]);
28588 +
28589 +echo "Handles' been cleaned up:\n";
28590 +http_persistent_handles_clean();
28591 +print_r(http_persistent_handles_count());
28592 +
28593 +echo "Done\n";
28594 +?>
28595 +--EXPECTF--
28596 +%aTEST
28597 +No free handles!
28598 +One free request handle within GLOBAL: int(1)
28599 +Reusing request handle: bool(true)
28600 +float(%f)
28601 +float(%f)
28602 +Handles' been cleaned up:
28603 +stdClass Object
28604 +(
28605 +    [http_request] => Array
28606 +        (
28607 +            [GLOBAL] => Array
28608 +                (
28609 +                    [used] => 0
28610 +                    [free] => 0
28611 +                )
28612 +
28613 +        )
28614 +
28615 +)
28616 +Done
28617 --- /dev/null
28618 +++ b/ext/http/tests/redirect_011.phpt
28619 @@ -0,0 +1,24 @@
28620 +--TEST--
28621 +http_redirect() with params
28622 +--SKIPIF--
28623 +<?php 
28624 +include 'skip.inc';
28625 +checkcgi();
28626 +checkmin("5.2.5");
28627 +?>
28628 +--ENV--
28629 +HTTP_HOST=localhost
28630 +--FILE--
28631 +<?php
28632 +include 'log.inc';
28633 +log_prepare(_REDIR_LOG);
28634 +http_redirect('redirect', array('a' => 1, 'b' => 2));
28635 +?>
28636 +--EXPECTF--
28637 +Status: 302%s
28638 +X-Powered-By: PHP/%a
28639 +Location: http://localhost/redirect?a=1&b=2
28640 +Content-type: %a
28641 +
28642 +Redirecting to <a href="http://localhost/redirect?a=1&b=2">http://localhost/redirect?a=1&b=2</a>.
28643 +
28644 --- /dev/null
28645 +++ b/ext/http/tests/redirect_011_logging.phpt
28646 @@ -0,0 +1,21 @@
28647 +--TEST--
28648 +logging redirects
28649 +--SKIPIF--
28650 +<?php
28651 +include 'skip.inc';
28652 +checkcgi();
28653 +checkmin("5.2.5");
28654 +?>
28655 +--ENV--
28656 +HTTP_HOST=example.com
28657 +--FILE--
28658 +<?php
28659 +echo "-TEST\n";
28660 +include 'log.inc';
28661 +log_content(_REDIR_LOG);
28662 +echo "Done";
28663 +?>
28664 +--EXPECTF--
28665 +%aTEST
28666 +%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d      [302-REDIRECT]  Location: http%a        <%a>
28667 +Done
28668 --- /dev/null
28669 +++ b/ext/http/tests/redirect_012.phpt
28670 @@ -0,0 +1,27 @@
28671 +--TEST--
28672 +http_redirect() with session
28673 +--SKIPIF--
28674 +<?php 
28675 +include 'skip.inc';
28676 +checkcgi();
28677 +checkmin("5.2.5");
28678 +checkext('session');
28679 +?>
28680 +--ENV--
28681 +HTTP_HOST=localhost
28682 +--FILE--
28683 +<?php
28684 +include 'log.inc';
28685 +log_prepare(_REDIR_LOG);
28686 +session_start();
28687 +http_redirect('redirect', array('a' => 1), true);
28688 +?>
28689 +--EXPECTF--
28690 +Status: 302%s
28691 +X-Powered-By: PHP/%a
28692 +Set-Cookie: PHPSESSID=%a; path=/
28693 +Expires: %a
28694 +Cache-Control: %a
28695 +Pragma: %a
28696 +Location: http://localhost/redirect?a=1&PHPSESSID=%a
28697 +Content-type: %a
28698 --- /dev/null
28699 +++ b/ext/http/tests/redirect_012_logging.phpt
28700 @@ -0,0 +1,22 @@
28701 +--TEST--
28702 +logging redirects
28703 +--SKIPIF--
28704 +<?php
28705 +include 'skip.inc';
28706 +checkcgi();
28707 +checkmin("5.2.5");
28708 +checkext("session");
28709 +?>
28710 +--ENV--
28711 +HTTP_HOST=example.com
28712 +--FILE--
28713 +<?php
28714 +echo "-TEST\n";
28715 +include 'log.inc';
28716 +log_content(_REDIR_LOG);
28717 +echo "Done";
28718 +?>
28719 +--EXPECTF--
28720 +%aTEST
28721 +%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d      [302-REDIRECT]  Location: http%a        <%a>
28722 +Done
28723 --- /dev/null
28724 +++ b/ext/http/tests/redirect_013.phpt
28725 @@ -0,0 +1,24 @@
28726 +--TEST--
28727 +http_redirect() permanent
28728 +--SKIPIF--
28729 +<?php 
28730 +include 'skip.inc';
28731 +checkcgi();
28732 +checkmin("5.2.5");
28733 +?>
28734 +--ENV--
28735 +HTTP_HOST=localhost
28736 +--FILE--
28737 +<?php
28738 +include 'log.inc';
28739 +log_prepare(_REDIR_LOG);
28740 +http_redirect('redirect', null, false, HTTP_REDIRECT_PERM);
28741 +?>
28742 +--EXPECTF--
28743 +Status: 301%s
28744 +X-Powered-By: PHP/%a
28745 +Location: http://localhost/redirect
28746 +Content-type: %a
28747 +
28748 +Redirecting to <a href="http://localhost/redirect">http://localhost/redirect</a>.
28749 +
28750 --- /dev/null
28751 +++ b/ext/http/tests/redirect_013_logging.phpt
28752 @@ -0,0 +1,21 @@
28753 +--TEST--
28754 +logging redirects
28755 +--SKIPIF--
28756 +<?php
28757 +include 'skip.inc';
28758 +checkcgi();
28759 +checkmin("5.2.5");
28760 +?>
28761 +--ENV--
28762 +HTTP_HOST=example.com
28763 +--FILE--
28764 +<?php
28765 +echo "-TEST\n";
28766 +include 'log.inc';
28767 +log_content(_REDIR_LOG);
28768 +echo "Done";
28769 +?>
28770 +--EXPECTF--
28771 +%aTEST
28772 +%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d      [301-REDIRECT]  Location: http%a        <%a>
28773 +Done
28774 --- /dev/null
28775 +++ b/ext/http/tests/request_cookies.phpt
28776 @@ -0,0 +1,52 @@
28777 +--TEST--
28778 +urlencoded cookies
28779 +--SKIPIF--
28780 +<?php
28781 +include 'skip.inc';
28782 +checkver(5);
28783 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), "need request support");
28784 +?>
28785 +--FILE--
28786 +<?php
28787 +echo "-TEST\n";
28788 +
28789 +$cookies = array("name" => "val=ue");
28790 +
28791 +$r = new HttpRequest("http://dev.iworks.at/ext-http/.print_request.php", HTTP_METH_GET, array("cookies" => $cookies));
28792 +$r->recordHistory = true;
28793 +$r->send();
28794 +$r->setOptions(array('encodecookies' => false));
28795 +$r->send();
28796 +echo $r->getHistory()->toString(true);
28797 +
28798 +echo "Done\n";
28799 +?>
28800 +--EXPECTF--
28801 +%aTEST
28802 +GET /ext-http/.print_request.php HTTP/1.1
28803 +User-Agent: %a
28804 +Host: dev.iworks.at
28805 +Accept: */*
28806 +Cookie: name=val%3Due
28807 +HTTP/1.1 200 OK
28808 +%a
28809 +
28810 +Array
28811 +(
28812 +    [name] => val=ue
28813 +)
28814 +
28815 +GET /ext-http/.print_request.php HTTP/1.1
28816 +User-Agent: %a
28817 +Host: dev.iworks.at
28818 +Accept: */*
28819 +Cookie: name=val=ue;
28820 +HTTP/1.1 200 OK
28821 +%a
28822 +
28823 +Array
28824 +(
28825 +    [name] => val=ue
28826 +)
28827 +
28828 +Done
28829 --- /dev/null
28830 +++ b/ext/http/tests/request_etag.phpt
28831 @@ -0,0 +1,21 @@
28832 +--TEST--
28833 +request etag
28834 +--SKIPIF--
28835 +<?php
28836 +include 'skip.inc';
28837 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), "need request support");
28838 +?>
28839 +--FILE--
28840 +<?php
28841 +echo "-TEST\n";
28842 +var_dump(http_get("http://dev.iworks.at/ext-http/etag", array("etag" => '"26ad3a-5-95eb19c0"')));
28843 +echo "Done\n";
28844 +?>
28845 +--EXPECTF--
28846 +%aTEST
28847 +string(%d) "HTTP/1.1 304 Not Modified
28848 +Date: %a
28849 +Server: %a
28850 +ETag: "26ad3a-5-95eb19c0"
28851 +"
28852 +Done
28853 \ No newline at end of file
28854 --- /dev/null
28855 +++ b/ext/http/tests/request_gzip.phpt
28856 @@ -0,0 +1,51 @@
28857 +--TEST--
28858 +GZIP request
28859 +--SKIPIF--
28860 +<?php
28861 +include 'skip.inc';
28862 +checkurl('dev.iworks.at');
28863 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), 'need curl support');
28864 +?>
28865 +--FILE--
28866 +<?php
28867 +echo "-TEST\n";
28868 +
28869 +var_dump(http_parse_message(http_get('http://dev.iworks.at/ext-http/.print_request.php?gzip=1', array('compress' => true))));
28870 +
28871 +echo "Done\n";
28872 +--EXPECTF--
28873 +%aTEST
28874 +object(stdClass)%a {
28875 +  ["type"]=>
28876 +  int(2)
28877 +  ["httpVersion"]=>
28878 +  float(1.1)
28879 +  ["responseCode"]=>
28880 +  int(200)
28881 +  ["responseStatus"]=>
28882 +  string(2) "OK"
28883 +  ["headers"]=>
28884 +  array(8) {
28885 +    %a
28886 +    ["Vary"]=>
28887 +    string(15) "Accept-Encoding"
28888 +    ["Content-Length"]=>
28889 +    string(2) "26"
28890 +    ["Content-Type"]=>
28891 +    string(9) "text/html"
28892 +    ["X-Original-Content-Encoding"]=>
28893 +    string(4) "gzip"
28894 +    ["X-Original-Content-Length"]=>
28895 +    string(2) "51"
28896 +  }
28897 +  ["body"]=>
28898 +  string(26) "Array
28899 +(
28900 +    [gzip] => 1
28901 +)
28902 +"
28903 +  ["parentMessage"]=>
28904 +  NULL
28905 +}
28906 +Done
28907 +
28908 --- /dev/null
28909 +++ b/ext/http/tests/request_methods.phpt
28910 @@ -0,0 +1,144 @@
28911 +--TEST--
28912 +request methods
28913 +--SKIPIF--
28914 +<?php
28915 +include 'skip.inc';
28916 +?>
28917 +--FILE--
28918 +<?php
28919 +echo "-TEST\n";
28920 +
28921 +for ($i = 0; $i <= HTTP_METH_ACL+1; ++$i) {
28922 +       var_dump(http_request_method_exists($i));
28923 +       echo $name = http_request_method_name($i), "\n";
28924 +       var_dump(http_request_method_exists($name));
28925 +}
28926 +
28927 +for ($i = 0; $i < 5; ++$i) {
28928 +       $n = http_request_method_register("M$i");
28929 +       var_dump(http_request_method_exists($n));
28930 +       var_dump(http_request_method_exists("M$i"));
28931 +}
28932 +for ($i = 0; $i < 5; ++$i) {
28933 +       var_dump(http_request_method_unregister("M$i"));
28934 +       var_dump(http_request_method_exists("M$i"));
28935 +       var_dump(http_request_method_exists($i+HTTP_METH_ACL+1));
28936 +}
28937 +
28938 +echo "Done\n";
28939 +?>
28940 +--EXPECTF--
28941 +%aTEST
28942 +int(0)
28943 +UNKNOWN
28944 +int(0)
28945 +int(1)
28946 +GET
28947 +int(1)
28948 +int(2)
28949 +HEAD
28950 +int(2)
28951 +int(3)
28952 +POST
28953 +int(3)
28954 +int(4)
28955 +PUT
28956 +int(4)
28957 +int(5)
28958 +DELETE
28959 +int(5)
28960 +int(6)
28961 +OPTIONS
28962 +int(6)
28963 +int(7)
28964 +TRACE
28965 +int(7)
28966 +int(8)
28967 +CONNECT
28968 +int(8)
28969 +int(9)
28970 +PROPFIND
28971 +int(9)
28972 +int(10)
28973 +PROPPATCH
28974 +int(10)
28975 +int(11)
28976 +MKCOL
28977 +int(11)
28978 +int(12)
28979 +COPY
28980 +int(12)
28981 +int(13)
28982 +MOVE
28983 +int(13)
28984 +int(14)
28985 +LOCK
28986 +int(14)
28987 +int(15)
28988 +UNLOCK
28989 +int(15)
28990 +int(16)
28991 +VERSION-CONTROL
28992 +int(16)
28993 +int(17)
28994 +REPORT
28995 +int(17)
28996 +int(18)
28997 +CHECKOUT
28998 +int(18)
28999 +int(19)
29000 +CHECKIN
29001 +int(19)
29002 +int(20)
29003 +UNCHECKOUT
29004 +int(20)
29005 +int(21)
29006 +MKWORKSPACE
29007 +int(21)
29008 +int(22)
29009 +UPDATE
29010 +int(22)
29011 +int(23)
29012 +LABEL
29013 +int(23)
29014 +int(24)
29015 +MERGE
29016 +int(24)
29017 +int(25)
29018 +BASELINE-CONTROL
29019 +int(25)
29020 +int(26)
29021 +MKACTIVITY
29022 +int(26)
29023 +int(27)
29024 +ACL
29025 +int(27)
29026 +int(0)
29027 +UNKNOWN
29028 +int(0)
29029 +int(28)
29030 +int(28)
29031 +int(29)
29032 +int(29)
29033 +int(30)
29034 +int(30)
29035 +int(31)
29036 +int(31)
29037 +int(32)
29038 +int(32)
29039 +bool(true)
29040 +int(0)
29041 +int(0)
29042 +bool(true)
29043 +int(0)
29044 +int(0)
29045 +bool(true)
29046 +int(0)
29047 +int(0)
29048 +bool(true)
29049 +int(0)
29050 +int(0)
29051 +bool(true)
29052 +int(0)
29053 +int(0)
29054 +Done
29055 --- /dev/null
29056 +++ b/ext/http/tests/request_put_data.phpt
29057 @@ -0,0 +1,22 @@
29058 +--TEST--
29059 +http_put_data()
29060 +--SKIPIF--
29061 +<?php
29062 +include 'skip.inc';
29063 +skipif(!http_support(HTTP_SUPPORT_REQUESTS), "need request support");
29064 +?>
29065 +--FILE--
29066 +<?php
29067 +echo "-TEST\n";
29068 +
29069 +$data = str_repeat("abc", 6000/* > CURLBUF_SIZE */);
29070 +$resp = http_put_data("http://dev.iworks.at/ext-http/.print_put.php5", $data);
29071 +$mess = http_parse_message($resp);
29072 +var_dump($data === $mess->body);
29073 +
29074 +echo "Done\n";
29075 +?>
29076 +--EXPECTF--
29077 +%aTEST
29078 +bool(true)
29079 +Done
29080 --- /dev/null
29081 +++ b/ext/http/tests/send_data_001.phpt
29082 @@ -0,0 +1,24 @@
29083 +--TEST--
29084 +http_send_data() NIL-NUM range
29085 +--SKIPIF--
29086 +<?php 
29087 +include 'skip.inc';
29088 +checkcgi();
29089 +checkmin("5.2.5");
29090 +?>
29091 +--ENV--
29092 +HTTP_RANGE=bytes=-5
29093 +--FILE--
29094 +<?php
29095 +http_send_content_type('text/plain');
29096 +http_send_data(str_repeat('123abc', 1000));
29097 +?>
29098 +--EXPECTF--
29099 +Status: 206%s
29100 +X-Powered-By: PHP/%s
29101 +Content-Type: text/plain
29102 +Accept-Ranges: bytes
29103 +Content-Range: bytes 5995-5999/6000
29104 +Content-Length: 5
29105 +
29106 +23abc
29107 --- /dev/null
29108 +++ b/ext/http/tests/send_data_002.phpt
29109 @@ -0,0 +1,24 @@
29110 +--TEST--
29111 +http_send_data() NUM-NUM range
29112 +--SKIPIF--
29113 +<?php 
29114 +include 'skip.inc';
29115 +checkcgi();
29116 +checkmin("5.2.5");
29117 +?>
29118 +--ENV--
29119 +HTTP_RANGE=bytes=5-6
29120 +--FILE--
29121 +<?php
29122 +http_send_content_type('text/plain');
29123 +http_send_data(str_repeat('123abc', 1000));
29124 +?>
29125 +--EXPECTF--
29126 +Status: 206%s
29127 +X-Powered-By: PHP/%s
29128 +Content-Type: text/plain
29129 +Accept-Ranges: bytes
29130 +Content-Range: bytes 5-6/6000
29131 +Content-Length: 2
29132 +
29133 +c1
29134 --- /dev/null
29135 +++ b/ext/http/tests/send_data_003.phpt
29136 @@ -0,0 +1,24 @@
29137 +--TEST--
29138 +http_send_data() NUM-NIL range
29139 +--SKIPIF--
29140 +<?php 
29141 +include 'skip.inc';
29142 +checkcgi();
29143 +checkmin("5.2.5");
29144 +?>
29145 +--ENV--
29146 +HTTP_RANGE=bytes=5981-
29147 +--FILE--
29148 +<?php
29149 +http_send_content_type('text/plain');
29150 +http_send_data(str_repeat('123abc', 1000));
29151 +?>
29152 +--EXPECTF--
29153 +Status: 206%s
29154 +X-Powered-By: PHP/%s
29155 +Content-Type: text/plain
29156 +Accept-Ranges: bytes
29157 +Content-Range: bytes 5981-5999/6000
29158 +Content-Length: 19
29159 +
29160 +c123abc123abc123abc
29161 --- /dev/null
29162 +++ b/ext/http/tests/send_data_004.phpt
29163 @@ -0,0 +1,22 @@
29164 +--TEST--
29165 +http_send_data() syntactically invalid range
29166 +--SKIPIF--
29167 +<?php 
29168 +include 'skip.inc';
29169 +checkcgi();
29170 +checkmin(5);
29171 +?>
29172 +--ENV--
29173 +HTTP_RANGE=bytes=123,-wtf ?
29174 +--FILE--
29175 +<?php
29176 +http_send_content_type('text/plain');
29177 +http_send_data(str_repeat('123abc', 1000));
29178 +?>
29179 +--EXPECTF--
29180 +X-Powered-By: PHP/%s
29181 +Content-Type: text/plain
29182 +Accept-Ranges: bytes
29183 +Content-Length: 6000
29184 +
29185 +123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc
29186 \ No newline at end of file
29187 --- /dev/null
29188 +++ b/ext/http/tests/send_data_005.phpt
29189 @@ -0,0 +1,17 @@
29190 +--TEST--
29191 +http_send_data() oversized range
29192 +--SKIPIF--
29193 +<?php 
29194 +include 'skip.inc';
29195 +checkcgi();
29196 +checkmin("5.2.5");
29197 +?>
29198 +--ENV--
29199 +HTTP_RANGE=bytes=5990-6000
29200 +--FILE--
29201 +<?php
29202 +http_send_content_type('text/plain');
29203 +http_send_data(str_repeat('123abc', 1000));
29204 +?>
29205 +--EXPECTF--
29206 +Status: 416%a
29207 \ No newline at end of file
29208 --- /dev/null
29209 +++ b/ext/http/tests/send_data_006.phpt
29210 @@ -0,0 +1,38 @@
29211 +--TEST--
29212 +http_send_data() multiple ranges
29213 +--SKIPIF--
29214 +<?php 
29215 +include 'skip.inc';
29216 +checkcgi();
29217 +checkmin("5.2.5");
29218 +?>
29219 +--ENV--
29220 +HTTP_RANGE=bytes=0-3, 4-5,9-11
29221 +--FILE--
29222 +<?php
29223 +http_send_content_type('text/plain');
29224 +http_send_data(str_repeat('123abc', 1000));
29225 +?>
29226 +--EXPECTF--
29227 +Status: 206%s
29228 +X-Powered-By: PHP/%s
29229 +Accept-Ranges: bytes
29230 +Content-Type: multipart/byteranges; boundary=%d.%d
29231 +
29232 +
29233 +--%d.%d
29234 +Content-Type: text/plain
29235 +Content-Range: bytes 0-3/6000
29236 +
29237 +123a
29238 +--%d.%d
29239 +Content-Type: text/plain
29240 +Content-Range: bytes 4-5/6000
29241 +
29242 +bc
29243 +--%d.%d
29244 +Content-Type: text/plain
29245 +Content-Range: bytes 9-11/6000
29246 +
29247 +abc
29248 +--%d.%d--
29249 --- /dev/null
29250 +++ b/ext/http/tests/send_data_010.phpt
29251 @@ -0,0 +1,20 @@
29252 +--TEST--
29253 +http_send_data() HTTP_SENDBUF_SIZE long string
29254 +--SKIPIF--
29255 +<?php 
29256 +include 'skip.inc';
29257 +checkcgi();
29258 +checkmin(5.1);
29259 +?>
29260 +--FILE--
29261 +<?php
29262 +http_throttle(0.01, 1);
29263 +http_send_data('00000000000000000000');
29264 +?>
29265 +--EXPECTF--
29266 +X-Powered-By: PHP/%s
29267 +Accept-Ranges: bytes
29268 +Content-Length: 20
29269 +Content-type: %s
29270 +
29271 +00000000000000000000
29272 --- /dev/null
29273 +++ b/ext/http/tests/send_data_011.phpt
29274 @@ -0,0 +1,22 @@
29275 +--TEST--
29276 +http_send_data() last modified caching
29277 +--SKIPIF--
29278 +<?php 
29279 +include 'skip.inc';
29280 +checkcgi();
29281 +checkmin(5.1);
29282 +?>
29283 +--FILE--
29284 +<?php
29285 +http_cache_last_modified(-5);
29286 +http_send_data("abc\n");
29287 +?>
29288 +--EXPECTF--
29289 +X-Powered-By: PHP/%s
29290 +Cache-Control: private, must-revalidate, max-age=0
29291 +Last-Modified: %s, %d %s %d %d:%d:%d GMT
29292 +Accept-Ranges: bytes
29293 +Content-Length: 4
29294 +Content-type: %s
29295 +
29296 +abc
29297 --- /dev/null
29298 +++ b/ext/http/tests/send_failed_precond_001.phpt
29299 @@ -0,0 +1,23 @@
29300 +--TEST--
29301 +http_send() failed precondition
29302 +--SKIPIF--
29303 +<?php
29304 +include 'skip.inc';
29305 +checkcgi();
29306 +checkver(5.1);
29307 +?>
29308 +--ENV--
29309 +HTTP_RANGE=bytes=0-1
29310 +HTTP_IF_UNMODIFIED_SINCE=Thu, 01 Jan 1970 00:16:40 GMT
29311 +--FILE--
29312 +<?php
29313 +http_cache_last_modified();
29314 +http_send_file(__FILE__);
29315 +?>
29316 +--EXPECTF--
29317 +Status: 412%s
29318 +X-Powered-By: %s
29319 +Cache-Control: private, must-revalidate, max-age=0
29320 +Last-Modified: %s
29321 +Accept-Ranges: bytes
29322 +Content-type: text/html
29323 --- /dev/null
29324 +++ b/ext/http/tests/send_file_005.phpt
29325 @@ -0,0 +1,38 @@
29326 +--TEST--
29327 +http_send_file() multiple ranges
29328 +--SKIPIF--
29329 +<?php 
29330 +include 'skip.inc';
29331 +checkcgi();
29332 +checkmin("5.2.5");
29333 +?>
29334 +--ENV--
29335 +HTTP_RANGE=bytes=0-3, 4-5,9-11
29336 +--FILE--
29337 +<?php
29338 +http_send_content_type('text/plain');
29339 +http_send_file('data.txt');
29340 +?>
29341 +--EXPECTF--
29342 +Status: 206%s
29343 +X-Powered-By: PHP/%s
29344 +Accept-Ranges: bytes
29345 +Content-Type: multipart/byteranges; boundary=%d.%d
29346 +
29347 +
29348 +--%d.%d
29349 +Content-Type: text/plain
29350 +Content-Range: bytes 0-3/1010
29351 +
29352 +0123
29353 +--%d.%d
29354 +Content-Type: text/plain
29355 +Content-Range: bytes 4-5/1010
29356 +
29357 +45
29358 +--%d.%d
29359 +Content-Type: text/plain
29360 +Content-Range: bytes 9-11/1010
29361 +
29362 +901
29363 +--%d.%d--
29364 --- /dev/null
29365 +++ b/ext/http/tests/send_file_008.phpt
29366 @@ -0,0 +1,28 @@
29367 +--TEST--
29368 +http_send_file()
29369 +--SKIPIF--
29370 +<?php 
29371 +include 'skip.inc';
29372 +checkcgi();
29373 +checkmin(5.1);
29374 +?>
29375 +--FILE--
29376 +<?php
29377 +http_send_file('data.txt');
29378 +?>
29379 +--EXPECTF--
29380 +X-Powered-By: PHP/%s
29381 +Accept-Ranges: bytes
29382 +Content-Length: 1010
29383 +Content-type: %s
29384 +
29385 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29386 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29387 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29388 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29389 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29390 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29391 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29392 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29393 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29394 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29395 --- /dev/null
29396 +++ b/ext/http/tests/send_file_009.phpt
29397 @@ -0,0 +1,23 @@
29398 +--TEST--
29399 +http_send_file() NUM-NUM range
29400 +--SKIPIF--
29401 +<?php 
29402 +include 'skip.inc';
29403 +checkcgi();
29404 +checkmin("5.2.5");
29405 +?>
29406 +--ENV--
29407 +HTTP_RANGE=bytes=5-9
29408 +--FILE--
29409 +<?php
29410 +http_send_file('data.txt');
29411 +?>
29412 +--EXPECTF--
29413 +Status: 206%s
29414 +X-Powered-By: PHP/%s
29415 +Accept-Ranges: bytes
29416 +Content-Range: bytes 5-9/1010
29417 +Content-Length: 5
29418 +Content-type: %s
29419 +
29420 +56789
29421 --- /dev/null
29422 +++ b/ext/http/tests/send_file_010.phpt
29423 @@ -0,0 +1,23 @@
29424 +--TEST--
29425 +http_send_file() NIL-NUM range
29426 +--SKIPIF--
29427 +<?php 
29428 +include 'skip.inc';
29429 +checkcgi();
29430 +checkmin("5.2.5");
29431 +?>
29432 +--ENV--
29433 +HTTP_RANGE=bytes=-9
29434 +--FILE--
29435 +<?php
29436 +http_send_file('data.txt');
29437 +?>
29438 +--EXPECTF--
29439 +Status: 206%s
29440 +X-Powered-By: PHP/%s
29441 +Accept-Ranges: bytes
29442 +Content-Range: bytes 1001-1009/1010
29443 +Content-Length: 9
29444 +Content-type: %s
29445 +
29446 +23456789
29447 --- /dev/null
29448 +++ b/ext/http/tests/send_file_011.phpt
29449 @@ -0,0 +1,23 @@
29450 +--TEST--
29451 +http_send_file() NUM-NIL range
29452 +--SKIPIF--
29453 +<?php 
29454 +include 'skip.inc';
29455 +checkcgi();
29456 +checkmin("5.2.5");
29457 +?>
29458 +--ENV--
29459 +HTTP_RANGE=bytes=1000- 
29460 +--FILE--
29461 +<?php
29462 +http_send_file('data.txt');
29463 +?>
29464 +--EXPECTF--
29465 +Status: 206%s
29466 +X-Powered-By: PHP/%s
29467 +Accept-Ranges: bytes
29468 +Content-Range: bytes 1000-1009/1010
29469 +Content-Length: 10
29470 +Content-type: %s
29471 +
29472 +123456789
29473 --- /dev/null
29474 +++ b/ext/http/tests/send_file_012.phpt
29475 @@ -0,0 +1,30 @@
29476 +--TEST--
29477 +http_send_file() syntactically invalid range
29478 +--SKIPIF--
29479 +<?php 
29480 +include 'skip.inc';
29481 +checkcgi();
29482 +checkmin(5.1);
29483 +?>
29484 +--ENV--
29485 +HTTP_RANGE=bytes=xxx
29486 +--FILE--
29487 +<?php
29488 +http_send_file('data.txt');
29489 +?>
29490 +--EXPECTF--
29491 +X-Powered-By: PHP/%s
29492 +Accept-Ranges: bytes
29493 +Content-Length: 1010
29494 +Content-type: %s
29495 +
29496 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29497 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29498 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29499 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29500 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29501 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29502 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29503 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29504 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29505 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
29506 --- /dev/null
29507 +++ b/ext/http/tests/send_file_013.phpt
29508 @@ -0,0 +1,19 @@
29509 +--TEST--
29510 +http_send_file() oversized range
29511 +--SKIPIF--
29512 +<?php 
29513 +include 'skip.inc';
29514 +checkcgi();
29515 +checkmin("5.2.5");
29516 +?>
29517 +--ENV--
29518 +HTTP_RANGE=bytes=-1111
29519 +--FILE--
29520 +<?php
29521 +http_send_file('data.txt');
29522 +?>
29523 +--EXPECTF--
29524 +Status: 416
29525 +X-Powered-By: PHP/%s
29526 +Accept-Ranges: bytes
29527 +Content-type: %s
29528 --- /dev/null
29529 +++ b/ext/http/tests/send_ifrange_001.phpt
29530 @@ -0,0 +1,27 @@
29531 +--TEST--
29532 +http_send() If-Range
29533 +--SKIPIF--
29534 +<?php
29535 +include 'skip.inc';
29536 +checkcgi();
29537 +checkmin("5.2.5");
29538 +?>
29539 +--ENV--
29540 +HTTP_RANGE=bytes=0-1
29541 +HTTP_IF_RANGE="abc"
29542 +--FILE--
29543 +<?php
29544 +http_cache_etag('abc');
29545 +http_send_file(__FILE__);
29546 +?>
29547 +--EXPECTF--
29548 +Status: 206%s
29549 +X-Powered-By: %s
29550 +Cache-Control: private, must-revalidate, max-age=0
29551 +ETag: "abc"
29552 +Accept-Ranges: bytes
29553 +Content-Range: bytes 0-1/%d
29554 +Content-Length: 2
29555 +Content-type: text/html
29556 +
29557 +<?
29558 --- /dev/null
29559 +++ b/ext/http/tests/send_ifrange_003.phpt
29560 @@ -0,0 +1,25 @@
29561 +--TEST--
29562 +http_send() If-Range
29563 +--SKIPIF--
29564 +<?php
29565 +include 'skip.inc';
29566 +checkcgi();
29567 +checkmin("5.2.5");
29568 +?>
29569 +--ENV--
29570 +HTTP_RANGE=bytes=0-1
29571 +HTTP_IF_RANGE="abcd"
29572 +--FILE--
29573 +<?php
29574 +http_cache_etag('abc');
29575 +http_send_file(__FILE__);
29576 +?>
29577 +--EXPECTF--
29578 +X-Powered-By: %s
29579 +Cache-Control: private, must-revalidate, max-age=0
29580 +ETag: "abc"
29581 +Accept-Ranges: bytes
29582 +Content-Length: %d
29583 +Content-type: text/html
29584 +
29585 +%a
29586 --- /dev/null
29587 +++ b/ext/http/tests/skip.inc
29588 @@ -0,0 +1,15 @@
29589 +<?php
29590 +defined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));
29591 +if (!function_exists('fprintf')) {
29592 +       function fprintf(){ $a=func_get_args(); $s=array_shift($a); return fwrite($s, call_user_func_array('sprintf',$a)); }
29593 +}
29594 +function skipif($if, $skip) { if ($if) { fprintf(STDOUT, "skip $skip"); exit(); }}
29595 +function checkcgi() { skipif(!strncasecmp('CLI', PHP_SAPI, 3), 'need CGI SAPI'); }
29596 +function checkext($ext) { skipif(!extension_loaded($ext), "need ext/$ext"); }
29597 +function checkmin($ver) { skipif(version_compare(PHP_VERSION, $ver) < 0, sprintf("need PHP >= v%s",$ver)); }
29598 +function checkmax($ver) { skipif(version_compare(PHP_VERSION, $ver) > 0, sprintf("need PHP <= v%s",$ver)); }
29599 +function checkurl($url) { skipif(!@fsockopen($url, 80), "$url not responsive"); }
29600 +function checkcls($cls) { skipif(!class_exists($cls), "need class $cls"); }
29601 +function checkver($ver) { checkmin($ver); }
29602 +checkext('http');
29603 +?>
29604 --- /dev/null
29605 +++ b/ext/http/tests/stream_filters_001.phpt
29606 @@ -0,0 +1,45 @@
29607 +--TEST--
29608 +stream filters
29609 +--SKIPIF--
29610 +<?php
29611 +include 'skip.inc';
29612 +checkmin("5.2.5");
29613 +?>
29614 +--FILE--
29615 +<?php
29616 +echo "-TEST\n";
29617 +
29618 +define('F', 'http.test_stream_filters');
29619 +
29620 +$f = fopen(F, 'w');
29621 +stream_filter_append($f, 'http.chunked_encode');
29622 +
29623 +fwrite($f, "Here ");
29624 +fwrite($f, "we");
29625 +fwrite($f, " go!\n");
29626 +fclose($f);
29627 +
29628 +var_dump(file_get_contents(F));
29629 +
29630 +$f = fopen(F, 'r');
29631 +stream_filter_append($f, 'http.chunked_decode');
29632 +var_dump(fread($f, 256));
29633 +fclose($f);
29634 +
29635 +unlink(F);
29636 +echo "Done\n";
29637 +?>
29638 +--EXPECTF--
29639 +%aTEST
29640 +string(30) "5
29641 +Here 
29642 +2
29643 +we
29644 +5
29645 + go!
29646 +
29647 +0
29648 +"
29649 +string(12) "Here we go!
29650 +"
29651 +Done
29652 --- /dev/null
29653 +++ b/ext/http/tests/stream_filters_002.phpt
29654 @@ -0,0 +1,50 @@
29655 +--TEST--
29656 +gzip stream filters
29657 +--SKIPIF--
29658 +<?php
29659 +include 'skip.inc';
29660 +checkver(5);
29661 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib support");
29662 +?>
29663 +--FILE--
29664 +<?php
29665 +
29666 +echo "-TEST\n";
29667 +
29668 +$d = file_get_contents(__FILE__);
29669 +$n = tempnam(dirname(__FILE__), 'hsf');
29670 +
29671 +$f = fopen($n, 'wb');
29672 +stream_filter_append($f, 'http.deflate', STREAM_FILTER_WRITE, HTTP_DEFLATE_TYPE_GZIP);
29673 +fwrite($f, $d);
29674 +fflush($f);
29675 +fwrite($f, $d);
29676 +fclose($f);
29677 +var_dump($d.$d == http_inflate(file_get_contents($n)));
29678 +
29679 +$f = fopen($n, 'wb');
29680 +stream_filter_append($f, 'http.deflate', STREAM_FILTER_WRITE);
29681 +fwrite($f, $d);
29682 +fflush($f);
29683 +fwrite($f, $d);
29684 +fclose($f);
29685 +var_dump($d.$d == http_inflate(file_get_contents($n)));
29686 +
29687 +$f = fopen($n, 'wb');
29688 +stream_filter_append($f, 'http.deflate', STREAM_FILTER_WRITE, HTTP_DEFLATE_TYPE_RAW);
29689 +fwrite($f, $d);
29690 +fflush($f);
29691 +fwrite($f, $d);
29692 +fclose($f);
29693 +var_dump($d.$d == http_inflate(file_get_contents($n)));
29694 +
29695 +unlink($n);
29696 +
29697 +echo "Done\n";
29698 +?>
29699 +--EXPECTF--
29700 +%aTEST
29701 +bool(true)
29702 +bool(true)
29703 +bool(true)
29704 +Done
29705 --- /dev/null
29706 +++ b/ext/http/tests/stream_filters_003.phpt
29707 @@ -0,0 +1,42 @@
29708 +--TEST--
29709 +stream filter fun
29710 +--SKIPIF--
29711 +<?php
29712 +include 'skip.inc';
29713 +checkmin("5.2.5");
29714 +skipif(!http_support(HTTP_SUPPORT_ENCODINGS), "need zlib");
29715 +?>
29716 +--FILE--
29717 +<?php
29718 +echo "-TEST\n";
29719 +
29720 +define('OUT', fopen('php://output', 'w'));
29721 +
29722 +stream_filter_append(OUT, 'http.chunked_encode');
29723 +stream_filter_append(OUT, 'http.deflate');
29724 +stream_filter_append(OUT, 'http.chunked_encode');
29725 +stream_filter_append(OUT, 'http.deflate');
29726 +stream_filter_append(OUT, 'http.inflate');
29727 +stream_filter_append(OUT, 'http.chunked_decode');
29728 +stream_filter_append(OUT, 'http.inflate');
29729 +stream_filter_append(OUT, 'http.chunked_decode');
29730 +
29731 +$text = <<<SOME_TEXT
29732 +This is some stream filter fun; we'll see if it bails out or not.
29733 +The text should come out at the other end of the stream exactly like written to it.
29734 +Go figure!
29735 +SOME_TEXT;
29736 +
29737 +srand(time());
29738 +foreach (str_split($text, 5) as $part) {
29739 +       fwrite(OUT, $part);
29740 +       if (rand(0, 1)) {
29741 +               fflush(OUT);
29742 +       }
29743 +}
29744 +?>
29745 +--EXPECTF--
29746 +%aTEST
29747 +This is some stream filter fun; we'll see if it bails out or not.
29748 +The text should come out at the other end of the stream exactly like written to it.
29749 +Go figure!
29750 --- /dev/null
29751 +++ b/ext/http/tests/urls.txt
29752 @@ -0,0 +1,49 @@
29753 +http://www.microsoft.com
29754 +http://www.opensource.org
29755 +http://www.google.com
29756 +http://www.yahoo.com
29757 +http://www.ibm.com
29758 +http://www.mysql.com
29759 +http://www.oracle.com
29760 +http://www.ripe.net
29761 +http://www.iana.org
29762 +http://www.amazon.com
29763 +http://www.netcraft.com
29764 +http://www.heise.de
29765 +http://www.chip.de
29766 +http://www.ca.com
29767 +http://www.cnet.com
29768 +http://www.news.com
29769 +http://www.cnn.com
29770 +http://www.wikipedia.org
29771 +http://www.dell.com
29772 +http://www.hp.com
29773 +http://www.cert.org
29774 +http://www.mit.edu
29775 +http://www.nist.gov
29776 +http://www.ebay.com
29777 +http://www.playstation.com
29778 +http://www.uefa.com
29779 +http://www.ieee.org
29780 +http://www.apple.com
29781 +http://www.sony.com
29782 +http://www.symantec.com
29783 +http://www.zdnet.com
29784 +http://www.fujitsu.com
29785 +http://www.supermicro.com
29786 +http://www.hotmail.com
29787 +http://www.ecma.com
29788 +http://www.bbc.co.uk
29789 +http://news.google.com
29790 +http://www.foxnews.com
29791 +http://www.msn.com
29792 +http://www.wired.com
29793 +http://www.sky.com
29794 +http://www.usatoday.com
29795 +http://www.cbs.com
29796 +http://www.nbc.com
29797 +http://slashdot.org
29798 +http://www.bloglines.com
29799 +http://www.techweb.com
29800 +http://www.newslink.org
29801 +http://www.un.org
29802 \ No newline at end of file