File: test_no_proxy.c

package info (click to toggle)
aws-crt-python 0.28.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 78,428 kB
  • sloc: ansic: 437,955; python: 27,657; makefile: 5,855; sh: 4,289; ruby: 208; java: 82; perl: 73; cpp: 25; xml: 11
file content (446 lines) | stat: -rw-r--r-- 17,804 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

#include <aws/http/connection.h>
#include <aws/http/proxy.h>

#include <aws/common/environment.h>
#include <aws/common/string.h>
#include <aws/io/uri.h>

#include <aws/http/private/no_proxy.h>
#include <aws/testing/aws_test_harness.h>
#include <aws/testing/io_testing_channel.h>

static int s_test_no_proxy_helper(
    struct aws_allocator *allocator,
    const char *host,
    const char *no_proxy_value,
    bool expected_bypass) {
    /* Create a no_proxy string for testing */
    struct aws_string *no_proxy_str = aws_string_new_from_c_str(allocator, no_proxy_value);

    /* Call the function that checks NO_PROXY */
    ASSERT_UINT_EQUALS(
        aws_http_host_matches_no_proxy(allocator, aws_byte_cursor_from_c_str(host), no_proxy_str), expected_bypass);

    /* Clean up */
    aws_string_destroy(no_proxy_str);

    return AWS_OP_SUCCESS;
}

/**
 * Test subdomain matching with NO_PROXY
 */
static int s_test_no_proxy_subdomain_matching(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value = ".example.com";

    aws_http_library_init(allocator);

    /* Test that a subdomain matches when NO_PROXY contains a domain with leading dot */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "sub.example.com", no_proxy_value, true));
    /* cannot match */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "sub.subexample.com", no_proxy_value, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_subdomain_matching, s_test_no_proxy_subdomain_matching);

/**
 * Test wildcard patterns in NO_PROXY
 */
static int s_test_no_proxy_wildcard_patterns(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value = "*";

    aws_http_library_init(allocator);

    /* Test that a wildcard pattern matches all hosts */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "any.example.com", no_proxy_value, true));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_wildcard_patterns, s_test_no_proxy_wildcard_patterns);

/**
 * Test case insensitivity in NO_PROXY
 */
static int s_test_no_proxy_case_insensitivity(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value = "example.COM";

    aws_http_library_init(allocator);

    /* Test that case insensitive matching works for both host and NO_PROXY entries */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "EXAMPLE.com", no_proxy_value, true));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_case_insensitivity, s_test_no_proxy_case_insensitivity);

/**
 * Test IPv6 addresses
 */
static int s_test_no_proxy_ipv6_address(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    /* Pattern don't allow `[]`, just follows what curl does. */
    const char *no_proxy_value = "2001:db8::1, ::1, [2001:db8::2]";

    aws_http_library_init(allocator);

    /* Test that an IPv6 address in brackets matches */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8::1]", no_proxy_value, true));

    /* Test another IPv6 address format (localhost) */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "::1", no_proxy_value, true));

    /* Test a non-matching IPv6 address */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8::2]", no_proxy_value, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_ipv6_address, s_test_no_proxy_ipv6_address);

/**
 * Test multiple patterns in NO_PROXY
 */
static int s_test_no_proxy_multiple_patterns(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    /* Only wildcard support is a single `*`, if it's in the list, it will be ignored. */
    /* commas at start or end won't affect it. */
    const char *no_proxy_value = ",,foo.bar,example.com,other.net,*,";

    aws_http_library_init(allocator);

    /* Test that a host matches when it's in the middle of a comma-separated list */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "example.com", no_proxy_value, true));

    /* Test that another host in the list also matches */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "foo.bar", no_proxy_value, true));

    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "foo.", no_proxy_value, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_multiple_patterns, s_test_no_proxy_multiple_patterns);

/**
 * Test whitespace handling in NO_PROXY
 */
static int s_test_no_proxy_whitespace_handling(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value = " example.com , foo.bar ";

    aws_http_library_init(allocator);

    /* Test that whitespace is properly handled in NO_PROXY entries */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "example.com", no_proxy_value, true));

    /* Test that another host with whitespace also matches */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "foo.bar", no_proxy_value, true));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_whitespace_handling, s_test_no_proxy_whitespace_handling);

/**
 * Test IP addresses in NO_PROXY
 */
static int s_test_no_proxy_ip_address(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value = "192.168.1.1,10.0.0.0";

    aws_http_library_init(allocator);

    /* Test that IP address matching works */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1.1", no_proxy_value, true));

    /* Test that a different IP doesn't match */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.2.1", no_proxy_value, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_ip_address, s_test_no_proxy_ip_address);

/**
 * Test port-specific exclusions in NO_PROXY
 *
 * NOTE: This tests a curl-specific feature where entries like "example.com:8080"
 * can be used to bypass the proxy only for specific ports. The current implementation
 * doesn't support this feature, so this test documents that behavior.
 */
static int s_test_no_proxy_port_specific(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value = "example.com:8080";

    aws_http_library_init(allocator);

    /* Our implementation only does hostname matching and ignores port information.
     * In curl, this would bypass only on port 8080, but in our implementation it
     * bypasses for all ports. */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "example.com", no_proxy_value, true));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_port_specific, s_test_no_proxy_port_specific);

/**
 * Test CIDR notation in NO_PROXY
 *
 * Tests the CIDR notation support (similar to curl 7.86.0) where "192.168.0.0/16"
 * would match all addresses starting with "192.168".
 */
static int s_test_no_proxy_cidr_notation(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value_16 = "192.168.0.0/16";
    const char *no_proxy_value_24 = "192.168.5.0/24";

    aws_http_library_init(allocator);

    /* Test that an IP address in a CIDR range matches */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.5.10", no_proxy_value_16, true));

    /* Test that an IP address outside the CIDR range doesn't match */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "10.0.5.10", no_proxy_value_16, false));

    /* Test that an IP address in a more specific CIDR range matches */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.5.10", no_proxy_value_24, true));

    /* Test that an IP address outside the specific CIDR range doesn't match */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.6.10", no_proxy_value_24, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_cidr_notation, s_test_no_proxy_cidr_notation);

/**
 * Test IPv6 CIDR notation in NO_PROXY
 *
 * Tests the CIDR notation support for IPv6 addresses where "2001:db8::/32"
 * would match all addresses starting with "2001:db8".
 */
static int s_test_no_proxy_ipv6_cidr_notation(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;
    const char *no_proxy_value_32 = "2001:db8::/32";
    const char *no_proxy_value_64 = "2001:db8:1:2::/64";

    aws_http_library_init(allocator);

    /* Test that an IPv6 address in a CIDR range matches */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8:1:2::3]", no_proxy_value_32, true));

    /* Test that an IPv6 address outside the CIDR range doesn't match */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db9:1:2::3]", no_proxy_value_32, false));

    /* Test that an IPv6 address in a more specific CIDR range matches */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8:1:2::3]", no_proxy_value_64, true));

    /* Test that an IPv6 address outside the specific CIDR range doesn't match */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8:1:3::3]", no_proxy_value_64, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_ipv6_cidr_notation, s_test_no_proxy_ipv6_cidr_notation);

/**
 * Test invalid IP addresses and CIDR blocks in NO_PROXY
 *
 * Verifies that the NO_PROXY implementation safely handles and ignores invalid
 * IP addresses and CIDR blocks without crashing.
 */
static int s_test_no_proxy_invalid_patterns(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;

    aws_http_library_init(allocator);

    /* Test with invalid IP addresses and CIDR notations mixed with valid entries */
    const char *no_proxy_value = "example.com,999.999.999.999,192.168.1.3/33,192.168.b.c,"
                                 "2001:xyz::bad:ipv6,2001:db8::/129,not:a:valid:ip/64,"
                                 "[malformed],192.168.1.2,"
                                 "192.168.1.1/99999999999999999," /* Invalid network bits */
                                 "192.168.1.1/9/9/9,"             /* Invalid network bits */
                                 "2001:db8::/999999";             /* Invalid IPv6 prefix */
    // const char *no_proxy_value = "192.168.1.1/9/9/9";

    /* Test that invalid IP addresses and CIDR blocks are safely ignored */
    /* The last valid entry (192.168.1.2) should still match */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1.2", no_proxy_value, true));

    /* Test that the valid hostname entry still works */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "example.com", no_proxy_value, true));

    /* Test with an invalid host address parameter */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1.1", no_proxy_value, false));

    /* An invalid IP address will be treated as regular hostname and match as regular hostname. */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "999.999.999.999", no_proxy_value, true));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "999.999.999.999.999", no_proxy_value, true));

    /* Test with only invalid entries */
    const char *invalid_only = "999.999.999.999,192.168.1.1/33,not:an:ip:addr,2001:xyz::bad";

    /* Test that a valid IP doesn't match when NO_PROXY contains only invalid entries */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1.1", invalid_only, false));

    /* Test with empty host parameter */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "", invalid_only, false));

    /* Test with a very malformed CIDR input that could cause parsing issues */
    const char *malformed_cidr = "192.168.1.1/abcdef,2001:db8::/xyz";

    /* Malformed CIDR will be taken as the entry */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "2001:db8::", malformed_cidr, false));

    /* Test with very large CIDR parts that would be rejected in the buffer size check */
    char large_value[200];
    memset(large_value, 'x', sizeof(large_value) - 1);
    large_value[sizeof(large_value) - 1] = '\0';

    char large_cidr[256];
    snprintf(large_cidr, sizeof(large_cidr), "192.168.1.1/%s", large_value);

    /* Test with oversized CIDR notation */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1.1", large_cidr, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_invalid_patterns, s_test_no_proxy_invalid_patterns);

/**
 * Test invalid host inputs to aws_http_host_matches_no_proxy
 *
 * Verifies that the aws_http_host_matches_no_proxy function handles malformed host inputs
 * gracefully without crashing. These tests specifically check the host parameter
 * rather than the NO_PROXY environment variable content.
 */
static int s_test_no_proxy_invalid_host_inputs(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;

    aws_http_library_init(allocator);

    /* Set up a valid NO_PROXY value for testing */
    const char *no_proxy_value = "example.com,192.168.1.0/24,2001:db8::/32";

    /* Test with invalid IPv4 address */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "999.999.999.999", no_proxy_value, false));

    /* Test with malformed IPv4 address formats */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1", no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168..1", no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1.", no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, ".192.168.1", no_proxy_value, false));

    /* Test with invalid IPv6 address variants */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8::xyz]", no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8::]:", no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "2001:db8:::", no_proxy_value, false));

    /* Test with malformed IPv6 address brackets */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8::1", no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "2001:db8::1]", no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[[2001:db8::1]]", no_proxy_value, false));

    /* Test with empty host */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "", no_proxy_value, false));

    /* Test with extremely long host that exceeds buffer sizes */
    char long_host[1024];
    memset(long_host, 'a', sizeof(long_host) - 1);
    long_host[sizeof(long_host) - 1] = '\0';
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, long_host, no_proxy_value, false));

    /* Test with extremely long IPv4 address that would hit buffer checks */
    char long_ipv4[150] = "192.168.1.1";
    for (int i = 0; i < 130; i++) {
        long_ipv4[11 + i] = '9'; /* Padding with extra digits */
    }
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, long_ipv4, no_proxy_value, false));

    /* Test with extremely long IPv6 address that would hit buffer checks */
    char long_ipv6[150] = "[2001:db8::1";
    for (int i = 0; i < 130; i++) {
        long_ipv6[11 + i] = '1'; /* Padding with extra digits */
    }
    long_ipv6[141] = ']';
    long_ipv6[142] = '\0';
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, long_ipv6, no_proxy_value, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_invalid_host_inputs, s_test_no_proxy_invalid_host_inputs);

/**
 * Test behavior when NO_PROXY is empty
 *
 * Verifies that the aws_http_host_matches_no_proxy function correctly handles cases where
 * the NO_PROXY value is empty.
 */
static int s_test_no_proxy_empty(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;

    aws_http_library_init(allocator);

    /* Test with empty NO_PROXY */
    const char *empty_no_proxy_value = "";

    /* With empty NO_PROXY, aws_http_host_matches_no_proxy should return false for any host */
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "example.com", empty_no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "192.168.1.1", empty_no_proxy_value, false));
    ASSERT_SUCCESS(s_test_no_proxy_helper(allocator, "[2001:db8::1]", empty_no_proxy_value, false));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_empty, s_test_no_proxy_empty);

/**
 * Test using the direct no_proxy parameter
 *
 * Verifies that the aws_http_host_matches_no_proxy function correctly uses the provided no_proxy parameter.
 */
static int s_test_no_proxy_direct_parameter(struct aws_allocator *allocator, void *ctx) {
    (void)ctx;

    aws_http_library_init(allocator);

    /* Create different no_proxy values to test with */
    const char *direct_no_proxy_value = "direct.example.com";
    const char *wildcard_no_proxy_value = "*";

    /* Test with specific host */
    ASSERT_TRUE(aws_http_host_matches_no_proxy(
        allocator,
        aws_byte_cursor_from_c_str("direct.example.com"),
        aws_string_new_from_c_str(allocator, direct_no_proxy_value)));

    ASSERT_FALSE(aws_http_host_matches_no_proxy(
        allocator,
        aws_byte_cursor_from_c_str("other.example.com"),
        aws_string_new_from_c_str(allocator, direct_no_proxy_value)));

    /* Test with wildcard */
    ASSERT_TRUE(aws_http_host_matches_no_proxy(
        allocator,
        aws_byte_cursor_from_c_str("any.host.com"),
        aws_string_new_from_c_str(allocator, wildcard_no_proxy_value)));

    aws_http_library_clean_up();
    return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(test_no_proxy_direct_parameter, s_test_no_proxy_direct_parameter);