Skip to content

Commit

Permalink
Merge branch 'bref-binary-response'
Browse files Browse the repository at this point in the history
  • Loading branch information
mnapoli committed Sep 26, 2019
2 parents cd7df0a + 72a81a5 commit 5ee5f63
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 0 deletions.
19 changes: 19 additions & 0 deletions demo/http.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,23 @@
sleep(10);
}

if (isset($_GET['img'])) {
$fp = fopen('https://bref.sh/img/logo-small.png', 'rb');
header('Content-Type: image/png');
fpassthru($fp);
exit(0);
}

if (isset($_GET['json'])) {
header('Content-Type: application/json');
echo json_encode(['Hello' => '🌍']);
exit(0);
}

if (isset($_GET['weird'])) {
header('Content-Type: foo/bar');
echo 'Hello 🌍';
exit(0);
}

echo 'Hello world!';
31 changes: 31 additions & 0 deletions docs/runtimes/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,37 @@ Lambda and API Gateway are only used for executing code. Serving assets via PHP

Deploying a website and serving assets (e.g. CSS, JavaScript, images) is covered in [the "Websites" documentation](/docs/websites.md).

In some cases however, you will need to serve images (or other assets) via PHP. One example would be if you served generated images via PHP. In those cases, you need to read the [Binary response](#binary-responses) section below.

## Binary responses

By default API Gateway **does not support binary HTTP responses** like images, PDF, binary files… To achieve this, you need to enable the option for binary responses in `serverless.yml`:

```yaml
provider:
# ...
apiGateway:
binaryMediaTypes:
- '*/*'
```

This will make API Gateway support binary responses for all responses. Your application can now return binary responses as usual.

**However, you must define a `Content-Type` header on binary responses.** If you don't, you may get the following error: *Failed encoding Lambda JSON response: Malformed UTF-8 characters, possibly incorrectly encoded*. [Symfony's helpers](https://symfony.com/doc/current/components/http_foundation.html#serving-files) or [Laravel's helpers](https://laravel.com/docs/5.8/responses#file-downloads) will take care of that for you. If you don't use them, here are some examples:

```php
// Vanilla PHP example with a JPEG image response:
header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($filename));
fpassthru(fopen($filename, 'rb'));
// PSR-7 example:
return $response
->withHeader('Content-Type', 'image/jpeg')
->withHeader('Content-Length', (string) filesize($filename))
->withBody(new Stream($filename));
```

## Cold starts

AWS Lambda automatically destroys Lambda containers that have been unused for 10 to 60 minutes. Warming up a new container can take some time, especially if your package is large or if your Lambda is connected to a VPC. This delay is called [cold start](https://mikhail.io/serverless/coldstarts/aws/).
Expand Down
3 changes: 3 additions & 0 deletions serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ provider:
name: aws
runtime: provided
region: us-east-2
apiGateway:
binaryMediaTypes:
- '*/*'

plugins:
- ./index.js
Expand Down
13 changes: 13 additions & 0 deletions src/Runtime/LambdaRuntime.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,19 @@ public function failInitialization(string $message, ?\Throwable $error = null):
*/
private function postJson(string $url, $data): void
{
$contentType = $data['multiValueHeaders']['content-type'][0] ?? null;
/**
* API Gateway does not support binary content in HTTP responses.
* What we do is:
* - if we are certain the response is not binary (either JSON or the content type starts with `text/*`) we don't encode
* - else we encode all other responses to base64
* API Gateway checks `isBase64Encoded` and decodes what we returned if necessary.
*/
if ($contentType && $contentType !== 'application/json' && strpos($contentType, 'text/') !== 0) {
$data['body'] = base64_encode($data['body']);
$data['isBase64Encoded'] = true;
}

$jsonData = json_encode($data);
if ($jsonData === false) {
throw new \Exception('Failed encoding Lambda JSON response: ' . json_last_error_msg());
Expand Down

0 comments on commit 5ee5f63

Please sign in to comment.