Use FormUrlEncoded when posting non-binary data
This commit is contained in:
parent
8da76862fa
commit
aecca9778e
@ -13,6 +13,7 @@ namespace Symfony\Component\BrowserKit;
|
|||||||
|
|
||||||
use Symfony\Component\HttpClient\HttpClient;
|
use Symfony\Component\HttpClient\HttpClient;
|
||||||
use Symfony\Component\Mime\Part\AbstractPart;
|
use Symfony\Component\Mime\Part\AbstractPart;
|
||||||
|
use Symfony\Component\Mime\Part\DataPart;
|
||||||
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
|
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
|
||||||
use Symfony\Component\Mime\Part\TextPart;
|
use Symfony\Component\Mime\Part\TextPart;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
@ -43,13 +44,10 @@ class HttpBrowser extends AbstractBrowser
|
|||||||
protected function doRequest($request)
|
protected function doRequest($request)
|
||||||
{
|
{
|
||||||
$headers = $this->getHeaders($request);
|
$headers = $this->getHeaders($request);
|
||||||
$body = '';
|
[$body, $extraHeaders] = $this->getBodyAndExtraHeaders($request);
|
||||||
if (null !== $part = $this->getBody($request)) {
|
|
||||||
$headers = array_merge($headers, $part->getPreparedHeaders()->toArray());
|
|
||||||
$body = $part->bodyToIterable();
|
|
||||||
}
|
|
||||||
$response = $this->client->request($request->getMethod(), $request->getUri(), [
|
$response = $this->client->request($request->getMethod(), $request->getUri(), [
|
||||||
'headers' => $headers,
|
'headers' => array_merge($headers, $extraHeaders),
|
||||||
'body' => $body,
|
'body' => $body,
|
||||||
'max_redirects' => 0,
|
'max_redirects' => 0,
|
||||||
]);
|
]);
|
||||||
@ -57,10 +55,13 @@ class HttpBrowser extends AbstractBrowser
|
|||||||
return new Response($response->getContent(false), $response->getStatusCode(), $response->getHeaders(false));
|
return new Response($response->getContent(false), $response->getStatusCode(), $response->getHeaders(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getBody(Request $request): ?AbstractPart
|
/**
|
||||||
|
* @return array [$body, $headers]
|
||||||
|
*/
|
||||||
|
private function getBodyAndExtraHeaders(Request $request): array
|
||||||
{
|
{
|
||||||
if (\in_array($request->getMethod(), ['GET', 'HEAD'])) {
|
if (\in_array($request->getMethod(), ['GET', 'HEAD'])) {
|
||||||
return null;
|
return ['', []];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!class_exists(AbstractPart::class)) {
|
if (!class_exists(AbstractPart::class)) {
|
||||||
@ -68,19 +69,33 @@ class HttpBrowser extends AbstractBrowser
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $content = $request->getContent()) {
|
if (null !== $content = $request->getContent()) {
|
||||||
return new TextPart($content, 'utf-8', 'plain', '8bit');
|
$part = new TextPart($content, 'utf-8', 'plain', '8bit');
|
||||||
|
|
||||||
|
return [$part->bodyToString(), $part->getPreparedHeaders()->toArray()];
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields = $request->getParameters();
|
$fields = $request->getParameters();
|
||||||
|
$hasFile = false;
|
||||||
foreach ($request->getFiles() as $name => $file) {
|
foreach ($request->getFiles() as $name => $file) {
|
||||||
if (!isset($file['tmp_name'])) {
|
if (!isset($file['tmp_name'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hasFile = true;
|
||||||
$fields[$name] = DataPart::fromPath($file['tmp_name'], $file['name']);
|
$fields[$name] = DataPart::fromPath($file['tmp_name'], $file['name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FormDataPart($fields);
|
if ($hasFile) {
|
||||||
|
$part = new FormDataPart($fields);
|
||||||
|
|
||||||
|
return [$part->bodyToIterable(), $part->getPreparedHeaders()->toArray()];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($fields)) {
|
||||||
|
return ['', []];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [http_build_query($fields, '', '&', PHP_QUERY_RFC1738), ['Content-Type' => 'application/x-www-form-urlencoded']];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getHeaders(Request $request): array
|
private function getHeaders(Request $request): array
|
||||||
|
@ -17,6 +17,8 @@ use Symfony\Component\BrowserKit\HttpBrowser;
|
|||||||
use Symfony\Component\BrowserKit\Response;
|
use Symfony\Component\BrowserKit\Response;
|
||||||
use Symfony\Component\HttpClient\MockHttpClient;
|
use Symfony\Component\HttpClient\MockHttpClient;
|
||||||
use Symfony\Component\HttpClient\Response\MockResponse;
|
use Symfony\Component\HttpClient\Response\MockResponse;
|
||||||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
class SpecialHttpResponse extends Response
|
class SpecialHttpResponse extends Response
|
||||||
{
|
{
|
||||||
@ -112,4 +114,62 @@ class HttpBrowserTest extends AbstractBrowserTest
|
|||||||
$this->assertNotInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getInternalResponse());
|
$this->assertNotInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getInternalResponse());
|
||||||
$this->assertInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getResponse());
|
$this->assertInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider validContentTypes
|
||||||
|
*/
|
||||||
|
public function testRequestHeaders(array $request, array $exepectedCall)
|
||||||
|
{
|
||||||
|
$client = $this->createMock(HttpClientInterface::class);
|
||||||
|
$client
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with(...$exepectedCall)
|
||||||
|
->willReturn($this->createMock(ResponseInterface::class));
|
||||||
|
|
||||||
|
$browser = new HttpBrowser($client);
|
||||||
|
$browser->request(...$request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validContentTypes()
|
||||||
|
{
|
||||||
|
$defaultHeaders = ['user-agent' => 'Symfony BrowserKit', 'host' => 'example.com'];
|
||||||
|
yield 'GET/HEAD' => [
|
||||||
|
['GET', 'http://example.com/', ['key' => 'value']],
|
||||||
|
['GET', 'http://example.com/', ['headers' => $defaultHeaders, 'body' => '', 'max_redirects' => 0]],
|
||||||
|
];
|
||||||
|
yield 'empty form' => [
|
||||||
|
['POST', 'http://example.com/'],
|
||||||
|
['POST', 'http://example.com/', ['headers' => $defaultHeaders, 'body' => '', 'max_redirects' => 0]],
|
||||||
|
];
|
||||||
|
yield 'form' => [
|
||||||
|
['POST', 'http://example.com/', ['key' => 'value', 'key2' => 'value']],
|
||||||
|
['POST', 'http://example.com/', ['headers' => $defaultHeaders + ['Content-Type' => 'application/x-www-form-urlencoded'], 'body' => 'key=value&key2=value', 'max_redirects' => 0]],
|
||||||
|
];
|
||||||
|
yield 'content' => [
|
||||||
|
['POST', 'http://example.com/', [], [], [], 'content'],
|
||||||
|
['POST', 'http://example.com/', ['headers' => $defaultHeaders + ['Content-Type: text/plain; charset=utf-8', 'Content-Transfer-Encoding: 8bit'], 'body' => 'content', 'max_redirects' => 0]],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultiPartRequest()
|
||||||
|
{
|
||||||
|
$client = $this->createMock(HttpClientInterface::class);
|
||||||
|
$client
|
||||||
|
->expects($this->once())
|
||||||
|
->method('request')
|
||||||
|
->with('POST', 'http://example.com/', $this->callback(function ($options) {
|
||||||
|
$this->assertContains('Content-Type: multipart/form-data', implode('', $options['headers']));
|
||||||
|
$this->assertInstanceOf('\Generator', $options['body']);
|
||||||
|
$this->assertContains('my_file', implode('', iterator_to_array($options['body'])));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}))
|
||||||
|
->willReturn($this->createMock(ResponseInterface::class));
|
||||||
|
|
||||||
|
$browser = new HttpBrowser($client);
|
||||||
|
$path = tempnam(sys_get_temp_dir(), 'http');
|
||||||
|
file_put_contents($path, 'my_file');
|
||||||
|
$browser->request('POST', 'http://example.com/', [], ['file' => ['tmp_name' => $path, 'name' => 'foo']]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user