Skip to content

Disable gzip compression of URL Metric by default #1924

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

Closed
wants to merge 11 commits into from

Conversation

westonruter
Copy link
Member

@westonruter westonruter commented Mar 14, 2025

This is a follow-up to:

Most recently, it now addresses #1928 by disabling gzip compression by default since doing so at the pagehide event results in errors in Safari and the detect() function's execution being aborted at the point that compression is performed.

This PR also does the following, which were the original scope of this PR:

  • Use Content-Encoding header instead of Content-Type to indicate gzip compression
  • Use fetch() with keepalive instead of navigator.sendBeacon()
  • Add a od_gzip_url_metric_store_request_payloads filter (which now is false by default)

In the former, gzip compression was introduced for the URL Metric JSON data being submitted. This drastically reduces the payload size which is important because there is a 64 KiB limit for beacons. However, when I look at the request in DevTools I see the following:

POST /wp-json/optimization-detective/v1/url-metrics:store?_wpnonce=f5ee4cdd67&slug=d751713988987e9331980363e24189ce&current_etag=5dff21b3549bbe22019407c953755389&cache_purge_post_id=484&hmac=e186efbbb61f1cb879117236ccc6fc95 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 1592
Content-Type: application/gzip

Screenshot 2025-03-14 14 52 28

Notice how the request payload is displayed in binary in DevTools. This got me to thinking whether using the application/gzip was correct. At first I thought maybe application/json+gzip would be a solution, but that isn't standard. Then I remembered the Content-Encoding request header. It allows for the Content-Type to remain application/json (which seems important!) but then to also send a Content-Encoding: gzip when the request body is compressed with gzip.

Nevertheless, it is not possible to set the Content-Encoding header when using navigator.sendBeacon() however. But, there is a new equivalent to navigator.sendBeacon() by using fetch() with the keepalive: true option. This was previously discovered in #1311 (comment). This is Baseline Widely Available (caniuse). And fetch() with keepalive does allow you to include arbitrary request headers (as well as use HTTP methods other than POST). Additionally, according to umami-software/umami#1160, navigator.sendBeacon() is blocked by ad blockers like uBlock Origin, so switching to fetch() with keepalive could result in additional URL Metrics being collected.

I conferred with Gemini which confirmed that using Content-Type: application/json with Content-Encoding: gzip is the correct and standard approach: https://g.co/gemini/share/ba550d36273e

With all this said, Chrome DevTools still doesn't pretty-print the gzip-encoded JSON. But this seems like a limitation with DevTools.

Nevertheless, if it so happens that the server is unable to accept gzip-compressed JSON request bodies, or if during development you want to be able to see the uncompressed data being sent, this PR introduces od_gzip_url_metric_store_request_payloads filter which can prevent gzip compression from being used, regardless of whether gzdecode() is available in PHP. This is false by default since.

This PR also updates the detection script to log out the compression percentage when gzip is being used. Lastly, it moves the OD_REST_URL_Metrics_Store_Endpoint::decompress_rest_request_body() method to be a separate od_decompress_rest_request_body() function per #1865 (comment).

@westonruter westonruter added [Type] Bug An existing feature is broken [Plugin] Optimization Detective Issues for the Optimization Detective plugin labels Mar 14, 2025
@westonruter westonruter requested a review from felixarntz as a code owner March 14, 2025 23:31
Copy link

github-actions bot commented Mar 14, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: westonruter <[email protected]>
Co-authored-by: felixarntz <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@westonruter westonruter added skip changelog PRs that should not be mentioned in changelogs and removed skip changelog PRs that should not be mentioned in changelogs labels Mar 14, 2025
@westonruter westonruter changed the title Update/url metric store request compression Use Content-Encoding header instead of Content-Type to indicate gzip compression, use fetch() with keepalive instead of navigator.sendBeacon(), and add od_gzip_url_metric_store_request_payloads filter Mar 14, 2025
@@ -722,6 +722,7 @@ export default async function detect( {
urlMetric.elements.push( elementData );
elementsByXPath.set( elementData.xpath, elementData );
}
breadcrumbedElementsMap.clear();
Copy link
Member Author

Choose a reason for hiding this comment

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

This didn't make sense at the end of the function. So I moved it up here after it is last used.

Copy link

codecov bot commented Mar 14, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 71.38%. Comparing base (47eef00) to head (0bae565).

Additional details and impacted files
@@            Coverage Diff             @@
##            trunk    #1924      +/-   ##
==========================================
- Coverage   71.39%   71.38%   -0.01%     
==========================================
  Files          86       86              
  Lines        7043     7042       -1     
==========================================
- Hits         5028     5027       -1     
  Misses       2015     2015              
Flag Coverage Δ
multisite 71.38% <100.00%> (-0.01%) ⬇️
single 40.44% <0.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@felixarntz
Copy link
Member

@westonruter I saw this coming by but don't have capacity to review it right now. I can try Monday morning, but especially since it's a bug fix, I think it would be reasonable to milestone it for the following beta instead - unless it's a critical bug that would affect lots of sites?

@westonruter
Copy link
Member Author

@felixarntz Monday morning should be good. I'm going to deploy to my site and test in Chrome, Safari, and Firefox to make sure that URL Metrica are gathered as expected. Since the gzip compression is a new feature in the release, the bugfix to ensure Content-Encoding is used correctly seems important to go out with the release.

@westonruter
Copy link
Member Author

This PR is probably a dead end based on what I've found in #1928

@westonruter westonruter changed the title Use Content-Encoding header instead of Content-Type to indicate gzip compression, use fetch() with keepalive instead of navigator.sendBeacon(), and add od_gzip_url_metric_store_request_payloads filter Disable gzip compression of URL Metric by default Mar 16, 2025
@westonruter
Copy link
Member Author

As opposed to keeping the code but disabling it by default, I've opened #1929 to revert the code altogether.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked [Plugin] Optimization Detective Issues for the Optimization Detective plugin [Type] Bug An existing feature is broken
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants