Coverage Report

Created: 2023-06-07 07:02

/src/curl/lib/http_proxy.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
27
#include "http_proxy.h"
28
29
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
30
31
#include <curl/curl.h>
32
#ifdef USE_HYPER
33
#include <hyper.h>
34
#endif
35
#include "sendf.h"
36
#include "http.h"
37
#include "url.h"
38
#include "select.h"
39
#include "progress.h"
40
#include "cfilters.h"
41
#include "cf-h1-proxy.h"
42
#include "cf-h2-proxy.h"
43
#include "connect.h"
44
#include "curlx.h"
45
#include "vtls/vtls.h"
46
#include "transfer.h"
47
#include "multiif.h"
48
49
/* The last 3 #include files should be in this order */
50
#include "curl_printf.h"
51
#include "curl_memory.h"
52
#include "memdebug.h"
53
54
55
struct cf_proxy_ctx {
56
  /* the protocol specific sub-filter we install during connect */
57
  struct Curl_cfilter *cf_protocol;
58
};
59
60
static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
61
                                      struct Curl_easy *data,
62
                                      bool blocking, bool *done)
63
0
{
64
0
  struct cf_proxy_ctx *ctx = cf->ctx;
65
0
  CURLcode result;
66
67
0
  if(cf->connected) {
68
0
    *done = TRUE;
69
0
    return CURLE_OK;
70
0
  }
71
72
0
  DEBUGF(LOG_CF(data, cf, "connect"));
73
0
connect_sub:
74
0
  result = cf->next->cft->connect(cf->next, data, blocking, done);
75
0
  if(result || !*done)
76
0
    return result;
77
78
0
  *done = FALSE;
79
0
  if(!ctx->cf_protocol) {
80
0
    struct Curl_cfilter *cf_protocol = NULL;
81
0
    int alpn = Curl_conn_cf_is_ssl(cf->next)?
82
0
      cf->conn->proxy_alpn : CURL_HTTP_VERSION_1_1;
83
84
    /* First time call after the subchain connected */
85
0
    switch(alpn) {
86
0
    case CURL_HTTP_VERSION_NONE:
87
0
    case CURL_HTTP_VERSION_1_0:
88
0
    case CURL_HTTP_VERSION_1_1:
89
0
      DEBUGF(LOG_CF(data, cf, "installing subfilter for HTTP/1.1"));
90
0
      infof(data, "CONNECT tunnel: HTTP/1.%d negotiated",
91
0
            (alpn == CURL_HTTP_VERSION_1_0)? 0 : 1);
92
0
      result = Curl_cf_h1_proxy_insert_after(cf, data);
93
0
      if(result)
94
0
        goto out;
95
0
      cf_protocol = cf->next;
96
0
      break;
97
0
#ifdef USE_NGHTTP2
98
0
    case CURL_HTTP_VERSION_2:
99
0
      DEBUGF(LOG_CF(data, cf, "installing subfilter for HTTP/2"));
100
0
      infof(data, "CONNECT tunnel: HTTP/2 negotiated");
101
0
      result = Curl_cf_h2_proxy_insert_after(cf, data);
102
0
      if(result)
103
0
        goto out;
104
0
      cf_protocol = cf->next;
105
0
      break;
106
0
#endif
107
0
    default:
108
0
      DEBUGF(LOG_CF(data, cf, "installing subfilter for default HTTP/1.1"));
109
0
      infof(data, "CONNECT tunnel: unsupported ALPN(%d) negotiated", alpn);
110
0
      result = CURLE_COULDNT_CONNECT;
111
0
      goto out;
112
0
    }
113
114
0
    ctx->cf_protocol = cf_protocol;
115
    /* after we installed the filter "below" us, we call connect
116
     * on out sub-chain again.
117
     */
118
0
    goto connect_sub;
119
0
  }
120
0
  else {
121
    /* subchain connected and we had already installed the protocol filter.
122
     * This means the protocol tunnel is established, we are done.
123
     */
124
0
    DEBUGASSERT(ctx->cf_protocol);
125
0
    result = CURLE_OK;
126
0
  }
127
128
0
out:
129
0
  if(!result) {
130
0
    cf->connected = TRUE;
131
0
    *done = TRUE;
132
0
  }
133
0
  return result;
134
0
}
135
136
void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf,
137
                                 struct Curl_easy *data,
138
                                 const char **phost,
139
                                 const char **pdisplay_host,
140
                                 int *pport)
141
0
{
142
0
  (void)data;
143
0
  if(!cf->connected) {
144
0
    *phost = cf->conn->http_proxy.host.name;
145
0
    *pdisplay_host = cf->conn->http_proxy.host.dispname;
146
0
    *pport = (int)cf->conn->http_proxy.port;
147
0
  }
148
0
  else {
149
0
    cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
150
0
  }
151
0
}
152
153
static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
154
                                  struct Curl_easy *data)
155
0
{
156
0
  struct cf_proxy_ctx *ctx = cf->ctx;
157
158
0
  (void)data;
159
0
  DEBUGF(LOG_CF(data, cf, "destroy"));
160
0
  free(ctx);
161
0
}
162
163
static void http_proxy_cf_close(struct Curl_cfilter *cf,
164
                                struct Curl_easy *data)
165
0
{
166
0
  struct cf_proxy_ctx *ctx = cf->ctx;
167
168
0
  DEBUGF(LOG_CF(data, cf, "close"));
169
0
  cf->connected = FALSE;
170
0
  if(ctx->cf_protocol) {
171
0
    struct Curl_cfilter *f;
172
    /* if someone already removed it, we assume he also
173
     * took care of destroying it. */
174
0
    for(f = cf->next; f; f = f->next) {
175
0
      if(f == ctx->cf_protocol) {
176
        /* still in our sub-chain */
177
0
        Curl_conn_cf_discard_sub(cf, ctx->cf_protocol, data, FALSE);
178
0
        break;
179
0
      }
180
0
    }
181
0
    ctx->cf_protocol = NULL;
182
0
  }
183
0
  if(cf->next)
184
0
    cf->next->cft->close(cf->next, data);
185
0
}
186
187
188
struct Curl_cftype Curl_cft_http_proxy = {
189
  "HTTP-PROXY",
190
  CF_TYPE_IP_CONNECT,
191
  0,
192
  http_proxy_cf_destroy,
193
  http_proxy_cf_connect,
194
  http_proxy_cf_close,
195
  Curl_cf_http_proxy_get_host,
196
  Curl_cf_def_get_select_socks,
197
  Curl_cf_def_data_pending,
198
  Curl_cf_def_send,
199
  Curl_cf_def_recv,
200
  Curl_cf_def_cntrl,
201
  Curl_cf_def_conn_is_alive,
202
  Curl_cf_def_conn_keep_alive,
203
  Curl_cf_def_query,
204
};
205
206
CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
207
                                         struct Curl_easy *data)
208
0
{
209
0
  struct Curl_cfilter *cf;
210
0
  struct cf_proxy_ctx *ctx = NULL;
211
0
  CURLcode result;
212
213
0
  (void)data;
214
0
  ctx = calloc(1, sizeof(*ctx));
215
0
  if(!ctx) {
216
0
    result = CURLE_OUT_OF_MEMORY;
217
0
    goto out;
218
0
  }
219
0
  result = Curl_cf_create(&cf, &Curl_cft_http_proxy, ctx);
220
0
  if(result)
221
0
    goto out;
222
0
  ctx = NULL;
223
0
  Curl_conn_cf_insert_after(cf_at, cf);
224
225
0
out:
226
0
  free(ctx);
227
0
  return result;
228
0
}
229
230
#endif /* ! CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */