title: Caching reverse proxy for dynamic content
body: <p>I was thinking about asking on <a href="https://softwarerecs.stackexchange.com/questions/ask">Software Recommendations</a>, but then I've found out that it may be a too strange request and it needs some clarification first.</p>
  
  <p>My points are:</p>
  
  <ul>
  <li>Each response contains an <code>etag</code>
  
  <ul>
  <li>which is a hash of the content</li>
  <li>and which is globally unique (with sufficient probability)</li>
  </ul></li>
  <li>The content is (mostly) dynamic and may change anytime (<code>expires</code> and <code>max-age</code> headers are useless here).</li>
  <li>The content is <em>partly</em> user-dependent, as given by the permissions (which itself change sometimes).</li>
  </ul>
  
  <p>Basically, the proxy should contain a cache mapping the <code>etag</code> to the response content. The <code>etag</code> gets obtained from the server and in the most common case, the server does not deal with the response content at all.</p>
  
  <p>It should go like follows: The proxy <em>always</em> sends a request to the server and then either</p>
  
  <ul>
  <li><strong>1</strong> the server returns only the <code>etag</code> and the proxy makes a lookup based on it and
  
  <ul>
  <li><strong>1.1</strong> on cache hit,
  
  <ul>
  <li>it reads the response data from cache</li>
  <li>and sends a response to the client</li>
  </ul></li>
  <li><strong>1.2</strong> on cache miss,
  
  <ul>
  <li>it asks the server again and then</li>
  <li>the server returns the response with content and <code>etag</code>,</li>
  <li>the proxy stores it in its cache</li>
  <li>and sends a response to the client</li>
  </ul></li>
  </ul></li>
  <li><strong>2</strong> or the server returns the response with content and <code>etag</code>,
  
  <ul>
  <li>the proxy stores the data in its cache</li>
  <li>and sends a response to the client</li>
  </ul></li>
  </ul>
  
  <p>For simplicity, I left out the handling of the <code>if-none-match</code> header, which is rather obvious.</p>
  
  <p>My reason for this is that the most common case 1.1 can be implemented very efficiently in the server (using its cache mapping requests to <code>etags</code>; the content isn't cached in the server), so that most requests can be handled without the server dealing with the response content. This should be better than first getting the content from a side cache and then serving it.</p>
  
  <p>In case 1.2, there are two requests to the server, which sounds bad, but is no worse than the server asking a side cache and getting a miss.</p>
  
  <p><strong>Q1:</strong> I wonder, how to map the first request to HTTP. In case 1, it's like a HEAD request. In case 2, it's like GET. The decision between the two is up to the server: If it can serve the <code>etag</code> without computing the content, then it's case 1, otherwise, it's case 2.</p>
  
  <p><strong>Q2:</strong> Is there a reverse proxy doing something like this? I've read about nginx, HAProxy and Varnish and it doesn't seem to be the case. This leads me to <strong>Q3:</strong> Is this a bad idea? Why?</p>
  
  <p><strong>Q4:</strong> If not, then which existing proxy is easiest to adapt?</p>
  
  <h1>An Example</h1>
  
  <p>A GET request like <code>/catalog/123/item/456</code> from user <code>U1</code> was served with some content <code>C1</code> and <code>etag: 777777</code>. The proxy stored <code>C1</code> under the key <code>777777</code>.</p>
  
  <p>Now the same request comes from user <code>U2</code>. The proxy forwards it, the server returns just <code>etag: 777777</code> and the proxy is lucky, finds <code>C1</code> in its cache (case <strong>1.1</strong>) and sends it to <code>U2</code>. <em>In this example, neither the clients not the proxy knew the expected result.</em></p>
  
  <p>The interesting part is how could the server know the <code>etag</code> without computing the answer. For example, it can have a rule stating that requests of this form return the same result for all users, assuming that the given user is allowed to see it. So when the request from <code>U1</code> came, it computed <code>C1</code> and stored the <code>etag</code> under the key <code>/catalog/123/item/456</code>. When the same request came from <code>U2</code>, it just verified that <code>U2</code> is permitted to see the result.</p>