{"id":12861,"date":"2019-12-06T07:45:28","date_gmt":"2019-12-06T06:45:28","guid":{"rendered":"https:\/\/daniel.haxx.se\/blog\/?p=12861"},"modified":"2019-12-06T07:45:28","modified_gmt":"2019-12-06T06:45:28","slug":"curl-speaks-etag","status":"publish","type":"post","link":"https:\/\/daniel.haxx.se\/blog\/2019\/12\/06\/curl-speaks-etag\/","title":{"rendered":"curl speaks etag"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>The <strong><code>ETag<\/code><\/strong> HTTP response header is an  identifier for a specific version of a resource. It lets caches be more  efficient and save bandwidth, as a web server does not need to resend a  full response if the content has not changed. Additionally, etags help  prevent simultaneous updates of a resource from overwriting each other (<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/ETag#Caching_of_unchanged_resources\">&#8220;mid-air collisions&#8221;<\/a>).<\/p><\/blockquote>\n\n\n\n<p>That&#8217;s a quote from the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/ETag\">mozilla ETag documentation<\/a>. The header is defined in <a href=\"https:\/\/tools.ietf.org\/html\/rfc7232#section-2.3\">RFC 7232<\/a>.<\/p>\n\n\n\n<p>In short, a server can include this header when it responds with a resource, and in subsequent requests when a client wants to get an updated version of that document it sends back the same ETag and says <em>&#8220;please give me a new version if it doesn&#8217;t match this ETag anymore&#8221;<\/em>. The server will then respond with a 304 if there&#8217;s nothing new to return.<\/p>\n\n\n\n<p>It is a better way than modification time stamp to identify a specific resource version on the server.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">ETag options<\/h2>\n\n\n\n<p>Starting in version 7.68.0 (due to ship on January 8th, 2020), curl will feature two new command line options that makes it easier for users to take advantage of these features. You can of course try it out already now if you build from <a href=\"https:\/\/github.com\/curl\/curl\">git<\/a> or get a <a href=\"https:\/\/curl.haxx.se\/snapshots\/\">daily snapshot<\/a>.<\/p>\n\n\n\n<p>The ETag options are perfect for situations like when you run a curl command in a cron job to update a file if it has indeed changed on the server.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>--etag-save &lt;filename&gt;<\/code> <\/h3>\n\n\n\n<p>Issue the curl command and if there&#8217;s an ETag coming back in the response, it gets saved in the given file.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>--etag-compare &lt;filename&gt;<\/code> <\/h3>\n\n\n\n<p>Load a previously stored ETag from the given file and include that in the outgoing request (the file should only consist of the specific ETag &#8220;value&#8221; and nothing else). If the server deems that the resource hasn&#8217;t changed, this will result in a 304 response code. If it has changed, the new content will be returned.<\/p>\n\n\n\n<p>Update the file if newer than previously stored ETag:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">curl --etag-compare etag.txt --etag-save etag.txt https:\/\/example.com -o saved-file<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">If-Modified-Since options<\/h2>\n\n\n\n<p>The other method to accomplish something similar is the<a href=\"https:\/\/curl.haxx.se\/docs\/manpage.html#-z\"> -z<\/a> (or <code>--time-cond<\/code>) option. It has been supported by curl since the early days. Using this, you give curl a specific time that will be used in a conditional request. &#8220;only respond with content if the document is newer than this&#8221;:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">curl -z \"5 dec 2019\" https:\/example.com<\/pre>\n\n\n\n<p>You can also do the inversion of the condition and ask for the file to get delivered only if it is older than a certain time (by prefixing the date with a dash):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">curl -z \"-1 jan 2003\" https:\/\/example.com<\/pre>\n\n\n\n<p>Perhaps this is most conveniently used when you let curl get the time from a file. Typically you&#8217;d use the same file that you&#8217;ve saved from a previous invocation and now you want to update if the file is newer on the remote site:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">curl -z saved-file -o saved-file https:\/\/example.com<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Tool, not libcurl<\/h2>\n\n\n\n<p>It could be noted that these new features are built entirely in the curl tool by using libcurl correctly with the already provided API, so this change is done entirely outside of the library.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Credits<\/h2>\n\n\n\n<p><a href=\"https:\/\/github.com\/curl\/curl\/issues\/4277\">The idea<\/a> for the ETag goodness came from Paul Hoffman. <a href=\"https:\/\/github.com\/curl\/curl\/pull\/4543\">The implementation<\/a> was brought by Maros Priputen &#8211; as his first contribution to curl! Thanks!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The ETag HTTP response header is an identifier for a specific version of a resource. It lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed. Additionally, etags help prevent simultaneous updates of a resource from overwriting each other &hellip; <a href=\"https:\/\/daniel.haxx.se\/blog\/2019\/12\/06\/curl-speaks-etag\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">curl speaks etag<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":5,"featured_media":12136,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[33,230],"class_list":["post-12861","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-curl","tag-curl-and-libcurl","tag-http"],"_links":{"self":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/12861","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/comments?post=12861"}],"version-history":[{"count":20,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/12861\/revisions"}],"predecessor-version":[{"id":12916,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/12861\/revisions\/12916"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media\/12136"}],"wp:attachment":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media?parent=12861"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/categories?post=12861"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/tags?post=12861"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}