AWS SDK

AWS SDK

rev. 7b929c2a147df61bb7fa8bb8ba54ebd6829e5397 (ignoring whitespace)

Files changed:

tmp-codegen-diff/aws-sdk/Cargo.lock

@@ -1231,1231 +1320,1323 @@
 1251   1251   
 "tokio",
 1252   1252   
 "tracing",
 1253   1253   
]
 1254   1254   
 1255   1255   
[[package]]
 1256   1256   
name = "aws-smithy-http-auth"
 1257   1257   
version = "0.60.3"
 1258   1258   
 1259   1259   
[[package]]
 1260   1260   
name = "aws-smithy-http-client"
 1261         -
version = "1.0.6"
        1261  +
version = "1.1.0"
 1262   1262   
dependencies = [
 1263   1263   
 "aws-smithy-async",
 1264   1264   
 "aws-smithy-protocol-test",
 1265   1265   
 "aws-smithy-runtime-api",
 1266   1266   
 "aws-smithy-types",
        1267  +
 "base64 0.22.1",
 1267   1268   
 "bytes",
 1268   1269   
 "h2 0.3.27",
 1269   1270   
 "h2 0.4.12",
 1270   1271   
 "http 0.2.12",
 1271   1272   
 "http 1.3.1",
 1272   1273   
 "http-body 0.4.6",
 1273   1274   
 "http-body 1.0.1",
 1274   1275   
 "http-body-util",
 1275   1276   
 "hyper 0.14.32",
 1276   1277   
 "hyper 1.6.0",
 1277   1278   
 "hyper-rustls 0.24.2",
 1278   1279   
 "hyper-rustls 0.27.7",
 1279   1280   
 "hyper-util",
 1280   1281   
 "indexmap",
 1281   1282   
 "pin-project-lite",
 1282   1283   
 "rustls 0.21.12",
 1283   1284   
 "rustls 0.23.31",
 1284   1285   
 "rustls-native-certs 0.8.1",
 1285   1286   
 "rustls-pemfile 2.2.0",
 1286   1287   
 "rustls-pki-types",
 1287   1288   
 "s2n-tls",
 1288   1289   
 "s2n-tls-hyper",
        1290  +
 "s2n-tls-tokio",
 1289   1291   
 "serde",
 1290   1292   
 "serde_json",
        1293  +
 "serial_test",
 1291   1294   
 "tokio",
 1292   1295   
 "tokio-rustls 0.26.2",
 1293   1296   
 "tower",
 1294   1297   
 "tracing",
 1295   1298   
]
 1296   1299   
 1297   1300   
[[package]]
 1298   1301   
name = "aws-smithy-http-tower"
 1299   1302   
version = "0.60.3"
 1300   1303   
@@ -1352,1355 +1440,1443 @@
 1372   1375   
[[package]]
 1373   1376   
name = "aws-smithy-query"
 1374   1377   
version = "0.60.7"
 1375   1378   
dependencies = [
 1376   1379   
 "aws-smithy-types",
 1377   1380   
 "urlencoding",
 1378   1381   
]
 1379   1382   
 1380   1383   
[[package]]
 1381   1384   
name = "aws-smithy-runtime"
 1382         -
version = "1.8.6"
        1385  +
version = "1.9.0"
 1383   1386   
dependencies = [
 1384   1387   
 "approx",
 1385   1388   
 "aws-smithy-async",
 1386   1389   
 "aws-smithy-http",
 1387   1390   
 "aws-smithy-http-client",
 1388   1391   
 "aws-smithy-observability",
 1389   1392   
 "aws-smithy-runtime-api",
 1390   1393   
 "aws-smithy-types",
 1391   1394   
 "bytes",
 1392   1395   
 "fastrand 2.3.0",
 1393   1396   
 "futures-util",
 1394   1397   
 "http 0.2.12",
 1395   1398   
 "http 1.3.1",
 1396   1399   
 "http-body 0.4.6",
 1397   1400   
 "http-body 1.0.1",
 1398   1401   
 "hyper 0.14.32",
 1399   1402   
 "pin-project-lite",
 1400   1403   
 "pin-utils",
 1401   1404   
 "pretty_assertions",
 1402   1405   
 "tokio",
 1403   1406   
 "tracing",
 1404   1407   
 "tracing-subscriber",
 1405   1408   
 "tracing-test",
 1406   1409   
]
 1407   1410   
 1408   1411   
[[package]]
 1409   1412   
name = "aws-smithy-runtime-api"
 1410         -
version = "1.8.7"
        1413  +
version = "1.9.0"
 1411   1414   
dependencies = [
 1412   1415   
 "aws-smithy-async",
 1413   1416   
 "aws-smithy-types",
 1414   1417   
 "bytes",
 1415   1418   
 "http 0.2.12",
 1416   1419   
 "http 1.3.1",
 1417   1420   
 "pin-project-lite",
 1418   1421   
 "proptest",
 1419   1422   
 "tokio",
 1420   1423   
 "tracing",
@@ -3835,3838 +3935,3938 @@
 3855   3858   
]
 3856   3859   
 3857   3860   
[[package]]
 3858   3861   
name = "ryu"
 3859   3862   
version = "1.0.20"
 3860   3863   
source = "registry+https://github.com/rust-lang/crates.io-index"
 3861   3864   
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
 3862   3865   
 3863   3866   
[[package]]
 3864   3867   
name = "s2n-tls"
 3865         -
version = "0.3.12"
        3868  +
version = "0.3.24"
 3866   3869   
source = "registry+https://github.com/rust-lang/crates.io-index"
 3867         -
checksum = "bca784a7bd2303b31dee13fe5d8617bd27c9e983342b6f07277d7bc07a2f32ea"
        3870  +
checksum = "902398e2a0bd7ed40ecc61ba85f5985139213b86bb6decb547120367733c9545"
 3868   3871   
dependencies = [
 3869   3872   
 "errno",
 3870   3873   
 "hex",
 3871   3874   
 "libc",
 3872   3875   
 "pin-project-lite",
 3873   3876   
 "s2n-tls-sys",
 3874   3877   
]
 3875   3878   
 3876   3879   
[[package]]
 3877   3880   
name = "s2n-tls-hyper"
 3878         -
version = "0.0.4"
        3881  +
version = "0.0.16"
 3879   3882   
source = "registry+https://github.com/rust-lang/crates.io-index"
 3880         -
checksum = "de97dea004ba2d03d6f1618f0ee770b4a63e3ba98d1764a0fecd2e520123f9ec"
        3883  +
checksum = "d5bfd127ef11ae746efd789549ee807f5370d5cb04e2955324420f361b2c2bbe"
 3881   3884   
dependencies = [
 3882   3885   
 "http 1.3.1",
 3883   3886   
 "hyper 1.6.0",
 3884   3887   
 "hyper-util",
 3885   3888   
 "s2n-tls",
 3886   3889   
 "s2n-tls-tokio",
 3887   3890   
 "tower-service",
 3888   3891   
]
 3889   3892   
 3890   3893   
[[package]]
 3891   3894   
name = "s2n-tls-sys"
 3892         -
version = "0.3.12"
        3895  +
version = "0.3.24"
 3893   3896   
source = "registry+https://github.com/rust-lang/crates.io-index"
 3894         -
checksum = "9ac0a964de7522dd815253bea5f17e70fd382920ab20c69783ad5294519f4712"
        3897  +
checksum = "c17994d4b67dcca7c7c01120ad30a639c1500c589d695478490e7ad6584683fd"
 3895   3898   
dependencies = [
 3896   3899   
 "aws-lc-rs",
 3897   3900   
 "cc",
 3898   3901   
 "libc",
 3899   3902   
]
 3900   3903   
 3901   3904   
[[package]]
 3902   3905   
name = "s2n-tls-tokio"
 3903         -
version = "0.3.12"
        3906  +
version = "0.3.24"
 3904   3907   
source = "registry+https://github.com/rust-lang/crates.io-index"
 3905         -
checksum = "8ef2b3f1b676575bf221cb8fe5c0bb5720736b98957e7dc9d873cd50412cbc7a"
        3908  +
checksum = "84e990a681d8c701037c14d475c239803b353cdd6dcec9c8d5ba4216d4a58937"
 3906   3909   
dependencies = [
 3907   3910   
 "errno",
 3908   3911   
 "libc",
 3909   3912   
 "pin-project-lite",
 3910   3913   
 "s2n-tls",
 3911   3914   
 "tokio",
 3912   3915   
]
 3913   3916   
 3914   3917   
[[package]]
 3915   3918   
name = "same-file"

tmp-codegen-diff/aws-sdk/sdk/aws-config/Cargo.toml

@@ -39,39 +157,157 @@
   59     59   
path = "../aws-smithy-http"
   60     60   
version = "0.62.3"
   61     61   
   62     62   
[dependencies.aws-smithy-json]
   63     63   
path = "../aws-smithy-json"
   64     64   
version = "0.61.4"
   65     65   
   66     66   
[dependencies.aws-smithy-runtime]
   67     67   
path = "../aws-smithy-runtime"
   68     68   
features = ["client"]
   69         -
version = "1.8.6"
          69  +
version = "1.9.0"
   70     70   
   71     71   
[dependencies.aws-smithy-runtime-api]
   72     72   
path = "../aws-smithy-runtime-api"
   73     73   
features = ["client"]
   74         -
version = "1.8.7"
          74  +
version = "1.9.0"
   75     75   
   76     76   
[dependencies.aws-smithy-types]
   77     77   
path = "../aws-smithy-types"
   78     78   
version = "1.3.2"
   79     79   
   80     80   
[dependencies.aws-types]
   81     81   
path = "../aws-types"
   82     82   
version = "1.3.8"
   83     83   
   84     84   
[dependencies.time]
   85     85   
version = "0.3.4"
   86     86   
features = ["parsing"]
   87     87   
   88     88   
[dependencies.tokio]
   89     89   
version = "1.13.1"
   90     90   
features = ["sync"]
   91     91   
   92     92   
[dependencies.tracing]
   93     93   
version = "0.1"
   94     94   
   95     95   
[dependencies.aws-sdk-sso]
   96     96   
path = "../sso"
   97     97   
default-features = false
   98     98   
optional = true
   99     99   
version = "0.0.0-local"
  100    100   
  101    101   
[dependencies.ring]
  102    102   
version = "0.17.5"
  103    103   
optional = true
  104    104   
  105    105   
[dependencies.hex]
  106    106   
version = "0.4.3"
  107    107   
optional = true
  108    108   
  109    109   
[dependencies.zeroize]
  110    110   
version = "1"
  111    111   
optional = true
  112    112   
  113    113   
[dependencies.aws-sdk-ssooidc]
  114    114   
path = "../ssooidc"
  115    115   
default-features = false
  116    116   
optional = true
  117    117   
version = "0.0.0-local"
  118    118   
  119    119   
[dev-dependencies]
  120    120   
tracing-test = "0.2.4"
  121    121   
serde_json = "1"
  122    122   
  123    123   
[dev-dependencies.aws-smithy-async]
  124    124   
path = "../aws-smithy-async"
  125    125   
features = ["rt-tokio", "test-util"]
  126    126   
version = "1.2.5"
  127    127   
  128    128   
[dev-dependencies.aws-smithy-http-client]
  129    129   
path = "../aws-smithy-http-client"
  130    130   
features = ["default-client", "test-util"]
  131         -
version = "1.0.7"
         131  +
version = "1.1.0"
  132    132   
  133    133   
[dev-dependencies.aws-smithy-runtime]
  134    134   
path = "../aws-smithy-runtime"
  135    135   
features = ["client", "test-util"]
  136         -
version = "1.8.6"
         136  +
version = "1.9.0"
  137    137   
  138    138   
[dev-dependencies.aws-smithy-runtime-api]
  139    139   
path = "../aws-smithy-runtime-api"
  140    140   
features = ["test-util"]
  141         -
version = "1.8.7"
         141  +
version = "1.9.0"
  142    142   
  143    143   
[dev-dependencies.futures-util]
  144    144   
version = "0.3.29"
  145    145   
default-features = false
  146    146   
  147    147   
[dev-dependencies.tracing-subscriber]
  148    148   
version = "0.3.16"
  149    149   
features = ["fmt", "json"]
  150    150   
  151    151   
[dev-dependencies.tokio]

tmp-codegen-diff/aws-sdk/sdk/aws-credential-types/Cargo.toml

@@ -7,7 +49,49 @@
   27     27   
path = "../aws-smithy-async"
   28     28   
version = "1.2.5"
   29     29   
   30     30   
[dependencies.aws-smithy-types]
   31     31   
path = "../aws-smithy-types"
   32     32   
version = "1.3.2"
   33     33   
   34     34   
[dependencies.aws-smithy-runtime-api]
   35     35   
path = "../aws-smithy-runtime-api"
   36     36   
features = ["client", "http-auth"]
   37         -
version = "1.8.7"
          37  +
version = "1.9.0"
   38     38   
   39     39   
[dev-dependencies]
   40     40   
async-trait = "0.1.74"
   41     41   
   42     42   
[dev-dependencies.aws-smithy-runtime-api]
   43     43   
path = "../aws-smithy-runtime-api"
   44     44   
features = ["test-util"]
   45         -
version = "1.8.7"
          45  +
version = "1.9.0"
   46     46   
   47     47   
[dev-dependencies.tokio]
   48     48   
version = "1.23.1"
   49     49   
features = ["full", "test-util", "rt"]

tmp-codegen-diff/aws-sdk/sdk/aws-runtime/Cargo.toml

@@ -28,28 +144,144 @@
   48     48   
optional = true
   49     49   
version = "0.60.10"
   50     50   
   51     51   
[dependencies.aws-smithy-http]
   52     52   
path = "../aws-smithy-http"
   53     53   
version = "0.62.3"
   54     54   
   55     55   
[dependencies.aws-smithy-runtime]
   56     56   
path = "../aws-smithy-runtime"
   57     57   
features = ["client"]
   58         -
version = "1.8.6"
          58  +
version = "1.9.0"
   59     59   
   60     60   
[dependencies.aws-smithy-runtime-api]
   61     61   
path = "../aws-smithy-runtime-api"
   62     62   
features = ["client"]
   63         -
version = "1.8.7"
          63  +
version = "1.9.0"
   64     64   
   65     65   
[dependencies.aws-smithy-types]
   66     66   
path = "../aws-smithy-types"
   67     67   
version = "1.3.2"
   68     68   
   69     69   
[dependencies.aws-types]
   70     70   
path = "../aws-types"
   71     71   
version = "1.3.8"
   72     72   
   73     73   
[dependencies.http-02x]
   74     74   
package = "http"
   75     75   
version = "0.2.9"
   76     76   
   77     77   
[dependencies.http-body-04x]
   78     78   
package = "http-body"
   79     79   
version = "0.4.5"
   80     80   
   81     81   
[dependencies.http-1x]
   82     82   
package = "http"
   83     83   
version = "1.1.0"
   84     84   
optional = true
   85     85   
   86     86   
[dependencies.http-body-1x]
   87     87   
package = "http-body"
   88     88   
version = "1.0.0"
   89     89   
optional = true
   90     90   
   91     91   
[dependencies.regex-lite]
   92     92   
version = "0.1.5"
   93     93   
optional = true
   94     94   
   95     95   
[dependencies.uuid]
   96     96   
version = "1"
   97     97   
   98     98   
[dev-dependencies]
   99     99   
arbitrary = "1.3"
  100    100   
bytes-utils = "0.1.2"
  101    101   
convert_case = "0.6.0"
  102    102   
proptest = "1.2"
  103    103   
serde_json = "1"
  104    104   
tracing-test = "0.2.4"
  105    105   
  106    106   
[dev-dependencies.aws-credential-types]
  107    107   
path = "../aws-credential-types"
  108    108   
features = ["test-util"]
  109    109   
version = "1.2.5"
  110    110   
  111    111   
[dev-dependencies.aws-smithy-async]
  112    112   
path = "../aws-smithy-async"
  113    113   
features = ["test-util"]
  114    114   
version = "1.2.5"
  115    115   
  116    116   
[dev-dependencies.aws-smithy-protocol-test]
  117    117   
path = "../aws-smithy-protocol-test"
  118    118   
version = "0.63.4"
  119    119   
  120    120   
[dev-dependencies.aws-smithy-runtime-api]
  121    121   
path = "../aws-smithy-runtime-api"
  122    122   
features = ["test-util"]
  123         -
version = "1.8.7"
         123  +
version = "1.9.0"
  124    124   
  125    125   
[dev-dependencies.aws-smithy-types]
  126    126   
path = "../aws-smithy-types"
  127    127   
features = ["test-util"]
  128    128   
version = "1.3.2"
  129    129   
  130    130   
[dev-dependencies.futures-util]
  131    131   
version = "0.3.29"
  132    132   
default-features = false
  133    133   

tmp-codegen-diff/aws-sdk/sdk/aws-sigv4/Cargo.toml

@@ -31,31 +91,91 @@
   51     51   
optional = true
   52     52   
version = "0.60.10"
   53     53   
   54     54   
[dependencies.aws-smithy-http]
   55     55   
path = "../aws-smithy-http"
   56     56   
version = "0.62.3"
   57     57   
   58     58   
[dependencies.aws-smithy-runtime-api]
   59     59   
path = "../aws-smithy-runtime-api"
   60     60   
features = ["client"]
   61         -
version = "1.8.7"
          61  +
version = "1.9.0"
   62     62   
   63     63   
[dependencies.aws-smithy-types]
   64     64   
path = "../aws-smithy-types"
   65     65   
version = "1.3.2"
   66     66   
   67     67   
[dependencies.form_urlencoded]
   68     68   
version = "1.2.1"
   69     69   
optional = true
   70     70   
   71     71   
[dependencies.http0]
@@ -94,94 +130,130 @@
  114    114   
criterion = "0.5"
  115    115   
  116    116   
[dev-dependencies.aws-credential-types]
  117    117   
path = "../aws-credential-types"
  118    118   
features = ["test-util", "hardcoded-credentials"]
  119    119   
version = "1.2.5"
  120    120   
  121    121   
[dev-dependencies.aws-smithy-runtime-api]
  122    122   
path = "../aws-smithy-runtime-api"
  123    123   
features = ["client", "test-util"]
  124         -
version = "1.8.7"
         124  +
version = "1.9.0"
  125    125   
  126    126   
[dev-dependencies.time]
  127    127   
version = "0.3.5"
  128    128   
features = ["parsing"]
  129    129   
[target."cfg(not(any(target_arch = \"powerpc\", target_arch = \"powerpc64\")))".dev-dependencies]
  130    130   
ring = "0.17.5"

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-compression/Cargo.toml

@@ -3,3 +63,63 @@
   23     23   
futures-util = "0.3"
   24     24   
pin-project-lite = "0.2.14"
   25     25   
tracing = "0.1.40"
   26     26   
   27     27   
[dependencies.aws-smithy-types]
   28     28   
path = "../aws-smithy-types"
   29     29   
version = "1.3.2"
   30     30   
   31     31   
[dependencies.aws-smithy-runtime-api]
   32     32   
path = "../aws-smithy-runtime-api"
   33         -
version = "1.8.7"
          33  +
version = "1.9.0"
   34     34   
   35     35   
[dependencies.http-0-2]
   36     36   
package = "http"
   37     37   
version = "0.2.9"
   38     38   
optional = true
   39     39   
   40     40   
[dependencies.http-1-0]
   41     41   
package = "http"
   42     42   
version = "1"
   43     43   
optional = true

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/Cargo.toml

@@ -1,1 +147,156 @@
   16     16   
   17     17   
[[example]]
   18     18   
name = "custom-dns"
   19     19   
required-features = ["rustls-ring"]
   20     20   
doc-scrape-examples = true
   21     21   
   22     22   
[package]
   23     23   
name = "aws-smithy-http-client"
   24     24   
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
   25     25   
description = "HTTP client abstractions for generated smithy clients"
   26         -
version = "1.0.7"
          26  +
version = "1.1.0"
   27     27   
license = "Apache-2.0"
   28     28   
edition = "2021"
   29     29   
repository = "https://github.com/smithy-lang/smithy-rs"
   30     30   
[package.metadata.smithy-rs-release-tooling]
   31     31   
stable = true
   32     32   
[package.metadata.docs.rs]
   33     33   
all-features = false
   34     34   
features = ["default-client ", "wire-mock", "test-util", "rustls-ring", "rustls-aws-lc"]
   35     35   
targets = ["x86_64-unknown-linux-gnu"]
   36     36   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
   37     37   
rustdoc-args = ["--cfg", "docsrs"]
   38     38   
   39     39   
[features]
   40     40   
hyper-014 = ["aws-smithy-runtime-api/http-02x", "aws-smithy-types/http-body-0-4-x", "dep:http-02x", "dep:http-body-04x", "dep:hyper-0-14", "dep:h2-0-3"]
   41         -
default-client = ["aws-smithy-runtime-api/http-1x", "aws-smithy-types/http-body-1-x", "dep:hyper", "dep:hyper-util", "hyper-util?/client-legacy", "dep:http-1x", "dep:tower", "dep:rustls-pki-types", "dep:rustls-native-certs"]
          41  +
default-client = ["aws-smithy-runtime-api/http-1x", "aws-smithy-types/http-body-1-x", "dep:hyper", "dep:hyper-util", "hyper-util?/client-legacy", "hyper-util?/client-proxy", "dep:http-1x", "dep:tower", "dep:rustls-pki-types", "dep:rustls-native-certs"]
   42     42   
wire-mock = ["test-util", "default-client", "hyper-util?/server", "hyper-util?/server-auto", "hyper-util?/service", "hyper-util?/server-graceful", "tokio/macros", "dep:http-body-util"]
   43     43   
test-util = ["dep:aws-smithy-protocol-test", "dep:serde", "dep:serde_json", "dep:indexmap", "dep:bytes", "dep:http-1x", "aws-smithy-runtime-api/http-1x", "dep:http-body-1x", "aws-smithy-types/http-body-1-x", "tokio/rt"]
   44     44   
legacy-test-util = ["test-util", "dep:http-02x", "aws-smithy-runtime-api/http-02x", "aws-smithy-types/http-body-0-4-x"]
   45     45   
legacy-rustls-ring = ["dep:legacy-hyper-rustls", "dep:legacy-rustls", "hyper-014"]
   46         -
rustls-ring = ["dep:rustls", "rustls?/ring", "dep:hyper-rustls", "default-client"]
   47         -
rustls-aws-lc = ["dep:rustls", "rustls?/aws_lc_rs", "rustls?/prefer-post-quantum", "dep:hyper-rustls", "default-client"]
   48         -
rustls-aws-lc-fips = ["dep:rustls", "rustls?/fips", "rustls?/prefer-post-quantum", "dep:hyper-rustls", "default-client"]
   49         -
s2n-tls = ["dep:s2n-tls", "dep:s2n-tls-hyper", "default-client"]
          46  +
rustls-ring = ["dep:rustls", "rustls?/ring", "dep:hyper-rustls", "dep:tokio-rustls", "default-client"]
          47  +
rustls-aws-lc = ["dep:rustls", "rustls?/aws_lc_rs", "rustls?/prefer-post-quantum", "dep:hyper-rustls", "dep:tokio-rustls", "default-client"]
          48  +
rustls-aws-lc-fips = ["dep:rustls", "rustls?/fips", "rustls?/prefer-post-quantum", "dep:hyper-rustls", "dep:tokio-rustls", "default-client"]
          49  +
s2n-tls = ["dep:s2n-tls", "dep:s2n-tls-hyper", "dep:s2n-tls-tokio", "default-client"]
   50     50   
   51     51   
[dependencies]
   52     52   
pin-project-lite = "0.2.14"
   53     53   
tracing = "0.1.40"
   54     54   
   55     55   
[dependencies.aws-smithy-async]
   56     56   
path = "../aws-smithy-async"
   57     57   
version = "1.2.5"
   58     58   
   59     59   
[dependencies.aws-smithy-runtime-api]
   60     60   
path = "../aws-smithy-runtime-api"
   61     61   
features = ["client"]
   62         -
version = "1.8.7"
          62  +
version = "1.9.0"
   63     63   
   64     64   
[dependencies.aws-smithy-types]
   65     65   
path = "../aws-smithy-types"
   66     66   
version = "1.3.2"
   67     67   
   68     68   
[dependencies.aws-smithy-protocol-test]
   69     69   
path = "../aws-smithy-protocol-test"
   70     70   
optional = true
   71     71   
version = "0.63.4"
   72     72   
   73     73   
[dependencies.h2]
   74         -
version = "0.4.2"
          74  +
version = "0.4.11"
   75     75   
default-features = false
   76     76   
   77     77   
[dependencies.tokio]
   78     78   
version = "1.40"
   79     79   
features = []
   80     80   
   81     81   
[dependencies.hyper]
   82     82   
version = "1.6.0"
   83     83   
features = ["client", "http1", "http2"]
   84     84   
optional = true
   85     85   
   86     86   
[dependencies.hyper-util]
   87         -
version = "0.1.10"
          87  +
version = "0.1.16"
   88     88   
features = ["http1", "http2"]
   89     89   
optional = true
   90     90   
   91     91   
[dependencies.http-1x]
   92     92   
package = "http"
   93     93   
version = "1"
   94     94   
optional = true
   95     95   
   96     96   
[dependencies.http-body-1x]
   97     97   
package = "http-body"
   98     98   
version = "1"
   99     99   
optional = true
  100    100   
  101    101   
[dependencies.hyper-rustls]
  102    102   
version = "0.27"
  103    103   
features = ["http2", "http1", "native-tokio", "tls12"]
  104    104   
default-features = false
  105    105   
optional = true
  106    106   
  107    107   
[dependencies.rustls]
  108    108   
version = "0.23.31"
  109    109   
default-features = false
  110    110   
optional = true
  111    111   
         112  +
[dependencies.tokio-rustls]
         113  +
version = "0.26.2"
         114  +
default-features = false
         115  +
optional = true
         116  +
  112    117   
[dependencies.s2n-tls-hyper]
  113         -
version = "0.0.4"
         118  +
version = "0.0.16"
  114    119   
optional = true
  115    120   
  116    121   
[dependencies.s2n-tls]
  117         -
version = "0.3.12"
         122  +
version = "0.3.24"
         123  +
optional = true
         124  +
         125  +
[dependencies.s2n-tls-tokio]
         126  +
version = "0.3.24"
  118    127   
optional = true
  119    128   
  120    129   
[dependencies.tower]
  121    130   
version = "0.5.2"
  122    131   
optional = true
  123    132   
  124    133   
[dependencies.rustls-pki-types]
  125    134   
version = "1.12.0"
  126    135   
features = ["std"]
  127    136   
optional = true
@@ -151,160 +221,232 @@
  171    180   
version = "1.0.210"
  172    181   
features = ["derive"]
  173    182   
optional = true
  174    183   
  175    184   
[dependencies.serde_json]
  176    185   
version = "1.0.128"
  177    186   
features = ["preserve_order"]
  178    187   
optional = true
  179    188   
  180    189   
[dependencies.indexmap]
  181         -
version = "2.6.0"
         190  +
version = "2.10.0"
  182    191   
features = ["serde"]
  183    192   
optional = true
  184    193   
  185    194   
[dependencies.http-body-util]
  186    195   
version = "0.1.2"
  187    196   
optional = true
  188    197   
  189    198   
[dev-dependencies]
         199  +
serial_test = "3.2"
         200  +
base64 = "0.22"
  190    201   
rustls-pemfile = "2.2.0"
  191         -
tokio-rustls = "0.26.1"
         202  +
tokio-rustls = "0.26.2"
  192    203   
  193    204   
[dev-dependencies.aws-smithy-async]
  194    205   
path = "../aws-smithy-async"
  195    206   
features = ["rt-tokio", "test-util"]
  196    207   
version = "1.2.5"
  197    208   
  198    209   
[dev-dependencies.aws-smithy-runtime-api]
  199    210   
path = "../aws-smithy-runtime-api"
  200    211   
features = ["test-util"]
  201         -
version = "1.8.7"
         212  +
version = "1.9.0"
  202    213   
  203    214   
[dev-dependencies.aws-smithy-types]
  204    215   
path = "../aws-smithy-types"
  205    216   
features = ["http-body-0-4-x", "test-util"]
  206    217   
version = "1.3.2"
  207    218   
  208    219   
[dev-dependencies.http-body-util]
  209    220   
version = "0.1.2"
  210    221   
  211    222   
[dev-dependencies.hyper-util]
  212         -
version = "0.1.7"
         223  +
version = "0.1.16"
  213    224   
features = ["full"]
  214    225   
  215    226   
[dev-dependencies.rustls-pki-types]
  216    227   
version = "1.12.0"
  217    228   
features = ["std"]
  218    229   
  219    230   
[dev-dependencies.tokio]
  220    231   
version = "1"
  221    232   
features = ["macros", "rt", "rt-multi-thread", "test-util", "full"]

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/client.rs

@@ -1,1 +71,76 @@
    1      1   
/*
    2      2   
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    3      3   
 * SPDX-License-Identifier: Apache-2.0
    4      4   
 */
    5      5   
    6      6   
mod dns;
           7  +
/// Proxy configuration
           8  +
pub mod proxy;
    7      9   
mod timeout;
    8     10   
/// TLS connector(s)
    9     11   
pub mod tls;
   10     12   
          13  +
pub(crate) mod connect;
          14  +
   11     15   
use crate::cfg::cfg_tls;
   12     16   
use crate::tls::TlsContext;
   13     17   
use aws_smithy_async::future::timeout::TimedOutError;
   14     18   
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep};
   15     19   
use aws_smithy_runtime_api::box_error::BoxError;
   16     20   
use aws_smithy_runtime_api::client::connection::CaptureSmithyConnection;
   17     21   
use aws_smithy_runtime_api::client::connection::ConnectionMetadata;
   18     22   
use aws_smithy_runtime_api::client::connector_metadata::ConnectorMetadata;
   19     23   
use aws_smithy_runtime_api::client::http::{
   20     24   
    HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings, SharedHttpClient,
   21     25   
    SharedHttpConnector,
   22     26   
};
   23     27   
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
   24     28   
use aws_smithy_runtime_api::client::result::ConnectorError;
   25     29   
use aws_smithy_runtime_api::client::runtime_components::{
   26     30   
    RuntimeComponents, RuntimeComponentsBuilder,
   27     31   
};
   28     32   
use aws_smithy_runtime_api::shared::IntoShared;
   29     33   
use aws_smithy_types::body::SdkBody;
   30     34   
use aws_smithy_types::config_bag::ConfigBag;
   31     35   
use aws_smithy_types::error::display::DisplayErrorContext;
   32     36   
use aws_smithy_types::retry::ErrorKind;
   33     37   
use client::connect::Connection;
   34     38   
use h2::Reason;
   35     39   
use http_1x::{Extensions, Uri};
   36     40   
use hyper::rt::{Read, Write};
   37     41   
use hyper_util::client::legacy as client;
   38     42   
use hyper_util::client::legacy::connect::dns::GaiResolver;
   39     43   
use hyper_util::client::legacy::connect::{
   40     44   
    capture_connection, CaptureConnection, Connect, HttpConnector as HyperHttpConnector, HttpInfo,
   41     45   
};
          46  +
use hyper_util::client::proxy::matcher::Matcher;
   42     47   
use hyper_util::rt::TokioExecutor;
   43     48   
use std::borrow::Cow;
   44     49   
use std::collections::HashMap;
   45     50   
use std::error::Error;
   46     51   
use std::fmt;
   47     52   
use std::sync::RwLock;
   48     53   
use std::time::Duration;
   49     54   
   50     55   
/// Given `HttpConnectorSettings` and an `SharedAsyncSleep`, create a `SharedHttpConnector` from defaults depending on what cargo features are activated.
   51     56   
pub fn default_connector(
@@ -76,81 +228,265 @@
   96    101   
    }
   97    102   
}
   98    103   
   99    104   
impl HttpConnector for Connector {
  100    105   
    fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
  101    106   
        self.adapter.call(request)
  102    107   
    }
  103    108   
}
  104    109   
  105    110   
/// Builder for [`Connector`].
  106         -
#[derive(Default, Debug)]
         111  +
#[derive(Default, Debug, Clone)]
  107    112   
pub struct ConnectorBuilder<Tls = TlsUnset> {
  108    113   
    connector_settings: Option<HttpConnectorSettings>,
  109    114   
    sleep_impl: Option<SharedAsyncSleep>,
  110    115   
    client_builder: Option<hyper_util::client::legacy::Builder>,
  111    116   
    enable_tcp_nodelay: bool,
  112    117   
    interface: Option<String>,
         118  +
    proxy_config: Option<proxy::ProxyConfig>,
  113    119   
    #[allow(unused)]
  114    120   
    tls: Tls,
  115    121   
}
  116    122   
  117    123   
/// Initial builder state, `TlsProvider` choice required
  118         -
#[derive(Default)]
         124  +
#[derive(Default, Debug, Clone)]
  119    125   
#[non_exhaustive]
  120    126   
pub struct TlsUnset {}
  121    127   
  122    128   
/// TLS implementation selected
         129  +
#[derive(Debug, Clone)]
  123    130   
pub struct TlsProviderSelected {
  124    131   
    #[allow(unused)]
  125    132   
    provider: tls::Provider,
  126    133   
    #[allow(unused)]
  127    134   
    context: TlsContext,
  128    135   
}
  129    136   
  130    137   
impl ConnectorBuilder<TlsUnset> {
  131    138   
    /// Set the TLS implementation to use for this connector
  132    139   
    pub fn tls_provider(self, provider: tls::Provider) -> ConnectorBuilder<TlsProviderSelected> {
  133    140   
        ConnectorBuilder {
  134    141   
            connector_settings: self.connector_settings,
  135    142   
            sleep_impl: self.sleep_impl,
  136    143   
            client_builder: self.client_builder,
  137    144   
            enable_tcp_nodelay: self.enable_tcp_nodelay,
  138    145   
            interface: self.interface,
         146  +
            proxy_config: self.proxy_config,
  139    147   
            tls: TlsProviderSelected {
  140    148   
                provider,
  141    149   
                context: TlsContext::default(),
  142    150   
            },
  143    151   
        }
  144    152   
    }
  145    153   
  146    154   
    /// Build an HTTP connector sans TLS
  147    155   
    #[doc(hidden)]
  148    156   
    pub fn build_http(self) -> Connector {
         157  +
        if let Some(ref proxy_config) = self.proxy_config {
         158  +
            if proxy_config.requires_tls() {
         159  +
                tracing::warn!(
         160  +
                    "HTTPS proxy configured but no TLS provider set. \
         161  +
                     Connections to HTTPS proxy servers will fail. \
         162  +
                     Consider configuring a TLS provider to enable TLS support."
         163  +
                );
         164  +
            }
         165  +
        }
         166  +
  149    167   
        let base = self.base_connector();
         168  +
         169  +
        // Wrap with HTTP proxy support if proxy is configured
         170  +
        let proxy_config = self
         171  +
            .proxy_config
         172  +
            .clone()
         173  +
            .unwrap_or_else(proxy::ProxyConfig::disabled);
         174  +
         175  +
        if !proxy_config.is_disabled() {
         176  +
            let http_proxy_connector = connect::HttpProxyConnector::new(base, proxy_config);
         177  +
            self.wrap_connector(http_proxy_connector)
         178  +
        } else {
  150    179   
            self.wrap_connector(base)
  151    180   
        }
         181  +
    }
  152    182   
}
  153    183   
  154    184   
impl<Any> ConnectorBuilder<Any> {
  155    185   
    /// Create a [`Connector`] from this builder and a given connector.
  156    186   
    pub(crate) fn wrap_connector<C>(self, tcp_connector: C) -> Connector
  157    187   
    where
  158    188   
        C: Send + Sync + 'static,
  159    189   
        C: Clone,
  160    190   
        C: tower::Service<Uri>,
  161    191   
        C::Response: Read + Write + Connection + Send + Sync + Unpin,
  162    192   
        C: Connect,
  163    193   
        C::Future: Unpin + Send + 'static,
  164    194   
        C::Error: Into<BoxError>,
  165    195   
    {
  166    196   
        let client_builder =
  167    197   
            self.client_builder
  168    198   
                .unwrap_or(hyper_util::client::legacy::Builder::new(
  169    199   
                    TokioExecutor::new(),
  170    200   
                ));
  171    201   
        let sleep_impl = self.sleep_impl.or_else(default_async_sleep);
  172    202   
        let (connect_timeout, read_timeout) = self
  173    203   
            .connector_settings
  174    204   
            .map(|c| (c.connect_timeout(), c.read_timeout()))
  175    205   
            .unwrap_or((None, None));
  176    206   
  177    207   
        let connector = match connect_timeout {
  178    208   
            Some(duration) => timeout::ConnectTimeout::new(
  179    209   
                tcp_connector,
  180    210   
                sleep_impl
  181    211   
                    .clone()
  182    212   
                    .expect("a sleep impl must be provided in order to have a connect timeout"),
  183    213   
                duration,
  184    214   
            ),
  185    215   
            None => timeout::ConnectTimeout::no_timeout(tcp_connector),
  186    216   
        };
  187    217   
        let base = client_builder.build(connector);
  188    218   
        let read_timeout = match read_timeout {
  189    219   
            Some(duration) => timeout::HttpReadTimeout::new(
  190    220   
                base,
  191    221   
                sleep_impl.expect("a sleep impl must be provided in order to have a read timeout"),
  192    222   
                duration,
  193    223   
            ),
  194    224   
            None => timeout::HttpReadTimeout::no_timeout(base),
  195    225   
        };
         226  +
         227  +
        let proxy_matcher = self
         228  +
            .proxy_config
         229  +
            .as_ref()
         230  +
            .map(|config| config.clone().into_hyper_util_matcher());
         231  +
  196    232   
        Connector {
  197    233   
            adapter: Box::new(Adapter {
  198    234   
                client: read_timeout,
         235  +
                proxy_matcher,
  199    236   
            }),
  200    237   
        }
  201    238   
    }
  202    239   
  203    240   
    /// Get the base TCP connector by mapping our config to the underlying `HttpConnector` from hyper
  204    241   
    /// (which is a base TCP connector with no TLS or any wrapping)
  205    242   
    fn base_connector(&self) -> HyperHttpConnector {
  206    243   
        self.base_connector_with_resolver(GaiResolver::new())
  207    244   
    }
  208    245   
@@ -254,291 +395,501 @@
  274    311   
    ///
  275    312   
    /// This function is only available on Android, Fuchsia, and Linux.
  276    313   
    ///
  277    314   
    /// [VRF]: https://www.kernel.org/doc/Documentation/networking/vrf.txt
  278    315   
    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
  279    316   
    pub fn set_interface<S: Into<String>>(&mut self, interface: S) -> &mut Self {
  280    317   
        self.interface = Some(interface.into());
  281    318   
        self
  282    319   
    }
  283    320   
         321  +
    /// Configure proxy settings for this connector
         322  +
    ///
         323  +
    /// This method allows you to set explicit proxy configuration for the HTTP client.
         324  +
    /// The proxy configuration will be used to determine whether requests should be
         325  +
    /// routed through a proxy server or connect directly.
         326  +
    ///
         327  +
    /// # Examples
         328  +
    ///
         329  +
    /// ```rust
         330  +
    /// # #[cfg(feature = "rustls-aws-lc")]
         331  +
    /// # {
         332  +
    /// use aws_smithy_http_client::{Connector, proxy::ProxyConfig, tls};
         333  +
    ///
         334  +
    /// let proxy_config = ProxyConfig::http("http://proxy.example.com:8080")?;
         335  +
    /// let connector = Connector::builder()
         336  +
    ///     .proxy_config(proxy_config)
         337  +
    ///     .tls_provider(tls::Provider::Rustls(tls::rustls_provider::CryptoMode::AwsLc))
         338  +
    ///     .build();
         339  +
    /// # }
         340  +
    /// # Ok::<(), Box<dyn std::error::Error>>(())
         341  +
    /// ```
         342  +
    pub fn proxy_config(mut self, config: proxy::ProxyConfig) -> Self {
         343  +
        self.proxy_config = Some(config);
         344  +
        self
         345  +
    }
         346  +
         347  +
    /// Configure proxy settings for this connector
         348  +
    ///
         349  +
    /// This is the mutable version of [`proxy_config`](Self::proxy_config).
         350  +
    pub fn set_proxy_config(&mut self, config: Option<proxy::ProxyConfig>) -> &mut Self {
         351  +
        self.proxy_config = config;
         352  +
        self
         353  +
    }
         354  +
  284    355   
    /// Override the Hyper client [`Builder`](hyper_util::client::legacy::Builder) used to construct this client.
  285    356   
    ///
  286    357   
    /// This enables changing settings like forcing HTTP2 and modifying other default client behavior.
  287    358   
    pub(crate) fn hyper_builder(
  288    359   
        mut self,
  289    360   
        hyper_builder: hyper_util::client::legacy::Builder,
  290    361   
    ) -> Self {
  291    362   
        self.set_hyper_builder(Some(hyper_builder));
  292    363   
        self
  293    364   
    }
  294    365   
  295    366   
    /// Override the Hyper client [`Builder`](hyper_util::client::legacy::Builder) used to construct this client.
  296    367   
    ///
  297    368   
    /// This enables changing settings like forcing HTTP2 and modifying other default client behavior.
  298    369   
    pub(crate) fn set_hyper_builder(
  299    370   
        &mut self,
  300    371   
        hyper_builder: Option<hyper_util::client::legacy::Builder>,
  301    372   
    ) -> &mut Self {
  302    373   
        self.client_builder = hyper_builder;
  303    374   
        self
  304    375   
    }
  305    376   
}
  306    377   
  307    378   
/// Adapter to use a Hyper 1.0-based Client as an `HttpConnector`
  308    379   
///
  309    380   
/// This adapter also enables TCP `CONNECT` and HTTP `READ` timeouts via [`Connector::builder`].
  310    381   
struct Adapter<C> {
  311    382   
    client: timeout::HttpReadTimeout<
  312    383   
        hyper_util::client::legacy::Client<timeout::ConnectTimeout<C>, SdkBody>,
  313    384   
    >,
         385  +
    proxy_matcher: Option<Matcher>,
  314    386   
}
  315    387   
  316    388   
impl<C> fmt::Debug for Adapter<C> {
  317    389   
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  318    390   
        f.debug_struct("Adapter")
  319    391   
            .field("client", &"** hyper client **")
         392  +
            .field("proxy_matcher", &self.proxy_matcher.is_some())
  320    393   
            .finish()
  321    394   
    }
  322    395   
}
  323    396   
  324    397   
/// Extract a smithy connection from a hyper CaptureConnection
  325    398   
fn extract_smithy_connection(capture_conn: &CaptureConnection) -> Option<ConnectionMetadata> {
  326    399   
    let capture_conn = capture_conn.clone();
  327    400   
    if let Some(conn) = capture_conn.clone().connection_metadata().as_ref() {
  328    401   
        let mut extensions = Extensions::new();
  329    402   
        conn.get_extras(&mut extensions);
  330    403   
        let http_info = extensions.get::<HttpInfo>();
  331    404   
        let mut builder = ConnectionMetadata::builder()
  332    405   
            .proxied(conn.is_proxied())
  333    406   
            .poison_fn(move || match capture_conn.connection_metadata().as_ref() {
  334    407   
                Some(conn) => conn.poison(),
  335    408   
                None => tracing::trace!("no connection existed to poison"),
  336    409   
            });
  337    410   
  338    411   
        builder
  339    412   
            .set_local_addr(http_info.map(|info| info.local_addr()))
  340    413   
            .set_remote_addr(http_info.map(|info| info.remote_addr()));
  341    414   
  342    415   
        let smithy_connection = builder.build();
  343    416   
  344    417   
        Some(smithy_connection)
  345    418   
    } else {
  346    419   
        None
  347    420   
    }
  348    421   
}
  349    422   
         423  +
impl<C> Adapter<C> {
         424  +
    /// Add proxy authentication header to the request if needed
         425  +
    fn add_proxy_auth_header(&self, request: &mut http_1x::Request<SdkBody>) {
         426  +
        // Only add auth for HTTP requests (not HTTPS which uses CONNECT tunneling)
         427  +
        if request.uri().scheme() != Some(&http_1x::uri::Scheme::HTTP) {
         428  +
            return;
         429  +
        }
         430  +
         431  +
        // Don't override existing proxy authorization header
         432  +
        if request
         433  +
            .headers()
         434  +
            .contains_key(http_1x::header::PROXY_AUTHORIZATION)
         435  +
        {
         436  +
            return;
         437  +
        }
         438  +
         439  +
        if let Some(ref matcher) = self.proxy_matcher {
         440  +
            if let Some(intercept) = matcher.intercept(request.uri()) {
         441  +
                // Add basic auth header if available
         442  +
                if let Some(auth_header) = intercept.basic_auth() {
         443  +
                    request
         444  +
                        .headers_mut()
         445  +
                        .insert(http_1x::header::PROXY_AUTHORIZATION, auth_header.clone());
         446  +
                    tracing::debug!("added proxy authentication header for {}", request.uri());
         447  +
                }
         448  +
            }
         449  +
        }
         450  +
    }
         451  +
}
         452  +
  350    453   
impl<C> HttpConnector for Adapter<C>
  351    454   
where
  352    455   
    C: Clone + Send + Sync + 'static,
  353    456   
    C: tower::Service<Uri>,
  354    457   
    C::Response: Connection + Read + Write + Unpin + 'static,
  355    458   
    timeout::ConnectTimeout<C>: Connect,
  356    459   
    C::Future: Unpin + Send + 'static,
  357    460   
    C::Error: Into<BoxError>,
  358    461   
{
  359    462   
    fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
  360    463   
        let mut request = match request.try_into_http1x() {
  361    464   
            Ok(request) => request,
  362    465   
            Err(err) => {
  363    466   
                return HttpConnectorFuture::ready(Err(ConnectorError::user(err.into())));
  364    467   
            }
  365    468   
        };
         469  +
         470  +
        self.add_proxy_auth_header(&mut request);
         471  +
  366    472   
        let capture_connection = capture_connection(&mut request);
  367    473   
        if let Some(capture_smithy_connection) =
  368    474   
            request.extensions().get::<CaptureSmithyConnection>()
  369    475   
        {
  370    476   
            capture_smithy_connection
  371    477   
                .set_connection_retriever(move || extract_smithy_connection(&capture_connection));
  372    478   
        }
  373    479   
        let mut client = self.client.clone();
  374    480   
        use tower::Service;
  375    481   
        let fut = client.call(request);
@@ -587,693 +709,843 @@
  607    713   
            R::Error: Into<Box<dyn Error + Send + Sync>>,
  608    714   
        {
  609    715   
            match &self.tls.provider {
  610    716   
                // TODO(hyper1) - fix cfg_rustls! to allow matching on patterns so we can re-use it and not duplicate these cfg matches everywhere
  611    717   
                #[cfg(any(
  612    718   
                    feature = "rustls-aws-lc",
  613    719   
                    feature = "rustls-aws-lc-fips",
  614    720   
                    feature = "rustls-ring"
  615    721   
                ))]
  616    722   
                tls::Provider::Rustls(crypto_mode) => {
         723  +
                    let proxy_config = self.proxy_config.clone()
         724  +
                        .unwrap_or_else(proxy::ProxyConfig::disabled);
         725  +
  617    726   
                    let https_connector = tls::rustls_provider::build_connector::wrap_connector(
  618    727   
                        http_connector,
  619    728   
                        crypto_mode.clone(),
  620    729   
                        &self.tls.context,
         730  +
                        proxy_config,
  621    731   
                    );
  622    732   
                    self.wrap_connector(https_connector)
  623    733   
                },
  624    734   
                #[cfg(feature = "s2n-tls")]
  625    735   
                tls::Provider::S2nTls  => {
  626         -
                    let https_connector = tls::s2n_tls_provider::build_connector::wrap_connector(http_connector, &self.tls.context);
         736  +
                    let proxy_config = self.proxy_config.clone()
         737  +
                        .unwrap_or_else(proxy::ProxyConfig::disabled);
         738  +
         739  +
                    let https_connector = tls::s2n_tls_provider::build_connector::wrap_connector(
         740  +
                        http_connector,
         741  +
                        &self.tls.context,
         742  +
                        proxy_config,
         743  +
                    );
  627    744   
                    self.wrap_connector(https_connector)
  628    745   
                }
  629    746   
            }
  630    747   
        }
  631    748   
    }
  632    749   
  633    750   
    impl Builder<TlsProviderSelected> {
  634    751   
        /// Create an HTTPS client with the selected TLS provider.
  635    752   
        ///
  636    753   
        /// The trusted certificates will be loaded later when this becomes the selected
  637    754   
        /// HTTP client for a Smithy client.
  638    755   
        pub fn build_https(self) -> SharedHttpClient {
  639    756   
            build_with_conn_fn(
  640    757   
                self.client_builder,
  641    758   
                move |client_builder, settings, runtime_components| {
  642    759   
                    let builder = new_conn_builder(client_builder, settings, runtime_components)
  643    760   
                        .tls_provider(self.tls_provider.provider.clone())
  644    761   
                        .tls_context(self.tls_provider.context.clone());
  645    762   
                    builder.build()
  646    763   
                },
  647    764   
            )
  648    765   
        }
  649    766   
  650    767   
        /// Create an HTTPS client using a custom DNS resolver
  651    768   
        pub fn build_with_resolver(
  652    769   
            self,
  653    770   
            resolver: impl ResolveDns + Clone + 'static,
  654    771   
        ) -> SharedHttpClient {
  655    772   
            build_with_conn_fn(
  656    773   
                self.client_builder,
  657    774   
                move |client_builder, settings, runtime_components| {
  658    775   
                    let builder = new_conn_builder(client_builder, settings, runtime_components)
  659    776   
                        .tls_provider(self.tls_provider.provider.clone())
  660    777   
                        .tls_context(self.tls_provider.context.clone());
  661    778   
                    builder.build_with_resolver(resolver.clone())
  662    779   
                },
  663    780   
            )
  664    781   
        }
  665    782   
  666    783   
        /// Configure the TLS context
  667    784   
        pub fn tls_context(mut self, ctx: TlsContext) -> Self {
  668    785   
            self.tls_provider.context = ctx;
  669    786   
            self
  670    787   
        }
  671    788   
    }
  672    789   
}
  673    790   
  674    791   
impl Builder<TlsUnset> {
  675    792   
    /// Creates a new builder.
  676    793   
    pub fn new() -> Self {
  677    794   
        Self::default()
  678    795   
    }
  679    796   
         797  +
    /// Returns a [`SharedHttpClient`] that calls the given `connector` function to select an HTTP(S) connector.
         798  +
    #[doc(hidden)]
         799  +
    pub fn build_with_connector_fn<F>(self, connector_fn: F) -> SharedHttpClient
         800  +
    where
         801  +
        F: Fn(Option<&HttpConnectorSettings>, Option<&RuntimeComponents>) -> Connector
         802  +
            + Send
         803  +
            + Sync
         804  +
            + 'static,
         805  +
    {
         806  +
        build_with_conn_fn(
         807  +
            self.client_builder,
         808  +
            move |_builder, settings, runtime_components| {
         809  +
                connector_fn(settings, runtime_components)
         810  +
            },
         811  +
        )
         812  +
    }
         813  +
  680    814   
    /// Build a new HTTP client without TLS enabled
  681    815   
    #[doc(hidden)]
  682    816   
    pub fn build_http(self) -> SharedHttpClient {
  683    817   
        build_with_conn_fn(
  684    818   
            self.client_builder,
  685    819   
            move |client_builder, settings, runtime_components| {
  686    820   
                let builder = new_conn_builder(client_builder, settings, runtime_components);
  687    821   
                builder.build_http()
  688    822   
            },
  689    823   
        )
@@ -966,1100 +1026,1160 @@
  986   1120   
                let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
  987   1121   
                DnsFuture::ready(Ok(vec![localhost_v4]))
  988   1122   
            }
  989   1123   
        }
  990   1124   
  991   1125   
        let connector_settings = HttpConnectorSettings::builder()
  992   1126   
            .connect_timeout(Duration::from_secs(20))
  993   1127   
            .build();
  994   1128   
  995   1129   
        let resolver = HyperUtilResolver {
  996         -
            resolver: TestResolver::default(),
        1130  +
            resolver: TestResolver,
  997   1131   
        };
  998   1132   
        let connector = Connector::builder().base_connector_with_resolver(resolver);
  999   1133   
 1000   1134   
        let hyper = Connector::builder()
 1001   1135   
            .connector_settings(connector_settings)
 1002   1136   
            .sleep_impl(SharedAsyncSleep::new(TokioSleep::new()))
 1003   1137   
            .wrap_connector(connector)
 1004   1138   
            .adapter;
 1005   1139   
 1006   1140   
        let resp = hyper

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/client/connect.rs

@@ -0,1 +0,164 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
use crate::client::connect;
           6  +
use crate::proxy;
           7  +
use aws_smithy_runtime_api::box_error::BoxError;
           8  +
use http_1x::Uri;
           9  +
use hyper::rt::{Read, ReadBufCursor, Write};
          10  +
use hyper_util::client::legacy::connect::{Connected, Connection};
          11  +
use pin_project_lite::pin_project;
          12  +
use std::future::Future;
          13  +
use std::io;
          14  +
use std::io::IoSlice;
          15  +
use std::pin::Pin;
          16  +
use std::task::{Context, Poll};
          17  +
          18  +
pub(crate) trait AsyncConn:
          19  +
    Read + Write + Connection + Send + Sync + Unpin + 'static
          20  +
{
          21  +
}
          22  +
          23  +
impl<T: Read + Write + Connection + Send + Sync + Unpin + 'static> AsyncConn for T {}
          24  +
          25  +
pub(crate) type BoxConn = Box<dyn AsyncConn>;
          26  +
          27  +
// Future for connecting
          28  +
pub(crate) type Connecting = Pin<Box<dyn Future<Output = Result<Conn, BoxError>> + Send>>;
          29  +
          30  +
pin_project! {
          31  +
    pub(crate) struct Conn {
          32  +
        #[pin]
          33  +
        pub(super)inner: BoxConn,
          34  +
        pub(super) is_proxy: bool,
          35  +
    }
          36  +
}
          37  +
          38  +
impl Connection for Conn {
          39  +
    fn connected(&self) -> Connected {
          40  +
        self.inner.connected().proxy(self.is_proxy)
          41  +
    }
          42  +
}
          43  +
          44  +
impl Read for Conn {
          45  +
    fn poll_read(
          46  +
        self: Pin<&mut Self>,
          47  +
        cx: &mut Context<'_>,
          48  +
        buf: ReadBufCursor<'_>,
          49  +
    ) -> Poll<io::Result<()>> {
          50  +
        let this = self.project();
          51  +
        Read::poll_read(this.inner, cx, buf)
          52  +
    }
          53  +
}
          54  +
          55  +
impl Write for Conn {
          56  +
    fn poll_write(
          57  +
        self: Pin<&mut Self>,
          58  +
        cx: &mut Context<'_>,
          59  +
        buf: &[u8],
          60  +
    ) -> Poll<Result<usize, io::Error>> {
          61  +
        let this = self.project();
          62  +
        Write::poll_write(this.inner, cx, buf)
          63  +
    }
          64  +
          65  +
    fn poll_write_vectored(
          66  +
        self: Pin<&mut Self>,
          67  +
        cx: &mut Context<'_>,
          68  +
        bufs: &[IoSlice<'_>],
          69  +
    ) -> Poll<Result<usize, io::Error>> {
          70  +
        let this = self.project();
          71  +
        Write::poll_write_vectored(this.inner, cx, bufs)
          72  +
    }
          73  +
          74  +
    fn is_write_vectored(&self) -> bool {
          75  +
        self.inner.is_write_vectored()
          76  +
    }
          77  +
          78  +
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
          79  +
        let this = self.project();
          80  +
        Write::poll_flush(this.inner, cx)
          81  +
    }
          82  +
          83  +
    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
          84  +
        let this = self.project();
          85  +
        Write::poll_shutdown(this.inner, cx)
          86  +
    }
          87  +
}
          88  +
          89  +
/// HTTP-only proxy connector for handling HTTP requests through HTTP proxies
          90  +
///
          91  +
/// This connector handles the HTTP proxy logic when no TLS provider is selected,
          92  +
/// including request URL modification and proxy authentication.
          93  +
#[derive(Debug, Clone)]
          94  +
pub(crate) struct HttpProxyConnector<C> {
          95  +
    inner: C,
          96  +
    proxy_config: proxy::ProxyConfig,
          97  +
}
          98  +
          99  +
impl<C> HttpProxyConnector<C> {
         100  +
    pub(crate) fn new(inner: C, proxy_config: proxy::ProxyConfig) -> Self {
         101  +
        Self {
         102  +
            inner,
         103  +
            proxy_config,
         104  +
        }
         105  +
    }
         106  +
}
         107  +
         108  +
impl<C> tower::Service<Uri> for HttpProxyConnector<C>
         109  +
where
         110  +
    C: tower::Service<Uri> + Clone + Send + 'static,
         111  +
    C::Response: hyper::rt::Read
         112  +
        + hyper::rt::Write
         113  +
        + hyper_util::client::legacy::connect::Connection
         114  +
        + Send
         115  +
        + Sync
         116  +
        + Unpin
         117  +
        + 'static,
         118  +
    C::Future: Send + 'static,
         119  +
    C::Error: Into<BoxError>,
         120  +
{
         121  +
    type Response = connect::Conn;
         122  +
    type Error = BoxError;
         123  +
    type Future = connect::Connecting;
         124  +
         125  +
    fn poll_ready(
         126  +
        &mut self,
         127  +
        cx: &mut std::task::Context<'_>,
         128  +
    ) -> std::task::Poll<Result<(), Self::Error>> {
         129  +
        self.inner.poll_ready(cx).map_err(Into::into)
         130  +
    }
         131  +
         132  +
    fn call(&mut self, dst: Uri) -> Self::Future {
         133  +
        // Check if this request should be proxied
         134  +
        let proxy_intercept = if !self.proxy_config.is_disabled() {
         135  +
            let matcher = self.proxy_config.clone().into_hyper_util_matcher();
         136  +
            matcher.intercept(&dst)
         137  +
        } else {
         138  +
            None
         139  +
        };
         140  +
         141  +
        if let Some(intercept) = proxy_intercept {
         142  +
            // HTTP through proxy: Connect to proxy server
         143  +
            let proxy_uri = intercept.uri().clone();
         144  +
            let fut = self.inner.call(proxy_uri);
         145  +
            Box::pin(async move {
         146  +
                let conn = fut.await.map_err(Into::into)?;
         147  +
                Ok(connect::Conn {
         148  +
                    inner: Box::new(conn),
         149  +
                    is_proxy: true,
         150  +
                })
         151  +
            })
         152  +
        } else {
         153  +
            // Direct connection
         154  +
            let fut = self.inner.call(dst);
         155  +
            Box::pin(async move {
         156  +
                let conn = fut.await.map_err(Into::into)?;
         157  +
                Ok(connect::Conn {
         158  +
                    inner: Box::new(conn),
         159  +
                    is_proxy: false,
         160  +
                })
         161  +
            })
         162  +
        }
         163  +
    }
         164  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/client/proxy.rs

@@ -0,1 +0,816 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! Proxy configuration for HTTP clients
           7  +
//!
           8  +
//! This module provides types and utilities for configuring HTTP and HTTPS proxies,
           9  +
//! including support for environment variable detection, authentication, and bypass rules.
          10  +
          11  +
use http_1x::Uri;
          12  +
use hyper_util::client::proxy::matcher::Matcher;
          13  +
use std::fmt;
          14  +
          15  +
/// Proxy configuration for HTTP clients
          16  +
///
          17  +
/// Supports HTTP and HTTPS proxy configuration with authentication and bypass rules.
          18  +
/// Can be configured programmatically or automatically detected from environment variables.
          19  +
///
          20  +
/// # Examples
          21  +
///
          22  +
/// ```rust
          23  +
/// use aws_smithy_http_client::proxy::ProxyConfig;
          24  +
///
          25  +
/// // HTTP proxy for all traffic
          26  +
/// let config = ProxyConfig::http("http://proxy.example.com:8080")?;
          27  +
///
          28  +
/// // HTTPS traffic through HTTP proxy (common case - no TLS needed for proxy connection)
          29  +
/// let config = ProxyConfig::https("http://proxy.example.com:8080")?
          30  +
///     .with_basic_auth("username", "password")
          31  +
///     .no_proxy("localhost,*.internal");
          32  +
///
          33  +
/// // Detect from environment variables
          34  +
/// let config = ProxyConfig::from_env();
          35  +
/// # Ok::<(), Box<dyn std::error::Error>>(())
          36  +
/// ```
          37  +
#[derive(Debug, Clone)]
          38  +
pub struct ProxyConfig {
          39  +
    inner: ProxyConfigInner,
          40  +
}
          41  +
          42  +
/// Internal configuration representation
          43  +
#[derive(Debug, Clone)]
          44  +
enum ProxyConfigInner {
          45  +
    /// Use environment variable detection
          46  +
    FromEnvironment,
          47  +
    /// Explicit HTTP proxy
          48  +
    Http {
          49  +
        uri: Uri,
          50  +
        auth: Option<ProxyAuth>,
          51  +
        no_proxy: Option<String>,
          52  +
    },
          53  +
    /// Explicit HTTPS proxy
          54  +
    Https {
          55  +
        uri: Uri,
          56  +
        auth: Option<ProxyAuth>,
          57  +
        no_proxy: Option<String>,
          58  +
    },
          59  +
    /// Proxy for all traffic
          60  +
    All {
          61  +
        uri: Uri,
          62  +
        auth: Option<ProxyAuth>,
          63  +
        no_proxy: Option<String>,
          64  +
    },
          65  +
    /// Explicitly disabled
          66  +
    Disabled,
          67  +
}
          68  +
          69  +
/// Proxy authentication configuration
          70  +
///
          71  +
/// Stored for later conversion to hyper-util format.
          72  +
#[derive(Debug, Clone)]
          73  +
struct ProxyAuth {
          74  +
    /// Username for authentication
          75  +
    username: String,
          76  +
    /// Password for authentication
          77  +
    password: String,
          78  +
}
          79  +
          80  +
/// Errors that can occur during proxy configuration
          81  +
#[derive(Debug)]
          82  +
pub struct ProxyError {
          83  +
    kind: ErrorKind,
          84  +
}
          85  +
          86  +
#[derive(Debug)]
          87  +
enum ErrorKind {
          88  +
    InvalidUrl(String),
          89  +
}
          90  +
          91  +
impl From<ErrorKind> for ProxyError {
          92  +
    fn from(value: ErrorKind) -> Self {
          93  +
        Self { kind: value }
          94  +
    }
          95  +
}
          96  +
          97  +
impl fmt::Display for ProxyError {
          98  +
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          99  +
        match &self.kind {
         100  +
            ErrorKind::InvalidUrl(url) => write!(f, "invalid proxy URL: {}", url),
         101  +
        }
         102  +
    }
         103  +
}
         104  +
         105  +
impl std::error::Error for ProxyError {}
         106  +
         107  +
impl ProxyConfig {
         108  +
    /// Create a new proxy configuration for HTTP traffic only
         109  +
    ///
         110  +
    /// # Arguments
         111  +
    /// * `proxy_url` - The HTTP proxy URL
         112  +
    ///
         113  +
    /// # Examples
         114  +
    /// ```rust
         115  +
    /// use aws_smithy_http_client::proxy::ProxyConfig;
         116  +
    ///
         117  +
    /// let config = ProxyConfig::http("http://proxy.example.com:8080")?;
         118  +
    /// # Ok::<(), Box<dyn std::error::Error>>(())
         119  +
    /// ```
         120  +
    pub fn http<U>(proxy_url: U) -> Result<Self, ProxyError>
         121  +
    where
         122  +
        U: TryInto<Uri>,
         123  +
        U::Error: fmt::Display,
         124  +
    {
         125  +
        let uri = proxy_url
         126  +
            .try_into()
         127  +
            .map_err(|e| ErrorKind::InvalidUrl(e.to_string()))?;
         128  +
         129  +
        Self::validate_proxy_uri(&uri)?;
         130  +
         131  +
        Ok(ProxyConfig {
         132  +
            inner: ProxyConfigInner::Http {
         133  +
                uri,
         134  +
                auth: None,
         135  +
                no_proxy: None,
         136  +
            },
         137  +
        })
         138  +
    }
         139  +
         140  +
    /// Create a new proxy configuration for HTTPS traffic only
         141  +
    ///
         142  +
    /// This proxy will only be used for `https://` requests. HTTP requests
         143  +
    /// will connect directly unless a separate HTTP proxy is configured.
         144  +
    ///
         145  +
    /// The proxy URL itself can use either HTTP or HTTPS scheme:
         146  +
    /// - `http://proxy.example.com:8080` - Connect to proxy using HTTP (no TLS needed)
         147  +
    /// - `https://proxy.example.com:8080` - Connect to proxy using HTTPS (TLS required)
         148  +
    ///
         149  +
    /// **Note**: If the proxy URL itself uses HTTPS scheme, TLS support must be
         150  +
    /// available when building the connector, otherwise connections will fail.
         151  +
    ///
         152  +
    /// # Arguments
         153  +
    /// * `proxy_url` - The proxy URL
         154  +
    ///
         155  +
    /// # Examples
         156  +
    /// ```rust
         157  +
    /// use aws_smithy_http_client::proxy::ProxyConfig;
         158  +
    ///
         159  +
    /// // HTTPS traffic through HTTP proxy (no TLS needed for proxy connection)
         160  +
    /// let config = ProxyConfig::https("http://proxy.example.com:8080")?;
         161  +
    ///
         162  +
    /// // HTTPS traffic through HTTPS proxy (TLS needed for proxy connection)
         163  +
    /// let config = ProxyConfig::https("https://secure-proxy.example.com:8080")?;
         164  +
    /// # Ok::<(), Box<dyn std::error::Error>>(())
         165  +
    /// ```
         166  +
    pub fn https<U>(proxy_url: U) -> Result<Self, ProxyError>
         167  +
    where
         168  +
        U: TryInto<Uri>,
         169  +
        U::Error: fmt::Display,
         170  +
    {
         171  +
        let uri = proxy_url
         172  +
            .try_into()
         173  +
            .map_err(|e| ErrorKind::InvalidUrl(e.to_string()))?;
         174  +
         175  +
        Self::validate_proxy_uri(&uri)?;
         176  +
         177  +
        Ok(ProxyConfig {
         178  +
            inner: ProxyConfigInner::Https {
         179  +
                uri,
         180  +
                auth: None,
         181  +
                no_proxy: None,
         182  +
            },
         183  +
        })
         184  +
    }
         185  +
         186  +
    /// Create a new proxy configuration for all HTTP and HTTPS traffic
         187  +
    ///
         188  +
    /// This proxy will be used for both `http://` and `https://` requests.
         189  +
    /// This is equivalent to setting both HTTP and HTTPS proxies to the same URL.
         190  +
    ///
         191  +
    /// **Note**: If the proxy URL itself uses HTTPS scheme, TLS support must be
         192  +
    /// available when building the connector, otherwise connections will fail.
         193  +
    ///
         194  +
    /// # Arguments
         195  +
    /// * `proxy_url` - The proxy URL
         196  +
    ///
         197  +
    /// # Examples
         198  +
    /// ```rust
         199  +
    /// use aws_smithy_http_client::proxy::ProxyConfig;
         200  +
    ///
         201  +
    /// let config = ProxyConfig::all("http://proxy.example.com:8080")?;
         202  +
    /// # Ok::<(), Box<dyn std::error::Error>>(())
         203  +
    /// ```
         204  +
    pub fn all<U>(proxy_url: U) -> Result<Self, ProxyError>
         205  +
    where
         206  +
        U: TryInto<Uri>,
         207  +
        U::Error: fmt::Display,
         208  +
    {
         209  +
        let uri = proxy_url
         210  +
            .try_into()
         211  +
            .map_err(|e| ErrorKind::InvalidUrl(e.to_string()))?;
         212  +
         213  +
        Self::validate_proxy_uri(&uri)?;
         214  +
         215  +
        Ok(ProxyConfig {
         216  +
            inner: ProxyConfigInner::All {
         217  +
                uri,
         218  +
                auth: None,
         219  +
                no_proxy: None,
         220  +
            },
         221  +
        })
         222  +
    }
         223  +
         224  +
    /// Create a proxy configuration that disables all proxy usage
         225  +
    ///
         226  +
    /// This is useful for explicitly disabling proxy support even when
         227  +
    /// environment variables are set.
         228  +
    ///
         229  +
    /// # Examples
         230  +
    /// ```rust
         231  +
    /// use aws_smithy_http_client::proxy::ProxyConfig;
         232  +
    ///
         233  +
    /// let config = ProxyConfig::disabled();
         234  +
    /// ```
         235  +
    pub fn disabled() -> Self {
         236  +
        ProxyConfig {
         237  +
            inner: ProxyConfigInner::Disabled,
         238  +
        }
         239  +
    }
         240  +
         241  +
    /// Add basic authentication to this proxy configuration
         242  +
    ///
         243  +
    /// # Arguments
         244  +
    /// * `username` - Username for proxy authentication
         245  +
    /// * `password` - Password for proxy authentication
         246  +
    ///
         247  +
    /// # Examples
         248  +
    /// ```rust
         249  +
    /// use aws_smithy_http_client::proxy::ProxyConfig;
         250  +
    ///
         251  +
    /// let config = ProxyConfig::http("http://proxy.example.com:8080")?
         252  +
    ///     .with_basic_auth("username", "password");
         253  +
    /// # Ok::<(), Box<dyn std::error::Error>>(())
         254  +
    /// ```
         255  +
    pub fn with_basic_auth<U, P>(mut self, username: U, password: P) -> Self
         256  +
    where
         257  +
        U: Into<String>,
         258  +
        P: Into<String>,
         259  +
    {
         260  +
        let auth = ProxyAuth {
         261  +
            username: username.into(),
         262  +
            password: password.into(),
         263  +
        };
         264  +
         265  +
        match &mut self.inner {
         266  +
            ProxyConfigInner::Http {
         267  +
                auth: ref mut a, ..
         268  +
            } => *a = Some(auth),
         269  +
            ProxyConfigInner::Https {
         270  +
                auth: ref mut a, ..
         271  +
            } => *a = Some(auth),
         272  +
            ProxyConfigInner::All {
         273  +
                auth: ref mut a, ..
         274  +
            } => *a = Some(auth),
         275  +
            ProxyConfigInner::FromEnvironment | ProxyConfigInner::Disabled => {
         276  +
                // Cannot add auth to environment or disabled configs
         277  +
            }
         278  +
        }
         279  +
         280  +
        self
         281  +
    }
         282  +
         283  +
    /// Add NO_PROXY rules to this configuration
         284  +
    ///
         285  +
    /// NO_PROXY rules specify hosts that should bypass the proxy and connect directly.
         286  +
    ///
         287  +
    /// # Arguments
         288  +
    /// * `rules` - Comma-separated list of bypass rules
         289  +
    ///
         290  +
    /// # Examples
         291  +
    /// ```rust
         292  +
    /// use aws_smithy_http_client::proxy::ProxyConfig;
         293  +
    ///
         294  +
    /// let config = ProxyConfig::http("http://proxy.example.com:8080")?
         295  +
    ///     .no_proxy("localhost,127.0.0.1,*.internal,10.0.0.0/8");
         296  +
    /// # Ok::<(), Box<dyn std::error::Error>>(())
         297  +
    /// ```
         298  +
    pub fn no_proxy<S: AsRef<str>>(mut self, rules: S) -> Self {
         299  +
        let rules_str = rules.as_ref().to_string();
         300  +
         301  +
        match &mut self.inner {
         302  +
            ProxyConfigInner::Http {
         303  +
                no_proxy: ref mut n,
         304  +
                ..
         305  +
            } => *n = Some(rules_str),
         306  +
            ProxyConfigInner::Https {
         307  +
                no_proxy: ref mut n,
         308  +
                ..
         309  +
            } => *n = Some(rules_str),
         310  +
            ProxyConfigInner::All {
         311  +
                no_proxy: ref mut n,
         312  +
                ..
         313  +
            } => *n = Some(rules_str),
         314  +
            ProxyConfigInner::FromEnvironment | ProxyConfigInner::Disabled => {
         315  +
                // Cannot add no_proxy to environment or disabled configs
         316  +
                // Environment configs will use NO_PROXY env var
         317  +
                // FIXME - is this what we want?
         318  +
            }
         319  +
        }
         320  +
         321  +
        self
         322  +
    }
         323  +
         324  +
    /// Create proxy configuration from environment variables
         325  +
    ///
         326  +
    /// Reads standard proxy environment variables:
         327  +
    /// - `HTTP_PROXY` / `http_proxy`: HTTP proxy URL
         328  +
    /// - `HTTPS_PROXY` / `https_proxy`: HTTPS proxy URL
         329  +
    /// - `ALL_PROXY` / `all_proxy`: Proxy for all protocols (fallback)
         330  +
    /// - `NO_PROXY` / `no_proxy`: Comma-separated bypass rules
         331  +
    ///
         332  +
    /// If no proxy environment variables are set, this returns a configuration
         333  +
    /// that won't intercept any requests (equivalent to no proxy).
         334  +
    ///
         335  +
    /// # Examples
         336  +
    /// ```rust
         337  +
    /// use aws_smithy_http_client::proxy::ProxyConfig;
         338  +
    ///
         339  +
    /// // Always succeeds, even if no environment variables are set
         340  +
    /// let config = ProxyConfig::from_env();
         341  +
    /// ```
         342  +
    pub fn from_env() -> Self {
         343  +
        // Delegate to environment variable parsing
         344  +
        // If no env vars are set, creates a matcher that doesn't intercept anything
         345  +
        ProxyConfig {
         346  +
            inner: ProxyConfigInner::FromEnvironment,
         347  +
        }
         348  +
    }
         349  +
         350  +
    /// Check if proxy is disabled (no proxy configuration)
         351  +
    pub fn is_disabled(&self) -> bool {
         352  +
        matches!(self.inner, ProxyConfigInner::Disabled)
         353  +
    }
         354  +
         355  +
    /// Check if this configuration uses environment variables
         356  +
    pub fn is_from_env(&self) -> bool {
         357  +
        matches!(self.inner, ProxyConfigInner::FromEnvironment)
         358  +
    }
         359  +
         360  +
    /// Convert this configuration to internal proxy matcher
         361  +
    ///
         362  +
    /// This method converts the user-friendly configuration to the internal
         363  +
    /// proxy matching implementation used by the HTTP client.
         364  +
    pub(crate) fn into_hyper_util_matcher(self) -> Matcher {
         365  +
        match self.inner {
         366  +
            ProxyConfigInner::FromEnvironment => Matcher::from_env(),
         367  +
            ProxyConfigInner::Http {
         368  +
                uri,
         369  +
                auth,
         370  +
                no_proxy,
         371  +
            } => {
         372  +
                let mut builder = Matcher::builder();
         373  +
         374  +
                // Set HTTP proxy with authentication embedded in URL if present
         375  +
                let proxy_url = Self::build_proxy_url(uri, auth);
         376  +
                builder = builder.http(proxy_url);
         377  +
         378  +
                // Add NO_PROXY rules if present
         379  +
                if let Some(no_proxy_rules) = no_proxy {
         380  +
                    builder = builder.no(no_proxy_rules);
         381  +
                }
         382  +
         383  +
                builder.build()
         384  +
            }
         385  +
            ProxyConfigInner::Https {
         386  +
                uri,
         387  +
                auth,
         388  +
                no_proxy,
         389  +
            } => {
         390  +
                let mut builder = Matcher::builder();
         391  +
         392  +
                // Set HTTPS proxy with authentication embedded in URL if present
         393  +
                let proxy_url = Self::build_proxy_url(uri, auth);
         394  +
                builder = builder.https(proxy_url);
         395  +
         396  +
                // Add NO_PROXY rules if present
         397  +
                if let Some(no_proxy_rules) = no_proxy {
         398  +
                    builder = builder.no(no_proxy_rules);
         399  +
                }
         400  +
         401  +
                builder.build()
         402  +
            }
         403  +
            ProxyConfigInner::All {
         404  +
                uri,
         405  +
                auth,
         406  +
                no_proxy,
         407  +
            } => {
         408  +
                let mut builder = Matcher::builder();
         409  +
         410  +
                // Set proxy for all traffic with authentication embedded in URL if present
         411  +
                let proxy_url = Self::build_proxy_url(uri, auth);
         412  +
                builder = builder.all(proxy_url);
         413  +
         414  +
                // Add NO_PROXY rules if present
         415  +
                if let Some(no_proxy_rules) = no_proxy {
         416  +
                    builder = builder.no(no_proxy_rules);
         417  +
                }
         418  +
         419  +
                builder.build()
         420  +
            }
         421  +
            ProxyConfigInner::Disabled => {
         422  +
                // Create an empty matcher that won't intercept anything
         423  +
                Matcher::builder().build()
         424  +
            }
         425  +
        }
         426  +
    }
         427  +
         428  +
    /// Check if this proxy configuration requires TLS support
         429  +
    ///
         430  +
    /// Returns true if any of the configured proxy URLs use HTTPS scheme,
         431  +
    /// which requires TLS to establish the connection to the proxy server.
         432  +
    pub(crate) fn requires_tls(&self) -> bool {
         433  +
        match &self.inner {
         434  +
            ProxyConfigInner::Http { uri, .. } => uri.scheme_str() == Some("https"),
         435  +
            ProxyConfigInner::Https { uri, .. } => uri.scheme_str() == Some("https"),
         436  +
            ProxyConfigInner::All { uri, .. } => uri.scheme_str() == Some("https"),
         437  +
            ProxyConfigInner::FromEnvironment => {
         438  +
                // Check environment variables for HTTPS proxy URLs
         439  +
                Self::env_vars_require_tls()
         440  +
            }
         441  +
            ProxyConfigInner::Disabled => false,
         442  +
        }
         443  +
    }
         444  +
         445  +
    /// Check if any environment proxy variables contain HTTPS URLs
         446  +
    fn env_vars_require_tls() -> bool {
         447  +
        let proxy_vars = [
         448  +
            "HTTP_PROXY",
         449  +
            "http_proxy",
         450  +
            "HTTPS_PROXY",
         451  +
            "https_proxy",
         452  +
            "ALL_PROXY",
         453  +
            "all_proxy",
         454  +
        ];
         455  +
         456  +
        for var in &proxy_vars {
         457  +
            if let Ok(proxy_url) = std::env::var(var) {
         458  +
                if !proxy_url.is_empty() {
         459  +
                    // Simple check for https:// scheme
         460  +
                    if proxy_url.starts_with("https://") {
         461  +
                        return true;
         462  +
                    }
         463  +
                }
         464  +
            }
         465  +
        }
         466  +
        false
         467  +
    }
         468  +
         469  +
    fn validate_proxy_uri(uri: &Uri) -> Result<(), ProxyError> {
         470  +
        // Validate scheme
         471  +
        match uri.scheme_str() {
         472  +
            Some("http") | Some("https") => {}
         473  +
            Some(scheme) => {
         474  +
                return Err(
         475  +
                    ErrorKind::InvalidUrl(format!("unsupported proxy scheme: {}", scheme)).into(),
         476  +
                );
         477  +
            }
         478  +
            None => {
         479  +
                return Err(ErrorKind::InvalidUrl(
         480  +
                    "proxy URL must include scheme (http:// or https://)".to_string(),
         481  +
                )
         482  +
                .into());
         483  +
            }
         484  +
        }
         485  +
         486  +
        // Validate host
         487  +
        if uri.host().is_none() {
         488  +
            return Err(ErrorKind::InvalidUrl("proxy URL must include host".to_string()).into());
         489  +
        }
         490  +
         491  +
        Ok(())
         492  +
    }
         493  +
         494  +
    fn build_proxy_url(uri: Uri, auth: Option<ProxyAuth>) -> String {
         495  +
        let uri_str = uri.to_string();
         496  +
         497  +
        if let Some(auth) = auth {
         498  +
            // Embed authentication in the URL: scheme://username:password@host:port/path
         499  +
            if let Some(scheme_end) = uri_str.find("://") {
         500  +
                let scheme = &uri_str[..scheme_end + 3];
         501  +
                let rest = &uri_str[scheme_end + 3..];
         502  +
         503  +
                // Check if auth is already present in the URI
         504  +
                if rest.contains('@') {
         505  +
                    // Auth already present, return as-is
         506  +
                    uri_str
         507  +
                } else {
         508  +
                    // Add auth to the URI
         509  +
                    format!("{}{}:{}@{}", scheme, auth.username, auth.password, rest)
         510  +
                }
         511  +
            } else {
         512  +
                // Invalid URI format, return as-is
         513  +
                uri_str
         514  +
            }
         515  +
        } else {
         516  +
            // No authentication, return URI as-is
         517  +
            uri_str
         518  +
        }
         519  +
    }
         520  +
}
         521  +
         522  +
#[cfg(test)]
         523  +
mod tests {
         524  +
    use super::*;
         525  +
    use std::env;
         526  +
         527  +
    #[test]
         528  +
    fn test_proxy_config_http() {
         529  +
        let config = ProxyConfig::http("http://proxy.example.com:8080").unwrap();
         530  +
        assert!(!config.is_disabled());
         531  +
        assert!(!config.is_from_env());
         532  +
    }
         533  +
         534  +
    #[test]
         535  +
    fn test_proxy_config_https() {
         536  +
        let config = ProxyConfig::https("http://proxy.example.com:8080").unwrap();
         537  +
        assert!(!config.is_disabled());
         538  +
        assert!(!config.is_from_env());
         539  +
    }
         540  +
         541  +
    #[test]
         542  +
    fn test_proxy_config_all() {
         543  +
        let config = ProxyConfig::all("http://proxy.example.com:8080").unwrap();
         544  +
        assert!(!config.is_disabled());
         545  +
        assert!(!config.is_from_env());
         546  +
    }
         547  +
         548  +
    #[test]
         549  +
    fn test_proxy_config_disabled() {
         550  +
        let config = ProxyConfig::disabled();
         551  +
        assert!(config.is_disabled());
         552  +
        assert!(!config.is_from_env());
         553  +
    }
         554  +
         555  +
    #[test]
         556  +
    fn test_proxy_config_with_auth() {
         557  +
        let config = ProxyConfig::http("http://proxy.example.com:8080")
         558  +
            .unwrap()
         559  +
            .with_basic_auth("user", "pass");
         560  +
         561  +
        // Auth is stored internally
         562  +
        assert!(!config.is_disabled());
         563  +
    }
         564  +
         565  +
    #[test]
         566  +
    fn test_proxy_config_with_no_proxy() {
         567  +
        let config = ProxyConfig::http("http://proxy.example.com:8080")
         568  +
            .unwrap()
         569  +
            .no_proxy("localhost,*.internal");
         570  +
         571  +
        // NO_PROXY rules are stored internally
         572  +
        assert!(!config.is_disabled());
         573  +
    }
         574  +
         575  +
    #[test]
         576  +
    fn test_proxy_config_invalid_url() {
         577  +
        let result = ProxyConfig::http("not-a-url");
         578  +
        assert!(result.is_err());
         579  +
    }
         580  +
         581  +
    #[test]
         582  +
    fn test_proxy_config_invalid_scheme() {
         583  +
        let result = ProxyConfig::http("ftp://proxy.example.com:8080");
         584  +
        assert!(result.is_err());
         585  +
    }
         586  +
         587  +
    #[test]
         588  +
    #[serial_test::serial]
         589  +
    fn test_proxy_config_from_env_with_vars() {
         590  +
        // Save original environment
         591  +
        let original_http = env::var("HTTP_PROXY");
         592  +
         593  +
        // Set test environment
         594  +
        env::set_var("HTTP_PROXY", "http://test-proxy:8080");
         595  +
         596  +
        let config = ProxyConfig::from_env();
         597  +
        assert!(config.is_from_env());
         598  +
         599  +
        // Restore original environment
         600  +
        match original_http {
         601  +
            Ok(val) => env::set_var("HTTP_PROXY", val),
         602  +
            Err(_) => env::remove_var("HTTP_PROXY"),
         603  +
        }
         604  +
    }
         605  +
         606  +
    #[test]
         607  +
    #[serial_test::serial]
         608  +
    fn test_proxy_config_from_env_without_vars() {
         609  +
        // Save original environment
         610  +
        let original_vars: Vec<_> = [
         611  +
            "HTTP_PROXY",
         612  +
            "http_proxy",
         613  +
            "HTTPS_PROXY",
         614  +
            "https_proxy",
         615  +
            "ALL_PROXY",
         616  +
            "all_proxy",
         617  +
        ]
         618  +
        .iter()
         619  +
        .map(|var| (*var, env::var(var)))
         620  +
        .collect();
         621  +
         622  +
        // Clear all proxy environment variables
         623  +
        for (var, _) in &original_vars {
         624  +
            env::remove_var(var);
         625  +
        }
         626  +
         627  +
        let config = ProxyConfig::from_env();
         628  +
        assert!(config.is_from_env());
         629  +
         630  +
        // Restore original environment
         631  +
        for (var, original_value) in original_vars {
         632  +
            match original_value {
         633  +
                Ok(val) => env::set_var(var, val),
         634  +
                Err(_) => env::remove_var(var),
         635  +
            }
         636  +
        }
         637  +
    }
         638  +
         639  +
    #[test]
         640  +
    #[serial_test::serial]
         641  +
    fn test_auth_cannot_be_added_to_env_config() {
         642  +
        // Save original environment
         643  +
        let original_http = env::var("HTTP_PROXY");
         644  +
        env::set_var("HTTP_PROXY", "http://test-proxy:8080");
         645  +
         646  +
        let config = ProxyConfig::from_env().with_basic_auth("user", "pass"); // This should be ignored
         647  +
         648  +
        assert!(config.is_from_env());
         649  +
         650  +
        // Restore original environment
         651  +
        match original_http {
         652  +
            Ok(val) => env::set_var("HTTP_PROXY", val),
         653  +
            Err(_) => env::remove_var("HTTP_PROXY"),
         654  +
        }
         655  +
    }
         656  +
         657  +
    #[test]
         658  +
    #[serial_test::serial]
         659  +
    fn test_no_proxy_cannot_be_added_to_env_config() {
         660  +
        // Save original environment
         661  +
        let original_http = env::var("HTTP_PROXY");
         662  +
        env::set_var("HTTP_PROXY", "http://test-proxy:8080");
         663  +
         664  +
        let config = ProxyConfig::from_env().no_proxy("localhost"); // This should be ignored
         665  +
         666  +
        assert!(config.is_from_env());
         667  +
         668  +
        // Restore original environment
         669  +
        match original_http {
         670  +
            Ok(val) => env::set_var("HTTP_PROXY", val),
         671  +
            Err(_) => env::remove_var("HTTP_PROXY"),
         672  +
        }
         673  +
    }
         674  +
         675  +
    #[test]
         676  +
    fn test_build_proxy_url_without_auth() {
         677  +
        let uri = "http://proxy.example.com:8080".parse().unwrap();
         678  +
        let url = ProxyConfig::build_proxy_url(uri, None);
         679  +
        assert_eq!(url, "http://proxy.example.com:8080/");
         680  +
    }
         681  +
         682  +
    #[test]
         683  +
    fn test_build_proxy_url_with_auth() {
         684  +
        let uri = "http://proxy.example.com:8080".parse().unwrap();
         685  +
        let auth = ProxyAuth {
         686  +
            username: "user".to_string(),
         687  +
            password: "pass".to_string(),
         688  +
        };
         689  +
        let url = ProxyConfig::build_proxy_url(uri, Some(auth));
         690  +
        assert_eq!(url, "http://user:pass@proxy.example.com:8080/");
         691  +
    }
         692  +
         693  +
    #[test]
         694  +
    fn test_build_proxy_url_with_existing_auth() {
         695  +
        let uri = "http://existing:creds@proxy.example.com:8080"
         696  +
            .parse()
         697  +
            .unwrap();
         698  +
        let auth = ProxyAuth {
         699  +
            username: "user".to_string(),
         700  +
            password: "pass".to_string(),
         701  +
        };
         702  +
        let url = ProxyConfig::build_proxy_url(uri, Some(auth));
         703  +
        // Should not override existing auth
         704  +
        assert_eq!(url, "http://existing:creds@proxy.example.com:8080/");
         705  +
    }
         706  +
         707  +
    #[test]
         708  +
    #[serial_test::serial]
         709  +
    fn test_into_hyper_util_matcher_from_env() {
         710  +
        // Save original environment
         711  +
        let original_http = env::var("HTTP_PROXY");
         712  +
        env::set_var("HTTP_PROXY", "http://test-proxy:8080");
         713  +
         714  +
        let config = ProxyConfig::from_env();
         715  +
        let matcher = config.into_hyper_util_matcher();
         716  +
         717  +
        // Test that the matcher intercepts HTTP requests
         718  +
        let test_uri = "http://example.com".parse().unwrap();
         719  +
        let intercept = matcher.intercept(&test_uri);
         720  +
        assert!(intercept.is_some());
         721  +
         722  +
        // Restore original environment
         723  +
        match original_http {
         724  +
            Ok(val) => env::set_var("HTTP_PROXY", val),
         725  +
            Err(_) => env::remove_var("HTTP_PROXY"),
         726  +
        }
         727  +
    }
         728  +
         729  +
    #[test]
         730  +
    fn test_into_hyper_util_matcher_http() {
         731  +
        let config = ProxyConfig::http("http://proxy.example.com:8080").unwrap();
         732  +
        let matcher = config.into_hyper_util_matcher();
         733  +
         734  +
        // Test that the matcher intercepts HTTP requests
         735  +
        let test_uri = "http://example.com".parse().unwrap();
         736  +
        let intercept = matcher.intercept(&test_uri);
         737  +
        assert!(intercept.is_some());
         738  +
        // The intercept URI might be normalized
         739  +
        assert!(intercept
         740  +
            .unwrap()
         741  +
            .uri()
         742  +
            .to_string()
         743  +
            .starts_with("http://proxy.example.com:8080"));
         744  +
         745  +
        // Test that it doesn't intercept HTTPS requests
         746  +
        let https_uri = "https://example.com".parse().unwrap();
         747  +
        let https_intercept = matcher.intercept(&https_uri);
         748  +
        assert!(https_intercept.is_none());
         749  +
    }
         750  +
         751  +
    #[test]
         752  +
    fn test_into_hyper_util_matcher_with_auth() {
         753  +
        let config = ProxyConfig::http("http://proxy.example.com:8080")
         754  +
            .unwrap()
         755  +
            .with_basic_auth("user", "pass");
         756  +
        let matcher = config.into_hyper_util_matcher();
         757  +
         758  +
        // Test that the matcher intercepts HTTP requests
         759  +
        let test_uri = "http://example.com".parse().unwrap();
         760  +
        let intercept = matcher.intercept(&test_uri);
         761  +
        assert!(intercept.is_some());
         762  +
         763  +
        let intercept = intercept.unwrap();
         764  +
        // The proxy URI should contain the host (auth is handled separately)
         765  +
        assert!(intercept
         766  +
            .uri()
         767  +
            .to_string()
         768  +
            .contains("proxy.example.com:8080"));
         769  +
         770  +
        // Test that basic auth is available
         771  +
        assert!(intercept.basic_auth().is_some());
         772  +
    }
         773  +
         774  +
    #[test]
         775  +
    fn test_into_hyper_util_matcher_disabled() {
         776  +
        let config = ProxyConfig::disabled();
         777  +
        let matcher = config.into_hyper_util_matcher();
         778  +
         779  +
        // Test that the matcher doesn't intercept any requests
         780  +
        let test_uri = "http://example.com".parse().unwrap();
         781  +
        let intercept = matcher.intercept(&test_uri);
         782  +
        assert!(intercept.is_none());
         783  +
    }
         784  +
         785  +
    #[test]
         786  +
    #[serial_test::serial]
         787  +
    fn test_requires_tls_detection() {
         788  +
        // HTTP proxy should not require TLS
         789  +
        let http_config = ProxyConfig::http("http://proxy.example.com:8080").unwrap();
         790  +
        assert!(!http_config.requires_tls());
         791  +
         792  +
        // HTTPS proxy URL should require TLS
         793  +
        let https_config = ProxyConfig::http("https://proxy.example.com:8080").unwrap();
         794  +
        assert!(https_config.requires_tls());
         795  +
         796  +
        // All proxy with HTTP URL should not require TLS
         797  +
        let all_http_config = ProxyConfig::all("http://proxy.example.com:8080").unwrap();
         798  +
        assert!(!all_http_config.requires_tls());
         799  +
         800  +
        // Environment config with HTTPS proxy should require TLS
         801  +
        env::set_var("HTTP_PROXY", "https://proxy.example.com:8080");
         802  +
        let env_config = ProxyConfig::from_env();
         803  +
        assert!(env_config.requires_tls()); // Now detects HTTPS in env vars
         804  +
        env::remove_var("HTTP_PROXY");
         805  +
         806  +
        // Environment config with HTTP proxy should not require TLS
         807  +
        env::set_var("HTTP_PROXY", "http://proxy.example.com:8080");
         808  +
        let env_config = ProxyConfig::from_env();
         809  +
        assert!(!env_config.requires_tls());
         810  +
        env::remove_var("HTTP_PROXY");
         811  +
         812  +
        // Disabled config should not require TLS
         813  +
        let disabled_config = ProxyConfig::disabled();
         814  +
        assert!(!disabled_config.requires_tls());
         815  +
    }
         816  +
}