Skip to content

Commit

Permalink
Merge pull request #469 from WordPress/fix/manage-expect-header-with-…
Browse files Browse the repository at this point in the history
…curl-transport

Manage "Expect" header with cURL transport
  • Loading branch information
schlessera authored Apr 16, 2021
2 parents 519ac37 + f110fc6 commit d9161d4
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 0 deletions.
40 changes: 40 additions & 0 deletions library/Requests/Transport/cURL.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,21 @@ protected function setup_handle($url, $headers, $data, $options) {
$headers['Connection'] = 'close';
}

/**
* Add "Expect" header.
*
* By default, cURL adds a "Expect: 100-Continue" to most requests. This header can
* add as much as a second to the time it takes for cURL to perform a request. To
* prevent this, we need to set an empty "Expect" header. To match the behaviour of
* Guzzle, we'll add the empty header to requests that are smaller than 1 MB and use
* HTTP/1.1.
*
* https://curl.se/mail/lib-2017-07/0013.html
*/
if (!isset($headers['Expect']) && $options['protocol_version'] === 1.1) {
$headers['Expect'] = $this->get_expect_header($data);
}

$headers = Requests::flatten($headers);

if (!empty($data)) {
Expand Down Expand Up @@ -546,4 +561,29 @@ public static function test($capabilities = array()) {

return true;
}

/**
* Get the correct "Expect" header for the given request data.
*
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD.
* @return string The "Expect" header.
*/
protected function get_expect_header($data) {
if (!is_array($data)) {
return strlen((string) $data) >= 1048576 ? '100-Continue' : '';
}

$bytesize = 0;
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data));

foreach ($iterator as $datum) {
$bytesize += strlen((string) $datum);

if ($bytesize >= 1048576) {
return '100-Continue';
}
}

return '';
}
}
100 changes: 100 additions & 0 deletions tests/Transport/cURL.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,104 @@ public function testRevokedHTTPS() {
public function testBadDomain() {
parent::testBadDomain();
}

/**
* @small
*/
public function testDoesntOverwriteExpectHeaderIfManuallySet() {
$headers = array(
'Expect' => 'foo',
);
$request = Requests::post(httpbin('/post'), $headers, array(), $this->getOptions());

$result = json_decode($request->body, true);

$this->assertSame($headers['Expect'], $result['headers']['Expect']);
}

/**
* @small
*/
public function testDoesntSetExpectHeaderIfBodyExactly1MbButProtocolIsnt11() {
$options = array(
'protocol_version' => 1.0,
);
$request = Requests::post(httpbin('/post'), array(), str_repeat('x', 1048576), $this->getOptions($options));

$result = json_decode($request->body, true);

$this->assertFalse(isset($result['headers']['Expect']));
}

/**
* @small
*/
public function testSetsEmptyExpectHeaderWithDefaultSettings() {
$request = Requests::post(httpbin('/post'), array(), array(), $this->getOptions());

$result = json_decode($request->body, true);

$this->assertFalse(isset($result['headers']['Expect']));
}

/**
* @small
*/
public function testSetsEmptyExpectHeaderIfBodyIsANestedArrayLessThan1Mb() {
$data = array(
str_repeat('x', 148576),
array(
str_repeat('x', 548576),
),
);
$request = Requests::post(httpbin('/post'), array(), $data, $this->getOptions());

$result = json_decode($request->body, true);

$this->assertFalse(isset($result['headers']['Expect']));
}

public function testSetsExpectHeaderIfBodyIsExactlyA1MbString() {
$request = Requests::post(httpbin('/post'), array(), str_repeat('x', 1048576), $this->getOptions());

$result = json_decode($request->body, true);

$this->assertSame('100-Continue', $result['headers']['Expect']);
}

public function testSetsExpectHeaderIfBodyIsANestedArrayGreaterThan1Mb() {
$data = array(
str_repeat('x', 148576),
array(
str_repeat('x', 548576),
array(
str_repeat('x', 648576),
),
),
);
$request = Requests::post(httpbin('/post'), array(), $data, $this->getOptions());

$result = json_decode($request->body, true);

$this->assertSame('100-Continue', $result['headers']['Expect']);
}

public function testSetsExpectHeaderIfBodyExactly1Mb() {
$request = Requests::post(httpbin('/post'), array(), str_repeat('x', 1048576), $this->getOptions());

$result = json_decode($request->body, true);

$this->assertSame('100-Continue', $result['headers']['Expect']);
}

/**
* @small
*/
public function testSetsEmptyExpectHeaderIfBodySmallerThan1Mb() {
$request = Requests::post(httpbin('/post'), array(), str_repeat('x', 1048575), $this->getOptions());

$result = json_decode($request->body, true);

$this->assertFalse(isset($result['headers']['Expect']));
}
}

0 comments on commit d9161d4

Please sign in to comment.