Hi there,

Please find in attachement a couple of patches to allow caching responses
to OPTIONS requests, used in CORS pattern.
In modern API where CORS is applied, there may be a bunch of OPTIONS
requests coming in to the API servers, so caching these responses will
improve API response time and lower the load on the servers.
Given that HAProxy does not yet support the Vary header, this means this
feature is useful in a single case, when the server send the following
header "set access-control-allow-origin: *".

William, can you check if my patches look correct, or if this is totally
wrong and then I'll open an issue on github for tracking this one.

Baptiste
From b1ed59901522dc32fa112e77c93c9a723ecc2189 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Wed, 7 Aug 2019 12:24:36 +0200
Subject: [PATCH 2/2] MINOR: http: allow caching of OPTIONS request

Allow HAProxy to cache responses to OPTIONS HTTP requests.
This is useful in the use case of "Cross-Origin Resource Sharing" (cors)
to cache CORS responses from API servers.

Since HAProxy does not support Vary header for now, this would be only
useful for "access-control-allow-origin: *" use case.
---
 src/cache.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/cache.c b/src/cache.c
index 5b4062384..001532651 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -560,8 +560,8 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
 	if (!(txn->req.flags & HTTP_MSGF_VER_11))
 		goto out;
 
-	/* cache only GET method */
-	if (txn->meth != HTTP_METH_GET)
+	/* cache only GET or OPTIONS method */
+	if (txn->meth != HTTP_METH_GET && txn->meth != HTTP_METH_OPTIONS)
 		goto out;
 
 	/* cache key was not computed */
@@ -1058,6 +1058,9 @@ int sha1_hosturi(struct stream *s)
 	ctx.blk = NULL;
 
 	switch (txn->meth) {
+	case HTTP_METH_OPTIONS:
+		chunk_memcat(trash, "OPTIONS", 7);
+		break;
 	case HTTP_METH_HEAD:
 	case HTTP_METH_GET:
 		chunk_memcat(trash, "GET", 3);
@@ -1093,10 +1096,10 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
 	struct cache_flt_conf *cconf = rule->arg.act.p[0];
 	struct cache *cache = cconf->c.cache;
 
-	/* Ignore cache for HTTP/1.0 requests and for requests other than GET
-	 * and HEAD */
+	/* Ignore cache for HTTP/1.0 requests and for requests other than GET,
+	 * HEAD and OPTIONS */
 	if (!(txn->req.flags & HTTP_MSGF_VER_11) ||
-	    (txn->meth != HTTP_METH_GET && txn->meth != HTTP_METH_HEAD))
+	    (txn->meth != HTTP_METH_GET && txn->meth != HTTP_METH_HEAD && txn->meth != HTTP_METH_OPTIONS))
 		txn->flags |= TX_CACHE_IGNORE;
 
 	http_check_request_for_cacheability(s, &s->req);
-- 
2.17.1

From e3aee8fe302e108e2652842f537dc850978d2e59 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Mon, 5 Aug 2019 16:55:32 +0200
Subject: [PATCH 1/2] MINOR: http: add method to cache hash

Current HTTP cache hash contains only the Host header and the url path.
That said, request method should also be added to the mix to support
caching other request methods on the same URL. IE GET and OPTIONS.
---
 src/cache.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/cache.c b/src/cache.c
index 9cef0cab6..5b4062384 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -1041,9 +1041,9 @@ enum act_parse_ret parse_cache_store(const char **args, int *orig_arg, struct pr
 	return ACT_RET_PRS_OK;
 }
 
-/* This produces a sha1 hash of the concatenation of the first
- * occurrence of the Host header followed by the path component if it
- * begins with a slash ('/'). */
+/* This produces a sha1 hash of the concatenation of the HTTP method,
+ * the first occurrence of the Host header followed by the path component
+ * if it begins with a slash ('/'). */
 int sha1_hosturi(struct stream *s)
 {
 	struct http_txn *txn = s->txn;
@@ -1056,6 +1056,16 @@ int sha1_hosturi(struct stream *s)
 
 	trash = get_trash_chunk();
 	ctx.blk = NULL;
+
+	switch (txn->meth) {
+	case HTTP_METH_HEAD:
+	case HTTP_METH_GET:
+		chunk_memcat(trash, "GET", 3);
+		break;
+	default:
+		return 0;
+	}
+
 	if (!http_find_header(htx, ist("Host"), &ctx, 0))
 		return 0;
 	chunk_memcat(trash, ctx.value.ptr, ctx.value.len);
-- 
2.17.1

Reply via email to