Static files not working when deployed
wezm opened this issue · comments
Static files are not served on Deno Deploy; images are corrupt locally and when deployed.
I've created a sample project to reproduce this issue: https://github.com/wezm/repro-sift-static
In Deno Deploy it's linked to https://github.com/wezm/repro-sift-static/blob/main/src/index.ts, accessible at https://quiet-owl-61.deno.dev/.
When running locally with deployctl run --watch --libs=ns,fetchevent --addr :8888 src/index.ts
the style sheet loads properly (somtimes) but when deployed it does not. The image does not load locally or when deployed.
When I run https://quiet-owl-61.deno.dev/
Open the chrome-develop-tools select the network tab, then refresh the page,
I see that the image.png is loading as 'type json'
If you click on the file in the list you can examine the headers.
image,png should have a content type of ' image/png ', not 'application/json'
Also, there is an error message for response that says {"error":"Headers are immutable."}
This had to happen in sift.
Perhaps Sift is trying to mutate the contentType header instead of replacing it.
@satyarohith looks like sift may be trying to mutate the contentType header. see above.
@satyarohith
The browser will reject a mutated headers object
// in line 76 you are trying to mutate the existing header
for (const [key, value] of newHeaders) {
existingHeaders.set(key, value);
}
Instead, build a fresh set of headers from the existing
and the browser will accept them.
// replace with the following
// first place the existingHeaders in a new headers object
const newHeaders = new Headers(existingHeaders);
// do any housekeeping with this set...
if (newHeaders.has("x-github-request-id")) {
newHeaders.delete("content-security-policy");
}
// then add you contentType header...
for (const [key, value] of headers) {
newHeaders.set(key, value);
}
// finally, return the newHeaders object in a new Responce object
// line 80
return new Response(res.body, {
headers: newHeaders,
status: res.status,
statusText: res.statusText,
});
I learned this the hard way when I built my own static file server for Deploy ... https://clock.deno.dev/
SEE: https://github.com/nhrones/DotClock
Thanks for looking into it, @nhrones! That's the root cause. Are you interested in opening a PR?
a. clone repo
b. make changes
c. pull request
These are the only steps to get started. It's similar to how you opened denoland/deployctl#67. :)
@satyarohith please forgive my rants. I fixed my Gmail (had a bad theme that mangled everything from Github)..
Are you still interest in help?
Thanks for the patience, @wezm! I fixed the issue and released a new version 0.3.4
. Please try it out and let me know if you face any issues.
The image does not load locally or when deployed.
There's a tracking issue (denoland/deployctl#60) on deployctl. But you'll soon be able to run sift
using deno
without the need for deployctl
, which should fix the local static assets issue.
Wonderful, I can confirm that the image and stylesheet now work.
Hi, i'm having a similar issue. I'm using sift 0.3.4 and deployctl 0.3.0. (also tried with main)
my code: https://github.com/sylc/test_sift/blob/main/server.ts.
deployment: https://old-donkey-81.deno.dev/
- with deploctl, the style file is loaded but the png file is not showing (the response is noted as 200 in devTools)
- when deployed, neither the styling or the png is loaded (there is no response)
I also cloned wezm code to test with my local deployctl. The image is not loading correctly.
I have deno version 1.12.1
@sylc. See note above with the link to denoland/deployctl#60. Images won't load properly locally but as of 0.3.4 they are now loading when deployed (for me).
@sylc, the website seems to be working fine for me on Chrome and Safari.
@wezm @satyarohith Thanks for the feedback.
It seems that i was facing 2 issue:
- the local issue is due to the deployctl bug.
- the deno deployment issue is a csp issue. I'm normally using chrome. in devtools console there is
Refused to load the stylesheet 'https://old-donkey-81.deno.dev/assets/styles.css' because it violates the following Content Security Policy directive: "style-src 'unsafe-inline'". Note that 'style-src-elem' was not explicitly set, so 'style-src' is used as a fallback.
I tried in edge and firefox and the image was loaded successfully at first. But then I open the devtools and disable the cache and reload and I get the same error in both browser. I guess i can try to set a meta tag in the head but i would expect the server to handle this by a header in the response. It is unclear why this is not happening on @wezm repro site.
@sylc @satyarohith I get the same errors as you. On https://old-donkey-81.deno.dev/.
Both the stylesheet and the img are rejected. Windows 10/ Chrome browser. I had set up a test app after 0.3.4 and for several
hours testing the error I was getting just went away? I looked on Discord but could see no reason for that to have happened.
The error I was testing for was a header mutation error in chrome. I first saw it on @wezm app from to denoland/deployctl#60. My test was producing the mutated header rejection, and after a few hours, it changed to a content-type error???
In my test case I'm retrieving the index.html
from github.
If I instead replace it with a baked in response in serve eg: '/': () => new Response(html, { headers: { "content-type": "text/html; charset=UTF-8", } }),
(similar to @wezm initial site), then it is working.
I can see that any files retrieved from github has a content-security-policy
header set, which does not allow to load further files
It seems that that there is an attempt in the code to remove this header. ref
Line 74 in 2088f39
@satyarohith @sylc
Please note that in line#74, the case may be that you are not actually removing the header. Often, as was the case with content-type header, mutation is blocked on original header but not on NEW header.
Consider ...
// here originalResponse.headers will be the init values of a new headers object
const newHeaders = new Headers(originalResponse.headers)
// now you may be able to make changes. Worth a try.
newHeaders.delete("content-security-policy");
As with the content-type issue, the newHeaders object should allow mutations.
@sylc @satyarohith
This is taken directly from the Deploy Docs, 'Serving static assets' page!
const response = await fetch(style);
// We cannot directly modify the headers of a Response instance
// as they are immuntable. So we create a new headers object
// using the existing headers of the response.
const headers = new Headers(response.headers);
// Set the appropriate content-type header value.
headers.set("content-type", "text/css; charset=utf-8");
// Construct a new response with the modified headers.
return new Response(response.body, { ...response, headers });
@sylc @satyarohith
I'm wrong again. Did some testing. I forgot that the new Response object on line#65 also returns a new Headers object. So yes the header delete will happen. What confused me was the reuse of the param 'response' to new. I saw the name at params and thought it was what was referenced at line#74 response.headers.delete.
Sorry!