@matthewp it’s looking better for me.
Edit: this is only deployed to the server where that frosty-frog-2648
is running.
@matthewp it’s looking better for me.
Edit: this is only deployed to the server where that frosty-frog-2648
is running.
Yep! It’s intentionally slowed down to show the stream. Looks correct to me now. Anything you can share or is it just internal code stuff?
It’s a crate we use in our custom proxy. It didn’t flush nearly enough for streaming responses.
I’ve used somebody else’s fix with a small change of mine.
I’ve deployed the change everywhere now!
We just added support for Cache-Control: no-transform
Do Fly apps have inbuilt BREACH attack prevention like Cloudflare? https://support.cloudflare.com/hc/en-us/articles/205043158-PCI-compliance-and-Cloudflare-SSL
Hey @jerome, returning streaming responses should be supported right?
I’m trying to stream my response in a Go app on v2 Fly Machines. When I flush()
I’m expecting the content was written to the response stream to be sent back to the client, but nothing happens. Here are my headers:
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("transfer-encoding", "chunked")
w.Header().Set("content-encoding", "none")
w.Header().Set("cache-control", "no-transform")
The client just hangs and once I cancel the request I’m seeing this error server side:
iad [error] could not make HTTP request to instance: error from user's HttpBody stream: error reading a body from connection: unexpected end of file
Yes, it supports streaming responses.
Can you add a flyio-debug: doit
header and give us a fly request ID (returned in the response headers, if you’re getting them back) so we can take a look into what’s happening here?
Thanks for the quick reply and for the confirmation. Went back and tested some more and was able to get the response body to stream.
Do you also support streaming the request body? Here is a request ID if it helps.
fly-request-id":"01GVHPJ9HM0GV8VDM0V01CBMC4-iad"
What did you change to get a response body to stream? Streams should just work, but I wonder if there’s some combination of headers that prevented it.
Every HTTP feature (well… maybe not CONNECT) should be available, yes.
So if I have other cache directives I should do something like this?
'Cache-Control: no-transform, public, max-age=60, s-maxage=3600'
First thing I had wrong was my code was using a buffer that was larger that what I was trying to flush. I’m a Go noob
buf := make([]byte, 1024)
To get the response to stream between two servers all I needed was:
Transfer-Encoding: chunked
(This is set implicitly by Go when you use Flush
) The other headers listed above were not necessary.
This did not work in the browser though Looks like another header is needed for it to work in the browser
X-Content-Type-Options: nosiff
Still working on getting the request body to stream.
Ok, streaming the request body does work. It was working locally but not on Fly so I compared the response headers and Connection: close
was being set locally but not on Fly.
I explicitly set that header before streaming the request and streaming the response and it is working as expected now!
w.Header().Set("connection", "close")
@jerome Regarding the Brotli issue, is there any chance this could be revisited? Could you point me at the upstream issue?
Hey there! This is the issue I filed: Panic (slice indexes) when encoding with brotli · Issue #103 · Nullus157/async-compression · GitHub
However, I believe we brought back brotli by using a fork that did not panic. Fixed by: Fix #72 with more explicit control flow that mimics the basic blocks … · dropbox/rust-brotli@0c107fa · GitHub
@shugel Brotli should therefore be working, are you seeing otherwise?
Good question…I just checked, and my machines have compressed (.gz
and .br
) versions of e.g. index.css
available in their static files folder.
My fly toml is set up to map these folders correctly (app
is the Docker WORKDIR
) :
[[statics]]
guest_path = "/app/staticfiles"
url_prefix = "/assets"
And I’ve configured Whitenoise (Python static files plugin for Flask and Django) to set up staticfiles
as the internal static path, externally mapped to assets
:
app = Flask(__name__, static_folder="assets")
app.wsgi_app = WhiteNoise(
app.wsgi_app,
root=os.path.join(
os.path.dirname(__file__), "staticfiles"
),
prefix="assets/",
max_age=WHITENOISE_MAX_AGE,
)
My request header for index.css
:
request: Accept-Encoding: gzip, deflate, br
And the response:
:status: 200
Accept-Ranges: bytes
Cache-Control: public, max-age=0, must-revalidate
Content-Encoding: gzip
Content-Type: text/css
Date: Fri, 15 Sep 2023 15:00:33 GMT
ETag: W/"3228d-65045ce8.0"
fly-cache-status: HIT
fly-request-id: 01HACNQ8EDXG7NTSRV3H5KDBGF-cdg
Last-Modified: Fri, 15 Sep 2023 13:32:24 GMT
Server: Fly/6cc3f7e5 (2023-09-12)
Via: 2 fly.io
Just to revisit this: I just accidentally messed up my fly statics entry and briefly served static files using my web app’s settings, which resulted in Brotli-compressed assets being served. I’m not sure how fly’s static setup works (I gather you pull files out of the specified dir in the Docker image, but I don’t know whether you’re then compressing them), but it’s definitely “only” serving gzip: it’s not producing brotli-compressed assets, or picking up brotli-compressed assets that are present in the specified static dir.
We’re looking into this and should have a resolution this week!
Hi @shugel
This should be fixed now. Can you give it another try, please?
Yes, working correctly now. Thank you (and @jerome)!