Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preloaded Data Changes #10129

Closed
wants to merge 2 commits into from
Closed

Preloaded Data Changes #10129

wants to merge 2 commits into from

Conversation

xfalcox
Copy link
Member

@xfalcox xfalcox commented Jun 25, 2020

!!! This is just a draft for discussion !!!

This draft moves the big preloaded data payload we send on the HTML from a data-attribute to a Javascript variable.

In doing this, it greatly reduces the size of the HTML (around ~50KB depending on site, before gzip) and reduces the number of necessary JSON.parse on the browser boot. To work with CSP it adds a nonce to secure the inline script, keeping this payload inline with the main document.

On the Ruby side, we are still generating/storing JSONs everywhere, so this PR hacks around by doing parsing each part back into a Hash so it can create a proper JSON only in the last step. If this approach is deemed worth to follow up we will need to fix this by adding Hash versions of each method so we don't do double the work on the backend.

I would like the review on this refactor to see if it is something worth pursuing.

One unexpected change from this PR is that it fix the "View Source" breaking on Firefox :D . I believe the 350KB single HTML tag highlight was the culprit.

@@ -108,7 +108,9 @@
</form>
<% end %>

<div class="hidden" id="data-preloaded" data-preloaded="<%= preloaded_json %>"></div>
<script nonce="<%= csp_nonce %>">
Copy link
Contributor

@riking riking Jun 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you use script type="text/discourse-preload" and JSON.parse the body instead? This avoids the HTML attribute escaping

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That even bypasses the need for a nonce! Which also fixed the perf concern from @eviltrout and the nonce cache from @davidtaylorhq

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the other hand means I need to escape script close tags 🤔

Copy link
Contributor

@eviltrout eviltrout left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory, I like it. It is much simpler. However, does it make us potential victims of this slow path?

https://v8.dev/blog/cost-of-javascript-2019#json

It might be faster to emit a variable that is a JSON.parse even though that seems counter intuitive.

@@ -19,14 +19,12 @@ export default {
if (isTesting()) {
return;
}
const preloadedDataElement = document.getElementById("data-preloaded");
const preloadedData = window.preloaded;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Premature feedback, perhaps, but we should use a much more complex variable name here to avoid conflicts since it's a global namespace.

@davidtaylorhq
Copy link
Member

The nonce-based CSP option is only secure if the nonce is unique on every request. I think that's mostly true with this implementation, except when the anon cache comes into play. When that happens, the same nonce will get sent to multiple clients. An attacker could then take that nonce and potentially use it to perform an XSS attack.

Maybe we could use the Hash method instead?

@davidtaylorhq
Copy link
Member

I am curious why we need the sub thing... I think having < or > will never be included in json. For example:

pry(main)> puts ({test: "</script>h4cked"}.to_json)
{"test":"\u003c/script\u003eh4cked"}

But there must be a reason it was there before 🤔

@riking
Copy link
Contributor

riking commented Jun 27, 2020

Check if the existing Rails html escaper takes care of the angle brackets, yeah.

@trs80
Copy link

trs80 commented Oct 8, 2020

There's also been some sort of performance regression since Firefox 77 relating to this data attribute https://bugzilla.mozilla.org/show_bug.cgi?id=1647942

@davidtaylorhq
Copy link
Member

@xfalcox do you think we should explore this further? Or should we close this out?

@xfalcox
Copy link
Member Author

xfalcox commented Feb 19, 2021 via email

@SamSaffron
Copy link
Member

overall I support a change here if we can get it past the line, I think it probably makes sense to have a dev todo for this.

will take lots of testing, maybe even we ship it behind an experimental setting for a while.

@SamSaffron SamSaffron closed this May 21, 2021
@tgxworld tgxworld deleted the preloaded branch July 8, 2021 02:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
6 participants