]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
proxy: refactor haproxy protocol handling as connection filter
authorStefan Eissing <stefan@eissing.org>
Mon, 14 Nov 2022 15:44:12 +0000 (16:44 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 15 Nov 2022 14:56:25 +0000 (15:56 +0100)
Closes #9893

lib/cfilters.c
lib/http.c
lib/http_proxy.c
lib/http_proxy.h
lib/urldata.h

index aa8bb4305f019e4b55ce260d2e1d6daf6439eb8f..7c439cd63a4e2dadac9937e4dadaba4693b1c0fd 100644 (file)
@@ -328,6 +328,15 @@ CURLcode Curl_cfilter_setup(struct Curl_easy *data,
 #else
     (void)ssl_mode;
 #endif /* USE_SSL */
+
+#ifndef CURL_DISABLE_PROXY
+    if(data->set.haproxyprotocol) {
+      result = Curl_cfilter_haproxy_add(data, conn, sockindex);
+      if(result)
+        goto out;
+    }
+#endif /* !CURL_DISABLE_PROXY */
+
   }
   DEBUGASSERT(conn->cfilter[sockindex]);
   cf = data->conn->cfilter[sockindex];
index 41a3a62b8d50d152142ece08d61a623db3e19765..cc2abf79efb596aaf70915f35b895aa7240979c1 100644 (file)
@@ -102,10 +102,6 @@ static int http_getsock_do(struct Curl_easy *data,
                            curl_socket_t *socks);
 static bool http_should_fail(struct Curl_easy *data);
 
-#ifndef CURL_DISABLE_PROXY
-static CURLcode add_haproxy_protocol_header(struct Curl_easy *data);
-#endif
-
 static CURLcode http_setup_conn(struct Curl_easy *data,
                                 struct connectdata *conn);
 #ifdef USE_WEBSOCKETS
@@ -1532,30 +1528,13 @@ Curl_compareheader(const char *headerline, /* line to check */
  */
 CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
 {
-  CURLcode result;
   struct connectdata *conn = data->conn;
 
   /* We default to persistent connections. We set this already in this connect
      function to make the re-use checks properly be able to check this bit. */
   connkeep(conn, "HTTP default");
 
-  result = Curl_cfilter_connect(data, conn, FIRSTSOCKET, FALSE, done);
-  if(result || !*done)
-    return result;
-
-#ifndef CURL_DISABLE_PROXY
-  if(data->set.haproxyprotocol && !data->state.is_haproxy_hdr_sent) {
-    /* add HAProxy PROXY protocol header */
-    result = add_haproxy_protocol_header(data);
-    if(result)
-      return result;
-
-    /* do not send the header again after successful try */
-    data->state.is_haproxy_hdr_sent = TRUE;
-  }
-#endif
-
-  return CURLE_OK;
+  return Curl_cfilter_connect(data, conn, FIRSTSOCKET, FALSE, done);
 }
 
 /* this returns the socket to wait for in the DO and DOING state for the multi
@@ -1571,42 +1550,6 @@ static int http_getsock_do(struct Curl_easy *data,
   return GETSOCK_WRITESOCK(0);
 }
 
-#ifndef CURL_DISABLE_PROXY
-static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
-{
-  struct dynbuf req;
-  CURLcode result;
-  const char *tcp_version;
-  DEBUGASSERT(data->conn);
-  Curl_dyn_init(&req, DYN_HAXPROXY);
-
-#ifdef USE_UNIX_SOCKETS
-  if(data->conn->unix_domain_socket)
-    /* the buffer is large enough to hold this! */
-    result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
-  else {
-#endif
-  /* Emit the correct prefix for IPv6 */
-  tcp_version = data->conn->bits.ipv6 ? "TCP6" : "TCP4";
-
-  result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
-                         tcp_version,
-                         data->info.conn_local_ip,
-                         data->info.conn_primary_ip,
-                         data->info.conn_local_port,
-                         data->info.conn_primary_port);
-
-#ifdef USE_UNIX_SOCKETS
-  }
-#endif
-
-  if(!result)
-    result = Curl_buffer_send(&req, data, &data->info.request_size,
-                              0, FIRSTSOCKET);
-  return result;
-}
-#endif
-
 /*
  * Curl_http_done() gets called after a single HTTP request has been
  * performed.
index 1f6bc06be655be7523cb8f827bd428103b95765b..97403020506ce3dfdb2e36807a8c12e8023da772 100644 (file)
@@ -1188,4 +1188,91 @@ CURLcode Curl_cfilter_http_proxy_add(struct Curl_easy *data,
   return result;
 }
 
+#endif /* !CURL_DISABLE_PROXY && !defined(CURL_DISABLE_HTTP) */
+
+#if !defined(CURL_DISABLE_PROXY)
+
+static CURLcode send_haproxy_header(struct Curl_cfilter*cf,
+                                    struct Curl_easy *data)
+{
+  struct dynbuf req;
+  CURLcode result;
+  const char *tcp_version;
+  Curl_dyn_init(&req, DYN_HAXPROXY);
+
+#ifdef USE_UNIX_SOCKETS
+  if(cf->conn->unix_domain_socket)
+    /* the buffer is large enough to hold this! */
+    result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
+  else {
+#endif
+  /* Emit the correct prefix for IPv6 */
+  tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
+
+  result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
+                         tcp_version,
+                         data->info.conn_local_ip,
+                         data->info.conn_primary_ip,
+                         data->info.conn_local_port,
+                         data->info.conn_primary_port);
+
+#ifdef USE_UNIX_SOCKETS
+  }
+#endif
+
+  if(!result)
+    result = Curl_buffer_send(&req, data, &data->info.request_size,
+                              0, FIRSTSOCKET);
+  return result;
+}
+
+static CURLcode haproxy_cf_connect(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   bool blocking, bool *done)
+{
+  CURLcode result;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  result = cf->next->cft->connect(cf->next, data, blocking, done);
+  if(result || !*done)
+    return result;
+
+  result = send_haproxy_header(cf, data);
+  *done = (!result);
+  cf->connected = *done;
+  return result;
+}
+
+static const struct Curl_cftype cft_haproxy = {
+  "HAPROXY",
+  Curl_cf_def_destroy,
+  Curl_cf_def_attach_data,
+  Curl_cf_def_detach_data,
+  Curl_cf_def_setup,
+  Curl_cf_def_close,
+  haproxy_cf_connect,
+  Curl_cf_def_get_select_socks,
+  Curl_cf_def_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+};
+
+CURLcode Curl_cfilter_haproxy_add(struct Curl_easy *data,
+                                  struct connectdata *conn,
+                                  int sockindex)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  result = Curl_cfilter_create(&cf, data, conn, sockindex,
+                               &cft_haproxy, NULL);
+  if(!result)
+    Curl_cfilter_add(data, conn, sockindex, cf);
+  return result;
+}
+
 #endif /* !CURL_DISABLE_PROXY */
index fe10acd022bb05f0d2a61d5859d3428fc4d63c47..7e27f3241439deb453475ed842efd0925c8d5057 100644 (file)
@@ -38,4 +38,12 @@ CURLcode Curl_cfilter_http_proxy_add(struct Curl_easy *data,
 
 #endif
 
+#if !defined(CURL_DISABLE_PROXY)
+
+CURLcode Curl_cfilter_haproxy_add(struct Curl_easy *data,
+                                  struct connectdata *conn,
+                                  int sockindex);
+
+#endif
+
 #endif /* HEADER_CURL_HTTP_PROXY_H */
index 9cc2b323033bb8ef200feab086ecb82d2e5ef381..638763cf77797f8231e4033103c826a9da163049 100644 (file)
@@ -1427,10 +1427,6 @@ struct UrlState {
   trailers_state trailers_state; /* whether we are sending trailers
                                     and what stage are we at */
 #endif
-#ifndef CURL_DISABLE_PROXY
-  /* to keep track whether we already sent PROXY header or not */
-  BIT(is_haproxy_hdr_sent);
-#endif
 #ifdef USE_HYPER
   bool hconnect;  /* set if a CONNECT request */
   CURLcode hresult; /* used to pass return codes back from hyper callbacks */