Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[HttpClient] Streaming request changes in HttplugClient result in curl error CURLE_SEND_FAIL_REWIND #59489

Copy link
Copy link
Closed
@veewee

Description

@veewee
Issue body actions

Symfony version(s) affected

7.2.2+

Description

Since this change in 7.2.2 that allows for streaming the HTTP request body with CURLOPT_READFUNCTION instead of CURLOPT_POSTFIELDS: bbdf0e0 (introduced by @nicolas-grekas)

We are receiving: CURLE_SEND_FAIL_REWIND (65)

When doing a send operation curl had to rewind the data to retransmit, but the rewinding operation failed.

  Unable to read stream contents: Necessary data rewind wasn't possible for "http://xxxx"

Exception trace:
  at /app/vendor/symfony/http-client/Response/CurlResponse.php:319
 Symfony\Component\HttpClient\Response\CurlResponse::perform() at /app/vendor/symfony/http-client/Response/TransportResponseTrait.php:167
 Symfony\Component\HttpClient\Response\CurlResponse::stream() at /app/vendor/symfony/http-client/Response/StreamWrapper.php:123
 Symfony\Component\HttpClient\Response\StreamWrapper->stream_read() at n/a:n/a
 stream_get_contents() at /app/vendor/nyholm/psr7/src/Stream.php:270
 Nyholm\Psr7\Stream->getContents() at /app/vendor/nyholm/psr7/src/StreamTrait.php:23
 Nyholm\Psr7\Stream->__toString() at /app/vendor/php-soap/psr18-transport/src/HttpBinding/Psr7Converter.php:41

This happens on the second request. The first request gets handled as expected.

The server is private and cannot be shared.
Some details:

  • It's a SOAP 1.1 server
  • It has NTLM authentication (meaning curl will perform additional NTLM authentication requests / responses internally)

This happens on:

  • PHP 8.3
  • curl version 8.11.0

Our best guess is that using CURLOPT_READFUNCTION in combination with NTLM is resulting in this specific error inside curl.
When we use this code-change on other endpoints, it works as expected.

We found following issues on the web which might or might not be related:

How to reproduce

As mentioned, the server is private and cannot be shared.

The configuration of the client is straight forward and looks like this:

use Symfony\Component\HttpClient\CurlHttpClient;
use Symfony\Component\HttpClient\HttplugClient;

$client = new HttplugClient(
    new CurlHttpClient([
        'auth_ntlm' => 'user:password',
    ])
)

ℹ️ The first request that is sent over the shared connection will succeed as usual. The second request will fail with the error Unable to read stream contents: Necessary data rewind wasn't possible

The request is a SOAP request that looks like this:

$headers = [
    0 => "Host: host:port"
    1 => "SOAPAction: "..."
    2 => "Content-Type: text/xml; charset="utf-8""
    3 => "Content-Length: 376"
    4 => "Accept: */*"
    5 => "User-Agent: Symfony HttpClient (Curl)"
    6 => "Accept-Encoding: gzip"
    7 => "expect:"
    8 => "Transfer-Encoding:"
];

$body = <<<EOXML
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <tns:AppInitialise xmlns:tns="uri:foo">
            <tns:useragent>foo</tns:useragent>
            <tns:languagecode>NLB</tns:languagecode>
        </tns:AppInitialise>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
EOXML;

which results in following curl options:

^ array:31 [
  10002 => "http://..."
  121 => true
  181 => 3
  182 => 3
  52 => true
  68 => 20
  10031 => ""
  13 => 0
  10004 => null
  10177 => ""
  64 => true
  81 => 2
  10065 => null
  10097 => null
  10083 => null
  10025 => null
  10087 => null
  10026 => null
  172 => false
  32 => 6
  107 => 8
  84 => 2
  10005 => "user:password"
  91 => false
  229 => 1
  10036 => "POST"
  47 => true
  10023 => array:9 [
    0 => "Host: horst:port"
    1 => "SOAPAction: "action""
    2 => "Content-Type: text/xml; charset="utf-8""
    3 => "Content-Length: 376"
    4 => "Accept: */*"
    5 => "User-Agent: Symfony HttpClient (Curl)"
    6 => "Accept-Encoding: gzip"
    7 => "expect:"
    8 => "Transfer-Encoding:"
  ]
  20012 => Closure($ch, $fd, $length)^ {#39732
    class: "Symfony\Component\HttpClient\CurlHttpClient"
    use: {
      $body: Closure(int $size)^ {#39649 …}
      $eof: false
      $buffer: ""
    }
  }
  14 => 502
  10100 => CurlShareHandle {#39677}
]

Let me know if I can add anything to this issue report to make it easier for you to reproduce or figure out what is going wrong.

Possible Solution

We are not sure what is causing this specific error. It might be an issue in curl instead of symfony/http-client.

Following configuration got us around the actual issue, but seems like a bad idea performance-wise.

CURLOPT_FORBID_REUSE - make connection get closed at once after use

$client = new HttplugClient(
    new CurlHttpClient([
        'auth_ntlm' => 'user:password',
        'extra' => [
            'curl' => [
                \CURLOPT_FORBID_REUSE => true,
            ]
        ]
    ])
);

Another option around the problem would be to introduce a new CurlHttpClient option.
Something like $options['stream_request'] which has a default of true to use the CURLOPT_READFUNCTION implementation, but can be set to false for using the CURLOPT_POSTFIELDS logic.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.