Code Monkey home page Code Monkey logo

ext-http's Introduction

ext-http

Build Status Coverity Scan Build Status codecov

Extended HTTP support for PHP.

Branches and Versions:

NOTE:
Use v3.x branch, and resp. v3 releases, for PHP-7. master and v4 releases are only for PHP-8.

Documentation

See the online markdown reference.

Known issues are listed in BUGS and future ideas can be found in TODO.

Install

PECL

pecl install pecl_http

PHARext

Watch out for PECL replicates and pharext packages attached to releases.

Checkout

git clone https://github.com/m6w6/ext-http.git
cd ext-http
/path/to/phpize
./configure --with-php-config=/path/to/php-config
make
sudo make install

ChangeLog

A comprehensive list of changes can be obtained from the ChangeLog and the list of fixed CVEs.

License

ext-http is licensed under the 2-Clause-BSD license, which can be found in the accompanying LICENSE file.

Contributing

All forms of contribution are welcome! Please see the bundled CONTRIBUTING note for the general principles followed.

The list of past and current contributors is maintained in THANKS.

ext-http's People

Contributors

daverandom avatar dsp avatar edinkad avatar felipensp avatar fmk avatar gitter-badger avatar helly25 avatar jan-e avatar m6w6 avatar mhei avatar mixedreturns avatar nunoplopes avatar oerdnj avatar pierrejoye avatar rc0r avatar remicollet avatar rlerdorf avatar sean-der avatar sebastianbergmann avatar tony2001 avatar weltling avatar whissi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ext-http's Issues

Unexpected Cookies sent if persistent_handle_id is used

Given the following trivial test program that always sends a cookie "test" and, if Cookie "test" was received, the additional cookie "test2":

<?php if (!empty($_COOKIE["test"])) setcookie("test2", $_COOKIE["test"]); setcookie("test", "1"); echo "done";

Then ext-httpd 3.0.1 unexpectedly sends the "test" cookie in the second request of the test program below:

<?php                                                                                                                                                            
$url = 'http://192.168.56.1:14080/cookie.php';                                                                                                                   

foreach (array('a', 'B') as $id) {
    $client = new http\Client('curl', $id);
    $req1 = new  http\Client\Request('GET', $url);
    $client->enqueue($req1);
    $client->send();
    $response1 = $client->getResponse($req1);
    fprintf(STDERR, ">%s<\n", print_r($response1->getHeaders(), true));
    printf("curl: %s http: %s\n\n\n", $response1->getTransferInfo('curlcode'), $response1->getTransferInfo('response_code')); 
}

i.e. the output contains test2=1, although the persistent handle was different for each request, and both client and request were new objects:

[Set-Cookie] => Array
    (
        [0] => test2=1
        [1] => test=1
    )

This bahaviour is not present if no persistent handle id is used.

Heap corruption

The following somewhat weird program crashes reproducibly. $url points to a server secured by Basic auth. As I don't provide any credentials the expected response is 401.
I won't publish the URL here but will send it to you via mail if you should need it.

<?php

$url = 'https://...if needed I will provide the URL on request...';

$request = new http\Client\Request('GET', $url);

// If compression is deactivated, it won't crash.
$request->setOptions([ 'compress' => true ]);

// If this function code is inlined it won't crash.
function send(http\Client\Request $request) {
    $client = new http\Client();
    $client->enqueue($request);
    $client->send();

    $x = // If this line is removed it won't crash.
    $client->getResponse($request);
}

send($request);

$client2 = new http\Client();
$request2 = new http\Client\Request('GET', 'http://example.com/');
$client2->enqueue($request2);
$client2->send(); // >>>>>>>> Crash!

print("OK\n");
Program received signal SIGSEGV, Segmentation fault.
zend_mm_alloc_small (bin_num=5, size=<optimized out>, heap=0x7ffff3600040) at /build/php-7.0.7/Zend/zend_alloc.c:1295
1295                    heap->free_slot[bin_num] = p->next_free_slot;
(gdb) bt
#0  zend_mm_alloc_small (bin_num=5, size=<optimized out>, heap=0x7ffff3600040) at /build/php-7.0.7/Zend/zend_alloc.c:1295
#1  zend_mm_alloc_heap (size=<optimized out>, heap=0x7ffff3600040) at /build/php-7.0.7/Zend/zend_alloc.c:1366
#2  _emalloc (size=<optimized out>) at /build/php-7.0.7/Zend/zend_alloc.c:2450
#3  0x00007ffff2d86aa0 in zend_string_alloc (persistent=0, len=19) at /home/joe/FIT/git/dist/include/php/Zend/zend_string.h:121
#4  zend_string_init (persistent=0, len=19, str=0xe64260 "http://example.com/") at /home/joe/FIT/git/dist/include/php/Zend/zend_string.h:157
#5  php_http_curle_get_info (info=0x7ffff3656498, ch=0xe7aab0) at /build/pecl_http-3.1.0-dev/src/php_http_client_curl.c:347
#6  php_http_client_curl_getopt (h=<optimized out>, opt=<optimized out>, arg=<optimized out>, res=0x7fffffffa0d8)
    at /build/pecl_http-3.1.0-dev/src/php_http_client_curl.c:2565
#7  0x00007ffff2d85a77 in php_http_client_getopt (h=h@entry=0x7ffff3677480, opt=opt@entry=PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, arg=<optimized out>,
    res_ptr=res_ptr@entry=0x7fffffffa0d8) at /build/pecl_http-3.1.0-dev/src/php_http_client.c:322
#8  0x00007ffff2d8606d in handle_response (arg=<optimized out>, client=0x7ffff3677480, e=0x7ffff3689048, response=<optimized out>)
    at /build/pecl_http-3.1.0-dev/src/php_http_client.c:410
#9  0x00007ffff2d8bd2d in php_http_curlm_responsehandler (context=0x7ffff3677480)
    at /build/pecl_http-3.1.0-dev/src/php_http_client_curl.c:715
#10 php_http_client_curl_once (h=h@entry=0x7ffff3677480) at /build/pecl_http-3.1.0-dev/src/php_http_client_curl.c:2446
#11 0x00007ffff2d8bf64 in php_http_client_curl_exec (h=0x7ffff3677480) at /build/pecl_http-3.1.0-dev/src/php_http_client_curl.c:2474
#12 0x00007ffff2d8544c in php_http_client_exec (h=<optimized out>) at /build/pecl_http-3.1.0-dev/src/php_http_client.c:294
#13 0x00007ffff2d854ed in zim_HttpClient_send (execute_data=0x7ffff36141b0, return_value=0x7ffff36141a0)
    at /build/pecl_http-3.1.0-dev/src/php_http_client.c:788
#14 0x0000000000760f1a in ZEND_DO_FCALL_SPEC_HANDLER () at /build/php-7.0.7/Zend/zend_vm_execute.h:842
#15 0x000000000072bfb2 in execute_ex (ex=<optimized out>) at /build/php-7.0.7/Zend/zend_vm_execute.h:414
#16 0x000000000077f4dc in zend_execute (op_array=0x7ffff365d780, return_value=0x0) at /build/php-7.0.7/Zend/zend_vm_execute.h:458
#17 0x00000000006db40e in zend_execute_scripts (type=type@entry=8, retval=0x7ffff3614030, retval@entry=0x0, file_count=file_count@entry=3)
    at /build/php-7.0.7/Zend/zend.c:1427
#18 0x000000000066c136 in php_execute_script (primary_file=primary_file@entry=0x7fffffffc790) at /build/php-7.0.7/main/main.c:2494
#19 0x0000000000780c4d in do_cli (argc=argc@entry=2, argv=argv@entry=0xcdbe00) at /build/php-7.0.7/sapi/cli/php_cli.c:974
#20 0x00000000007819aa in main (argc=2, argv=0xcdbe00) at /build/php-7.0.7/sapi/cli/php_cli.c:1344

Besides a couple of memory leaks valgrind complains about Conditional jump or move depends on uninitialised value(s) and Use of uninitialised value of size 8.

I'm using master (74e7358).

Persistent curl handles: error code not properly reset

After a curl error (e.g. timeout, failed SSL handshake), the errorcode is not properly reset. I'm using persistent handles. Resetting the errorcode in php_http_curlm_responsehandler seems to help:

    if (CURLE_OK != msg->data.result) {
        …
    } else {
        st = php_http_curle_get_storage(msg->easy_handle);
        st->errorcode = 0;
        …
    }

Memory constantly growing

I want to send using only 1 client instance lot of requests (100000) using enqueue() + a callback and a send() each 50 requests, but memory keeps constantly growing despite that finished requests are dequeued (count() is never above 50), only a call reset() on client (or destroy then recreate client instance) seems to free memory... it seems to keep references of finished requests is that a normal behaviour? php script is at 128MB around 1500 requests...

Tested on 2.5.5 version with PHP 5.6

php7 ext-http-RELEASE_3_0_0_RC1 sgement fault

Program received signal SIGILL, Illegal instruction.
0x000000302ee14be0 in _dl_x86_64_save_sse () from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0 0x000000302ee14be0 in _dl_x86_64_save_sse () from /lib64/ld-linux-x86-64.so.2
#1 0x000000302ee0aad8 in _dl_lookup_symbol_x () from /lib64/ld-linux-x86-64.so.2
#2 0x000000302ee0df40 in _dl_fixup () from /lib64/ld-linux-x86-64.so.2
#3 0x000000302ee14625 in _dl_runtime_resolve () from /lib64/ld-linux-x86-64.so.2
#4 0x00007fffedf1b1d4 in zm_startup_http_client_curl (type=, module_number=43) at /home/zhaoxu-b/ext-http-RELEASE_3_0_0_RC1/src/php_http_client_curl.c:2510
#5 0x00007fffedf14c17 in zm_startup_http (type=1, module_number=43) at /home/zhaoxu-b/ext-http-RELEASE_3_0_0_RC1/src/php_http.c:147
#6 0x000000000080a563 in zend_startup_module_ex (module=0x11504d0) at /home/zhaoxu-b/php-7.0.0/Zend/zend_API.c:1841
#7 0x0000000000812223 in zend_hash_apply (ht=0x113b280, apply_func=0x80a5f0 <zend_startup_module_zval>) at /home/zhaoxu-b/php-7.0.0/Zend/zend_hash.c:1500
#8 0x000000000080d05a in zend_startup_modules () at /home/zhaoxu-b/php-7.0.0/Zend/zend_API.c:1967
#9 0x00000000007a9c25 in php_module_startup (sf=, additional_modules=, num_additional_modules=) at /home/zhaoxu-b/php-7.0.0/main/main.c:2194
#10 0x0000000000898fcd in php_cli_startup (sapi_module=) at /home/zhaoxu-b/php-7.0.0/sapi/cli/php_cli.c:423
#11 0x000000000089a741 in main (argc=1, argv=0x113ea80) at /home/zhaoxu-b/php-7.0.0/sapi/cli/php_cli.c:1325

[phpng] Runtime dependency on raphf isn't resolved by php

In /etc/php/conf.d I have these configuration files:

  • http.ini:

    extension=http.so
    
  • propro.ini:

    extension=propro.so
    
  • raphf.ini:

    extension=raphf.so
    

When I execute php -m with PHP 7.0.0 Beta 1 from the AUR and the phpng branches of raphf, propro, and this extension, I get:

PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib/php/modules/http.so' - /usr/lib/php/modules/http.so: undefined symbol: php_persistent_handle_abandon in Unknown on line 0

Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php/modules/http.so' - /usr/lib/php/modules/http.so: undefined symbol: php_persistent_handle_abandon in Unknown on line 0
[PHP Modules]
...
raphf
...

which clearly indicates that raphf has for some reason been loaded after http, while http depends on it. Accordingly, http is loaded just fine when I move extension=raphf.so from raphf.ini right before extension=http.so in http.ini
However, when I disable propro, I get:

PHP Warning:  Cannot load module 'http' because required module 'propro' is not loaded in Unknown on line 0

Warning: Cannot load module 'http' because required module 'propro' is not loaded in Unknown on line 0
[PHP Modules]
...

Since this time PHP complains about missing modules instead of missing symbols, I'm pretty sure that the raphf error originates from a bug regarding dependency resolution in http. Any thoughts?

setOptions() with empty string as value

I've stumbled accross a problem related to #32 when attempting to override http_proxy and related environment variables by setting CURLOPT_PROXY to an empty string via 'proxyhost'. ext-http internally substitutes NULL for the empty string, which does not have the desired effect. The enclosed trivial patch retains the empty string as is when calling curl_easy_setopt().

setopt_empty_string.patch.txt

Underscores in host names: libidn Failed to parse IDN; http\Exception\RuntimeException: http\Client::enqueue()

If ext-http is built with libidn, URLs with "_" (undescore) in the hostname cannot be loaded due to a libidn parse failure. The code below logs the error messages given underneath:

$client = new http\Client();
$client->enqueue(new http\Client\Request("GET", "http://local_host:80/"));
$client->send();
Warning: http\Client\Request::__construct(): Failed to parse IDN; Non-digit/letter/hyphen in input in pecl_http-3.1.0beta1/tests/client030.phpt on line 12

Fatal error: Uncaught http\Exception\RuntimeException: http\Client::enqueue(): Cannot request empty URL in pecl_http-3.1.0beta1/tests/client030.phpt:12
Stack trace:
#0 pecl_http-3.1.0beta1/tests/client030.phpt(12): http\Client->enqueue(Object(http\Client\Request))
#1 {main}
  thrown in pecl_http-3.1.0beta1/tests/client030.phpt on line 12

URLs containing _ can be loaded if ext-http is not built with libidn support. The curl command line client or browsers (such as Firefox or Chrome) also handle such URLs.

Release 2.5.0 broken with VC11

Compiling PHP 5.5.27 with VC11:

php_http_env_response.c
ext\http\php_http_env_response.c(232) : error C2143: syntax error : missing ';' before 'type'
ext\http\php_http_env_response.c(234) : error C2065: 'status' : undeclared identifier
ext\http\php_http_env_response.c(249) : error C2061: syntax error : identifier 'output'
ext\http\php_http_env_response.c(249) : error C2059: syntax error : ';'
ext\http\php_http_env_response.c(249) : error C2059: syntax error : 'type'
ext\http\php_http_env_response.c(289) : error C2065: 'output' : undeclared identifier
ext\http\php_http_env_response.c(289) : warning C4047: 'function' : 'php_http_buffer_pass_func_t' differs in levels of indirection from 'int'
ext\http\php_http_env_response.c(289) : warning C4024: 'php_http_buffer_chunked_output' : different types for formal and actual parameter 5
ext\http\php_http_env_response.c(292) : error C2065: 'output' : undeclared identifier
ext\http\php_http_env_response.c(292) : warning C4047: 'function' : 'php_http_buffer_pass_func_t' differs in levels of indirection from 'int'
ext\http\php_http_env_response.c(292) : warning C4024: 'php_http_buffer_chunked_output' : different types for formal and actual parameter 5
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\BIN\cl.
exe"' : return code '0x2'
Stop.

Lines 231 and 232 in php_http_env_responce.c should be switched.

http\Url uses http request path by default

We have found an issue with http\Url class.

Steps to reproduce: If you create apache site with document root pointed to the directory with this file test.php and open an url http://localhost/test.php it behaves incorrectly.

//test.php
use http\Url;

$url2 = new Url('http://foo.bar');
$url2->port = '123';

var_dump("$url2");
string 'http://foo.bar:123/test.php' (length=27)

If you use cli to run php ./test.php it works well returning string(19) "http://foo.bar:123/"

[phpng] Crash when query string has nested array keys

In testing the PHP 7 branch I've run into a strange issue:
When the query string contains nested array keys of the form ?a[0][0]=x&a[1][0]=x (outer key changes), PHP crashes (SIGSEGV).
It only happens with some scripts and not others; where it does happen, it happens reliably. I cannot figure out what the common factor is.

Backtrace:

#0  0x00000000007854b1 in _zend_hash_index_update ()
#1  0x00007f18351877c7 in push_param () from /php7/lib/php/extensions/no-debug-non-zts-20141001/http.so
#2  0x00007f1835186738 in php_http_params_parse () from /php7/lib/php/extensions/no-debug-non-zts-20141001/http.so
#3  0x00007f183518a81e in php_http_querystring_parse () from /php7/lib/php/extensions/no-debug-non-zts-20141001/http.so
#4  0x00007f183518a9ff in php_http_querystring_update () from /php7/lib/php/extensions/no-debug-non-zts-20141001/http.so
#5  0x00007f183518adae in zim_HttpQueryString___construct () from /php7/lib/php/extensions/no-debug-non-zts-20141001/http.so
#6  0x00000000007cc060 in ZEND_DO_FCALL_SPEC_HANDLER ()
#7  0x00000000007b68c8 in execute_ex ()
#8  0x00000000007b6d2e in zend_execute ()
#9  0x00000000007757a6 in zend_execute_scripts ()
#10 0x000000000070d56f in php_execute_script ()
#11 0x0000000000814de2 in main ()

Using latest source (GitHub) version of ext-http and PHP 7. Debian x86_64, clang 3.5.2.

3.0.1 build issue on Windows

Compiling php_http.dll on Windows (x64, PHP7.0.11, nts, VC14) leads to this error with the 3.0.1RC1 release or the sources from git head

c:\php-sdk\php70dev\ext\http\src\php_http_api.h(116): error C2016: C requires that a struct
 or union has at least one member (compiling source file ext\http\src\php_http_options.c)

Null pointer deref in sanitize_value()

I stumbled across another null ptr deref in sanitize_value()/php_url_mod() caused by the following code:

<?php
    /* url_mod.php */
    $urls = [
        "",
        "? = ="
    ];

    $url0=new http\Url($urls[0]);
    $url1=$url0->mod($urls[1]);
?>

Result:

$ sapi/cli/php url_mod.php
[1]    22267 segmentation fault (core dumped)  sapi/cli/php url_mod.php

I came up with a quick fix for this issue in ab5d9e2. However, since I'm not very familiar with the code base I'm not sure if it's the right thing to do. If it is, just ping me and I'll be happy to open a PR. :)

Backtrace and registers:

gdb> r url_mod.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
sanitize_value (flags=<optimized out>, str=0x7ffff167100a " =", len=2, zv=0x0, rfc5987=<optimized out>) at ext/http/src/php_http_params.c:368

0x00000000010eae41 e8 2a 7e 39 ff             sanitize_value+53 callq  0x482c70 <memcpy@plt>
0x00000000010eae46 41 c6 44 1f 18 00          sanitize_value+58 movb   $0x0,0x18(%r15,%rbx,1)
0x00000000010eae4c 41 f6 44 24 09 04          sanitize_value+64 testb  $0x4,0x9(%r12)    <-
0x00000000010eae52 74 60                      sanitize_value+70 je     0x10eaeb4 <push_param+1220>
0x00000000010eae54 64 48 8b 04 25 00 00 00 00 sanitize_value+72 mov    %fs:0x0,%rax

gdb> bt
#0  sanitize_value (flags=<optimized out>, str=0x7ffff167100a " =", len=2, zv=0x0, rfc5987=<optimized out>) at ext/http/src/php_http_params.c:368
#1  push_param (params=<optimized out>, state=<optimized out>, opts=<optimized out>) at ext/http/src/php_http_params.c:558
#2  0x00000000010ea034 in php_http_params_parse (params=<optimized out>, opts=<optimized out>) at ext/http/src/php_http_params.c:753
#3  0x00000000010f6060 in php_http_querystring_parse (ht=<optimized out>, str=<optimized out>, len=<optimized out>) at ext/http/src/php_http_querystring.c:224
#4  0x00000000010f6739 in php_http_querystring_update (qarray=<optimized out>, params=0x7fffffff9f58, outstring=0x0) at ext/http/src/php_http_querystring.c:268
#5  0x00000000010fe4c0 in php_http_url_mod (old_url=<optimized out>, new_url=<optimized out>, flags=<optimized out>) at ext/http/src/php_http_url.c:237
#6  0x000000000110833e in zim_HttpUrl_mod (execute_data=0x7ffff1613130, return_value=<optimized out>) at ext/http/src/php_http_url.c:1670
#7  0x00000000013fedfd in ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (execute_data=0x7ffff1613030) at Zend/zend_vm_execute.h:1103
#8  0x000000000139b6ae in execute_ex (ex=<optimized out>) at Zend/zend_vm_execute.h:432
#9  0x000000000139c144 in zend_execute (op_array=<optimized out>, return_value=<optimized out>) at Zend/zend_vm_execute.h:474
#10 0x00000000012b364b in zend_execute_scripts (type=<optimized out>, retval=<optimized out>, file_count=<optimized out>) at Zend/zend.c:1441
#11 0x000000000116b2b8 in php_execute_script (primary_file=<optimized out>) at main/main.c:2532
#12 0x000000000150cffb in do_cli (argc=<optimized out>, argv=<optimized out>) at sapi/cli/php_cli.c:990
#13 0x000000000150ac11 in main (argc=<optimized out>, argv=<optimized out>) at sapi/cli/php_cli.c:1383
gdb> i r
rax            0x7ffff16556b8   140737243338424
rbx            0x2  2
rcx            0x3d20   15648
rdx            0x2  2
rsi            0x7ffff1673d20   140737243462944
rdi            0x7ffff16556b8   140737243338424
rbp            0x7ffff167100a   0x7ffff167100a
rsp            0x7fffffff9b60   0x7fffffff9b60
r8             0x7fffffff9b8f   140737488329615
r9             0x1  1
r10            0x477    1143
r11            0x7ffff2c54ea0   140737266405024
r12*           0x0  0
r13            0x7fffffff9d00   140737488329984
r14            0x1dad868    31119464
r15            0x7ffff16556a0   140737243338400
rip            0x10eae4c    0x10eae4c <push_param+1116>
eflags         0x10202  [ IF RF ]
[...]

HTTP/2 response message parsing broken with libcurl >= 7.49.1

Adding this here for reference and to possibly gather more feedback, re curl/curl#888

In the past libcurl provided the response line HTTP/2.0 NNN to the header callback, where NNN is the response status code.

In 7.49.1 libcurl changed that string from HTTP/2.0 NNN to just HTTP/2 NNN (note the missing minor version including the separator) in a bug fix/consistency cleanup. The HTTP/2 working group (and the community?) made clear that they do not plan to incrementally produce minor version upgrades (e.g. to HTTP/2.1) of HTTP/2. As such, the protocol's name actually is HTTP/2 and not HTTP/2.0.

While the burden for header parsers is minor, even the HTTP/2 spec uses HTTP/2.0 in the connection preface, apparently for BC's sake.

I think this is a reasonable approach, so we'll wait how the curl project decides to move on with this issue.

determine the SSL backend used by curl at runtime

Since the behaviour of ssl/cainfo and ssl/capath depends on the SSL backend used by curl, it would be useful to be able to retrieve this information at runtime. With ext/curl, curl_version() could be used, I'm not aware of any equivalent function in pecl_http.

Make failed

All the modules compile fine except for this one:

libtool: compile: cc -I. -I/tmp/pear/temp/pecl_http -DPHP_ATOM_INC -I/tmp/pear/temp/pear-build-frd-opsDznPSo/pecl_http-2.5.0/include -I/tmp/pear/temp/pear-build-frd-opsDznPSo/pecl_http-2.5.0/main -I/tmp/pear/temp/pecl_http -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -I/usr/include/php5/ext/raphf -I/usr/include/php5/ext/propro -I/usr/include/php5/ext/hash -DHAVE_CONFIG_H -g -O2 -c /tmp/pear/temp/pecl_http/php_http_querystring.c -fPIC -DPIC -o .libs/php_http_querystring.o
/tmp/pear/temp/pecl_http/php_http_querystring.c: In function 'php_http_querystring_xlate':
/tmp/pear/temp/pecl_http/php_http_querystring.c:89:8: error: 'PHP_ICONV_ERR_SUCCESS' undeclared (first use in this function)
if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.str, key.len-1, &xkey, &xlen, oe, ie)) {
^
/tmp/pear/temp/pecl_http/php_http_querystring.c:89:8: note: each undeclared identifier is reported only once for each function it appears in
make: *** [php_http_querystring.lo] Error 1
ERROR: `make' failed

Any ideas what dependency is missing? Already installed all dependencies listed on the PECL page. This is on OpenSUSE x64 13.1 with PHP 5.6.9 on pecl_http 2.5.0

3.1.0RC1 build issue with old gcc

On RHEL-6, with gcc 4.4.7

/builddir/build/BUILD/php-pecl-http-3.1.0/NTS/src/php_http_url.c: In function 'parse_uidn_2003':
/builddir/build/BUILD/php-pecl-http-3.1.0/NTS/src/php_http_url.c:1007: error: #pragma GCC diagnostic not allowed inside functions
/builddir/build/BUILD/php-pecl-http-3.1.0/NTS/src/php_http_url.c:1011: error: #pragma GCC diagnostic not allowed inside functions

URL's with underscore in the domain name

Trying to set URL like https://foo_bar-bucket.s3.amazonaws.com causes an error: http\Message::setRequestUrl(): Failed to parse IDN; ICU error 66563.

While cURL works correctly with such domain names.

No Content-Length header with empty POST requests

Hi,

Previously (v 1.7.3) there was always Content-Length header with all POST requests, even with empty post body. What rationale was behind the decision to do not include this header with empty POSTs in 2.X version?

Our issue is that couple API clients stop working after migration, because most of the servers require this header even with empty POSTs (For example most of the Microsoft API endpoints).

According to RFC, nothing bad in including "Content-Length: 0" for empty requests.

Regards,
Igor

$http->setSslOptions() notice w/ curl 7.43

Description

When we try to execute this code:

<?php
error_reporting(E_ALL);
ini_set('display_errors', true);

$req = new \http\Client\Request("GET", "http://google.com");

$req->setOptions([
    'redirect'       => 10,
    'timeout'        => 30,
    'connecttimeout' => 30,
    'cookiesession'  => true,
]);

$req->setSslOptions([
    'verifypeer' => false,
    'verifyhost' => false
]);

$response = (new \http\Client())->enqueue($req)->send()->getResponse($req);

var_dump($response->getBody()->toString());

It barks with notices:

Notice: http\Client::enqueue(): Could not set option verifystatus (No error) in /Users/igor/Sites/scalr/test.php on line 20

Notice: http\Client::enqueue(): Could not set option ssl (No error) in /Users/igor/Sites/scalr/test.php on line 20

System info

$ php -i | grep -i -A1 "http support"
HTTP Support => enabled
Extension Version => 2.5.5

$ php -i | grep -i "libcurl"
libcurl => 7.43.0 => 7.43.0

$ curl -V
curl 7.43.0 (x86_64-apple-darwin15.0) libcurl/7.43.0 SecureTransport zlib/1.2.5
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz UnixSockets 

$ php -v
PHP 5.6.16 (cli) (built: Nov 27 2015 10:28:34) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies

http\Env\Request::getForm/getQuery crash

There is a reproducible crash (SIGSEGV) that seems to happen due to incorrect handling of the "Array to string conversion" notice when converted to an Exception by a custom error handler.

If a form or query parameter is an array but is cast to string by passing http\QueryString::TYPE_STRING to getForm/getQuery, PHP raises an E_NOTICE level error for the array-to-string conversion.
If there is a custom error handler defined that throws exceptions, this causes a segmentation fault and the entire worker process crashes.

Reproduction script (Debian x86_64, gcc 4.9.3, http 2.5.0, PHP 5.6.11):

<?php
set_error_handler(function() {
    throw new Exception();
});

$request = new http\Env\Request();
var_dump($request->getForm("test", http\QueryString::TYPE_STRING));
?>
<form method="POST">
    <input type="text" name="test[array]">
    <button type="submit">Submit</button>
</form>

fatal error when using punycode in URLs

Trying to load http://www.köln.de punycode encoded results in warnings and fatal errors.

<?php
$url = 'http://www.xn--kln-sna.de';
$req = new \http\Client\Request('GET', $url);
$client = (new \http\Client())->enqueue($req)->send();
PHP Warning:  http\Client\Request::__construct(): Failed to parse host; unexpected '-' at pos 7 in 'www.xn--kln-sna.de'
PHP Fatal error:  Uncaught http\Exception\RuntimeException: http\Client::enqueue(): Cannot request empty URL
Stack trace:
#0 ...: http\Client->enqueue(Object(http\Client\Request))
#1 {main}

`resolve` option (DNS cache) not honored with persistent handles

A client with persistent handle sends requests to unexpected hosts when using the pre-populated DNS cache via the resolve option:

<?php

$request = new http\Client\Request('GET', 'http://example.com/');

$client = new http\Client('curl', 'persistentID');
$client->enqueue($request);
$client->send(); // opens persistent connection to example.com

$request2 = new http\Client\Request('GET', 'http://example.com/');
$options = [ 'resolve' => ['example.com:80:127.0.0.1'] ];
$request2->setOptions($options); // remap example.com to 127.0.0.1
$client->enqueue($request2);
$client->send(); // Unexpectedly re-uses handle, issues 2nd request to example.com
print(substr($client->getResponse($request2)->getBody(), 0, 150));

I expected it to open a fresh connection when the resolve option is actually effective.

http\Message::getInfo() is misleading

The documentation states that this will "Retrieve the first line of a request", but it is inconsistent with what actually ends up on the wire.

For example, the following:

$req = new http\Client\Request('GET', 'http://www.php.net/');
printf("%s\n", $req->getInfo());

outputs:

$ php getInfo.php
GET http://www.php.net/ HTTP/1.1

However, when running tcpdump -A, i see:

GET / HTTP/1.1

I'm arguing that getInfo() should represent what goes on the wire. It would also be nice if a new http\Client\Request object would have its $headers initialised with what will go on the wire too, specifically the Host header.

Cheers,
dlg

segfault in http\Client->send() with wantProxyNTLMhttp

Sometimes, we're getting segfaults in http\Client->send() in one of our unit tests that makes use of NTLM Proxy authentication if a persistent client that did not previously use Proxy auth is re-used. An xdebug call trace call shows that the attached observer receives a few updates before the segfault occurs, and usually ends on SplObjectStorage->valid(), which is associated with the send() call. The segault is always in __strcasecmp_l_avx() via curl_strequal().

Just the ext-http calls by themselves, such as in ntlm_clean.php appear to be insufficient to cause a segfault, so for the time being, I can't provide a reproducer. The "proxy" used in the tests is just an Apache httpd that responds with 404.

(gdb) zbacktrace
[0x7ffff14179d0] http\Client->send() [internal function]
[0x7ffff14175e0] RequestLoader->send() /lib/php/http/RequestLoader.php:1021 

(gdb) bt
#0  __strcasecmp_l_avx () at ../sysdeps/x86_64/multiarch/strcmp-sse42.S:165
#1  0x00007ffff6dc26e9 in curl_strequal (first=<optimized out>, second=<optimized out>) at strequal.c:37
#2  0x00007ffff6dba7bc in ConnectionExists (waitpipe=<synthetic pointer>, force_reuse=<synthetic pointer>, usethis=<synthetic pointer>, needle=0xf859a0, data=0xf7a6c0) at url.c:3344
#3  create_conn (async=0x7fffffff9e58, in_connect=0xf7a6d0, data=<optimized out>) at url.c:5719
#4  Curl_connect (data=data@entry=0xf7a6c0, in_connect=in_connect@entry=0xf7a6d0, asyncp=asyncp@entry=0x7fffffff9e58, protocol_done=protocol_done@entry=0x7fffffff9e59) at url.c:5979
#5  0x00007ffff6dcb5d3 in multi_runsingle (multi=multi@entry=0xed0b90, now=..., data=data@entry=0xf7a6c0) at multi.c:1089
#6  0x00007ffff6dcc02d in curl_multi_perform (multi_handle=0xed0b90, running_handles=running_handles@entry=0x7fffdd8d2548) at multi.c:1793
#7  0x00007fffee6f9deb in php_http_client_curl_once (h=0x7fffdd410cc0) at /external/pecl_http-3.0.1/src/php_http_client_curl.c:2394
#8  php_http_client_curl_exec (h=0x7fffdd410cc0) at /external/pecl_http-3.0.1/src/php_http_client_curl.c:2424
#9  0x00007fffee6f36f1 in zim_HttpClient_send (execute_data=0x7ffff14179d0, return_value=0x7ffff14178d0) at /external/pecl_http-3.0.1/src/php_http_client.c:788
#10 0x000000000075cec2 in ZEND_DO_FCALL_SPEC_HANDLER () at /external/php-7.0.5/Zend/zend_vm_execute.h:842
#11 0x000000000071ab6b in execute_ex (ex=<optimized out>) at /external/php-7.0.5/Zend/zend_vm_execute.h:414
#12 0x00000000006c5d6d in zend_call_function (fci=fci@entry=0x7fffffffa220, fci_cache=fci_cache@entry=0x7fffffffa1f0) at /external/php-7.0.5/Zend/zend_execute_API.c:863
#13 0x0000000000572e78 in zim_reflection_method_invokeArgs (execute_data=<optimized out>, return_value=0x7ffff1417020) at /external/php-7.0.5/ext/reflection/php_reflection.c:3348
#14 0x000000000075cec2 in ZEND_DO_FCALL_SPEC_HANDLER () at /external/php-7.0.5/Zend/zend_vm_execute.h:842
#15 0x000000000071ab6b in execute_ex (ex=<optimized out>) at /external/php-7.0.5/Zend/zend_vm_execute.h:414
#16 0x000000000077d7fb in zend_execute (op_array=0x7ffff1488000, op_array@entry=0x7ffff1416e20, return_value=return_value@entry=0x0) at /external/php-7.0.5/Zend/zend_vm_execute.h:458
#17 0x00000000006d4a00 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=2) at /external/php-7.0.5/Zend/zend.c:1427
#18 0x000000000066a63a in php_execute_script (primary_file=primary_file@entry=0x7fffffffc900) at /external/php-7.0.5/main/main.c:2503
#19 0x000000000077f786 in do_cli (argc=4, argv=0xd056b0) at /external/php-7.0.5/sapi/cli/php_cli.c:974
#20 0x000000000042d824 in main (argc=4, argv=0xd056b0) at /external/php-7.0.5/sapi/cli/php_cli.c:1344


(gdb) bt full
#0  __strcasecmp_l_avx () at ../sysdeps/x86_64/multiarch/strcmp-sse42.S:165
No locals.
#1  0x00007ffff6dc26e9 in curl_strequal (first=<optimized out>, second=<optimized out>) at strequal.c:37
No locals.
#2  0x00007ffff6dba7bc in ConnectionExists (waitpipe=<synthetic pointer>, force_reuse=<synthetic pointer>, usethis=<synthetic pointer>, needle=0xf859a0, 
    data=0xf7a6c0) at url.c:3344
        match = true
        pipeLen = 0
        max_pipe_len = 5
        best_pipe_len = 5
        curr = 0x0
        chosen = 0x0
        bundle = <optimized out>
        wantProxyNTLMhttp = true
        check = 0xf83710
        canPipeline = false
        wantNTLMhttp = true
#3  create_conn (async=0x7fffffff9e58, in_connect=0xf7a6d0, data=<optimized out>) at url.c:5719
        conn = <optimized out>
        result = <optimized out>
        options = 0x15b00 <error: Cannot access memory at address 0x15b00>
        proxy = 0x0
        max_host_connections = <optimized out>
        conn_temp = 0x0
        urllen = <optimized out>
        passwd = 0xf85860 ""
        prot_missing = <optimized out>
        connections_available = true
        max_total_connections = <optimized out>
        user = 0xf85840 ""
        reuse = <optimized out>
        force_reuse = false
        waitpipe = false
#4  Curl_connect (data=data@entry=0xf7a6c0, in_connect=in_connect@entry=0xf7a6d0, asyncp=asyncp@entry=0x7fffffff9e58, 
    protocol_done=protocol_done@entry=0x7fffffff9e59) at url.c:5979
        result = <optimized out>
#5  0x00007ffff6dcb5d3 in multi_runsingle (multi=multi@entry=0xed0b90, now=..., data=data@entry=0xf7a6c0) at multi.c:1089
        disconnect_conn = false
        msg = <optimized out>
        connected = false
        async = false
        protocol_connect = false
        dophase_done = false
        done = false
        rc = CURLM_OK
        result = CURLE_OK
        k = <optimized out>
        timeout_ms = <optimized out>
        control = 32767
#6  0x00007ffff6dcc02d in curl_multi_perform (multi_handle=0xed0b90, running_handles=running_handles@entry=0x7fffdd8d2548) at multi.c:1793
        result = <optimized out>
        wc = 0xf83258
        pipe_st = {old_pipe_act = {__sigaction_handler = {sa_handler = 0x1, sa_sigaction = 0x1}, sa_mask = {__val = {4096, 140736911328648, 
                6545642012970847240, 140736911609880, 6545642014900255232, 140737488330224, 6545642014900255232, 140737488330224, 140737193644977, 
                140736911328648, 140733193391112, 140737488330296, 140737488330292, 140736905654208, 6545642014900255232, 140736911329576}}, 
            sa_flags = 335544320, sa_restorer = 0x7ffff640e2f0 <__restore_rt>}, no_signal = false}
        multi = 0xed0b90
        data = 0xf7a6c0
        returncode = CURLM_OK
        t = 0x0
#7  0x00007fffee6f9deb in php_http_client_curl_once (h=0x7fffdd410cc0)
    at /external/pecl_http-3.0.1/src/php_http_client_curl.c:2394
        curl = 0x7fffdd8d2540
#8  php_http_client_curl_exec (h=0x7fffdd410cc0) at /external/pecl_http-3.0.1/src/php_http_client_curl.c:2424
No locals.
#9  0x00007fffee6f36f1 in zim_HttpClient_send (execute_data=0x7ffff14179d0, return_value=0x7ffff14178d0)
    at /external/pecl_http-3.0.1/src/php_http_client.c:788
        __zeh = {handling = EH_NORMAL, exception = 0x0, user_handler = {value = {lval = 140736905654208, dval = 6.9533270185744858e-310, 
              counted = 0x7fffdd44afc0, str = 0x7fffdd44afc0, arr = 0x7fffdd44afc0, obj = 0x7fffdd44afc0, res = 0x7fffdd44afc0, ref = 0x7fffdd44afc0, 
              ast = 0x7fffdd44afc0, zv = 0x7fffdd44afc0, ptr = 0x7fffdd44afc0, ce = 0x7fffdd44afc0, func = 0x7fffdd44afc0, ww = {w1 = 3712266176, w2 = 32767}}, 
            u1 = {v = {type = 7 '\a', type_flags = 28 '\034', const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 7175}, u2 = {var_flags = 0, next = 0, 
              cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0}}}
#10 0x000000000075cec2 in ZEND_DO_FCALL_SPEC_HANDLER () at /external/php-7.0.5/Zend/zend_vm_execute.h:842
        should_change_scope = 1
        call = 0x7ffff14179d0
        fbc = 0xeb35d0
        object = <optimized out>
        ret = <optimized out>
#11 0x000000000071ab6b in execute_ex (ex=<optimized out>) at /external/php-7.0.5/Zend/zend_vm_execute.h:414
        orig_opline = 0x0
        orig_execute_data = 0xe46c20
#12 0x00000000006c5d6d in zend_call_function (fci=fci@entry=0x7fffffffa220, fci_cache=fci_cache@entry=0x7fffffffa1f0)
    at /external/php-7.0.5/Zend/zend_execute_API.c:863
        call_via_handler = 1
        i = <optimized out>
        calling_scope = <optimized out>
        call = 0xc3
        dummy_execute_data = {opline = 0x0, call = 0x0, return_value = 0x7fffffffa150, func = 0x80, This = {value = {lval = 0, dval = 0, counted = 0x0, 
              str = 0x0, arr = 0x0, obj = 0x0, res = 0x0, ref = 0x0, ast = 0x0, zv = 0x0, ptr = 0x0, ce = 0x0, func = 0x0, ww = {w1 = 0, w2 = 0}}, u1 = {v = {
                type = 0 '\000', type_flags = 0 '\000', const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 0}, u2 = {var_flags = 32767, next = 32767, 
              cache_slot = 32767, lineno = 32767, num_args = 32767, fe_pos = 32767, fe_iter_idx = 32767}}, called_scope = 0xe46c20, 
          prev_execute_data = 0x710c9a <zend_object_std_init+42>, symbol_table = 0xe46c20, run_time_cache = 0xe46c20, literals = 0x7fffdd9a0238}
        fci_cache_local = {initialized = 64 '@', function_handler = 0x7fffdd44bc5b, calling_scope = 0xe46c20, 
          called_scope = 0x713c07 <zend_std_write_property+439>, object = 0x0}
        func = 0x7fffddb22f68
        orig_scope = 0x7ffff14175e0
#13 0x0000000000572e78 in zim_reflection_method_invokeArgs (execute_data=<optimized out>, return_value=0x7ffff1417020)
    at /external/php-7.0.5/ext/reflection/php_reflection.c:3348
        retval = {value = {lval = 140736912917632, dval = 6.9533273774353128e-310, counted = 0x7fffddb38480, str = 0x7fffddb38480, arr = 0x7fffddb38480, 
            obj = 0x7fffddb38480, res = 0x7fffddb38480, ref = 0x7fffddb38480, ast = 0x7fffddb38480, zv = 0x7fffddb38480, ptr = 0x7fffddb38480, 
            ce = 0x7fffddb38480, func = 0x7fffddb38480, ww = {w1 = 3719529600, w2 = 32767}}, u1 = {v = {type = 0 '\000', type_flags = 0 '\000', 
              const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 0}, u2 = {var_flags = 0, next = 0, cache_slot = 0, lineno = 0, num_args = 0, 
            fe_pos = 0, fe_iter_idx = 0}}
        params = 0x7fffdd831560
        val = <optimized out>
        object = 0x7ffff14173b0
        mptr = <optimized out>
        i = <optimized out>
        argc = <optimized out>
        result = <optimized out>
        fci = {size = 72, function_table = 0x0, function_name = {value = {lval = 140736911386712, dval = 6.9533273017978149e-310, counted = 0x7fffdd9c2858, 
              str = 0x7fffdd9c2858, arr = 0x7fffdd9c2858, obj = 0x7fffdd9c2858, res = 0x7fffdd9c2858, ref = 0x7fffdd9c2858, ast = 0x7fffdd9c2858, 
              zv = 0x7fffdd9c2858, ptr = 0x7fffdd9c2858, ce = 0x7fffdd9c2858, func = 0x7fffdd9c2858, ww = {w1 = 3717998680, w2 = 32767}}, u1 = {v = {
                type = 0 '\000', type_flags = 0 '\000', const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 0}, u2 = {var_flags = 0, next = 0, 
              cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0}}, symbol_table = 0x0, retval = 0x7fffffffa1e0, params = 0x7fffdd831560, 
          object = 0x7fffddb88300, no_separation = 1 '\001', param_count = 0}
        fcc = {initialized = 1 '\001', function_handler = 0x7fffddb22f68, calling_scope = 0x7fffddb20a60, called_scope = 0x7fffddb20a60, 
          object = 0x7fffddb88300}
        obj_ce = 0x7fffddb20a60
        param_array = 0x7ffff14173c0
#14 0x000000000075cec2 in ZEND_DO_FCALL_SPEC_HANDLER () at /external/php-7.0.5/Zend/zend_vm_execute.h:842
        should_change_scope = 1
        call = 0x7ffff1417350
        fbc = 0xd50230
        object = <optimized out>
        ret = <optimized out>
#15 0x000000000071ab6b in execute_ex (ex=<optimized out>) at /external/php-7.0.5/Zend/zend_vm_execute.h:414
        orig_opline = 0x1
        orig_execute_data = 0x7ffff1488000
#16 0x000000000077d7fb in zend_execute (op_array=0x7ffff1488000, op_array@entry=0x7ffff1416e20, return_value=return_value@entry=0x0)
    at /external/php-7.0.5/Zend/zend_vm_execute.h:458
        execute_data = 0x7ffff1414030
#17 0x00000000006d4a00 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=2)
    at /external/php-7.0.5/Zend/zend.c:1427
        files = {{gp_offset = 32, fp_offset = 32767, overflow_arg_area = 0x7fffffffa400, reg_save_area = 0x7fffffffa390}}
        i = 0
        file_handle = 0x7fffffffc900
        op_array = 0x7ffff1416e20
#18 0x000000000066a63a in php_execute_script (primary_file=primary_file@entry=0x7fffffffc900)
    at /external/php-7.0.5/main/main.c:2503
        orig_start_lineno = 2
        realfile = "/scripts/devel/runTest.php\000\000\000\vzN\000\000\000\000\000`\000\000\000\000\000\000\000\022\000\000\000\000\000\000\000\254\272\377\377\377\177\000\000\200\267\377\377\377\177\000\000\020\272\377\377\377\177\000\000\264\267\377\377\377\177\000\000\001\000\000\000\000\000\000\000\a\000\000\000\061", '\000' <repeats 19 times>, "[\000\000\000n", '\000' <repeats 19 times>, "w\000\000\000|\000\000\000\260\070\331\000\000\000\000\000\200\273\325\000\000\000\000\000\001\000\000\000\001", '\000' <repeats 11 times>...
        __orig_bailout = 0x7fffffffc970
        __bailout = {{__jmpbuf = {140737488341360, 3230684716981082733, 13653776, 10123608, 1, 140737488345880, 3230684720271514221, -3230684498283668883}, 
            __mask_was_saved = 0, __saved_mask = {__val = {140737351952052, 130, 140737274569429, 0, 140737351916829, 33780297937977475, 140733344413699, 
                33780297971531907, 33884779560597507, 7228277404077127176, 13109978517422995065, 8651696361302917119, 18446603336858761216, 140737488336367, 
                140737277096190, 0}}}}
        prepend_file_p = 0x7fffffffb430
        append_file_p = 0x0
        prepend_file = {handle = {fd = -246959360, fp = 0x7ffff147b300, stream = {handle = 0x7ffff147b300, isatty = 0, mmap = {len = 4510, pos = 0, map = 0x0, 
                buf = 0x7ffff7ff3000 "", old_handle = 0x0, old_closer = 0x0}, reader = 0x683ef0 <_php_stream_read>, fsizer = 0x668020 <php_zend_stream_fsizer>, 
              closer = 0x668000 <php_zend_stream_mmap_closer>}}, filename = 0xd22a18 "init/bootstrap.php", opened_path = 0x0, type = ZEND_HANDLE_MAPPED, 
          free_filename = 0 '\000'}
        append_file = {handle = {fd = 0, fp = 0x0, stream = {handle = 0x0, isatty = 0, mmap = {len = 0, pos = 0, map = 0x0, buf = 0x0, old_handle = 0x0, 
                old_closer = 0x0}, reader = 0x0, fsizer = 0x0, closer = 0x0}}, filename = 0x0, opened_path = 0x0, type = ZEND_HANDLE_FILENAME, 
          free_filename = 0 '\000'}
        old_cwd = 0x7fffffffa400 ""
        retval = 0
#19 0x000000000077f786 in do_cli (argc=4, argv=0xd056b0) at /external/php-7.0.5/sapi/cli/php_cli.c:974
        __orig_bailout = 0x7fffffffdb20
        __bailout = {{__jmpbuf = {13377760, 3230684717153573485, 0, 0, 0, 140737488345880, 3230684717016734317, -3230684354615518611}, __mask_was_saved = 0, 
            __saved_mask = {__val = {10004352, 10004376, 9893079, 9893100, 10004389, 10004409, 10004426, 10004990, 10004447, 10004461, 10004483, 10004502, 
                10004529, 10004558, 0, 2133424}}}}
        c = <optimized out>
        file_handle = {handle = {fd = -246951760, fp = 0x7ffff147d0b0, stream = {handle = 0x7ffff147d0b0, isatty = 0, mmap = {len = 7396, pos = 0, 
                map = 0x7ffff7fec000, buf = 0x7ffff7fec014 <error: Cannot access memory at address 0x7ffff7fec014>, old_handle = 0xeccef0, 
                old_closer = 0x6f2b50 <zend_stream_stdio_closer>}, reader = 0x6f2b80 <zend_stream_stdio_reader>, fsizer = 0x6f2ad0 <zend_stream_stdio_fsizer>, 
              closer = 0x6f2a50 <zend_stream_mmap_closer>}}, filename = 0xd05710 "/scripts/devel/runTest.php", opened_path = 0x0, 
          type = ZEND_HANDLE_MAPPED, free_filename = 0 '\000'}
        behavior = <optimized out>
        reflection_what = 0x0
        request_started = 1
        exit_status = 0
        php_optarg = 0x0
        php_optind = 2
        exec_direct = <optimized out>
        exec_run = <optimized out>
        exec_begin = <optimized out>
        exec_end = <optimized out>
        arg_free = <optimized out>
        arg_excp = <optimized out>
        script_file = <optimized out>
        translated_path = 0xecce40 "/scripts/devel/runTest.php"
        lineno = 2
        param_error = 0x0
#20 0x000000000042d824 in main (argc=4, argv=0xd056b0) at /external/php-7.0.5/sapi/cli/php_cli.c:1344
        __orig_bailout = 0x0
        __bailout = {{__jmpbuf = {13377760, 3230684717153573485, 0, 0, 0, 140737488345880, 3230684717102717549, -3230684191535080851}, __mask_was_saved = 0, 
            __saved_mask = {__val = {4131212846, 4294967295, 140737351944685, 140737324683768, 140737353954544, 1, 140737324664544, 10, 4, 140737488346376, 
                140737351974768, 140737301641600, 140737351974768, 4294958068, 0, 1}}}}
        c = <optimized out>
        exit_status = 0
        module_started = 1
        sapi_started = 1
        php_optarg = 0x0
        php_optind = 1
        use_extended_info = 0
        ini_path_override = 0x0
        ini_entries = 0xd059b0 "html_errors=0\nregister_argc_argv=1\nimplicit_flush=1\noutput_buffering=0\nmax_execution_time=0\nmax_input_time=-1\n"
        ini_entries_len = 0
        ini_ignore = 0
        sapi_module = <optimized out>

verify certificates against the SSL backend's default 'capath'

By default, ext-http currently does not verify certificates against the 'capath' that is built into the SSL backend used by curl. Therefore, a hashed directory of certificates isn't checked unless the location is explicitly set.

Since the correct value for CURLOPT_CAPATH depends on the type of SSL backend used and its compile-time and run-time configuration, it's difficult to even make a good educated guess which value to set in ['ssl']['capath'].

With the "plain" curl PHP extension, the default CAPATH of the SSL backend is used to verify a peer's SSL certificate, even if CURLOP_CAINFO is set to a non-default file.

Failed test with curl build with --with-libpsl

See https://apps.fedoraproject.org/koschei/package/php-pecl-http

TEST 29/182 [tests/client021.phpt]
========DIFF========
007+ Set-Cookie: counter=1;
007- Set-Cookie: counter=2;
011+ Set-Cookie: counter=1;
011- Set-Cookie: counter=3;
015+ Set-Cookie: counter=1;
015- Set-Cookie: counter=4;
019+ Set-Cookie: counter=1;
019- Set-Cookie: counter=5;
023+ Set-Cookie: counter=1;
024+ Etag: ""
025+ X-Original-Transfer-Encoding: chunked
026+ HTTP/1.1 200 OK
027+ Set-Cookie: counter=1;
028+ Etag: ""
029+ X-Original-Transfer-Encoding: chunked
030+ HTTP/1.1 200 OK
031+ Set-Cookie: counter=1;
023- Set-Cookie: counter=6;
039- Set-Cookie: counter=2;
042- HTTP/1.1 200 OK
047+ Set-Cookie: counter=1;
050+ ===DONE===
043- Set-Cookie: counter=3;
044- Etag: ""
045- X-Original-Transfer-Encoding: chunked
046- HTTP/1.1 200 OK
047- Set-Cookie: counter=4;
048- Etag: ""
049- X-Original-Transfer-Encoding: chunked
050- ===DONE===
========DONE========
FAIL client cookies [tests/client021.phpt] 

Explan,ation from curl maintainer in Fedora:

The cookie is dropped by libcurl because the domain "localhost" is recognized
as a public suffix by libpsl. You can have a look at the attached minimal
example.

Sending multiple header fields with identical names

As of 3.0.1, ext-http cannot send multiple header fields with identical names, e.g.

$request->setHeaders('Foo' => Array(0 => 'aaa', 1 => 'bbb')));

results in a log message ("PHP Notice: Array to string conversion in ..../pecl_http.php on line 27") and a request that sends a header:

Foo: Array

While headers (excluding a few documented exceptions) can be combined into comma separated lists, not all servers / web applications handle this properly, therefore it is desirable to be able to actually send multiple header fields instead of combining them.

ext-http-multi-header.patch.txt

3.1.0RC1 build issue

With curl 7.43 (Fedora 23) or 7.50 (Fedora 25)

/dev/shm/BUILD/php70-php-pecl-http-3.1.0/NTS/src/php_http_client_curl.c: In function 'php_http_curle_option_set_ssl_tlsauthtype':
/dev/shm/BUILD/php70-php-pecl-http-3.1.0/NTS/src/php_http_client_curl.c:1113:19: error: 'PHP_HTTP_LIBCURL_TLSAUTH_SRP' undeclared (first use in this function)
    if (CURLE_OK == curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_LIBCURL_TLSAUTH_SRP)) {
                   ^
/dev/shm/BUILD/php70-php-pecl-http-3.1.0/NTS/src/php_http_client_curl.c:1113:19: note: each undeclared identifier is reported only once for each function it appears in
/dev/shm/BUILD/php70-php-pecl-http-3.1.0/NTS/src/php_http_client_curl.c:1121:17: error: 'PHP_HTTP_LIBCURL_TLSAUTH_DEF' undeclared (first use in this function)
  if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_LIBCURL_TLSAUTH_DEF)) {
                 ^

symbol lookup error

I have installed http and required extension on ubuntu 16.04
PHP Version 7.0

getting this error
/usr/sbin/apache2: symbol lookup error: /usr/lib/php/20151012/http.so: undefined symbol: uidna_IDNToASCII

thanks

[phpng] PHP7 with ZTS: use of undeclared identifier 'ERROR'

I just successfully rebuilt PHP7 beta 1 with ZTS enabled. However, when trying to rebuild ext-http I get the following error:

...
 clang -I. -I/home/jakob/Downloads/ext-http -DPHP_ATOM_INC -I/home/jakob/Downloads/ext-http/include -I/home/jakob/Downloads/ext-http/main -I/home/jakob/Downloads/ext-http -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM -I/usr/include/php/Zend -I/usr/include/php/ext -I/usr/include/php/ext/date/lib -I/usr/include/php/ext/raphf -I/usr/include/php/ext/propro -I/usr/include/php/ext/hash -DHAVE_CONFIG_H -g -O0 -c /home/jakob/Downloads/ext-http/php_http_client_curl.c  -fPIC -DPIC -o .libs/php_http_client_curl.o
/home/jakob/Downloads/ext-http/php_http_client_curl.c:223:2: error: use of
      undeclared identifier 'ERROR'
        TSRMLS_FETCH_FROM_CTX(body->ts);
        ^
./php_http_api.h:124:37: note: expanded from macro 'TSRMLS_FETCH_FROM_CTX'
#       define TSRMLS_FETCH_FROM_CTX(ctx) ERROR
                                          ^
/home/jakob/Downloads/ext-http/php_http_client_curl.c:1646:2: error: use of
      undeclared identifier 'ERROR'
        TSRMLS_FETCH_FROM_CTX(client->ts);
        ^
./php_http_api.h:124:37: note: expanded from macro 'TSRMLS_FETCH_FROM_CTX'
#       define TSRMLS_FETCH_FROM_CTX(ctx) ERROR
                                          ^
/home/jakob/Downloads/ext-http/php_http_client_curl.c:2417:2: error: use of
      undeclared identifier 'ERROR'
        TSRMLS_FETCH_FROM_CTX(h->ts);
        ^
./php_http_api.h:124:37: note: expanded from macro 'TSRMLS_FETCH_FROM_CTX'
#       define TSRMLS_FETCH_FROM_CTX(ctx) ERROR
                                          ^
3 errors generated.
Makefile:200: recipe for target 'php_http_client_curl.lo' failed
make: *** [php_http_client_curl.lo] Error 1

When compiling with gcc instead of clang the error messages differ, but not the error itself, so I'm pretty sure this isn't related to the compiler.

Joining query with empty original variable in query

First of all, i'm not sure i'm running the latest version, but couldn't find anything about this in the changelogs.

When you join query and the original parameter value is empty, it's removed from the modifies query string.

Example:

$hurl = new http\url("http://www.google.com/?a");

$hurl = $hurl->mod(array(
'query' => 'b=3'),
http\url::JOIN_QUERY
);
$url = $hurl->toString();

Output: http://www.google.com/?b=3
Expected output: http://www.google.com/?a&b=3

http\Client::dequeue() within http\Client::setDebug() causes segfault

We want to abort curl requests as soon as possible in case the resolved IP address is in our blacklist, however using the http\Client::dequeue() (http\Client::reset()) method from the setDebug()-callback causes a segmentation fault. We are using pecl_http 3.1.0 (master) with PHP 7.0.9 and curl 7.29.0.

To demonstrate the problem, I took the example from #35 and used the http\Client::dequeue() method within the setDebug():

<?php
$c = new http\Client;
$c->enqueue(new http\Client\Request("GET", "https://m6w6.name"));

$c->setDebug(function(http\Client $c, http\Client\Request $r, int $type, string $data) {
    if ($type & http\Client::DEBUG_HEADER) {
        $c->dequeue($r);
    }
});

$c->send();

With gdb I get this backtrace:

#0  0x00007ffff7754c7a in multi_runsingle (multi=multi@entry=0xda6bb0, now=..., easy=easy@entry=0xdbe1b0) at multi.c:1239
#1  0x00007ffff7755121 in curl_multi_perform (multi_handle=0xda6bb0, running_handles=running_handles@entry=0x7ffff14b9148) at multi.c:1723
#2  0x00007fffe859fe5e in php_http_client_curl_once (h=0x7ffff1477840) at pecl_http-3.1.0-dev/src/php_http_client_curl.c:2268
#3  php_http_client_curl_exec (h=0x7ffff1477840) at pecl_http-3.1.0-dev/src/php_http_client_curl.c:2285
#4  0x00007fffe859a1ef in zim_HttpClient_send (execute_data=0x7ffff1414130, return_value=0x7ffff1414120) at pecl_http-3.1.0-dev/src/php_http_client.c:867
#5  0x00000000006db70b in ZEND_DO_FCALL_SPEC_HANDLER () at php-7.0.9/Zend/zend_vm_execute.h:842
#6  0x00000000006a1f7b in execute_ex (ex=<optimized out>) at php-7.0.9/Zend/zend_vm_execute.h:414
#7  0x00000000006fddc3 in zend_execute (op_array=0x7ffff1484000, op_array@entry=0x7ffff1414030, return_value=return_value@entry=0x0)
    at php-7.0.9/Zend/zend_vm_execute.h:458
#8  0x000000000065fcc0 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=2) at php-7.0.9/Zend/zend.c:1427
#9  0x00000000005fa05b in php_execute_script (primary_file=primary_file@entry=0x7fffffffcec0) at php-7.0.9/main/main.c:2510
#10 0x00000000006ffb3f in do_cli (argc=2, argv=0xc28ee0) at php-7.0.9/sapi/cli/php_cli.c:974
#11 0x000000000042d45b in main (argc=2, argv=0xc28ee0) at php-7.0.9/sapi/cli/php_cli.c:1344

PHP7 status on Windows (VC14)

@m6w6 Hi Mike,

What is the status of propro, raphf and http on Windows (VC14)? I got it to compile, but had to make some changes. See my forks at https://github.com/Jan-E/repositories

Building wit cUrl support failed with these errormessages:

ext\http\src/php_http_client_curl.c(2181): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2181): error C2198: 'php_persistent_handle_concede': too few arguments for call
ext\http\src/php_http_client_curl.c(2501): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2502): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2503): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2504): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2506): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2506): error C2198: 'php_http_client_driver_add': too few arguments for call
ext\http\src/php_http_client_curl.c(2510): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2510): error C2198: 'php_persistent_handle_provide': too few arguments for call
ext\http\src/php_http_client_curl.c(2513): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2513): error C2198: 'php_persistent_handle_provide': too few arguments for call
ext\http\src/php_http_client_curl.c(2607): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2607): error C2198: 'php_persistent_handle_cleanup': too few arguments for call
ext\http\src/php_http_client_curl.c(2608): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2608): error C2198: 'php_persistent_handle_cleanup': too few arguments for call
ext\http\src/php_http_client_curl.c(2609): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2609): error C2198: 'zend_string_release': too few arguments for call
ext\http\src/php_http_client_curl.c(2610): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2610): error C2198: 'zend_string_release': too few arguments for call
ext\http\src/php_http_client_curl.c(2611): error C2039: 'client': is not a member of '_zend_php_http_globals'
ext\http\src/php_http_client_curl.c(2611): error C2198: 'zend_string_release': too few arguments for call

Segmentation fault on wrong URL

Affected version: 2.5.2
reproduction:

<?php
$request = new \http\Client\Request();
$request->setRequestUrl("https://.example.com/"); // seg fault

Parsing of improperly %-encoded URLs fails

<?php

$url = 'https://de.wikipedia.org/w/index.php?title=%';

$client = new http\Client();
$request = new http\Client\Request('GET', $url);
$client->enqueue($request);

throws an exception

$ php -ddisplay_errors=1 /tmp/test.php

Warning: http\Client\Request::__construct(): Failed to parse query; invalid percent encoding at pos 6 in 'title=%' in /tmp/test.php on line 6

Warning: http\Client\Request::__construct(): Failed to parse URL query: '%' in /tmp/test.php on line 6

Fatal error: Uncaught http\Exception\RuntimeException: http\Client::enqueue(): Cannot request empty URL in /tmp/test.php:7
Stack trace:
#0 /tmp/test.php(7): http\Client->enqueue(Object(http\Client\Request))
#1 {main}
  thrown in /tmp/test.php on line 7

Compared to the behavior of other clients (Firefox, Chrome, curl, wget) the URL parsing appears to be too strict here. So for consistency with other clients, % characters not followed by two hex digits should be silently treated as %25.

Pipe character not supported in URL

$url = new http\Url("http://www.example.com/?x=a|b");

The above code results in a fatal error:

Uncaught exception 'http\Exception\BadUrlException' with message 'http\Url::__construct(): Failed to parse query; unexpected byte 0x7c at pos 3 in 'x=a|b''

However, pipe characters are valid in URLs, and widely used (for example by Google).

In general -- I would be in favour of making http\Url::__construct() as tolerant as possible, even when you pass an invalid URL to the constructor, the object should do its best to parse as much from it as is reasonably possible.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.