Skip to content

Commit

Permalink
Respect uploaded file tree instead of flat array (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
scaytrase authored May 24, 2020
1 parent 2091dd6 commit 954f257
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 6 deletions.
36 changes: 30 additions & 6 deletions src/PSR7/Validators/BodyValidator/MultipartValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use cebe\openapi\spec\MediaType;
use cebe\openapi\spec\Schema;
use cebe\openapi\spec\Type as CebeType;
use InvalidArgumentException;
use League\OpenAPIValidation\PSR7\Exception\NoPath;
use League\OpenAPIValidation\PSR7\Exception\Validation\InvalidBody;
use League\OpenAPIValidation\PSR7\Exception\Validation\InvalidHeaders;
Expand All @@ -22,11 +23,14 @@
use League\OpenAPIValidation\Schema\SchemaValidator;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UploadedFileInterface;
use Riverline\MultiPartParser\Converters\PSR7;
use Riverline\MultiPartParser\StreamedPart;
use RuntimeException;
use const JSON_ERROR_NONE;
use function array_replace;
use function in_array;
use function is_array;
use function json_decode;
use function json_last_error;
use function json_last_error_msg;
Expand Down Expand Up @@ -222,19 +226,17 @@ private function detectEncondingContentType(Encoding $encoding, StreamedPart $pa
/**
* ServerRequest does not have a plain HTTP body which we can parse. Instead, it has a parsed values in
* getParsedBody() (POST data) and getUploadedFiles (FILES data)
*
* @param MediaType[] $mediaTypeSpecs
*/
private function validateServerRequestMultipart(
OperationAddress $addr,
ServerRequestInterface $message,
Schema $schema
) : void {
$body = $message->getParsedBody();
$body = (array) $message->getParsedBody();

foreach ($message->getUploadedFiles() as $name => $file) {
$body[$name] = '~~~binary~~~';
}
$files = $this->normalizeFiles($message->getUploadedFiles());

$body = array_replace($body, $files);

$validator = new SchemaValidator($this->detectValidationStrategy($message));
try {
Expand Down Expand Up @@ -263,4 +265,26 @@ private function validateServerRequestMultipart(
// ...headers are parsed already by webserver...
}
}

/**
* @param UploadedFileInterface[]|array[] $files
*
* @return mixed[]
*/
private function normalizeFiles(array $files) : array
{
$normalized = [];

foreach ($files as $name => $file) {
if ($file instanceof UploadedFileInterface) {
$normalized[$name] = '~~~binary~~~';
} elseif (is_array($file)) {
$normalized[$name] = $this->normalizeFiles($file);
} else {
throw new InvalidArgumentException('Invalid file tree in request');
}
}

return $normalized;
}
}
65 changes: 65 additions & 0 deletions tests/FromCommunity/Issue62Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace League\OpenAPIValidation\Tests\FromCommunity;

use GuzzleHttp\Psr7\ServerRequest;
use GuzzleHttp\Psr7\UploadedFile;
use League\OpenAPIValidation\PSR7\ValidatorBuilder;
use PHPUnit\Framework\TestCase;

final class Issue62Test extends TestCase
{
/**
* @see https://github.com/thephpleague/openapi-psr7-validator/issues/62
*/
public function testIssue62() : void
{
$yaml = /** @lang yaml */
<<<YAML
openapi: 3.0.0
info:
title: Test API
version: '1.0'
servers:
- url: 'http://localhost:8000/api/v1'
paths:
/clam/scan:
put:
responses:
'202':
description: Accepted
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
upload:
type: array
items:
type: string
format: binary
YAML;

$validator = (new ValidatorBuilder())->fromYaml($yaml)->getServerRequestValidator();

$psrRequest = (new ServerRequest('post', 'http://localhost:8000/api/v1/clam/scan'))
->withUploadedFiles(
ServerRequest::normalizeFiles(
[
'upload' => [
new UploadedFile('body1', 5, 0, 'upload_1.txt', 'text/plain'),
new UploadedFile('body2', 5, 0, 'upload_2.txt', 'text/plain'),
],
]
)
)
->withMethod('PUT')
->withHeader('Content-Type', 'multipart/form-data');

$validator->validate($psrRequest);
$this->addToAssertionCount(1);
}
}

0 comments on commit 954f257

Please sign in to comment.