satyarohith / sift

Sift is a routing and utility library for Deno Deploy.

Home Page:https://deno.land/x/sift

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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/.

Screenshot 2021-07-09 at 08-50-55 Deno

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.

commented

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.

commented

@satyarohith looks like sift may be trying to mutate the contentType header. see above.

commented

@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?

commented
commented

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. :)

commented
commented

@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/

image

  • 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.
CleanShot 2021-07-21 at 10 26 43@2x

@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.

commented

@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

sift/mod.ts

Line 74 in 2088f39

response.headers.delete("content-security-policy");
This does not seem to work as intended

commented

@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.

commented

@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 });
commented

@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!