title: How to pass data (header?) through in Varnish 4.0
body: <p>I'm using <code>devicedetect.vcl</code> to send the <code>X-UA-Device</code> header to my app, so it knows which layout to render. The possible values that varnish will set for this header are <code>mobile</code> or <code>desktop</code>.</p>
  
  <p>On the way out, this header gets transformed to <code>Vary: User-Agent</code>.</p>
  
  <p>Now, as a separate, isolated project, I need to set another header on the <code>resp</code> object (which gets sent to our Golang proxy before it gets sent to the client). This header will be called <code>X-Analytics-Device</code> and will have the possible values of <code>bot</code>, <code>mobile</code>, <code>tablet</code>, or <code>desktop</code>.</p>
  
  <p>The backend server does <strong>not</strong> need to do anything with <code>X-Analytics-Device</code>. Only our Go proxy will parse and then remove this header before sending it to the client.</p>
  
  <p>The problem is, I need to set the <code>X-Analytics-Device</code> header based on the results of the subroutine <code>call devicedetect;</code>, which is in <code>vcl_recv</code>. I need to ultimately set it on <code>resp</code> which is in <code>vcl_deliver</code>, and I need to know the best way to pass the data.</p>
  
  <p>The only real way I can think of that might work (based on my limited understanding of Varnish), is that I need to set some other header, and access it later.</p>
  
  <p>Perhaps something like this (I left out <code>bot</code> for now):</p>
  
  <pre><code>if (req.http.X-UA-Device ~ "^mobile") {
    set req.http.X-UA-Device        = "mobile";
    set req.http.X-Analytics-Device = "mobile";
  
  } elseif (req.http.X-UA-Device ~ "^tablet") {
    set req.http.X-UA-Device        = "desktop";
    set req.http.X-Analytics-Device = "tablet";
  
  } else {
    set req.http.X-UA-Device        = "desktop";
    set req.http.X-Analytics-Device = "desktop";
  }
  </code></pre>
  
  <p>After this... I don't know. Do I need to set it like this in <code>vcl_deliver</code>?</p>
  
  <pre><code>set resp.http.X-Analytics-Device = req.http.X-Analytics-Device;
  </code></pre>
  
  <p>How does it get passed from the <code>resp</code> to the <code>req</code>? What happens if it's a hit or a miss? Does that matter? Is this going to try to cache this header in varnish (which it shouldnt be, obviously)?</p>
  
  <p>My main fear with doing it this way is that there are so many moving pieces I just don't know the best way.</p>
  
  <p>The end result is that... EVERY request needs to check the device, and on the way out it needs to set the header, without that value being cached along with the data in varnish, and while it doesnt hurt to send it to the backend, its not needed.</p>
  
  <p>Here's my full VCL, before I added the pseudo-code lines above.</p>
  
  <pre><code>vcl 4.0;
  
  backend default {
    .host = "127.0.0.1";
    .port = "8080";
  }
  
  import std;
  
  include "purge.vcl";
  include "devicedetect.vcl";
  
  acl purge {
    "localhost";
    "127.0.0.1";
    "10.0.0.0"/8;
  }
  
  sub vcl_recv {
    call devicedetect;
    if (req.http.X-UA-Device ~ "^mobile") {
      set req.http.X-UA-Device = "mobile";
    } else {
      set req.http.X-UA-Device = "desktop";
    }
  
    if (req.restarts == 0) {
      if (req.http.X-Forwarded-For) {
        set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
      } else {
        set req.http.X-Forwarded-For = client.ip;
      }
    }
  
    if (req.method !~ "^(GET|HEAD|PUT|POST|OPTIONS|DELETE)$") {
      return (synth(405));
    }
  
    # never cache anything except GET/HEAD
    if (req.method != "GET" &amp;&amp; req.method != "HEAD") {
      return (pass);
    }
  
    # don't cache images or assets
    if (req.url ~ "\.(js|css|jpg|jpeg|png|gif|ico|tiff|tif|bmp|svg)$") {
      return (pass);
    }
  
    # fix up the request
    unset req.http.cookie;
    return (hash);
  }
  
  sub vcl_backend_response {
    set beresp.do_stream = false;
  
    # device detect
    if (bereq.http.X-UA-Device) {
      if (!beresp.http.Vary) { # no Vary at all
        set beresp.http.Vary = "X-UA-Device";
      } elseif (beresp.http.Vary !~ "X-UA-Device") { # add to existing Vary
        set beresp.http.Vary = beresp.http.Vary + ", X-UA-Device";
      }
    }
  
    # bypass cache for files &gt; 5 MB
    if (std.integer(beresp.http.Content-Length, 0) &gt; 5242880) {
      set beresp.uncacheable = true;
      set beresp.ttl = 120s;
      return (deliver);
    }
  
    # catch obvious reasons we can't cache
    if (beresp.http.Set-Cookie) {
      set beresp.ttl = 0s;
    }
  
    # avoid caching error responses (1m grace period)
    if (beresp.status &gt;= 500) {
      set beresp.ttl = 1m;
      return (deliver);
    }
  
    # set times
    set beresp.ttl = 24h;
    set beresp.grace = 4h;
    return (deliver);
  }
  
  sub vcl_deliver {
    # device detect
    if ((req.http.X-UA-Device) &amp;&amp; (resp.http.Vary)) {
      set resp.http.Vary = regsub(resp.http.Vary, "X-UA-Device", "User-Agent");
    }
  
    # remove junk headers
    unset resp.http.Server;
    unset resp.http.Via;
    unset resp.http.X-Powered-By;
    unset resp.http.X-Runtime;
    unset resp.http.X-Varnish;
  
    if (obj.hits &gt; 0) {
      set resp.http.X-Cache = "HIT";
    } else {
      set resp.http.X-Cache = "MISS";
    }
  }
  </code></pre>