Multipoart support

This commit is contained in:
Matej Bačo 2024-07-01 06:57:18 +00:00
parent 66c761b73e
commit 7bdcd5c436
3 changed files with 172 additions and 9 deletions

View file

@ -274,6 +274,8 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
requestTimeout: 30
);
\var_dump($executionResponse);
$headersFiltered = [];
foreach ($executionResponse['headers'] as $key => $value) {
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
@ -325,13 +327,6 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
$body = $execution['responseBody'] ?? '';
$encodingKey = \array_search('x-open-runtimes-encoding', \array_column($execution['responseHeaders'], 'name'));
if ($encodingKey !== false) {
if (($execution['responseHeaders'][$encodingKey]['value'] ?? '') === 'base64') {
$body = \base64_decode($body);
}
}
$contentType = 'text/plain';
foreach ($execution['responseHeaders'] as $header) {
if (\strtolower($header['name']) === 'content-type') {

View file

@ -0,0 +1,152 @@
<?php
namespace Appwrite\Utopia\Fetch;
class BodyMultipart
{
/**
* @var array<string, mixed> $parts
*/
private array $parts = [];
private string $boundary = "";
public function __construct(string $boundary = null)
{
if (is_null($boundary)) {
$this->boundary = self::generateBoundary();
} else {
$this->boundary = $boundary;
}
}
public static function generateBoundary(): string
{
return '-----------------------------' . \uniqid();
}
public function load(string $body): self
{
$eol = "\r\n";
$sections = \explode('--' . $this->boundary, $body);
foreach ($sections as $section) {
if (empty($section)) {
continue;
}
if (strpos($section, $eol) === 0) {
$section = substr($section, \strlen($eol));
}
if (substr($section, -2) === $eol) {
$section = substr($section, 0, -1 * \strlen($eol));
}
if ($section == '--') {
continue;
}
$partChunks = \explode($eol . $eol, $section, 2);
if (\count($partChunks) < 2) {
continue; // Broken part
}
[ $partHeaders, $partBody ] = $partChunks;
$partHeaders = \explode($eol, $partHeaders);
$partName = "";
foreach ($partHeaders as $partHeader) {
if (!empty($partName)) {
break;
}
$partHeaderArray = \explode(':', $partHeader, 2);
$partHeaderName = \strtolower($partHeaderArray[0] ?? '');
$partHeaderValue = $partHeaderArray[1] ?? '';
if ($partHeaderName == "content-disposition") {
$dispositionChunks = \explode("; ", $partHeaderValue);
foreach ($dispositionChunks as $dispositionChunk) {
$dispositionChunkValues = \explode("=", $dispositionChunk, 2);
if (\count($dispositionChunkValues) >= 2) {
if ($dispositionChunkValues[0] === "name") {
$partName = \trim($dispositionChunkValues[1], "\"");
break;
}
}
}
}
}
if (!empty($partName)) {
$this->parts[$partName] = $partBody;
}
}
return $this;
}
/**
* @return array<string, mixed>
*/
public function getParts(): array
{
return $this->parts ?? [];
}
public function getPart(string $key, mixed $default = ''): mixed
{
return $this->parts[$key] ?? $default;
}
public function setPart(string $key, mixed $value): self
{
$this->parts[$key] = $value;
return $this;
}
public function getBoundary(): string
{
return $this->boundary;
}
public function setBoundary(string $boundary): self
{
$this->boundary = $boundary;
return $this;
}
public function exportHeader(): string
{
return 'multipart/form-data; boundary=' . $this->boundary;
}
public function exportBody(): string
{
$eol = "\r\n";
$query = '--' . $this->boundary;
foreach ($this->parts as $key => $value) {
$query .= $eol . 'Content-Disposition: form-data; name="' . $key . '"';
if (\is_array($value)) {
$query .= $eol . 'Content-Type: application/json';
$value = \json_encode($value);
} else {
$isBinary = ! mb_check_encoding($value, 'UTF-8');
if ($isBinary) {
$query .= $eol . 'Content-Transfer-Encoding: binary';
}
}
$query .= $eol . $eol;
$query .= $value . $eol;
$query .= '--' . $this->boundary;
}
$query .= "--" . $eol;
return $query;
}
}

View file

@ -2,6 +2,7 @@
namespace Executor;
use Appwrite\Utopia\Fetch\BodyMultipart;
use Exception;
use Utopia\System\System;
@ -250,7 +251,13 @@ class Executor
break;
case 'multipart/form-data':
$query = $this->flatten($params);
$multipart = new BodyMultipart();
foreach ($params as $key => $value) {
$multipart->setPart($key, $value);
}
$headers['content-type'] = $multipart->exportHeader();
$query = $multipart->exportBody();
break;
default:
@ -315,7 +322,16 @@ class Executor
$responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($decode) {
switch (substr($responseType, 0, strpos($responseType, ';'))) {
$strpos = strpos($responseType, ';');
$strpos = \is_bool($strpos) ? \strlen($responseType) : $strpos;
switch (substr($responseType, 0, $strpos)) {
case 'multipart/form-data':
$boundary = \explode('boundary=', $responseHeaders['content-type'] ?? '')[1] ?? '';
$multipartResponse = new BodyMultipart($boundary);
$multipartResponse->load(\is_bool($responseBody) ? '' : $responseBody);
$responseBody = $multipartResponse->getParts();
break;
case 'application/json':
$json = json_decode($responseBody, true);