Fix on multiparse request data

* bug fixin
* refactoring

Change-Id: I78d990c630a9149d8e762fdebdae9e908d3f194b
This commit is contained in:
smarcet 2019-04-25 17:09:59 -03:00
parent eedb771250
commit c75aa1f10b
8 changed files with 117 additions and 81 deletions

View File

@ -11,6 +11,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Http\Utils\FileTypes;
use libs\utils\HTMLCleaner;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
@ -640,7 +642,13 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController
'description',
];
$slide = $this->presentation_service->addSlideTo($request, $presentation_id, HTMLCleaner::cleanData($data, $fields));
$slide = $this->presentation_service->addSlideTo
(
$request,
$presentation_id,
HTMLCleaner::cleanData($data, $fields),
array_merge(FileTypes::ImagesExntesions, FileTypes::SlidesExtensions)
);
return $this->created(SerializerRegistry::getInstance()->getSerializer($slide)->serialize());
}
@ -675,25 +683,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController
if (is_null($summit)) return $this->error404();
$content_type = $request->headers->has('Content-Type') ? strtolower( $request->headers->get('Content-Type')) : null;
if (false !== $pos = strpos($content_type, ';')) {
$content_type = substr($content_type, 0, $pos);
}
$file = null;
$data = $request->all();
Log::debug("updatePresentationSlide: data ".var_dump($data));
if(strstr($content_type, 'multipart/form-data')) {
Log::debug("updatePresentationSlide: has multipart/form-data");
$parser = new ParseMultiPartFormDataInputStream(file_get_contents('php://input'));
$input = $parser->getInput();
Log::debug("updatePresentationSlide: input ".var_dump($input));
$data = $input['parameters'];
$files = $input['files'];
$file = null;
if (isset($files['file']))
$file = $files['file'];
}
$rules = [
'link' => 'nullable|url',
@ -720,7 +710,11 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController
$slide = $this->presentation_service->updateSlide
(
$request, $presentation_id, $slide_id, HTMLCleaner::cleanData($data, $fields), $file
$request,
$presentation_id,
$slide_id,
HTMLCleaner::cleanData($data, $fields),
array_merge(FileTypes::ImagesExntesions, FileTypes::SlidesExtensions)
);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($slide)->serialize());

View File

@ -1932,28 +1932,10 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
$summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$content_type = $request->headers->has('Content-Type') ? strtolower( $request->headers->get('Content-Type')) : null;
if (false !== $pos = strpos($content_type, ';')) {
$content_type = substr($content_type, 0, $pos);
}
if(!strstr($content_type, 'multipart/form-data'))
return $this->error400();
$parser = new ParseMultiPartFormDataInputStream(file_get_contents('php://input'));
$input = $parser->getInput();
$metadata = $input['parameters'];
$files = $input['files'];
$file = null;
if(isset($files['file']))
$file = $files['file'];
$rules = SummitLocationImageValidationRulesFactory::build(true);
$data = $request->all();
$rules = SummitLocationImageValidationRulesFactory::build(true);
// Creates a Validator instance and validates the data.
$validation = Validator::make($metadata, $rules);
$validation = Validator::make($data, $rules);
if ($validation->fails()) {
$messages = $validation->messages()->toArray();
@ -1971,9 +1953,9 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
$map_id,
HTMLCleaner::cleanData
(
$metadata, ['description']
$data, ['description']
),
$file
$request->hasFile('file') ? $request->file('file'):null
);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($map)->serialize());
@ -2148,28 +2130,10 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
try {
$summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$content_type = $request->headers->has('Content-Type') ? strtolower( $request->headers->get('Content-Type')) : null;
if (false !== $pos = strpos($content_type, ';')) {
$content_type = substr($content_type, 0, $pos);
}
if(!strstr($content_type, 'multipart/form-data'))
return $this->error400();
$parser = new ParseMultiPartFormDataInputStream(file_get_contents('php://input'));
$input = $parser->getInput();
$metadata = $input['parameters'];
$files = $input['files'];
$file = null;
if(isset($files['file']))
$file = $files['file'];
$rules = SummitLocationImageValidationRulesFactory::build(true);
$data = $request->all();
$rules = SummitLocationImageValidationRulesFactory::build(true);
// Creates a Validator instance and validates the data.
$validation = Validator::make($metadata, $rules);
$validation = Validator::make($data, $rules);
if ($validation->fails()) {
$messages = $validation->messages()->toArray();
@ -2187,9 +2151,9 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController
$image_id,
HTMLCleaner::cleanData
(
$metadata, ['description']
$data, ['description']
),
$file
$request->hasFile('file') ? $request->file('file'):null
);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($image)->serialize());

View File

@ -21,6 +21,7 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\CORSMiddleware::class,
\App\Http\Middleware\SecurityHTTPHeadersWriterMiddleware::class,
\App\Http\Middleware\ParseMultipartFormDataInputForNonPostRequests::class,
];
/**

View File

@ -0,0 +1,59 @@
<?php namespace App\Http\Middleware;
/**
* Copyright 2019 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use Closure;
use utils\ParseMultiPartFormDataInputStream;
/**
* Class ParseMultipartFormDataInputForNonPostRequests
* @package App\Http\Middleware
*/
final class ParseMultipartFormDataInputForNonPostRequests
{
/*
* Content-Type: multipart/form-data - only works for POST requests. All others fail, this is a bug in PHP since 2011.
* See comments here: https://github.com/laravel/framework/issues/13457
*
* This middleware converts all multi-part/form-data for NON-POST requests, into a properly formatted
* request variable for Laravel 5.6. It uses the ParseInputStream class, found here:
* https://gist.github.com/devmycloud/df28012101fbc55d8de1737762b70348
*/
public function handle($request, Closure $next)
{
if ($request->method() == 'POST' OR $request->method() == 'GET') {
return $next($request);
}
if (preg_match('/multipart\/form-data/', $request->headers->get('Content-Type')) or
preg_match('/multipart\/form-data/', $request->headers->get('content-type'))
) {
$parser = new ParseMultiPartFormDataInputStream(file_get_contents('php://input'));
$params = $parser->getInput();
$files = [];
$parameters = [];
foreach ($params as $key => $param) {
if ($param instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
$files[$key] = $param;
} else {
$parameters[$key] = $param;
}
}
if (count($files) > 0) {
$request->files->add($files);
}
if (count($parameters) > 0) {
$request->request->add($parameters);
}
}
return $next($request);
}
}

View File

@ -0,0 +1,24 @@
<?php namespace App\Http\Utils;
/**
* Copyright 2019 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class FileTypes
* @package App\Http\Utils
*/
final class FileTypes
{
const SlidesExtensions = ['ppt', 'pptx', 'xps', 'key', 'pdf'];
const ImagesExntesions = ['jpg', 'jpeg', 'png', 'svg', 'bmp', 'tga', 'tiff', 'gif'];
}

View File

@ -235,7 +235,7 @@ final class ParseMultiPartFormDataInputStream
{
$string = trim($string);
$data = [];
if ( preg_match('/name=\"(.*)\"\n*(.*)$/s', $string, $match) ) {
if ( preg_match('name=\"([^\"]*)\"[\n|\r]+([^\n\r].*)$', $string, $match) ) {
if (preg_match('/^(.*)\[\]$/i', $match[1], $tmp)) {
$data[$tmp[1]][] = ($match[2] !== NULL ? $match[2] : '');
} else {

View File

@ -1,5 +1,4 @@
<?php namespace services\model;
/**
* Copyright 2016 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,7 +20,6 @@ use models\summit\PresentationSlide;
use models\summit\PresentationVideo;
use models\summit\Summit;
use Illuminate\Http\Request as LaravelRequest;
use Illuminate\Http\UploadedFile;
/**
* Interface IPresentationService
* @package services\model
@ -107,7 +105,7 @@ interface IPresentationService
LaravelRequest $request,
$presentation_id,
array $slide_data,
array $allowed_extensions = ['ppt', 'pptx', 'xps', 'key', 'pdf', 'jpg', 'jpeg', 'png', 'svg', 'bmp', 'tga', 'tiff', 'gif'],
array $allowed_extensions = [],
$max_file_size = 10485760
);
@ -116,7 +114,6 @@ interface IPresentationService
* @param int $presentation_id
* @param int $slide_id
* @param array $slide_data
* @param UploadedFile $file
* @param array $allowed_extensions
* @param int $max_file_size
* @return mixed|PresentationSlide
@ -128,8 +125,7 @@ interface IPresentationService
$presentation_id,
$slide_id,
array $slide_data,
UploadedFile $file = null,
array $allowed_extensions = ['ppt', 'pptx', 'xps', 'key', 'pdf', 'jpg', 'jpeg', 'png', 'svg', 'bmp', 'tga', 'tiff', 'gif'],
array $allowed_extensions = [],
$max_file_size = 10485760
);

View File

@ -623,7 +623,7 @@ final class PresentationService
LaravelRequest $request,
$presentation_id,
array $slide_data,
array $allowed_extensions = ['ppt', 'pptx', 'xps', 'key', 'pdf', 'jpg', 'jpeg', 'png', 'svg', 'bmp', 'tga', 'tiff', 'gif'],
array $allowed_extensions = [],
$max_file_size = 10485760
)
{
@ -653,7 +653,7 @@ final class PresentationService
$slide = PresentationSlideFactory::build($slide_data);
// check if there is any file sent
if($request->hasFile('file')){
if($hasFile){
$file = $request->file('file');
if (!in_array($file->extension(), $allowed_extensions)) {
throw new ValidationException(
@ -684,7 +684,6 @@ final class PresentationService
* @param int $presentation_id
* @param int $slide_id
* @param array $slide_data
* @param UploadedFile $file
* @param array $allowed_extensions
* @param int $max_file_size
* @return mixed|PresentationSlide
@ -696,8 +695,7 @@ final class PresentationService
$presentation_id,
$slide_id,
array $slide_data,
UploadedFile $file = null,
array $allowed_extensions = ['ppt', 'pptx', 'xps', 'key', 'pdf', 'jpg', 'jpeg', 'png', 'svg', 'bmp', 'tga', 'tiff', 'gif'],
array $allowed_extensions = [],
$max_file_size = 10485760
){
@ -708,8 +706,7 @@ final class PresentationService
$slide_data,
$max_file_size,
$allowed_extensions,
$slide_id,
$file
$slide_id
) {
$presentation = $this->presentation_repository->getById($presentation_id);
@ -730,7 +727,7 @@ final class PresentationService
$hasLink = isset($slide_data['link']) && !empty($slide_data['link']);
$hasFile = !is_null($file);
$hasFile = $request->hasFile('file');
if($hasFile && $hasLink){
throw new ValidationException("you must provide a file or a link, not both.");
@ -751,6 +748,7 @@ final class PresentationService
// check if there is any file sent
if($hasFile){
$file = $request->file('file');
if (!in_array($file->extension(), $allowed_extensions)) {
throw new ValidationException(
sprintf("file does not has a valid extension '(%s)'.", implode("','", $allowed_extensions)));