xref: /third_party/curl/lib/cf-haproxy.c (revision 13498266)
113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#if !defined(CURL_DISABLE_PROXY)
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci#include <curl/curl.h>
3013498266Sopenharmony_ci#include "urldata.h"
3113498266Sopenharmony_ci#include "cfilters.h"
3213498266Sopenharmony_ci#include "cf-haproxy.h"
3313498266Sopenharmony_ci#include "curl_trc.h"
3413498266Sopenharmony_ci#include "multiif.h"
3513498266Sopenharmony_ci
3613498266Sopenharmony_ci/* The last 3 #include files should be in this order */
3713498266Sopenharmony_ci#include "curl_printf.h"
3813498266Sopenharmony_ci#include "curl_memory.h"
3913498266Sopenharmony_ci#include "memdebug.h"
4013498266Sopenharmony_ci
4113498266Sopenharmony_ci
4213498266Sopenharmony_citypedef enum {
4313498266Sopenharmony_ci    HAPROXY_INIT,     /* init/default/no tunnel state */
4413498266Sopenharmony_ci    HAPROXY_SEND,     /* data_out being sent */
4513498266Sopenharmony_ci    HAPROXY_DONE      /* all work done */
4613498266Sopenharmony_ci} haproxy_state;
4713498266Sopenharmony_ci
4813498266Sopenharmony_cistruct cf_haproxy_ctx {
4913498266Sopenharmony_ci  int state;
5013498266Sopenharmony_ci  struct dynbuf data_out;
5113498266Sopenharmony_ci};
5213498266Sopenharmony_ci
5313498266Sopenharmony_cistatic void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
5413498266Sopenharmony_ci{
5513498266Sopenharmony_ci  DEBUGASSERT(ctx);
5613498266Sopenharmony_ci  ctx->state = HAPROXY_INIT;
5713498266Sopenharmony_ci  Curl_dyn_reset(&ctx->data_out);
5813498266Sopenharmony_ci}
5913498266Sopenharmony_ci
6013498266Sopenharmony_cistatic void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
6113498266Sopenharmony_ci{
6213498266Sopenharmony_ci  if(ctx) {
6313498266Sopenharmony_ci    Curl_dyn_free(&ctx->data_out);
6413498266Sopenharmony_ci    free(ctx);
6513498266Sopenharmony_ci  }
6613498266Sopenharmony_ci}
6713498266Sopenharmony_ci
6813498266Sopenharmony_cistatic CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
6913498266Sopenharmony_ci                                        struct Curl_easy *data)
7013498266Sopenharmony_ci{
7113498266Sopenharmony_ci  struct cf_haproxy_ctx *ctx = cf->ctx;
7213498266Sopenharmony_ci  CURLcode result;
7313498266Sopenharmony_ci  const char *tcp_version;
7413498266Sopenharmony_ci  const char *client_ip;
7513498266Sopenharmony_ci
7613498266Sopenharmony_ci  DEBUGASSERT(ctx);
7713498266Sopenharmony_ci  DEBUGASSERT(ctx->state == HAPROXY_INIT);
7813498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
7913498266Sopenharmony_ci  if(cf->conn->unix_domain_socket)
8013498266Sopenharmony_ci    /* the buffer is large enough to hold this! */
8113498266Sopenharmony_ci    result = Curl_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
8213498266Sopenharmony_ci  else {
8313498266Sopenharmony_ci#endif /* USE_UNIX_SOCKETS */
8413498266Sopenharmony_ci  /* Emit the correct prefix for IPv6 */
8513498266Sopenharmony_ci  tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
8613498266Sopenharmony_ci  if(data->set.str[STRING_HAPROXY_CLIENT_IP])
8713498266Sopenharmony_ci    client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
8813498266Sopenharmony_ci  else
8913498266Sopenharmony_ci    client_ip = data->info.conn_local_ip;
9013498266Sopenharmony_ci
9113498266Sopenharmony_ci  result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
9213498266Sopenharmony_ci                         tcp_version,
9313498266Sopenharmony_ci                         client_ip,
9413498266Sopenharmony_ci                         data->info.conn_primary_ip,
9513498266Sopenharmony_ci                         data->info.conn_local_port,
9613498266Sopenharmony_ci                         data->info.conn_primary_port);
9713498266Sopenharmony_ci
9813498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
9913498266Sopenharmony_ci  }
10013498266Sopenharmony_ci#endif /* USE_UNIX_SOCKETS */
10113498266Sopenharmony_ci  return result;
10213498266Sopenharmony_ci}
10313498266Sopenharmony_ci
10413498266Sopenharmony_cistatic CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
10513498266Sopenharmony_ci                                   struct Curl_easy *data,
10613498266Sopenharmony_ci                                   bool blocking, bool *done)
10713498266Sopenharmony_ci{
10813498266Sopenharmony_ci  struct cf_haproxy_ctx *ctx = cf->ctx;
10913498266Sopenharmony_ci  CURLcode result;
11013498266Sopenharmony_ci  size_t len;
11113498266Sopenharmony_ci
11213498266Sopenharmony_ci  DEBUGASSERT(ctx);
11313498266Sopenharmony_ci  if(cf->connected) {
11413498266Sopenharmony_ci    *done = TRUE;
11513498266Sopenharmony_ci    return CURLE_OK;
11613498266Sopenharmony_ci  }
11713498266Sopenharmony_ci
11813498266Sopenharmony_ci  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
11913498266Sopenharmony_ci  if(result || !*done)
12013498266Sopenharmony_ci    return result;
12113498266Sopenharmony_ci
12213498266Sopenharmony_ci  switch(ctx->state) {
12313498266Sopenharmony_ci  case HAPROXY_INIT:
12413498266Sopenharmony_ci    result = cf_haproxy_date_out_set(cf, data);
12513498266Sopenharmony_ci    if(result)
12613498266Sopenharmony_ci      goto out;
12713498266Sopenharmony_ci    ctx->state = HAPROXY_SEND;
12813498266Sopenharmony_ci    FALLTHROUGH();
12913498266Sopenharmony_ci  case HAPROXY_SEND:
13013498266Sopenharmony_ci    len = Curl_dyn_len(&ctx->data_out);
13113498266Sopenharmony_ci    if(len > 0) {
13213498266Sopenharmony_ci      ssize_t written = Curl_conn_send(data, cf->sockindex,
13313498266Sopenharmony_ci                                       Curl_dyn_ptr(&ctx->data_out),
13413498266Sopenharmony_ci                                       len, &result);
13513498266Sopenharmony_ci      if(written < 0)
13613498266Sopenharmony_ci        goto out;
13713498266Sopenharmony_ci      Curl_dyn_tail(&ctx->data_out, len - (size_t)written);
13813498266Sopenharmony_ci      if(Curl_dyn_len(&ctx->data_out) > 0) {
13913498266Sopenharmony_ci        result = CURLE_OK;
14013498266Sopenharmony_ci        goto out;
14113498266Sopenharmony_ci      }
14213498266Sopenharmony_ci    }
14313498266Sopenharmony_ci    ctx->state = HAPROXY_DONE;
14413498266Sopenharmony_ci    FALLTHROUGH();
14513498266Sopenharmony_ci  default:
14613498266Sopenharmony_ci    Curl_dyn_free(&ctx->data_out);
14713498266Sopenharmony_ci    break;
14813498266Sopenharmony_ci  }
14913498266Sopenharmony_ci
15013498266Sopenharmony_ciout:
15113498266Sopenharmony_ci  *done = (!result) && (ctx->state == HAPROXY_DONE);
15213498266Sopenharmony_ci  cf->connected = *done;
15313498266Sopenharmony_ci  return result;
15413498266Sopenharmony_ci}
15513498266Sopenharmony_ci
15613498266Sopenharmony_cistatic void cf_haproxy_destroy(struct Curl_cfilter *cf,
15713498266Sopenharmony_ci                               struct Curl_easy *data)
15813498266Sopenharmony_ci{
15913498266Sopenharmony_ci  (void)data;
16013498266Sopenharmony_ci  CURL_TRC_CF(data, cf, "destroy");
16113498266Sopenharmony_ci  cf_haproxy_ctx_free(cf->ctx);
16213498266Sopenharmony_ci}
16313498266Sopenharmony_ci
16413498266Sopenharmony_cistatic void cf_haproxy_close(struct Curl_cfilter *cf,
16513498266Sopenharmony_ci                             struct Curl_easy *data)
16613498266Sopenharmony_ci{
16713498266Sopenharmony_ci  CURL_TRC_CF(data, cf, "close");
16813498266Sopenharmony_ci  cf->connected = FALSE;
16913498266Sopenharmony_ci  cf_haproxy_ctx_reset(cf->ctx);
17013498266Sopenharmony_ci  if(cf->next)
17113498266Sopenharmony_ci    cf->next->cft->do_close(cf->next, data);
17213498266Sopenharmony_ci}
17313498266Sopenharmony_ci
17413498266Sopenharmony_cistatic void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
17513498266Sopenharmony_ci                                      struct Curl_easy *data,
17613498266Sopenharmony_ci                                      struct easy_pollset *ps)
17713498266Sopenharmony_ci{
17813498266Sopenharmony_ci  if(cf->next->connected && !cf->connected) {
17913498266Sopenharmony_ci    /* If we are not connected, but the filter "below" is
18013498266Sopenharmony_ci     * and not waiting on something, we are sending. */
18113498266Sopenharmony_ci    Curl_pollset_set_out_only(data, ps, Curl_conn_cf_get_socket(cf, data));
18213498266Sopenharmony_ci  }
18313498266Sopenharmony_ci}
18413498266Sopenharmony_ci
18513498266Sopenharmony_cistruct Curl_cftype Curl_cft_haproxy = {
18613498266Sopenharmony_ci  "HAPROXY",
18713498266Sopenharmony_ci  0,
18813498266Sopenharmony_ci  0,
18913498266Sopenharmony_ci  cf_haproxy_destroy,
19013498266Sopenharmony_ci  cf_haproxy_connect,
19113498266Sopenharmony_ci  cf_haproxy_close,
19213498266Sopenharmony_ci  Curl_cf_def_get_host,
19313498266Sopenharmony_ci  cf_haproxy_adjust_pollset,
19413498266Sopenharmony_ci  Curl_cf_def_data_pending,
19513498266Sopenharmony_ci  Curl_cf_def_send,
19613498266Sopenharmony_ci  Curl_cf_def_recv,
19713498266Sopenharmony_ci  Curl_cf_def_cntrl,
19813498266Sopenharmony_ci  Curl_cf_def_conn_is_alive,
19913498266Sopenharmony_ci  Curl_cf_def_conn_keep_alive,
20013498266Sopenharmony_ci  Curl_cf_def_query,
20113498266Sopenharmony_ci};
20213498266Sopenharmony_ci
20313498266Sopenharmony_cistatic CURLcode cf_haproxy_create(struct Curl_cfilter **pcf,
20413498266Sopenharmony_ci                                  struct Curl_easy *data)
20513498266Sopenharmony_ci{
20613498266Sopenharmony_ci  struct Curl_cfilter *cf = NULL;
20713498266Sopenharmony_ci  struct cf_haproxy_ctx *ctx;
20813498266Sopenharmony_ci  CURLcode result;
20913498266Sopenharmony_ci
21013498266Sopenharmony_ci  (void)data;
21113498266Sopenharmony_ci  ctx = calloc(1, sizeof(*ctx));
21213498266Sopenharmony_ci  if(!ctx) {
21313498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
21413498266Sopenharmony_ci    goto out;
21513498266Sopenharmony_ci  }
21613498266Sopenharmony_ci  ctx->state = HAPROXY_INIT;
21713498266Sopenharmony_ci  Curl_dyn_init(&ctx->data_out, DYN_HAXPROXY);
21813498266Sopenharmony_ci
21913498266Sopenharmony_ci  result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx);
22013498266Sopenharmony_ci  if(result)
22113498266Sopenharmony_ci    goto out;
22213498266Sopenharmony_ci  ctx = NULL;
22313498266Sopenharmony_ci
22413498266Sopenharmony_ciout:
22513498266Sopenharmony_ci  cf_haproxy_ctx_free(ctx);
22613498266Sopenharmony_ci  *pcf = result? NULL : cf;
22713498266Sopenharmony_ci  return result;
22813498266Sopenharmony_ci}
22913498266Sopenharmony_ci
23013498266Sopenharmony_ciCURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at,
23113498266Sopenharmony_ci                                      struct Curl_easy *data)
23213498266Sopenharmony_ci{
23313498266Sopenharmony_ci  struct Curl_cfilter *cf;
23413498266Sopenharmony_ci  CURLcode result;
23513498266Sopenharmony_ci
23613498266Sopenharmony_ci  result = cf_haproxy_create(&cf, data);
23713498266Sopenharmony_ci  if(result)
23813498266Sopenharmony_ci    goto out;
23913498266Sopenharmony_ci  Curl_conn_cf_insert_after(cf_at, cf);
24013498266Sopenharmony_ci
24113498266Sopenharmony_ciout:
24213498266Sopenharmony_ci  return result;
24313498266Sopenharmony_ci}
24413498266Sopenharmony_ci
24513498266Sopenharmony_ci#endif /* !CURL_DISABLE_PROXY */
246