fix(cloudfront): stream origin responses and viewer request bodies (#5278)
A distribution read every origin response whole before answering the viewer: an S3 origin's object through getObject, a custom origin's body through the HTTP client into a byte array. A viewer's POST, PUT, PATCH or DELETE body was likewise read whole before it was forwarded. So an object or upload of about 2 GiB or more failed, and a smaller one could run the heap out of memory. S3 origins now open the object as a stream, the snapshot GetObject serves, and custom origins return their response before its body is read; either body is written to the viewer as it arrives, with its Content-Length, or chunked as the origin sent it. A viewer's body is streamed to the custom origin with its Content-Length, or chunked when the viewer sent it chunked or, as HTTP/2 allows, with no length. An origin response closed before its end, as when the viewer goes away or a custom error page replaces it, cancels its request instead of reading the rest of the body to reuse the connection. Since a streamed response holds its connection for the whole transfer, one origin may now use the whole connection pool, as CloudFront sets no per-origin limit. (cherry picked from commit 1f1d4f94dd8a179972bda124bc3aa47b9704f69b)
This commit is contained in:
@@ -156,9 +156,12 @@ PUT, PATCH and DELETE).
|
||||
method; any other method returns 403 `Invalid method.`. A behavior without `AllowedMethods` allows
|
||||
GET and HEAD. Origin forwarding preserves the raw path; custom-origin redirects are not followed.
|
||||
- POST, PUT, PATCH and DELETE are forwarded to custom origins with the viewer request body and its
|
||||
`Content-Type`; `Content-Length` is set from the body. Their responses are never cached, as on AWS.
|
||||
Signed URL and signed cookie enforcement applies to them like any other method. Request bodies are
|
||||
bounded by the emulator-wide `floci.protocols.max-request-size` limit.
|
||||
`Content-Type`. The body is streamed to the origin with the viewer's `Content-Length`, or chunked
|
||||
when the viewer sent it chunked or, as HTTP/2 allows, with no length, so it is never held in
|
||||
memory. Their responses are never cached, as on AWS. Signed URL and signed cookie enforcement
|
||||
applies to them like any other method. Request bodies are bounded by the emulator-wide
|
||||
`floci.protocols.max-request-size` limit (`FLOCI_PROTOCOLS_MAX_REQUEST_SIZE`, 2048 MB by default);
|
||||
CloudFront accepts up to 64 GB, so raise it for larger uploads.
|
||||
- Every distribution is also served as `{id}.cloudfront.{host}` for each endpoint host Floci
|
||||
resolves: `localhost`, `localhost.floci.io`, `localhost.localstack.cloud`, `FLOCI_HOSTNAME` and
|
||||
every `FLOCI_DNS_EXTRA_SUFFIXES` entry. `{id}.cloudfront.localhost.floci.io` and
|
||||
@@ -223,6 +226,10 @@ PUT, PATCH and DELETE).
|
||||
`Elemental-MediaPackage` or the `UseOriginCacheControlHeaders` policies.
|
||||
- In-process S3 origins do not apply forwarding settings: viewer query strings, cookies and headers
|
||||
do not change the S3 read.
|
||||
- Origin responses are streamed to the viewer, from in-process S3 origins and custom origins alike,
|
||||
so a large object is never held in memory. A custom origin's `Content-Length` is passed on, and a
|
||||
response it sends chunked stays chunked. Floci does not cache, so it serves objects larger than
|
||||
50 GB the way CloudFront does with caching disabled; with caching enabled, CloudFront refuses them.
|
||||
- Origin `Set-Cookie` headers always reach the viewer. With legacy `Forward=none`, AWS strips them
|
||||
from the response; Floci does not.
|
||||
- Custom origins that resolve to loopback, private, link-local, carrier-grade NAT, or other non-routable addresses are rejected by default. Development-only private origins must be explicitly allowlisted by exact hostname.
|
||||
|
||||
Reference in New Issue
Block a user