Accept-Encoding:gzip and Content-Encoding:gzip - http-headers

What is the difference between the two HTTP headers?
Accept-Encoding:gzip
Content-Encoding:gzip

Accept-Encoding:
It is a request header. The HTTP client uses this header to tell the server which encoding(s) it supports. The server is allowed to send the response content in any of these encodings.
From MDN
The Accept-Encoding request HTTP header advertises which content encoding, usually a compression algorithm, the client is able to understand. Using content negotiation, the server selects one of the proposals, uses it and informs the client of its choice with the Content-Encoding response header.
Content-Encoding:
It is a response header. The HTTP server uses this header to tell the client which particular encoding the content has actually been encoded in.
From MDN
The Content-Encoding entity header is used to compress the media-type. When present, its value indicates which encodings were applied to the entity-body. It lets the client know, how to decode in order to obtain the media-type referenced by the Content-Type header.
If you want to see them play in action, open Inspect Element in Firefox / Chrome, then check for the Network tab to see them in action. Look for Accept-Encoding in request headers and Content-Encoding in response headers.

Accept-Encoding
To paraphrase IETF internet standard RFC-7231, the Accept-Encoding request header field can be used by user agents to make requests that indicate what response content-codings are acceptable in the response.
The Accept-Encoding header can be quite complex, e.g.
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.4
Content-Encoding
The Content-Encoding response header field indicates what content codings have been applied to the response representation. Content-Encoding is primarily used to allow the response entity to be compressed without losing the identity of its underlying media type.
The Content-Encoding value is simple and should be accompanied by a "Vary" header, e.g.
Content-Encoding: gzip
Vary: Accept-Encoding
https://datatracker.ietf.org/doc/html/rfc7231#section-3.1.2.2

Related

Vary: Accept-Encoding Response Header

I am trying to understand the response Header "Vary: Accept-Encoding".
I am noticing the response header "Vary: Accept-Encoding" appears for some of the images in the developer tools for our application, but some images doesn't have this response header.
When i tried to hit same image url in the browser, not seeing this header "Vary: Accept-Encoding".
Why this header appears only for selected images in our application? What could be possibilities?
Either Tomcat or the application could be returning this header. If Tomcat is applying e.g. gzip encoding, then it's essential to respond with a Vary: Accept-Encoding because if the client doesn't specify that it supports gzip then the origin server (web server), a proxy, etc. must respond with a different type of data.
If the client requests /myapp/something and advertises that it is willing to accept only responses with encoding gzip, then /myapp/something should really only return a response in the identity or gzip encodings, or reply with a 412 response.
The Vary header is really for proxies. It tells a proxy that clients on the other side might get a different response if they have different Accept-Encoding values in their request headers. So, if two clients request the same resource, but one says Accept-Encoding: identity,gzip and the other says Accept-Encoding: identity,compress, they will (likely) get two responses, and the proxy should understand that it's not just the URL that is important, but also the Accept-Encoding of the client that should govern any caching that the proxy might want to provide.

How can I display multiple Content-Type in a HTTP response message?

In a socket programming, I must display multiple Content-Types.
ex)
Content-Type : text/html, text/css, text/javascript, image/png
However, this code doesn't work.
How can I display multiple Content-Type in a HTTP response message?
Thank you...
Content-Type means should be only one type based on the requester's Accept parameter of a default content type you may specify, however if your client is interested in a specific type, it should send the type he wants in Accept request header and you should respond back with the requested content type.
requester may send multiple types through to say for example
Accept: application/json
Accept: text/html
which means the requester can understand both types. If server can serve and respond back in json format otherwise it should response back with text/html
More info on Content-Type header and other HTTP specs, please check this

How to add "Vary: Accept-Encoding" header in yaws to cacheable files

I was testing my website for optimization and I got this recommendation:
The following publicly cacheable, compressible resources should have a "Vary: Accept-Encoding" header:
So, How do I add Vary: Accept-Encoding header using an embedded yaws to css and js files?
I am an arg_rewrite_mod I believe I should do something from there but i am not quite sure how.
According to the yaws.hyber.org:
Yaws will add Accept-Encoding in Vary header if the support of gzip compression is enabled or if the response is compressed.
The Vary header can be set using yaws:outh_set_vary(Fields) or by returning {header, {vary, Fields}} from scripts (where Fields is a list of header names).

IIS 7 Dynamic Compression is not consistently compressing responses

I have got Dynamic Compression enabled on IIS for all content types.
Requests to my WCF service are sending the following header:
Accept-Encoding: gzip, deflate
And responses from IIS are nearly always being compressed and show the following content in the header:
Content-Type: application/soap+xml; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
However, when the response to a request is large e.g. 14Mb, I'm finding that the the request is not being compressed. The request header includes the accept-encoding statement and the content type is the same, however, the response does not include the content-encoding or vary headers.
Is there a limit to the size of IIS request that can be compressed? My application is working correctly but performing slowly when the responses are big as a result of this problem.

Why browser does not send "If-None-Match" header?

I'm trying to download (and hopefully cache) a dynamically loaded image in PHP. Here are the headers sent and received:
Request:
GET /url:resource/Pomegranate/resources/images/logo.png HTTP/1.1
Host: pome.local
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: PHPSESSID=fb8ghv9ti6v5s3ekkmvtacr9u5
Response:
HTTP/1.1 200 OK
Date: Tue, 09 Apr 2013 11:00:36 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.14 ZendServer/5.0
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Disposition: inline; filename="logo"
ETag: "1355829295"
Last-Modified: Tue, 18 Dec 2012 14:44:55 Asia/Tehran
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: image/png
When I reload the URL, the exact same headers are sent and received. My question is what should I send in my response to see the If-None-Match header in the consequent request?
NOTE: I believe these headers were doing just fine not long ago, even though I can not be sure but I think browsers are changed not to sent the If-None-Match header anymore (I used to see that header). I'm testing with Chrome and Firefox and both fail to send the header.
Same Problem, Similar Solution
I've been trying to determine why Google Chrome won't send If-None-Match headers when visiting a site that I am developing. (Chrome 46.0.2490.71 m, though I'm not sure how relevant the version is.)
This is a different — though very similar — answer than the OP ultimately cited (in a comment regarding the Accepted Answer), but it addresses the same problem:
The browser does not send the If-None-Match header in subsequent requests "when it should" (i.e., server-side logic, via PHP or similar, has been used to send an ETag or Last-Modified header in the first response).
Prerequisites
Using a self-signed TLS certificate, which turns the lock red in Chrome, changes Chrome's caching behavior. Before attempting to troubleshoot an issue of this nature, install the self-signed certificate in the effective Trusted Root Store, and completely restart the browser, as explained at https://stackoverflow.com/a/19102293 .
1st Epiphany: If-None-Match requires an ETag from the server, first
I came to realize rather quickly that Chrome (and probably most or all other browsers) won't send an If-None-Match header until the server has already sent an ETag header in response to a previous request. Logically, this makes perfect sense; after all, how could Chrome send If-None-Match when it's never been given the value?
This lead me to look at my server-side logic — particularly, how headers are sent when I want the user-agent to cache the response — in an effort to determine for what reason the ETag header is not being sent in response to Chrome's very first request for the resource. I had made a calculated effort to include the ETag header in my application logic.
I happen to be using PHP, so #Mehran's (the OP's) comment jumped-out at me (he/she says that calling header_remove() before sending the desired cache-related headers solves the problem).
Candidly, I was skeptical about this solution, because a) I was pretty sure that PHP wouldn't send any headers of its own by default (and it doesn't, given my configuration); and b) when I called var_dump(headers_list()); just before setting my custom caching headers in PHP, the only header set was one that I was setting intentionally just above:
header('Content-type: application/javascript; charset=utf-8');
So, having nothing to lose, I tried calling header_remove(); just before sending my custom headers. And much to my surprise, PHP began sending the ETag header all of a sudden!
2nd Epiphany: gzipping the response changes its hash
It then me hit me like a bag of bricks: by specifying the Content-type header in PHP, I was telling NGINX (the webserver I'm using) to GZIP the response once PHP hands it back to NGINX! To be clear, the Content-type that I was specifying was on NGINX's list of types to gzip.
For thoroughness, my NGINX GZIP settings are as follows, and PHP is wired-up to NGINX via php-fpm:
gzip on;
gzip_min_length 1;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
gzip_vary on;
I pondered why NGINX might remove the ETag that I had sent in PHP when a "gzippable" content-type is specified, and came up with a now-obvious answer: because NGINX modifies the response body that PHP passes back when NGINX gzips it! This makes perfect sense; there is no point in sending the ETag when it's not going to match the response used to generate it. It's pretty slick that NGINX handles this scenario so intelligently.
I don't know if NGINX has always been smart enough not to compress response bodies that are uncompressed but contain ETag headers, but that seems to be what's happening here.
UPDATE: I found commentary that explains NGINX's behavior in this regard, which in turn cites two valuable discussions regarding this subject:
NGINX forum thread discussing the behavior.
Tangentially-related discussion in a project repository; see the comment Posted on Jun 15, 2013 by Massive Bird.
In the interest of preserving this valuable explanation, should it happen to disappear, I quote from Massive Bird's contribution to the discussion:
Nginx strips the Etag when gzipping a response on the fly. This is
according to spec, as the non-gzipped response is not byte-for-byte
comparable to the gzipped response.
However, NGINX's behavior in this regard might be considered slightly flawed in that the same spec
... also says there is a thing called weak Etags (an Etag value
prefixed with W/), and tells us it can be used to check if a response
is semantically equivalent. In that case, Nginx should not mess with
it. Unfortunately, that check never made it into the source tree [citation is now filled with spam, sadly]."
I'm unsure as to NGINX's current disposition in this regard, and specifically, whether or not it has added support for "weak" Etags.
So, What's the Solution?
So, what's the solution to getting ETag back into the response? Do the gzipping in PHP, so that NGINX sees that the response is already compressed, and simply passes it along while leaving the ETag header intact:
ob_start('ob_gzhandler');
Once I added this call prior to sending the headers and the response body, PHP began sending the ETag value with every response. Yes!
Other Lessons Learned
Here are some interesting tidbits gleaned from my research. This information is rather handy when attempting to test a server-side caching implementation, whether in PHP or another language.
Chrome, and its Developer Tools "Net" panel, behave differently depending on how the request is initiated.
If the request is "made fresh", e.g., by pressing Ctrl+F5, Chrome sends these headers:
Cache-Control: no-cache
Pragma: no-cache
and the server responds 200 OK.
If the request is made with only F5, Chrome sends these headers:
Pragma: no-cache
and the server responds 304 Not Modified.
Lastly, if the request is made by clicking on a link to the page you're already viewing, or placing focus into Chrome's address bar and pressing Enter, Chrome sends these headers:
Cache-Control: no-cache
Pragma: no-cache
and the server responds 200 OK (from cache).
While this behavior a bit confusing at first, if you don't know how it works, it's ideal behavior, because it allows one to test every possible request/response scenario very thoroughly.
Perhaps most confusing is that Chrome automatically inserts the Cache-Control: no-cache and Pragma: no-cache headers in the outgoing request when in fact Chrome is acquiring the responses from its cache (as evidenced in the 200 OK (from cache) response).
This experience was rather informative for me, and I hope others find this analysis of value in the future.
Your response headers include Cache-Control: no-store, no-cache; these prevent caching.
Remove those values (I think must-revalidate, post-check=0, pre-check=0 could/should be kept – they tell the browser to check with the server if there was a change).
And I would stick with Last-Modified alone (if the changes to your resources can be detected using this criterion alone) – ETag is a more complicated thing to handle (especially if you want to deal with it in your PHP script yourself), and Google PageSpeed/YSlow advise against this one too.
Posting this for future me...
I was having a similar problem, I was sending ETag in the response, but the HTTP client wasn't sending a If-None-Match header in subsequent requests (which was strange because it was the day before).
Turns out I was using http://localhost:9000 for development (which didn't use If-None-Match) - by switching to http://127.0.0.1:9000 Chrome1 automatically started sending the If-None-Match header in requests again.
Additionally - ensure Devtools > Network > Disable Cache [ ] is unchecked.
Chrome: Version 71.0.3578.98 (Official Build) (64-bit)
1 I can't find anywhere this is documented - I'm assuming Chrome was responsible for this logic.
Similar problem
I was trying to obtain Conditional GET request with If-None-Match header, having supplied proper Etag header, but to no avail in any browser I tried.
After a lot of trial I realize that browsers treat both GET and POST to the same path as a same cache candidate. Thus having GET with proper Etag was effectively canceled with immediate "POST" to the same path with Cache-Control:"no-cache, private", even though it was supplied by X-Requested-With:"XMLHttpRequest".
Hope this might be helpful to someone.
This was happening to me because I had set the cache size to be too small (via Group Policy).
It didn't happen in Incognito, which is what made me realize this might be the case.
Fixing that resolved the issue.
This happened to me due to 2 reasons:
My server didn't send etag response header. I updated my jetty web.xml to return etag by adding the following:
<init-param>
<param-name>etags</param-name>
<param-value>true</param-value>
</init-param>
The URL I called was for xml file. When I changed it to html file, chrome started sending "if-none-match" header!
I hope it helps someone