MINOR: http: add a function to check request's cache-control header field
The new function check_request_for_cacheability() is used to check if
a request may be served from the cache, and/or allows the response to
be stored into the cache. For this it checks the cache-control and
pragma header fields, and adjusts the existing TX_CACHEABLE and a new
TX_CACHE_IGNORE flags.
For now, just like its response side counterpart, it only checks the
first value of the header field. These functions should be reworked to
improve their parsers and validate all elements.
diff --git a/src/proto_http.c b/src/proto_http.c
index 701ced4..f585dee 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -7680,6 +7680,95 @@
/*
+ * Parses the Cache-Control and Pragma request header fields to determine if
+ * the request may be served from the cache and/or if it is cacheable. Updates
+ * s->txn->flags.
+ */
+void check_request_for_cacheability(struct stream *s, struct channel *chn)
+{
+ struct http_txn *txn = s->txn;
+ char *p1, *p2;
+ char *cur_ptr, *cur_end, *cur_next;
+ int pragma_found;
+ int cc_found;
+ int cur_idx;
+
+ if ((txn->flags & (TX_CACHEABLE|TX_CACHE_IGNORE)) == TX_CACHE_IGNORE)
+ return; /* nothing more to do here */
+
+ cur_idx = 0;
+ pragma_found = cc_found = 0;
+ cur_next = chn->buf->p + hdr_idx_first_pos(&txn->hdr_idx);
+
+ while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
+ struct hdr_idx_elem *cur_hdr;
+ int val;
+
+ cur_hdr = &txn->hdr_idx.v[cur_idx];
+ cur_ptr = cur_next;
+ cur_end = cur_ptr + cur_hdr->len;
+ cur_next = cur_end + cur_hdr->cr + 1;
+
+ /* We have one full header between cur_ptr and cur_end, and the
+ * next header starts at cur_next.
+ */
+
+ val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
+ if (val) {
+ if ((cur_end - (cur_ptr + val) >= 8) &&
+ strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
+ pragma_found = 1;
+ continue;
+ }
+ }
+
+ val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
+ if (!val)
+ continue;
+
+ /* OK, right now we know we have a cache-control header at cur_ptr */
+ cc_found = 1;
+ p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
+
+ if (p1 >= cur_end) /* no more info */
+ continue;
+
+ /* p1 is at the beginning of the value */
+ p2 = p1;
+ while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
+ p2++;
+
+ /* we have a complete value between p1 and p2. We don't check the
+ * values after max-age, max-stale nor min-fresh, we simply don't
+ * use the cache when they're specified.
+ */
+ if (((p2 - p1 == 7) && strncasecmp(p1, "max-age", 7) == 0) ||
+ ((p2 - p1 == 8) && strncasecmp(p1, "no-cache", 8) == 0) ||
+ ((p2 - p1 == 9) && strncasecmp(p1, "max-stale", 9) == 0) ||
+ ((p2 - p1 == 9) && strncasecmp(p1, "min-fresh", 9) == 0)) {
+ txn->flags |= TX_CACHE_IGNORE;
+ continue;
+ }
+
+ if ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) {
+ txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
+ continue;
+ }
+ }
+
+ /* RFC7234#5.4:
+ * When the Cache-Control header field is also present and
+ * understood in a request, Pragma is ignored.
+ * When the Cache-Control header field is not present in a
+ * request, caches MUST consider the no-cache request
+ * pragma-directive as having the same effect as if
+ * "Cache-Control: no-cache" were present.
+ */
+ if (!cc_found && pragma_found)
+ txn->flags |= TX_CACHE_IGNORE;
+}
+
+/*
* Check if response is cacheable or not. Updates s->txn->flags.
*/
void check_response_for_cacheability(struct stream *s, struct channel *rtr)