apache / incubator-pagespeed-ngx

Automatic PageSpeed optimization module for Nginx
http://ngxpagespeed.com/
Apache License 2.0
4.36k stars 363 forks source link

ngx_pagespeed breaks updating WP by caching POST requests #1657

Open Dreamsorcerer opened 5 years ago

Dreamsorcerer commented 5 years ago

When editing a post in a WordPress site's admin area, clicking the 'save draft' button appears to work successfully, but the content is not actually saved.

Looking at the network requests in Firefox, I can see that a POST request is sent to '/wp-json/wp/v2/posts/3591?_locale=user' with the post contents in the params, but the response contains the old contents of the post. This shows that the response appears to be cached on the server, I can also find a file in ngx_pagespeed's cache directory corresponding to that exact path.

This happens even with pagespeed RewriteLevel PassThrough; and adding pagespeed off; into an appropriate location block. The only way I can find stop this behaviour is to disable pagespeed for the entire server block.

Regardless, ngx_pagespeed should never be caching responses to POST requests in the first place.

oschaaf commented 5 years ago

What does the full response to a POST look like, including response headers, when pagespeed is out of the equation? I’m pretty sure ngx_pagespeed has no logic for caching post requests. In fact I think that it mostly doesn’t touch those at all (unless it initiated these POST requests itself for beaconing).

Dreamsorcerer commented 5 years ago

So, first request with Pagespeed enabled (hitting Save draft with the title changed to TEST):

Request headers

Host: <domain>
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, */*;q=0.1
Accept-Language: eo,en-GB;q=0.8,en;q=0.5,ja;q=0.3
Accept-Encoding: gzip, deflate, br
X-WP-Nonce: 3102092830
X-HTTP-Method-Override: PUT
Content-Type: application/json
Origin: <domain>
Content-Length: 69
DNT: 1
Connection: keep-alive
Referer: https://<domain>/wp-admin/post.php
Cookie: wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_722b1833171c7650292a2e1422d6b495=sam%7C1561995621%7CLSgIgZ0n7YiVXl8w2BOdJrN84z7mRLn7hXmxby5EoE5%7C2c78f7cff7a593ca312246ce251cabe92c41a4c379d987e75541298c5ae87861; wp-settings-8=editor%3Dtinymce%26libraryContent%3Dbrowse; wp-settings-time-8=1561822822
Pragma: no-cache
Cache-Control: no-cache
TE: Trailers

Response headers:

HTTP/2.0 200 OK
date: Sat, 29 Jun 2019 15:41:28 GMT
content-type: application/json; charset=UTF-8
x-robots-tag: noindex
link: <https://<domain>/wp-json/>; rel="https://api.w.org/"
x-content-type-options: nosniff
access-control-expose-headers: X-WP-Total, X-WP-TotalPages
access-control-allow-headers: Authorization, Content-Type
expires: Sat, 29 Jun 2019 15:56:28 GMT
x-wp-nonce: 3102092830
allow: GET, POST, PUT, PATCH, DELETE
access-control-allow-origin: https://<domain>
access-control-allow-methods: OPTIONS, GET, POST, PUT, PATCH, DELETE
access-control-allow-credentials: true
vary: Origin
strict-transport-security: max-age=31536000; includeSubDomains; preload
x-frame-options: DENY
content-security-policy: default-src 'none'; script-src 'self' 'unsafe-inline' www.gstatic.com s3.amazonaws.com www.google-analytics.com www.googletagmanager.com; object-src 'none'; style-src 'self' 'unsafe-inline' fonts.googleapis.com www.gstatic.com cdn-images.mailchimp.com; img-src 'self' data: www.google-analytics.com stats.g.doubleclick.net; media-src 'self'; frame-src www.youtube.com; font-src 'self' data: fonts.gstatic.com; connect-src 'self'; frame-ancestors 'self'; base-uri 'none'; form-action 'self'; manifest-src 'none'; worker-src 'none'; upgrade-insecure-requests; require-sri-for script style;
x-xss-protection: 1; mode=block
referrer-policy: no-referrer-when-downgrade
feature-policy: accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; usb 'none'; vibrate 'none'; vr 'none'
cache-control: max-age=900, s-maxage=10
X-Firefox-Spdy: h2

Response:

{"id":3748,"date":"2019-06-29T15:41:28","date_gmt":"2019-06-29T15:41:28","guid":{"rendered":"https:\/\/\/?p=3748","raw":"https:\/\/\/?p=3748"},"modified":"2019-06-29T15:41:28","modified_gmt":"2019-06-29T15:41:28","password":"","slug":"","status":"draft","type":"post","link":"https:\/\/\/?p=3748","title":{"raw":"TEST","rendered":"TEST"},"content":{"raw":"","rendered":"","protected":false,"block_version":0},"excerpt":{"raw":"","rendered":"","protected":false},"author":8,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[],"permalink_template":"https:\/\/\/%postname%\/","generated_slug":"test","_links":{"self":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"collection":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/\/wp-json\/wp\/v2\/comments?post=3748"}],"version-history":[{"count":1,"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748\/revisions"}],"predecessor-version":[{"id":3749,"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748\/revisions\/3749"}],"wp:attachment":[{"href":"https:\/\/\/wp-json\/wp\/v2\/media?parent=3748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/\/wp-json\/wp\/v2\/categories?post=3748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/\/wp-json\/wp\/v2\/tags?post=3748"}],"wp:action-publish":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-unfiltered-html":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-sticky":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-author":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-categories":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-categories":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-tags":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-tags":[{"href":"https:\/\/\/wp-json\/wp\/v2\/posts\/3748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}

The second run with PS enabled (I changed the title to TEST123, but notice the response is the same identical response, even including the date).

Request headers:

Host: <domain>
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, */*;q=0.1
Accept-Language: eo,en-GB;q=0.8,en;q=0.5,ja;q=0.3
Accept-Encoding: gzip, deflate, br
X-WP-Nonce: 3102092830
X-HTTP-Method-Override: PUT
Content-Type: application/json
Origin: https://<domain>
Content-Length: 42
DNT: 1
Connection: keep-alive
Referer: https://<domain>/wp-admin/post.php
Cookie: wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_722b1833171c7650292a2e1422d6b495=sam%7C1561995621%7CLSgIgZ0n7YiVXl8w2BOdJrN84z7mRLn7hXmxby5EoE5%7C2c78f7cff7a593ca312246ce251cabe92c41a4c379d987e75541298c5ae87861; wp-settings-8=editor%3Dtinymce%26libraryContent%3Dbrowse; wp-settings-time-8=1561822822
Pragma: no-cache
Cache-Control: no-cache
TE: Trailers

Response headers:

HTTP/2.0 200 OK
server: nginx
content-type: application/json; charset=UTF-8
x-robots-tag: noindex
link: <https://<domain>/wp-json/>; rel="https://api.w.org/"
x-content-type-options: nosniff
access-control-expose-headers: X-WP-Total, X-WP-TotalPages
access-control-allow-headers: Authorization, Content-Type
expires: Sat, 29 Jun 2019 15:56:28 GMT
x-wp-nonce: 3102092830
allow: GET, POST, PUT, PATCH, DELETE
access-control-allow-origin: https://<domain>
access-control-allow-methods: OPTIONS, GET, POST, PUT, PATCH, DELETE
access-control-allow-credentials: true
vary: Origin
strict-transport-security: max-age=31536000; includeSubDomains; preload
x-frame-options: DENY
content-security-policy: default-src 'none'; script-src 'self' 'unsafe-inline' www.gstatic.com s3.amazonaws.com www.google-analytics.com www.googletagmanager.com; object-src 'none'; style-src 'self' 'unsafe-inline' fonts.googleapis.com www.gstatic.com cdn-images.mailchimp.com; img-src 'self' data: www.google-analytics.com stats.g.doubleclick.net; media-src 'self'; frame-src www.youtube.com; font-src 'self' data: fonts.gstatic.com; connect-src 'self'; frame-ancestors 'self'; base-uri 'none'; form-action 'self'; manifest-src 'none'; worker-src 'none'; upgrade-insecure-requests; require-sri-for script style;
x-xss-protection: 1; mode=block
referrer-policy: no-referrer-when-downgrade
feature-policy: accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; usb 'none'; vibrate 'none'; vr 'none'
date: Sat, 29 Jun 2019 15:41:28 GMT
etag: W/"PSA-gF5icK_kr9"
vary: Accept-Encoding
x-original-content-length: 2668
content-encoding: gzip
content-length: 673
cache-control: max-age=900, s-maxage=10
X-Firefox-Spdy: h2

Response body:

5:41:28","date_gmt":"2019-06-29T15:41:28","guid":{"rendered":"https:\/\/<domain>\/?p=3748","raw":"https:\/\/<domain>\/?p=3748"},"modified":"2019-06-29T15:41:28","modified_gmt":"2019-06-29T15:41:28","password":"","slug":"","status":"draft","type":"post","link":"https:\/\/<domain>\/?p=3748","title":{"raw":"TEST","rendered":"TEST"},"content":{"raw":"","rendered":"","protected":false,"block_version":0},"excerpt":{"raw":"","rendered":"","protected":false},"author":8,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[],"permalink_template":"https:\/\/<domain>\/%postname%\/","generated_slug":"test","_links":{"self":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"collection":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/comments?post=3748"}],"version-history":[{"count":1,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748\/revisions"}],"predecessor-version":[{"id":3749,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748\/revisions\/3749"}],"wp:attachment":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/media?parent=3748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/categories?post=3748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/tags?post=3748"}],"wp:action-publish":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-unfiltered-html":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-sticky":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-author":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-categories":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-categories":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-tags":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-tags":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}

Now, with PS off and reloading the server:

Request headers:

Host: <domain>
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, */*;q=0.1
Accept-Language: eo,en-GB;q=0.8,en;q=0.5,ja;q=0.3
Accept-Encoding: gzip, deflate, br
X-WP-Nonce: 3102092830
X-HTTP-Method-Override: PUT
Content-Type: application/json
Origin: https://<domain>
Content-Length: 42
DNT: 1
Connection: keep-alive
Referer: https://<domain>/wp-admin/post.php
Cookie: wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_722b1833171c7650292a2e1422d6b495=sam%7C1561995621%7CLSgIgZ0n7YiVXl8w2BOdJrN84z7mRLn7hXmxby5EoE5%7C2c78f7cff7a593ca312246ce251cabe92c41a4c379d987e75541298c5ae87861; wp-settings-8=editor%3Dtinymce%26libraryContent%3Dbrowse; wp-settings-time-8=1561822822
Pragma: no-cache
Cache-Control: no-cache

Response headers:

HTTP/2.0 200 OK
date: Sat, 29 Jun 2019 15:46:35 GMT
content-type: application/json; charset=UTF-8
x-robots-tag: noindex
link: <https://<domain>/wp-json/>; rel="https://api.w.org/"
x-content-type-options: nosniff
access-control-expose-headers: X-WP-Total, X-WP-TotalPages
access-control-allow-headers: Authorization, Content-Type
expires: Sat, 29 Jun 2019 16:01:35 GMT
cache-control: max-age=900
x-wp-nonce: 3102092830
allow: GET, POST, PUT, PATCH, DELETE
access-control-allow-origin: https://<domain>
access-control-allow-methods: OPTIONS, GET, POST, PUT, PATCH, DELETE
access-control-allow-credentials: true
vary: Origin
strict-transport-security: max-age=31536000; includeSubDomains; preload
x-frame-options: DENY
content-security-policy: default-src 'none'; script-src 'self' 'unsafe-inline' www.gstatic.com s3.amazonaws.com www.google-analytics.com www.googletagmanager.com; object-src 'none'; style-src 'self' 'unsafe-inline' fonts.googleapis.com www.gstatic.com cdn-images.mailchimp.com; img-src 'self' data: www.google-analytics.com stats.g.doubleclick.net; media-src 'self'; frame-src www.youtube.com; font-src 'self' data: fonts.gstatic.com; connect-src 'self'; frame-ancestors 'self'; base-uri 'none'; form-action 'self'; manifest-src 'none'; worker-src 'none'; upgrade-insecure-requests; require-sri-for script style;
x-xss-protection: 1; mode=block
referrer-policy: no-referrer-when-downgrade
feature-policy: accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; usb 'none'; vibrate 'none'; vr 'none'
X-Firefox-Spdy: h2

Response body: {"id":3748,"date":"2019-06-29T15:46:35","date_gmt":"2019-06-29T15:46:35","guid":{"rendered":"https:\/\/<domain>\/?p=3748","raw":"https:\/\/<domain>\/?p=3748"},"modified":"2019-06-29T15:46:35","modified_gmt":"2019-06-29T15:46:35","password":"","slug":"","status":"draft","type":"post","link":"https:\/\/<domain>\/?p=3748","title":{"raw":"TESTabc","rendered":"TESTabc"},"content":{"raw":"","rendered":"","protected":false,"block_version":0},"excerpt":{"raw":"","rendered":"","protected":false},"author":8,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[],"permalink_template":"https:\/\/<domain>\/%postname%\/","generated_slug":"testabc","_links":{"self":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"collection":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/comments?post=3748"}],"version-history":[{"count":2,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748\/revisions"}],"predecessor-version":[{"id":3750,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748\/revisions\/3750"}],"wp:attachment":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/media?parent=3748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/categories?post=3748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/tags?post=3748"}],"wp:action-publish":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-unfiltered-html":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-sticky":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-author":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-categories":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-categories":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-tags":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-tags":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}

And, a second time with PS off (note that the title has been updated in the response both times).

Request headers:

Host: <domain>
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, */*;q=0.1
Accept-Language: eo,en-GB;q=0.8,en;q=0.5,ja;q=0.3
Accept-Encoding: gzip, deflate, br
X-WP-Nonce: 3102092830
X-HTTP-Method-Override: PUT
Content-Type: application/json
Origin: https://<domain>
Content-Length: 46
DNT: 1
Connection: keep-alive
Referer: https://<domain>/wp-admin/post.php
Cookie: wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_722b1833171c7650292a2e1422d6b495=sam%7C1561995621%7CLSgIgZ0n7YiVXl8w2BOdJrN84z7mRLn7hXmxby5EoE5%7C2c78f7cff7a593ca312246ce251cabe92c41a4c379d987e75541298c5ae87861; wp-settings-8=editor%3Dtinymce%26libraryContent%3Dbrowse; wp-settings-time-8=1561822822
Pragma: no-cache
Cache-Control: no-cache
TE: Trailers

Response headers:

HTTP/2.0 200 OK
date: Sat, 29 Jun 2019 15:47:50 GMT
content-type: application/json; charset=UTF-8
x-robots-tag: noindex
link: <https://<domain>/wp-json/>; rel="https://api.w.org/"
x-content-type-options: nosniff
access-control-expose-headers: X-WP-Total, X-WP-TotalPages
access-control-allow-headers: Authorization, Content-Type
expires: Sat, 29 Jun 2019 16:02:50 GMT
cache-control: max-age=900
x-wp-nonce: 3102092830
allow: GET, POST, PUT, PATCH, DELETE
access-control-allow-origin: https://<domain>
access-control-allow-methods: OPTIONS, GET, POST, PUT, PATCH, DELETE
access-control-allow-credentials: true
vary: Origin
strict-transport-security: max-age=31536000; includeSubDomains; preload
x-frame-options: DENY
content-security-policy: default-src 'none'; script-src 'self' 'unsafe-inline' www.gstatic.com s3.amazonaws.com www.google-analytics.com www.googletagmanager.com; object-src 'none'; style-src 'self' 'unsafe-inline' fonts.googleapis.com www.gstatic.com cdn-images.mailchimp.com; img-src 'self' data: www.google-analytics.com stats.g.doubleclick.net; media-src 'self'; frame-src www.youtube.com; font-src 'self' data: fonts.gstatic.com; connect-src 'self'; frame-ancestors 'self'; base-uri 'none'; form-action 'self'; manifest-src 'none'; worker-src 'none'; upgrade-insecure-requests; require-sri-for script style;
x-xss-protection: 1; mode=block
referrer-policy: no-referrer-when-downgrade
feature-policy: accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; usb 'none'; vibrate 'none'; vr 'none'
X-Firefox-Spdy: h2

Response body: {"id":3748,"date":"2019-06-29T15:47:50","date_gmt":"2019-06-29T15:47:50","guid":{"rendered":"https:\/\/<domain>\/?p=3748","raw":"https:\/\/<domain>\/?p=3748"},"modified":"2019-06-29T15:47:50","modified_gmt":"2019-06-29T15:47:50","password":"","slug":"","status":"draft","type":"post","link":"https:\/\/<domain>\/?p=3748","title":{"raw":"TESTanother","rendered":"TESTanother"},"content":{"raw":"","rendered":"","protected":false,"block_version":0},"excerpt":{"raw":"","rendered":"","protected":false},"author":8,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[],"permalink_template":"https:\/\/<domain>\/%postname%\/","generated_slug":"testanother","_links":{"self":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"collection":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/comments?post=3748"}],"version-history":[{"count":3,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748\/revisions"}],"predecessor-version":[{"id":3751,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748\/revisions\/3751"}],"wp:attachment":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/media?parent=3748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/categories?post=3748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/tags?post=3748"}],"wp:action-publish":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-unfiltered-html":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-sticky":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-author":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-categories":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-categories":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-create-tags":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"wp:action-assign-tags":[{"href":"https:\/\/<domain>\/wp-json\/wp\/v2\/posts\/3748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}

oschaaf commented 5 years ago

To be honest, I still don’t think ngx_pagespeed has a bug here. But I’ll double check. what strikes me is that that the responses you post show cache-control headers that express an actual desire for the behavior you observe. Granted, it’s sursprising it works, because most software I know of will ignore that considering the responses are associated to a POST request.

Dreamsorcerer commented 5 years ago

The thing that looks suspicious to me is the extra headers (e.g. etag) on the 2nd Pagespeed response, suggesting some kind of additional caching going on there.

jmarantz commented 5 years ago

I may not be remembering the details well, but I think PageSpeed might not realize the response is from a POST request, but it sees cache-control:max-age=900 and content-type:json and tries to optimize it in-place. Actually I'm not even remembering if PageSpeed tries to use its javascript-minification code to shrink JSON or not, or if that's fully legal, but I'm just throwing out theories.

And I haven't looked at your output enough to know what exactly is breaking there, but I would definitely recommend that your origin POST handlers avoid sending cache-control:max-age=900. They should probably send cache-control:nostore.

Dreamsorcerer commented 5 years ago

Yeah, but I think it would be difficult to tweak the nginx config to ignore POST requests. The current config block is:

    map $sent_http_content_type $expires {
        default         15m;
        ~*text/css      1M;
        ~*application/javascript    1M;
        ~*text/x-component  1M;
        ~*audio/.*      1M;
        ~*video/.*      1M;
        ~*image/.*      6M;
        ~*font/.*       1y;
    }
    expires $expires;
oschaaf commented 5 years ago

I haven't got around to seeing if I can reproduce it yet; but you could try disallowing affected url paths to see if that resolves the caching you experienced: https://www.modpagespeed.com/doc/restricting_urls#disallow

Regardless, it may be difficult, but there definitely is wisdom in @jmarantz reply. Because what we learned here is that when sending these cache-control headers in response to POST requests, one risks that something on the internet may listen to them. And cache the response. That could cause hard to debug issues with a select amount of unfortunate site-visitors, even though you can no longer observe it with the current setup.

Dreamsorcerer commented 5 years ago

Yep, looks like disallow works, and I've also figured out nginx config to not add cache headers to POST requests, which also works. So, it must be that Pagespeed is responding to the cache headers and caching them on the server.

    map "$request_method:$sent_http_content_type" $expires {
        default         15m;
        ~*(POST|PUT):.*     off;
        ~*.*:text/css       1M;
        ~*.*:application/javascript 1M;
        ~*.*:text/x-component   1M;
        ~*.*:audio/.*       1M;
        ~*.*:video/.*       1M;
        ~*.*:image/.*       6M;
        ~*.*:font/.*        1y;
    }
    expires $expires;