diff --git a/AbstractBrowser.php b/AbstractBrowser.php index 1520501..8364a2b 100644 --- a/AbstractBrowser.php +++ b/AbstractBrowser.php @@ -618,7 +618,7 @@ protected function getAbsoluteUri(string $uri): string } // protocol relative URL - if (0 === strpos($uri, '//')) { + if ('' !== trim($uri, '/') && str_starts_with($uri, '//')) { return parse_url($currentUri, \PHP_URL_SCHEME).':'.$uri; } diff --git a/HttpBrowser.php b/HttpBrowser.php index 4f036e2..d460605 100644 --- a/HttpBrowser.php +++ b/HttpBrowser.php @@ -82,7 +82,7 @@ private function getBodyAndExtraHeaders(Request $request, array $headers): array $fields = $request->getParameters(); if ($uploadedFiles = $this->getUploadedFiles($request->getFiles())) { - $part = new FormDataPart(array_merge($fields, $uploadedFiles)); + $part = new FormDataPart(array_replace_recursive($fields, $uploadedFiles)); return [$part->bodyToIterable(), $part->getPreparedHeaders()->toArray()]; } diff --git a/Tests/HttpBrowserTest.php b/Tests/HttpBrowserTest.php index f41fccf..c0254e7 100644 --- a/Tests/HttpBrowserTest.php +++ b/Tests/HttpBrowserTest.php @@ -94,7 +94,11 @@ public function testMultiPartRequestWithSingleFile() ->with('POST', 'http://example.com/', $this->callback(function ($options) { $this->assertStringContainsString('Content-Type: multipart/form-data', implode('', $options['headers'])); $this->assertInstanceOf(\Generator::class, $options['body']); - $this->assertStringContainsString('my_file', implode('', iterator_to_array($options['body']))); + $values = implode('', iterator_to_array($options['body'], false)); + $this->assertStringContainsString('name="foo[file]"', $values); + $this->assertStringContainsString('my_file', $values); + $this->assertStringContainsString('name="foo[bar]"', $values); + $this->assertStringContainsString('foo2', $values); return true; })) @@ -103,7 +107,7 @@ public function testMultiPartRequestWithSingleFile() $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']]); + $browser->request('POST', 'http://example.com/', ['foo' => ['bar' => 'foo2']], ['foo' => ['file' => ['tmp_name' => $path, 'name' => 'foo']]]); } public function testMultiPartRequestWithNormalFlatArray() @@ -180,6 +184,30 @@ public function testMultiPartRequestWithAdditionalParametersOfTheSameName() ]); } + /** + * @dataProvider forwardSlashesRequestPathProvider + */ + public function testMultipleForwardSlashesRequestPath(string $requestPath) + { + $client = $this->createMock(HttpClientInterface::class); + $client + ->expects($this->once()) + ->method('request') + ->with('GET', 'http://localhost'.$requestPath) + ->willReturn($this->createMock(ResponseInterface::class)); + $browser = new HttpBrowser($client); + $browser->request('GET', $requestPath); + } + + public function forwardSlashesRequestPathProvider() + { + return [ + 'one slash' => ['/'], + 'two slashes' => ['//'], + 'multiple slashes' => ['////'], + ]; + } + private function uploadFile(string $data): string { $path = tempnam(sys_get_temp_dir(), 'http');