From 93749c90b4d5f556e68914f68963373030cfcba7 Mon Sep 17 00:00:00 2001
From: Chris Hibbert <christopher.hibbert@mediakind.com>
Date: Thu, 9 Jan 2025 10:36:28 +0000
Subject: [PATCH] Add PATCH method to httpclient

---
 addons/ot/src/util.c     |  5 +++++
 doc/lua-api/index.rst    |  3 ++-
 include/haproxy/http-t.h |  1 +
 include/haproxy/spoe.h   |  1 +
 src/hlua.c               | 13 +++++++++++++
 src/http.c               |  2 ++
 6 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/addons/ot/src/util.c b/addons/ot/src/util.c
index fd040164d..2b4982d34 100644
--- a/addons/ot/src/util.c
+++ b/addons/ot/src/util.c
@@ -595,6 +595,11 @@ int flt_ot_sample_to_str(const struct sample_data *data, char *value, size_t siz
 
 		(void)memcpy(value, HTTP_METH_STR_PUT, retval + 1);
 	}
+	else if (data->u.meth.meth == HTTP_METH_PATCH) {
+		retval = FLT_OT_STR_SIZE(HTTP_METH_PATCH);
+
+		(void)memcpy(value, HTTP_METH_PATCH, retval + 1);
+	}
 	else if (data->u.meth.meth == HTTP_METH_DELETE) {
 		retval = FLT_OT_STR_SIZE(HTTP_METH_STR_DELETE);
 
diff --git a/doc/lua-api/index.rst b/doc/lua-api/index.rst
index e0afaffcd..f68b6adb5 100644
--- a/doc/lua-api/index.rst
+++ b/doc/lua-api/index.rst
@@ -2562,10 +2562,11 @@ HTTPClient class
 .. js:function:: HTTPClient.get(httpclient, request)
 .. js:function:: HTTPClient.head(httpclient, request)
 .. js:function:: HTTPClient.put(httpclient, request)
+.. js:function:: HTTPClient.patch(httpclient, request)
 .. js:function:: HTTPClient.post(httpclient, request)
 .. js:function:: HTTPClient.delete(httpclient, request)
 
-  Send a HTTP request and wait for a response. GET, HEAD PUT, POST and DELETE
+  Send a HTTP request and wait for a response. GET, HEAD PUT, PATCH, POST and DELETE
   methods can be used.
   The HTTPClient will send asynchronously the data and is able to send and
   receive more than HAProxy bufsize.
diff --git a/include/haproxy/http-t.h b/include/haproxy/http-t.h
index 5703f38b1..6a30561cf 100644
--- a/include/haproxy/http-t.h
+++ b/include/haproxy/http-t.h
@@ -63,6 +63,7 @@ enum http_meth_t {
 	HTTP_METH_OPTIONS,
 	HTTP_METH_GET,
 	HTTP_METH_HEAD,
+	HTTP_METH_PATCH,
 	HTTP_METH_POST,
 	HTTP_METH_PUT,
 	HTTP_METH_DELETE,
diff --git a/include/haproxy/spoe.h b/include/haproxy/spoe.h
index 585b8bff9..76c1beefd 100644
--- a/include/haproxy/spoe.h
+++ b/include/haproxy/spoe.h
@@ -155,6 +155,7 @@ static inline int spoe_encode_data(struct sample *smp, char **buf, char *end)
 				case HTTP_METH_HEAD   : m = "HEAD";    len = 4; break;
 				case HTTP_METH_POST   : m = "POST";    len = 4; break;
 				case HTTP_METH_PUT    : m = "PUT";     len = 3; break;
+				case HTTP_METH_PATCH  : m = "PATCH";   len = 5; break;
 				case HTTP_METH_DELETE : m = "DELETE";  len = 6; break;
 				case HTTP_METH_TRACE  : m = "TRACE";   len = 5; break;
 				case HTTP_METH_CONNECT: m = "CONNECT"; len = 7; break;
diff --git a/src/hlua.c b/src/hlua.c
index f3ed8999a..addaef61e 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -1118,6 +1118,7 @@ __LJMP static int hlua_smp2lua(lua_State *L, struct sample *smp)
 		case HTTP_METH_HEAD:    lua_pushstring(L, "HEAD");    break;
 		case HTTP_METH_POST:    lua_pushstring(L, "POST");    break;
 		case HTTP_METH_PUT:     lua_pushstring(L, "PUT");     break;
+		case HTTP_METH_PATCH:   lua_pushstring(L, "PATCH");   break;
 		case HTTP_METH_DELETE:  lua_pushstring(L, "DELETE");  break;
 		case HTTP_METH_TRACE:   lua_pushstring(L, "TRACE");   break;
 		case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
@@ -1166,6 +1167,7 @@ __LJMP static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
 		case HTTP_METH_HEAD:    lua_pushstring(L, "HEAD");    break;
 		case HTTP_METH_POST:    lua_pushstring(L, "POST");    break;
 		case HTTP_METH_PUT:     lua_pushstring(L, "PUT");     break;
+		case HTTP_METH_PATCH:   lua_pushstring(L, "PATCH");   break;
 		case HTTP_METH_DELETE:  lua_pushstring(L, "DELETE");  break;
 		case HTTP_METH_TRACE:   lua_pushstring(L, "TRACE");   break;
 		case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
@@ -8210,6 +8212,16 @@ __LJMP static int hlua_httpclient_put(lua_State *L)
 	return hlua_httpclient_send(L, HTTP_METH_PUT);
 }
 
+/*
+ * Sends an HTTP PATCH request and wait for a response
+ *
+ * httpclient:patch(url, headers, payload)
+ */
+__LJMP static int hlua_httpclient_patch(lua_State *L)
+{
+	return hlua_httpclient_send(L, HTTP_METH_PATCH);
+}
+
 /*
  * Send an HTTP POST request and wait for a response
  *
@@ -14195,6 +14207,7 @@ lua_State *hlua_init_state(int thread_num)
 	hlua_class_function(L, "get",         hlua_httpclient_get);
 	hlua_class_function(L, "head",        hlua_httpclient_head);
 	hlua_class_function(L, "put",         hlua_httpclient_put);
+	hlua_class_function(L, "patch",       hlua_httpclient_patch);
 	hlua_class_function(L, "post",        hlua_httpclient_post);
 	hlua_class_function(L, "delete",      hlua_httpclient_delete);
 	lua_settable(L, -3); /* Sets the __index entry. */
diff --git a/src/http.c b/src/http.c
index 10522206d..ee8374f28 100644
--- a/src/http.c
+++ b/src/http.c
@@ -358,6 +358,7 @@ const struct ist http_known_methods[HTTP_METH_OTHER] = {
 	[HTTP_METH_HEAD]    = IST("HEAD"),
 	[HTTP_METH_POST]    = IST("POST"),
 	[HTTP_METH_PUT]     = IST("PUT"),
+	[HTTP_METH_PATCH]   = IST("PATCH"),
 	[HTTP_METH_DELETE]  = IST("DELETE"),
 	[HTTP_METH_TRACE]   = IST("TRACE"),
 	[HTTP_METH_CONNECT] = IST("CONNECT"),
@@ -381,6 +382,7 @@ enum http_meth_t find_http_meth(const char *str, const int len)
 
 	if      (isteq(m, http_known_methods[HTTP_METH_GET]))     return HTTP_METH_GET;
 	else if (isteq(m, http_known_methods[HTTP_METH_PUT]))     return HTTP_METH_PUT;
+	else if (isteq(m, http_known_methods[HTTP_METH_PATCH]))   return HTTP_METH_PATCH;
 	else if (isteq(m, http_known_methods[HTTP_METH_HEAD]))    return HTTP_METH_HEAD;
 	else if (isteq(m, http_known_methods[HTTP_METH_POST]))    return HTTP_METH_POST;
 	else if (isteq(m, http_known_methods[HTTP_METH_TRACE]))   return HTTP_METH_TRACE;
-- 
2.25.1

