From d3b2f9e65b6b3200f3a0e791e3ab26942db84406 Mon Sep 17 00:00:00 2001 From: glendc Date: Mon, 2 Sep 2024 15:08:19 +0200 Subject: [PATCH 01/24] first phase of refactor (splitting crates) doesn't compile or work yet, giant WIP macros works for most part, same as rama-http-types... now in progress of rama-net, and building up from there --- Cargo.lock | 157 +++++- Cargo.toml | 59 +- README.md | 2 +- rama-cli/README.md | 2 +- rama-core/Cargo.toml | 19 +- rama-core/README.md | 58 ++ rama-core/src/dns/mod.rs | 112 +++- rama-core/src/lib.rs | 57 +- {src => rama-core/src}/telemetry/mod.rs | 0 .../src}/telemetry/opentelemetry.rs | 0 rama-core/src/utils/macros/mod.rs | 266 --------- rama-core/src/utils/mod.rs | 3 +- rama-error/Cargo.toml | 22 + rama-error/README.md | 49 ++ .../error => rama-error/src}/ext/backtrace.rs | 0 .../error => rama-error/src}/ext/context.rs | 0 .../src/error => rama-error/src}/ext/mod.rs | 2 +- .../error => rama-error/src}/ext/wrapper.rs | 2 +- .../src/error/mod.rs => rama-error/src/lib.rs | 54 ++ .../src/error => rama-error/src}/macros.rs | 6 +- rama-http-backend/Cargo.toml | 23 + rama-http-backend/README.md | 50 ++ rama-http-backend/src/lib.rs | 53 ++ rama-http-types/Cargo.toml | 43 ++ rama-http-types/README.md | 49 ++ {src/http => rama-http-types/src}/body.rs | 18 +- {src/http => rama-http-types/src}/body_ext.rs | 26 +- .../src}/body_limit.rs | 2 +- .../src}/headers/ext.rs | 6 +- rama-http-types/src/headers/mod.rs | 87 +++ src/http/mod.rs => rama-http-types/src/lib.rs | 98 ++-- .../src}/response/append_headers.rs | 4 +- .../src}/response/form.rs | 18 +- .../src}/response/html.rs | 4 +- .../src}/response/into_response.rs | 16 +- .../src}/response/into_response_parts.rs | 7 +- .../src}/response/json.rs | 20 +- .../src}/response/mod.rs | 4 +- .../src}/response/redirect.rs | 2 +- rama-http/Cargo.toml | 54 ++ rama-http/README.md | 0 {src/http => rama-http/src}/client/conn.rs | 0 {src/http => rama-http/src}/client/error.rs | 0 {src/http => rama-http/src}/client/ext.rs | 0 {src/http => rama-http/src}/client/mod.rs | 0 {src/http => rama-http/src}/client/svc.rs | 0 {src/http => rama-http/src}/executor.rs | 0 .../src}/headers/common/accept.rs | 17 +- .../src}/headers/common/mod.rs | 0 .../headers/forwarded/exotic_forward_ip.rs | 12 +- .../src}/headers/forwarded/mod.rs | 8 +- .../src}/headers/forwarded/via.rs | 14 +- .../src}/headers/forwarded/x_forwarded_for.rs | 12 +- .../headers/forwarded/x_forwarded_host.rs | 12 +- .../headers/forwarded/x_forwarded_proto.rs | 10 +- {src/http => rama-http/src}/headers/mod.rs | 9 +- .../src}/headers/util/csv.rs | 4 +- .../src}/headers/util/mod.rs | 0 .../src}/headers/util/quality_value.rs | 14 +- {src/http => rama-http/src}/io/mod.rs | 0 {src/http => rama-http/src}/io/request.rs | 0 {src/http => rama-http/src}/io/response.rs | 0 .../src}/layer/auth/add_authorization.rs | 0 .../layer/auth/async_require_authorization.rs | 0 {src/http => rama-http/src}/layer/auth/mod.rs | 0 .../src}/layer/auth/require_authorization.rs | 0 .../src}/layer/body_limit.rs | 0 .../src}/layer/catch_panic.rs | 0 .../layer/classify/grpc_errors_as_failures.rs | 0 .../src}/layer/classify/map_failure_class.rs | 0 .../src}/layer/classify/mod.rs | 0 .../classify/status_in_range_is_error.rs | 0 .../src}/layer/compression/body.rs | 0 .../src}/layer/compression/layer.rs | 0 .../src}/layer/compression/mod.rs | 0 .../src}/layer/compression/pin_project_cfg.rs | 0 .../src}/layer/compression/predicate.rs | 0 .../src}/layer/compression/service.rs | 0 .../src}/layer/cors/allow_credentials.rs | 0 .../src}/layer/cors/allow_headers.rs | 0 .../src}/layer/cors/allow_methods.rs | 0 .../src}/layer/cors/allow_origin.rs | 0 .../src}/layer/cors/allow_private_network.rs | 0 .../src}/layer/cors/expose_headers.rs | 0 .../src}/layer/cors/max_age.rs | 0 {src/http => rama-http/src}/layer/cors/mod.rs | 0 .../src}/layer/cors/tests.rs | 0 .../http => rama-http/src}/layer/cors/vary.rs | 0 .../src}/layer/decompression/body.rs | 0 .../src}/layer/decompression/layer.rs | 0 .../src}/layer/decompression/mod.rs | 0 .../src}/layer/decompression/request/layer.rs | 0 .../src}/layer/decompression/request/mod.rs | 0 .../layer/decompression/request/service.rs | 0 .../src}/layer/decompression/service.rs | 0 .../src}/layer/dns/dns_map/layer.rs | 0 .../src}/layer/dns/dns_map/mod.rs | 0 .../src}/layer/dns/dns_map/service.rs | 0 .../src}/layer/dns/dns_resolve/layer.rs | 0 .../src}/layer/dns/dns_resolve/mod.rs | 0 .../src}/layer/dns/dns_resolve/service.rs | 0 .../layer/dns/dns_resolve/username_parser.rs | 0 {src/http => rama-http/src}/layer/dns/mod.rs | 0 .../src}/layer/error_handling.rs | 0 .../src}/layer/follow_redirect/mod.rs | 0 .../src}/layer/follow_redirect/policy/and.rs | 0 .../follow_redirect/policy/clone_body_fn.rs | 0 .../policy/filter_credentials.rs | 0 .../layer/follow_redirect/policy/limited.rs | 0 .../src}/layer/follow_redirect/policy/mod.rs | 0 .../src}/layer/follow_redirect/policy/or.rs | 0 .../follow_redirect/policy/redirect_fn.rs | 0 .../follow_redirect/policy/same_origin.rs | 0 .../src}/layer/forwarded/get_forwarded.rs | 17 +- .../src}/layer/forwarded/mod.rs | 0 .../src}/layer/forwarded/set_forwarded.rs | 6 +- .../src}/layer/header_config.rs | 0 .../src}/layer/header_option_value.rs | 0 .../src}/layer/map_request_body.rs | 0 .../src}/layer/map_response_body.rs | 0 {src/http => rama-http/src}/layer/mod.rs | 4 +- .../src}/layer/normalize_path.rs | 0 .../src}/layer/opentelemetry.rs | 0 .../src}/layer/propagate_headers.rs | 0 .../src}/layer/proxy_auth.rs | 0 .../src}/layer/remove_header/mod.rs | 0 .../src}/layer/remove_header/request.rs | 0 .../src}/layer/remove_header/response.rs | 0 .../src}/layer/request_id.rs | 0 .../src}/layer/required_header/mod.rs | 0 .../src}/layer/required_header/request.rs | 0 .../src}/layer/required_header/response.rs | 0 .../src}/layer/retry/body.rs | 0 .../src}/layer/retry/layer.rs | 0 .../src}/layer/retry/managed.rs | 0 .../http => rama-http/src}/layer/retry/mod.rs | 0 .../src}/layer/retry/policy.rs | 0 .../src}/layer/retry/tests.rs | 0 .../src}/layer/sensitive_headers.rs | 0 .../src}/layer/set_header/mod.rs | 0 .../src}/layer/set_header/request.rs | 0 .../src}/layer/set_header/response.rs | 0 .../src}/layer/set_status.rs | 0 {src/http => rama-http/src}/layer/timeout.rs | 0 .../src}/layer/trace/body.rs | 0 .../src}/layer/trace/layer.rs | 0 .../src}/layer/trace/make_span.rs | 0 .../http => rama-http/src}/layer/trace/mod.rs | 0 .../src}/layer/trace/on_body_chunk.rs | 0 .../src}/layer/trace/on_eos.rs | 0 .../src}/layer/trace/on_failure.rs | 0 .../src}/layer/trace/on_request.rs | 0 .../src}/layer/trace/on_response.rs | 0 .../src}/layer/trace/service.rs | 0 .../src}/layer/traffic_writer/mod.rs | 0 .../src}/layer/traffic_writer/request.rs | 0 .../src}/layer/traffic_writer/response.rs | 0 src/ua/layer.rs => rama-http/src/layer/ua.rs | 21 - .../src}/layer/upgrade/layer.rs | 0 .../src}/layer/upgrade/mod.rs | 0 .../src}/layer/upgrade/service.rs | 0 .../src}/layer/upgrade/upgraded.rs | 0 .../src}/layer/util/compression.rs | 0 .../src}/layer/util/content_encoding.rs | 0 {src/http => rama-http/src}/layer/util/mod.rs | 0 .../layer/validate_request/accept_header.rs | 0 .../src}/layer/validate_request/mod.rs | 0 .../src}/layer/validate_request/validate.rs | 0 .../layer/validate_request/validate_fn.rs | 0 .../validate_request_header.rs | 0 rama-http/src/lib.rs | 87 +++ {src/http => rama-http/src}/matcher/domain.rs | 0 {src/http => rama-http/src}/matcher/header.rs | 0 {src/http => rama-http/src}/matcher/method.rs | 0 {src/http => rama-http/src}/matcher/mod.rs | 0 .../http => rama-http/src}/matcher/path/de.rs | 0 .../src}/matcher/path/mod.rs | 0 {src/http => rama-http/src}/matcher/uri.rs | 0 .../http => rama-http/src}/matcher/version.rs | 0 .../http => rama-http/src}/request_context.rs | 14 +- .../src}/server/hyper_conn.rs | 0 {src/http => rama-http/src}/server/mod.rs | 0 {src/http => rama-http/src}/server/service.rs | 0 .../src}/server/svc_hyper.rs | 0 {src/http => rama-http/src}/service/fs/mod.rs | 0 .../src}/service/fs/serve_dir/future.rs | 0 .../src}/service/fs/serve_dir/headers.rs | 0 .../src}/service/fs/serve_dir/mod.rs | 0 .../src}/service/fs/serve_dir/open_file.rs | 0 .../src}/service/fs/serve_dir/tests.rs | 0 .../src}/service/fs/serve_file.rs | 0 {src/http => rama-http/src}/service/mod.rs | 0 .../src}/service/redirect.rs | 0 .../service/web/endpoint/extract/authority.rs | 0 .../web/endpoint/extract/body/bytes.rs | 0 .../service/web/endpoint/extract/body/form.rs | 0 .../service/web/endpoint/extract/body/json.rs | 0 .../service/web/endpoint/extract/body/mod.rs | 0 .../service/web/endpoint/extract/body/text.rs | 0 .../service/web/endpoint/extract/context.rs | 0 .../src}/service/web/endpoint/extract/dns.rs | 0 .../service/web/endpoint/extract/extension.rs | 0 .../src}/service/web/endpoint/extract/host.rs | 0 .../service/web/endpoint/extract/method.rs | 0 .../src}/service/web/endpoint/extract/mod.rs | 0 .../src}/service/web/endpoint/extract/path.rs | 0 .../service/web/endpoint/extract/query.rs | 0 .../service/web/endpoint/extract/request.rs | 0 .../service/web/endpoint/extract/state.rs | 0 .../web/endpoint/extract/typed_header.rs | 0 .../src}/service/web/endpoint/mod.rs | 0 .../src}/service/web/endpoint/service.rs | 0 .../http => rama-http/src}/service/web/k8s.rs | 0 .../http => rama-http/src}/service/web/mod.rs | 0 .../src}/service/web/service.rs | 0 .../src}/utils/header_value.rs | 2 +- {src/http => rama-http/src}/utils/mod.rs | 0 .../src/utils}/utils/macros/http_error.rs | 0 .../src/utils}/utils/macros/mod.rs | 0 {src => rama-http/src/utils}/utils/mod.rs | 0 rama-macros-proc/Cargo.toml | 31 ++ rama-macros-proc/README.md | 50 ++ .../src/as_ref.rs | 0 .../src/attr_parsing.rs | 0 rama-macros-proc/src/lib.rs | 115 ++++ .../src/type_parsing.rs | 0 .../tests/as_ref/fail/generics.rs | 0 .../tests/as_ref/fail/generics.stderr | 0 .../tests/as_ref/fail/wrap_ambiguity.rs | 0 .../tests/as_ref/fail/wrap_ambiguity.stderr | 0 .../tests/as_ref/fail/wrap_no_arc.rs | 0 .../tests/as_ref/fail/wrap_no_arc.stderr | 0 .../tests/as_ref/pass/basic.rs | 0 .../tests/as_ref/pass/reference-types.rs | 0 .../tests/as_ref/pass/skip.rs | 0 .../tests/as_ref/pass/wrap.rs | 0 .../tests/as_ref/pass/wrap_skip.rs | 0 rama-macros/Cargo.toml | 12 +- rama-macros/README.md | 15 +- .../utils/macros => rama-macros/src}/error.rs | 0 rama-macros/src/lib.rs | 314 +++++++++-- .../utils/macros => rama-macros/src}/str.rs | 3 +- rama-net/Cargo.toml | 49 ++ rama-net/README.md | 52 ++ .../net => rama-net/src}/address/authority.rs | 8 +- .../net => rama-net/src}/address/domain.rs | 2 +- .../src/net => rama-net/src}/address/host.rs | 8 +- .../src/net => rama-net/src}/address/mod.rs | 0 .../src/net => rama-net/src}/address/proxy.rs | 6 +- {rama-core/src/net => rama-net/src}/asn.rs | 1 + .../src/net => rama-net/src}/client/conn.rs | 2 +- .../src/net => rama-net/src}/client/mod.rs | 0 .../src}/forwarded/element/mod.rs | 12 +- .../src}/forwarded/element/parser.rs | 6 +- .../src/net => rama-net/src}/forwarded/mod.rs | 14 +- .../net => rama-net/src}/forwarded/node.rs | 6 +- .../src}/forwarded/obfuscated.rs | 2 +- .../net => rama-net/src}/forwarded/proto.rs | 8 +- .../net => rama-net/src}/forwarded/version.rs | 16 +- rama-net/src/lib.rs | 68 +++ {rama-core/src/net => rama-net/src}/mod.rs | 0 {rama-core/src/net => rama-net/src}/proto.rs | 6 +- .../src}/stream/layer/http/body_limit.rs | 6 +- .../src}/stream/layer/http/mod.rs | 0 {src => rama-net/src}/stream/layer/mod.rs | 1 + .../src}/stream/layer/opentelemetry.rs | 6 +- .../src}/stream/layer/tracker/bytes.rs | 0 .../src}/stream/layer/tracker/incoming.rs | 5 +- .../src}/stream/layer/tracker/mod.rs | 0 .../src}/stream/layer/tracker/outgoing.rs | 6 +- {src => rama-net/src}/stream/matcher/ip.rs | 15 +- .../src}/stream/matcher/loopback.rs | 13 +- {src => rama-net/src}/stream/matcher/mod.rs | 9 +- {src => rama-net/src}/stream/matcher/port.rs | 13 +- .../src}/stream/matcher/private_ip.rs | 15 +- .../src}/stream/matcher/socket.rs | 9 +- {src => rama-net/src}/stream/mod.rs | 2 - {src => rama-net/src}/stream/read.rs | 0 {src => rama-net/src}/stream/service/echo.rs | 3 +- {src => rama-net/src}/stream/service/mod.rs | 0 {src => rama-net/src}/stream/socket.rs | 0 {src/stream => rama-net/src}/transport.rs | 8 +- .../src/net => rama-net/src}/user/auth.rs | 13 +- .../src}/user/credentials/basic.rs | 2 +- .../src}/user/credentials/bearer.rs | 2 +- .../src}/user/credentials/mod.rs | 0 .../src}/user/credentials/proxy.rs | 7 +- .../src/net => rama-net/src}/user/id.rs | 0 .../src/net => rama-net/src}/user/mod.rs | 2 + rama-proxy/Cargo.toml | 31 ++ rama-proxy/README.md | 50 ++ .../src}/http/client/layer/mod.rs | 0 .../src}/http/client/layer/proxy_address.rs | 0 .../http/client/layer/proxy_auth_header.rs | 0 .../client/layer/proxy_connector/connector.rs | 0 .../client/layer/proxy_connector/layer.rs | 0 .../http/client/layer/proxy_connector/mod.rs | 0 .../client/layer/proxy_connector/service.rs | 0 .../src}/http/client/mod.rs | 0 {src/proxy => rama-proxy/src}/http/mod.rs | 0 src/proxy/mod.rs => rama-proxy/src/lib.rs | 30 +- .../src}/pp/client/layer.rs | 0 .../proxy => rama-proxy/src}/pp/client/mod.rs | 0 {src/proxy => rama-proxy/src}/pp/mod.rs | 0 .../src}/pp/protocol/ip.rs | 0 .../src}/pp/protocol/mod.rs | 0 .../src}/pp/protocol/v1/error.rs | 0 .../src}/pp/protocol/v1/mod.rs | 0 .../src}/pp/protocol/v1/model.rs | 0 .../src}/pp/protocol/v2/builder.rs | 0 .../src}/pp/protocol/v2/error.rs | 0 .../src}/pp/protocol/v2/mod.rs | 0 .../src}/pp/protocol/v2/model.rs | 0 .../src}/pp/server/layer.rs | 0 .../proxy => rama-proxy/src}/pp/server/mod.rs | 0 rama-proxy/src/proxydb/csv.rs | 526 ++++++++++++++++++ .../src}/proxydb/internal.rs | 21 +- .../proxy => rama-proxy/src}/proxydb/layer.rs | 0 {src/proxy => rama-proxy/src}/proxydb/mod.rs | 8 +- {src/proxy => rama-proxy/src}/proxydb/str.rs | 0 .../src}/proxydb/test_proxydb_rows.csv | 0 .../src}/proxydb/update.rs | 0 {src/proxy => rama-proxy/src}/username.rs | 0 rama-tls/Cargo.toml | 39 ++ rama-tls/README.md | 50 ++ .../src}/backend/boring/client/http.rs | 0 .../src}/backend/boring/client/mod.rs | 0 .../src}/backend/boring/mod.rs | 0 .../src}/backend/boring/server/config.rs | 0 .../src}/backend/boring/server/layer.rs | 0 .../src}/backend/boring/server/mod.rs | 0 .../src}/backend/boring/server/service.rs | 0 {src/tls => rama-tls/src}/backend/mod.rs | 0 .../src}/backend/rustls/client/http.rs | 0 .../src}/backend/rustls/client/mod.rs | 0 .../src}/backend/rustls/mod.rs | 0 .../backend/rustls/server/client_config.rs | 0 .../src}/backend/rustls/server/layer.rs | 0 .../src}/backend/rustls/server/mod.rs | 0 .../src}/backend/rustls/server/service.rs | 0 .../src}/backend/rustls/verify.rs | 0 .../src}/client/hello/boring.rs | 0 {src/tls => rama-tls/src}/client/hello/mod.rs | 0 .../src}/client/hello/rustls.rs | 0 {src/tls => rama-tls/src}/client/mod.rs | 0 {src/tls => rama-tls/src}/client/parser.rs | 0 {src/tls => rama-tls/src}/enums/mod.rs | 0 {src/tls => rama-tls/src}/enums/rustls.rs | 0 src/tls/mod.rs => rama-tls/src/lib.rs | 54 ++ rama-ua/Cargo.toml | 24 + rama-ua/README.md | 50 ++ {src/ua => rama-ua/src}/info.rs | 4 +- src/ua/mod.rs => rama-ua/src/lib.rs | 76 ++- {src/ua => rama-ua/src}/parse.rs | 0 {src/ua => rama-ua/src}/parse_tests.rs | 0 src/lib.rs | 29 +- 356 files changed, 2901 insertions(+), 751 deletions(-) create mode 100644 rama-core/README.md rename {src => rama-core/src}/telemetry/mod.rs (100%) rename {src => rama-core/src}/telemetry/opentelemetry.rs (100%) delete mode 100644 rama-core/src/utils/macros/mod.rs create mode 100644 rama-error/Cargo.toml create mode 100644 rama-error/README.md rename {rama-core/src/error => rama-error/src}/ext/backtrace.rs (100%) rename {rama-core/src/error => rama-error/src}/ext/context.rs (100%) rename {rama-core/src/error => rama-error/src}/ext/mod.rs (99%) rename {rama-core/src/error => rama-error/src}/ext/wrapper.rs (99%) rename rama-core/src/error/mod.rs => rama-error/src/lib.rs (84%) rename {rama-core/src/error => rama-error/src}/macros.rs (77%) create mode 100644 rama-http-backend/Cargo.toml create mode 100644 rama-http-backend/README.md create mode 100644 rama-http-backend/src/lib.rs create mode 100644 rama-http-types/Cargo.toml create mode 100644 rama-http-types/README.md rename {src/http => rama-http-types/src}/body.rs (94%) rename {src/http => rama-http-types/src}/body_ext.rs (77%) rename {src/http => rama-http-types/src}/body_limit.rs (97%) rename {src/http => rama-http-types/src}/headers/ext.rs (84%) create mode 100644 rama-http-types/src/headers/mod.rs rename src/http/mod.rs => rama-http-types/src/lib.rs (58%) rename {src/http => rama-http-types/src}/response/append_headers.rs (96%) rename {src/http => rama-http-types/src}/response/form.rs (87%) rename {src/http => rama-http-types/src}/response/html.rs (88%) rename {src/http => rama-http-types/src}/response/into_response.rs (98%) rename {src/http => rama-http-types/src}/response/into_response_parts.rs (98%) rename {src/http => rama-http-types/src}/response/json.rs (90%) rename {src/http => rama-http-types/src}/response/mod.rs (97%) rename {src/http => rama-http-types/src}/response/redirect.rs (94%) create mode 100644 rama-http/Cargo.toml create mode 100644 rama-http/README.md rename {src/http => rama-http/src}/client/conn.rs (100%) rename {src/http => rama-http/src}/client/error.rs (100%) rename {src/http => rama-http/src}/client/ext.rs (100%) rename {src/http => rama-http/src}/client/mod.rs (100%) rename {src/http => rama-http/src}/client/svc.rs (100%) rename {src/http => rama-http/src}/executor.rs (100%) rename {src/http => rama-http/src}/headers/common/accept.rs (93%) rename {src/http => rama-http/src}/headers/common/mod.rs (100%) rename {src/http => rama-http/src}/headers/forwarded/exotic_forward_ip.rs (95%) rename {src/http => rama-http/src}/headers/forwarded/mod.rs (90%) rename {src/http => rama-http/src}/headers/forwarded/via.rs (96%) rename {src/http => rama-http/src}/headers/forwarded/x_forwarded_for.rs (94%) rename {src/http => rama-http/src}/headers/forwarded/x_forwarded_host.rs (94%) rename {src/http => rama-http/src}/headers/forwarded/x_forwarded_proto.rs (93%) rename {src/http => rama-http/src}/headers/mod.rs (94%) rename {src/http => rama-http/src}/headers/util/csv.rs (95%) rename {src/http => rama-http/src}/headers/util/mod.rs (100%) rename {src/http => rama-http/src}/headers/util/quality_value.rs (94%) rename {src/http => rama-http/src}/io/mod.rs (100%) rename {src/http => rama-http/src}/io/request.rs (100%) rename {src/http => rama-http/src}/io/response.rs (100%) rename {src/http => rama-http/src}/layer/auth/add_authorization.rs (100%) rename {src/http => rama-http/src}/layer/auth/async_require_authorization.rs (100%) rename {src/http => rama-http/src}/layer/auth/mod.rs (100%) rename {src/http => rama-http/src}/layer/auth/require_authorization.rs (100%) rename {src/http => rama-http/src}/layer/body_limit.rs (100%) rename {src/http => rama-http/src}/layer/catch_panic.rs (100%) rename {src/http => rama-http/src}/layer/classify/grpc_errors_as_failures.rs (100%) rename {src/http => rama-http/src}/layer/classify/map_failure_class.rs (100%) rename {src/http => rama-http/src}/layer/classify/mod.rs (100%) rename {src/http => rama-http/src}/layer/classify/status_in_range_is_error.rs (100%) rename {src/http => rama-http/src}/layer/compression/body.rs (100%) rename {src/http => rama-http/src}/layer/compression/layer.rs (100%) rename {src/http => rama-http/src}/layer/compression/mod.rs (100%) rename {src/http => rama-http/src}/layer/compression/pin_project_cfg.rs (100%) rename {src/http => rama-http/src}/layer/compression/predicate.rs (100%) rename {src/http => rama-http/src}/layer/compression/service.rs (100%) rename {src/http => rama-http/src}/layer/cors/allow_credentials.rs (100%) rename {src/http => rama-http/src}/layer/cors/allow_headers.rs (100%) rename {src/http => rama-http/src}/layer/cors/allow_methods.rs (100%) rename {src/http => rama-http/src}/layer/cors/allow_origin.rs (100%) rename {src/http => rama-http/src}/layer/cors/allow_private_network.rs (100%) rename {src/http => rama-http/src}/layer/cors/expose_headers.rs (100%) rename {src/http => rama-http/src}/layer/cors/max_age.rs (100%) rename {src/http => rama-http/src}/layer/cors/mod.rs (100%) rename {src/http => rama-http/src}/layer/cors/tests.rs (100%) rename {src/http => rama-http/src}/layer/cors/vary.rs (100%) rename {src/http => rama-http/src}/layer/decompression/body.rs (100%) rename {src/http => rama-http/src}/layer/decompression/layer.rs (100%) rename {src/http => rama-http/src}/layer/decompression/mod.rs (100%) rename {src/http => rama-http/src}/layer/decompression/request/layer.rs (100%) rename {src/http => rama-http/src}/layer/decompression/request/mod.rs (100%) rename {src/http => rama-http/src}/layer/decompression/request/service.rs (100%) rename {src/http => rama-http/src}/layer/decompression/service.rs (100%) rename {src/http => rama-http/src}/layer/dns/dns_map/layer.rs (100%) rename {src/http => rama-http/src}/layer/dns/dns_map/mod.rs (100%) rename {src/http => rama-http/src}/layer/dns/dns_map/service.rs (100%) rename {src/http => rama-http/src}/layer/dns/dns_resolve/layer.rs (100%) rename {src/http => rama-http/src}/layer/dns/dns_resolve/mod.rs (100%) rename {src/http => rama-http/src}/layer/dns/dns_resolve/service.rs (100%) rename {src/http => rama-http/src}/layer/dns/dns_resolve/username_parser.rs (100%) rename {src/http => rama-http/src}/layer/dns/mod.rs (100%) rename {src/http => rama-http/src}/layer/error_handling.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/mod.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/and.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/clone_body_fn.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/filter_credentials.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/limited.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/mod.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/or.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/redirect_fn.rs (100%) rename {src/http => rama-http/src}/layer/follow_redirect/policy/same_origin.rs (100%) rename {src/http => rama-http/src}/layer/forwarded/get_forwarded.rs (97%) rename {src/http => rama-http/src}/layer/forwarded/mod.rs (100%) rename {src/http => rama-http/src}/layer/forwarded/set_forwarded.rs (99%) rename {src/http => rama-http/src}/layer/header_config.rs (100%) rename {src/http => rama-http/src}/layer/header_option_value.rs (100%) rename {src/http => rama-http/src}/layer/map_request_body.rs (100%) rename {src/http => rama-http/src}/layer/map_response_body.rs (100%) rename {src/http => rama-http/src}/layer/mod.rs (96%) rename {src/http => rama-http/src}/layer/normalize_path.rs (100%) rename {src/http => rama-http/src}/layer/opentelemetry.rs (100%) rename {src/http => rama-http/src}/layer/propagate_headers.rs (100%) rename {src/http => rama-http/src}/layer/proxy_auth.rs (100%) rename {src/http => rama-http/src}/layer/remove_header/mod.rs (100%) rename {src/http => rama-http/src}/layer/remove_header/request.rs (100%) rename {src/http => rama-http/src}/layer/remove_header/response.rs (100%) rename {src/http => rama-http/src}/layer/request_id.rs (100%) rename {src/http => rama-http/src}/layer/required_header/mod.rs (100%) rename {src/http => rama-http/src}/layer/required_header/request.rs (100%) rename {src/http => rama-http/src}/layer/required_header/response.rs (100%) rename {src/http => rama-http/src}/layer/retry/body.rs (100%) rename {src/http => rama-http/src}/layer/retry/layer.rs (100%) rename {src/http => rama-http/src}/layer/retry/managed.rs (100%) rename {src/http => rama-http/src}/layer/retry/mod.rs (100%) rename {src/http => rama-http/src}/layer/retry/policy.rs (100%) rename {src/http => rama-http/src}/layer/retry/tests.rs (100%) rename {src/http => rama-http/src}/layer/sensitive_headers.rs (100%) rename {src/http => rama-http/src}/layer/set_header/mod.rs (100%) rename {src/http => rama-http/src}/layer/set_header/request.rs (100%) rename {src/http => rama-http/src}/layer/set_header/response.rs (100%) rename {src/http => rama-http/src}/layer/set_status.rs (100%) rename {src/http => rama-http/src}/layer/timeout.rs (100%) rename {src/http => rama-http/src}/layer/trace/body.rs (100%) rename {src/http => rama-http/src}/layer/trace/layer.rs (100%) rename {src/http => rama-http/src}/layer/trace/make_span.rs (100%) rename {src/http => rama-http/src}/layer/trace/mod.rs (100%) rename {src/http => rama-http/src}/layer/trace/on_body_chunk.rs (100%) rename {src/http => rama-http/src}/layer/trace/on_eos.rs (100%) rename {src/http => rama-http/src}/layer/trace/on_failure.rs (100%) rename {src/http => rama-http/src}/layer/trace/on_request.rs (100%) rename {src/http => rama-http/src}/layer/trace/on_response.rs (100%) rename {src/http => rama-http/src}/layer/trace/service.rs (100%) rename {src/http => rama-http/src}/layer/traffic_writer/mod.rs (100%) rename {src/http => rama-http/src}/layer/traffic_writer/request.rs (100%) rename {src/http => rama-http/src}/layer/traffic_writer/response.rs (100%) rename src/ua/layer.rs => rama-http/src/layer/ua.rs (90%) rename {src/http => rama-http/src}/layer/upgrade/layer.rs (100%) rename {src/http => rama-http/src}/layer/upgrade/mod.rs (100%) rename {src/http => rama-http/src}/layer/upgrade/service.rs (100%) rename {src/http => rama-http/src}/layer/upgrade/upgraded.rs (100%) rename {src/http => rama-http/src}/layer/util/compression.rs (100%) rename {src/http => rama-http/src}/layer/util/content_encoding.rs (100%) rename {src/http => rama-http/src}/layer/util/mod.rs (100%) rename {src/http => rama-http/src}/layer/validate_request/accept_header.rs (100%) rename {src/http => rama-http/src}/layer/validate_request/mod.rs (100%) rename {src/http => rama-http/src}/layer/validate_request/validate.rs (100%) rename {src/http => rama-http/src}/layer/validate_request/validate_fn.rs (100%) rename {src/http => rama-http/src}/layer/validate_request/validate_request_header.rs (100%) create mode 100644 rama-http/src/lib.rs rename {src/http => rama-http/src}/matcher/domain.rs (100%) rename {src/http => rama-http/src}/matcher/header.rs (100%) rename {src/http => rama-http/src}/matcher/method.rs (100%) rename {src/http => rama-http/src}/matcher/mod.rs (100%) rename {src/http => rama-http/src}/matcher/path/de.rs (100%) rename {src/http => rama-http/src}/matcher/path/mod.rs (100%) rename {src/http => rama-http/src}/matcher/uri.rs (100%) rename {src/http => rama-http/src}/matcher/version.rs (100%) rename {src/http => rama-http/src}/request_context.rs (98%) rename {src/http => rama-http/src}/server/hyper_conn.rs (100%) rename {src/http => rama-http/src}/server/mod.rs (100%) rename {src/http => rama-http/src}/server/service.rs (100%) rename {src/http => rama-http/src}/server/svc_hyper.rs (100%) rename {src/http => rama-http/src}/service/fs/mod.rs (100%) rename {src/http => rama-http/src}/service/fs/serve_dir/future.rs (100%) rename {src/http => rama-http/src}/service/fs/serve_dir/headers.rs (100%) rename {src/http => rama-http/src}/service/fs/serve_dir/mod.rs (100%) rename {src/http => rama-http/src}/service/fs/serve_dir/open_file.rs (100%) rename {src/http => rama-http/src}/service/fs/serve_dir/tests.rs (100%) rename {src/http => rama-http/src}/service/fs/serve_file.rs (100%) rename {src/http => rama-http/src}/service/mod.rs (100%) rename {src/http => rama-http/src}/service/redirect.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/authority.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/body/bytes.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/body/form.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/body/json.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/body/mod.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/body/text.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/context.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/dns.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/extension.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/host.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/method.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/mod.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/path.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/query.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/request.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/state.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/extract/typed_header.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/mod.rs (100%) rename {src/http => rama-http/src}/service/web/endpoint/service.rs (100%) rename {src/http => rama-http/src}/service/web/k8s.rs (100%) rename {src/http => rama-http/src}/service/web/mod.rs (100%) rename {src/http => rama-http/src}/service/web/service.rs (100%) rename {src/http => rama-http/src}/utils/header_value.rs (97%) rename {src/http => rama-http/src}/utils/mod.rs (100%) rename {src => rama-http/src/utils}/utils/macros/http_error.rs (100%) rename {src => rama-http/src/utils}/utils/macros/mod.rs (100%) rename {src => rama-http/src/utils}/utils/mod.rs (100%) create mode 100644 rama-macros-proc/Cargo.toml create mode 100644 rama-macros-proc/README.md rename {rama-macros => rama-macros-proc}/src/as_ref.rs (100%) rename {rama-macros => rama-macros-proc}/src/attr_parsing.rs (100%) create mode 100644 rama-macros-proc/src/lib.rs rename {rama-macros => rama-macros-proc}/src/type_parsing.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/fail/generics.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/fail/generics.stderr (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/fail/wrap_ambiguity.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/fail/wrap_ambiguity.stderr (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/fail/wrap_no_arc.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/fail/wrap_no_arc.stderr (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/pass/basic.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/pass/reference-types.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/pass/skip.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/pass/wrap.rs (100%) rename {rama-macros => rama-macros-proc}/tests/as_ref/pass/wrap_skip.rs (100%) rename {rama-core/src/utils/macros => rama-macros/src}/error.rs (100%) rename {rama-core/src/utils/macros => rama-macros/src}/str.rs (93%) create mode 100644 rama-net/Cargo.toml create mode 100644 rama-net/README.md rename {rama-core/src/net => rama-net/src}/address/authority.rs (98%) rename {rama-core/src/net => rama-net/src}/address/domain.rs (99%) rename {rama-core/src/net => rama-net/src}/address/host.rs (98%) rename {rama-core/src/net => rama-net/src}/address/mod.rs (100%) rename {rama-core/src/net => rama-net/src}/address/proxy.rs (98%) rename {rama-core/src/net => rama-net/src}/asn.rs (99%) rename {rama-core/src/net => rama-net/src}/client/conn.rs (98%) rename {rama-core/src/net => rama-net/src}/client/mod.rs (100%) rename {rama-core/src/net => rama-net/src}/forwarded/element/mod.rs (98%) rename {rama-core/src/net => rama-net/src}/forwarded/element/parser.rs (98%) rename {rama-core/src/net => rama-net/src}/forwarded/mod.rs (98%) rename {rama-core/src/net => rama-net/src}/forwarded/node.rs (99%) rename {rama-core/src/net => rama-net/src}/forwarded/obfuscated.rs (99%) rename {rama-core/src/net => rama-net/src}/forwarded/proto.rs (96%) rename {rama-core/src/net => rama-net/src}/forwarded/version.rs (87%) create mode 100644 rama-net/src/lib.rs rename {rama-core/src/net => rama-net/src}/mod.rs (100%) rename {rama-core/src/net => rama-net/src}/proto.rs (99%) rename {src => rama-net/src}/stream/layer/http/body_limit.rs (96%) rename {src => rama-net/src}/stream/layer/http/mod.rs (100%) rename {src => rama-net/src}/stream/layer/mod.rs (94%) rename {src => rama-net/src}/stream/layer/opentelemetry.rs (97%) rename {src => rama-net/src}/stream/layer/tracker/bytes.rs (100%) rename {src => rama-net/src}/stream/layer/tracker/incoming.rs (94%) rename {src => rama-net/src}/stream/layer/tracker/mod.rs (100%) rename {src => rama-net/src}/stream/layer/tracker/outgoing.rs (94%) rename {src => rama-net/src}/stream/matcher/ip.rs (97%) rename {src => rama-net/src}/stream/matcher/loopback.rs (96%) rename {src => rama-net/src}/stream/matcher/mod.rs (99%) rename {src => rama-net/src}/stream/matcher/port.rs (95%) rename {src => rama-net/src}/stream/matcher/private_ip.rs (97%) rename {src => rama-net/src}/stream/matcher/socket.rs (96%) rename {src => rama-net/src}/stream/mod.rs (97%) rename {src => rama-net/src}/stream/read.rs (100%) rename {src => rama-net/src}/stream/service/echo.rs (95%) rename {src => rama-net/src}/stream/service/mod.rs (100%) rename {src => rama-net/src}/stream/socket.rs (100%) rename {src/stream => rama-net/src}/transport.rs (94%) rename {rama-core/src/net => rama-net/src}/user/auth.rs (93%) rename {rama-core/src/net => rama-net/src}/user/credentials/basic.rs (99%) rename {rama-core/src/net => rama-net/src}/user/credentials/bearer.rs (98%) rename {rama-core/src/net => rama-net/src}/user/credentials/mod.rs (100%) rename {rama-core/src/net => rama-net/src}/user/credentials/proxy.rs (97%) rename {rama-core/src/net => rama-net/src}/user/id.rs (100%) rename {rama-core/src/net => rama-net/src}/user/mod.rs (81%) create mode 100644 rama-proxy/Cargo.toml create mode 100644 rama-proxy/README.md rename {src/proxy => rama-proxy/src}/http/client/layer/mod.rs (100%) rename {src/proxy => rama-proxy/src}/http/client/layer/proxy_address.rs (100%) rename {src/proxy => rama-proxy/src}/http/client/layer/proxy_auth_header.rs (100%) rename {src/proxy => rama-proxy/src}/http/client/layer/proxy_connector/connector.rs (100%) rename {src/proxy => rama-proxy/src}/http/client/layer/proxy_connector/layer.rs (100%) rename {src/proxy => rama-proxy/src}/http/client/layer/proxy_connector/mod.rs (100%) rename {src/proxy => rama-proxy/src}/http/client/layer/proxy_connector/service.rs (100%) rename {src/proxy => rama-proxy/src}/http/client/mod.rs (100%) rename {src/proxy => rama-proxy/src}/http/mod.rs (100%) rename src/proxy/mod.rs => rama-proxy/src/lib.rs (65%) rename {src/proxy => rama-proxy/src}/pp/client/layer.rs (100%) rename {src/proxy => rama-proxy/src}/pp/client/mod.rs (100%) rename {src/proxy => rama-proxy/src}/pp/mod.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/ip.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/mod.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/v1/error.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/v1/mod.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/v1/model.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/v2/builder.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/v2/error.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/v2/mod.rs (100%) rename {src/proxy => rama-proxy/src}/pp/protocol/v2/model.rs (100%) rename {src/proxy => rama-proxy/src}/pp/server/layer.rs (100%) rename {src/proxy => rama-proxy/src}/pp/server/mod.rs (100%) create mode 100644 rama-proxy/src/proxydb/csv.rs rename {src/proxy => rama-proxy/src}/proxydb/internal.rs (98%) rename {src/proxy => rama-proxy/src}/proxydb/layer.rs (100%) rename {src/proxy => rama-proxy/src}/proxydb/mod.rs (99%) rename {src/proxy => rama-proxy/src}/proxydb/str.rs (100%) rename {src/proxy => rama-proxy/src}/proxydb/test_proxydb_rows.csv (100%) rename {src/proxy => rama-proxy/src}/proxydb/update.rs (100%) rename {src/proxy => rama-proxy/src}/username.rs (100%) create mode 100644 rama-tls/Cargo.toml create mode 100644 rama-tls/README.md rename {src/tls => rama-tls/src}/backend/boring/client/http.rs (100%) rename {src/tls => rama-tls/src}/backend/boring/client/mod.rs (100%) rename {src/tls => rama-tls/src}/backend/boring/mod.rs (100%) rename {src/tls => rama-tls/src}/backend/boring/server/config.rs (100%) rename {src/tls => rama-tls/src}/backend/boring/server/layer.rs (100%) rename {src/tls => rama-tls/src}/backend/boring/server/mod.rs (100%) rename {src/tls => rama-tls/src}/backend/boring/server/service.rs (100%) rename {src/tls => rama-tls/src}/backend/mod.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/client/http.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/client/mod.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/mod.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/server/client_config.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/server/layer.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/server/mod.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/server/service.rs (100%) rename {src/tls => rama-tls/src}/backend/rustls/verify.rs (100%) rename {src/tls => rama-tls/src}/client/hello/boring.rs (100%) rename {src/tls => rama-tls/src}/client/hello/mod.rs (100%) rename {src/tls => rama-tls/src}/client/hello/rustls.rs (100%) rename {src/tls => rama-tls/src}/client/mod.rs (100%) rename {src/tls => rama-tls/src}/client/parser.rs (100%) rename {src/tls => rama-tls/src}/enums/mod.rs (100%) rename {src/tls => rama-tls/src}/enums/rustls.rs (100%) rename src/tls/mod.rs => rama-tls/src/lib.rs (50%) create mode 100644 rama-ua/Cargo.toml create mode 100644 rama-ua/README.md rename {src/ua => rama-ua/src}/info.rs (99%) rename src/ua/mod.rs => rama-ua/src/lib.rs (59%) rename {src/ua => rama-ua/src}/parse.rs (100%) rename {src/ua => rama-ua/src}/parse_tests.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 4ab160bf..311a2de8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1734,11 +1734,8 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" name = "rama" version = "0.2.0-alpha.2" dependencies = [ - "arc-swap", - "async-compression", "base64 0.22.1", "bitflags", - "boring", "brotli", "bytes", "const_format", @@ -1762,7 +1759,6 @@ dependencies = [ "itertools 0.13.0", "mime", "mime_guess", - "nom", "opentelemetry", "opentelemetry-otlp", "opentelemetry-semantic-conventions", @@ -1772,12 +1768,11 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rama-core", - "rcgen", + "rama-http", + "rama-proxy", + "rama-tls", + "rama-ua", "regex", - "rustls", - "rustls-native-certs", - "rustls-pemfile", - "rustls-pki-types", "rustversion", "serde", "serde_html_form", @@ -1785,16 +1780,12 @@ dependencies = [ "sync_wrapper 1.0.1", "tempfile", "tokio", - "tokio-boring", - "tokio-rustls", "tokio-test", "tokio-util", "tracing", "tracing-subscriber", "unicode-normalization", "uuid", - "venndb", - "webpki-roots", "zstd", ] @@ -1822,11 +1813,15 @@ dependencies = [ "futures-lite", "headers", "hickory-resolver", - "http", + "opentelemetry", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", "parking_lot", "paste", "pin-project-lite", "quickcheck", + "rama-error", + "rama-http-types", "rama-macros", "serde", "tokio", @@ -1836,6 +1831,10 @@ dependencies = [ "venndb", ] +[[package]] +name = "rama-error" +version = "0.2.0-alpha.2" + [[package]] name = "rama-fuzz" version = "0.0.0" @@ -1844,9 +1843,78 @@ dependencies = [ "rama", ] +[[package]] +name = "rama-http" +version = "0.2.0-alpha.2" +dependencies = [ + "async-compression", + "bytes", + "const_format", + "futures-core", + "futures-lite", + "headers", + "http", + "http-body", + "http-body-util", + "mime", + "mime_guess", + "paste", + "pin-project-lite", + "rama-core", + "rama-http-types", + "serde", + "serde_html_form", + "serde_json", + "sync_wrapper 1.0.1", + "tokio", + "tokio-test", + "tracing", +] + +[[package]] +name = "rama-http-backend" +version = "0.2.0-alpha.2" +dependencies = [ + "rama-core", +] + +[[package]] +name = "rama-http-types" +version = "0.2.0-alpha.2" +dependencies = [ + "bytes", + "const_format", + "futures-core", + "futures-lite", + "headers", + "http", + "http-body", + "http-body-util", + "mime", + "mime_guess", + "paste", + "pin-project-lite", + "rama-error", + "rama-macros", + "serde", + "serde_html_form", + "serde_json", + "sync_wrapper 1.0.1", + "tokio", + "tokio-test", + "tracing", +] + [[package]] name = "rama-macros" version = "0.2.0-alpha.2" +dependencies = [ + "rama-macros-proc", +] + +[[package]] +name = "rama-macros-proc" +version = "0.2.0-alpha.2" dependencies = [ "proc-macro2", "quote", @@ -1855,6 +1923,67 @@ dependencies = [ "trybuild", ] +[[package]] +name = "rama-net" +version = "0.2.0-alpha.2" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-lite", + "headers", + "hickory-resolver", + "ipnet", + "opentelemetry", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "parking_lot", + "paste", + "pin-project-lite", + "quickcheck", + "rama-core", + "rama-http-types", + "serde", + "tokio", + "tokio-graceful", + "tokio-test", + "tracing", + "venndb", +] + +[[package]] +name = "rama-proxy" +version = "0.2.0-alpha.2" +dependencies = [ + "arc-swap", + "rama-core", + "venndb", +] + +[[package]] +name = "rama-tls" +version = "0.2.0-alpha.2" +dependencies = [ + "boring", + "nom", + "rama-core", + "rcgen", + "rustls", + "rustls-native-certs", + "rustls-pemfile", + "rustls-pki-types", + "tokio-boring", + "tokio-rustls", + "webpki-roots", +] + +[[package]] +name = "rama-ua" +version = "0.2.0-alpha.2" +dependencies = [ + "rama-core", + "serde", +] + [[package]] name = "rand" version = "0.8.5" diff --git a/Cargo.toml b/Cargo.toml index 746ad113..e4dd9eff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,20 @@ [workspace] -members = [".", "fuzz", "rama-cli", "rama-core", "rama-macros"] +members = [ + ".", + "fuzz", + "rama-cli", + "rama-core", + "rama-error", + "rama-http", + "rama-http-backend", + "rama-http-types", + "rama-macros", + "rama-macros-proc", + "rama-net", + "rama-proxy", + "rama-tls", + "rama-ua", +] [workspace.package] version = "0.2.0-alpha.2" @@ -118,33 +133,23 @@ rust-version = { workspace = true } [features] default = [] -telemetry = [ - "dep:opentelemetry", - "dep:opentelemetry_sdk", - "dep:opentelemetry-semantic-conventions", -] -compression = ["dep:async-compression"] -rustls-ring = ["tokio-rustls/ring", "rustls/ring"] -tls = ["dep:rcgen"] -rustls = ["tls", "dep:rustls", "dep:rustls-native-certs", "dep:rustls-pemfile", "dep:rustls-pki-types", "dep:webpki-roots", "dep:tokio-rustls"] -boring = ["tls", "dep:boring", "dep:tokio-boring", "nom"] +telemetry = ["rama-core/telemetry"] +compression = ["http", "rama-http/compression"] +tls = [] +rustls = ["tls", "rama-tls/rustls"] +rustls-ring = ["tls", "rama-tls/rustls-ring"] +boring = ["tls", "rama-tls/boring"] cli = [] +http = ["dep:rama-http"] +proxy = ["dep:rama-proxy"] +ua = ["dep:rama-ua"] [build-dependencies] rustversion = { workspace = true } [dependencies] -arc-swap = { workspace = true } -async-compression = { workspace = true, features = [ - "tokio", - "brotli", - "zlib", - "gzip", - "zstd", -], optional = true } base64 = { workspace = true } bitflags = { workspace = true } -boring = { workspace = true, optional = true } bytes = { workspace = true } const_format = { workspace = true } futures-core = { workspace = true } @@ -163,7 +168,6 @@ ipnet = { workspace = true } iri-string = { workspace = true } mime = { workspace = true } mime_guess = { workspace = true } -nom = { workspace = true, optional = true } opentelemetry = { workspace = true, optional = true } opentelemetry-semantic-conventions = { workspace = true, optional = true } opentelemetry_sdk = { workspace = true, optional = true } @@ -172,25 +176,20 @@ paste = { workspace = true } percent-encoding = { workspace = true } pin-project-lite = { workspace = true } rama-core = { version = "0.2.0-alpha.2", path = "rama-core" } -rcgen = { workspace = true, optional = true } +rama-http = { version = "0.2.0-alpha.2", path = "rama-http", optional = true } +rama-proxy = { version = "0.2.0-alpha.2", path = "rama-proxy", optional = true } +rama-tls = { version = "0.2.0-alpha.2", path = "rama-tls", optional = true } +rama-ua = { version = "0.2.0-alpha.2", path = "rama-ua", optional = true } regex = { workspace = true } -rustls = { workspace = true, optional = true } -rustls-native-certs = { workspace = true, optional = true } -rustls-pemfile = { workspace = true, optional = true } -rustls-pki-types = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } serde_json = { workspace = true } sync_wrapper = { workspace = true } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } -tokio-boring = { workspace = true, optional = true } -tokio-rustls = { workspace = true, optional = true } tokio-util = { workspace = true } tracing = { workspace = true } unicode-normalization = { workspace = true } uuid = { workspace = true, features = ["v4"] } -venndb = { workspace = true } -webpki-roots = { workspace = true, optional = true } [dev-dependencies] brotli = { workspace = true } diff --git a/README.md b/README.md index cdb0f0c1..23a5a972 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Lines of Code][loc-badge]][loc-url] [crates-badge]: https://img.shields.io/crates/v/rama.svg -[crates-url]: https://crates.io/crates/rama/0.2.0-alpha.1 +[crates-url]: https://crates.io/crates/rama [docs-badge]: https://img.shields.io/docsrs/rama/latest [docs-url]: https://docs.rs/rama/latest/rama/index.html [license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg diff --git a/rama-cli/README.md b/rama-cli/README.md index faec00f0..3f11a0f0 100644 --- a/rama-cli/README.md +++ b/rama-cli/README.md @@ -13,7 +13,7 @@ [![Paypal Donation][paypal-badge]][paypal-url] [crates-badge]: https://img.shields.io/crates/v/rama.svg -[crates-url]: https://crates.io/crates/rama/0.2.0-alpha.1 +[crates-url]: https://crates.io/crates/rama [docs-badge]: https://img.shields.io/docsrs/rama/latest [docs-url]: https://docs.rs/rama/latest/rama/index.html [license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg diff --git a/rama-core/Cargo.toml b/rama-core/Cargo.toml index 92729cb6..baa06859 100644 --- a/rama-core/Cargo.toml +++ b/rama-core/Cargo.toml @@ -10,21 +10,36 @@ categories = { workspace = true } authors = { workspace = true } rust-version = { workspace = true } +[features] +default = [] +full = ["telemetry", "venndb", "http"] +telemetry = [ + "dep:opentelemetry", + "dep:opentelemetry_sdk", + "dep:opentelemetry-semantic-conventions", +] +venndb = ["dep:venndb"] +http = ["dep:rama-http-types"] + [dependencies] base64 = { workspace = true } futures-lite = { workspace = true } headers = { workspace = true } hickory-resolver = { workspace = true } -http = { workspace = true } +opentelemetry = { workspace = true, optional = true } +opentelemetry-semantic-conventions = { workspace = true, optional = true } +opentelemetry_sdk = { workspace = true, optional = true } parking_lot = { workspace = true } paste = { workspace = true } pin-project-lite = { workspace = true } +rama-error = { version = "0.2.0-alpha.2", path = "../rama-error" } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } rama-macros = { version = "0.2.0-alpha.2", path = "../rama-macros" } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } tokio-graceful = { workspace = true } tracing = { workspace = true } -venndb = { workspace = true } +venndb = { workspace = true, optional = true } [dev-dependencies] quickcheck = { workspace = true } diff --git a/rama-core/README.md b/rama-core/README.md new file mode 100644 index 00000000..4d3a12a0 --- /dev/null +++ b/rama-core/README.md @@ -0,0 +1,58 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-core.svg +[crates-url]: https://crates.io/crates/rama-core +[docs-badge]: https://img.shields.io/docsrs/rama-core/latest +[docs-url]: https://docs.rs/rama-core/latest/rama_core/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-core + +`async fn serve(&self, Context, Request) -> Result` + +Crate used by the end-user `rama` crate and `rama` crate authors alike. + +Learn more about `rama`: + +- Github: +- Book: + +### rama service + +Heavily inspired by [tower-service](https://docs.rs/tower-service/0.3.0/tower_service/trait.Service.html) +and the vast [Tokio](https://docs.rs/tokio/latest/tokio/) ecosystem which makes use of it. + +Initially the goal was to rely on `tower-service` directly, but it turned out to be +too restrictive and difficult to work with, for the use cases we have in Rama. +See for more information regarding this and more. diff --git a/rama-core/src/dns/mod.rs b/rama-core/src/dns/mod.rs index 4088e420..81c8021f 100644 --- a/rama-core/src/dns/mod.rs +++ b/rama-core/src/dns/mod.rs @@ -9,20 +9,77 @@ use std::{ collections::HashMap, net::{IpAddr, Ipv4Addr, Ipv6Addr}, sync::Arc, + fmt, }; - use hickory_resolver::{ config::{ResolverConfig, ResolverOpts}, proto::rr::rdata::{A, AAAA}, - IntoName, Name, TokioAsyncResolver, + Name as DnsName, TokioAsyncResolver, }; - use crate::{ combinators::Either, error::{ErrorContext, OpaqueError}, - net::address::Domain, }; +#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +/// A domain name +pub struct Name(DnsName); + +impl Name { + fn fqdn_from_domain(domain: impl TryIntoName) -> Result { + let mut domain = domain.try_into_name()?; + domain.0.set_fqdn(true); + Ok(domain) + } +} + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +/// Conversion into a Name +pub trait TryIntoName: Sized { + /// Convert this into [`Name`] + fn try_into_name(self) -> Result; +} + +impl TryIntoName for Name +{ + fn try_into_name(self) -> Result { + Ok(self) + } +} + +impl TryIntoName for T +where T: TryInto { + fn try_into_name(self) -> Result { + self.try_into() + } +} + +impl<'a> TryIntoName for &'a str { + /// Performs a utf8, IDNA or punycode, translation of the `str` into `Name` + fn try_into_name(self) -> Result { + DnsName::from_utf8(self).map(Name).context("try to convert &'a str into domain") + } +} + +impl TryIntoName for String { + /// Performs a utf8, IDNA or punycode, translation of the `String` into `Name` + fn try_into_name(self) -> Result { + DnsName::from_utf8(self).map(Name).context("try to convert String into domain") + } +} + +impl TryIntoName for &String { + /// Performs a utf8, IDNA or punycode, translation of the `&String` into `Name` + fn try_into_name(self) -> Result { + DnsName::from_utf8(self).map(Name).context("try to convert &String into domain") + } +} + #[derive(Debug, Clone)] /// Dns Resolver for all your lookup needs. /// @@ -33,7 +90,7 @@ use crate::{ /// with clear goals and motivation if you need more functionality. pub struct Dns { resolver: Arc, - overwrites: Option>>, + overwrites: Option>>, } impl Default for Dns { @@ -59,10 +116,10 @@ impl Dns { /// /// Note that this impacts both [`Self::ipv4_lookup`] and [`Self::ipv6_lookup`], /// meaning that no Ipv6 addresses will be returned for the domain. - pub fn insert_overwrite(&mut self, domain: Domain, addresses: Vec) -> &mut Self { + pub fn insert_overwrite(&mut self, name: Name, addresses: Vec) -> &mut Self { self.overwrites .get_or_insert_with(HashMap::new) - .insert(domain, addresses); + .insert(name, addresses); self } @@ -71,7 +128,7 @@ impl Dns { /// Existing mappings will be overwritten. /// /// See [`Self::insert_overwrite`] for more information. - pub fn extend_overwrites(&mut self, overwrites: HashMap>) -> &mut Self { + pub fn extend_overwrites(&mut self, overwrites: HashMap>) -> &mut Self { self.overwrites .get_or_insert_with(HashMap::new) .extend(overwrites); @@ -81,12 +138,14 @@ impl Dns { /// Performs a 'A' DNS record lookup. pub async fn ipv4_lookup( &self, - domain: Domain, + name: impl TryIntoName, ) -> Result, OpaqueError> { + let name = Name::fqdn_from_domain(name)?; + if let Some(addresses) = self .overwrites .as_ref() - .and_then(|cache| cache.get(&domain)) + .and_then(|cache| cache.get(&name)) { return Ok(Either::A(addresses.clone().into_iter().filter_map( |ip| match ip { @@ -95,7 +154,8 @@ impl Dns { }, ))); } - Ok(Either::B(self.ipv4_lookup_trusted(domain).await?)) + + Ok(Either::B(self.ipv4_lookup_trusted(name).await?)) } /// Performs a 'A' DNS record lookup. @@ -104,11 +164,13 @@ impl Dns { /// the overwrites first. pub async fn ipv4_lookup_trusted( &self, - domain: Domain, + name: impl TryIntoName, ) -> Result, OpaqueError> { + let name = Name::fqdn_from_domain(name)?; + Ok(self .resolver - .ipv4_lookup(domain_str_as_fqdn(domain)?) + .ipv4_lookup(name.0) .await .context("lookup IPv4 address(es)")? .into_iter() @@ -118,12 +180,14 @@ impl Dns { /// Performs a 'AAAA' DNS record lookup. pub async fn ipv6_lookup( &self, - domain: Domain, + name: impl TryIntoName, ) -> Result, OpaqueError> { + let name = Name::fqdn_from_domain(name)?; + if let Some(addresses) = self .overwrites .as_ref() - .and_then(|cache| cache.get(&domain)) + .and_then(|cache| cache.get(&name)) { return Ok(Either::A(addresses.clone().into_iter().filter_map( |ip| match ip { @@ -132,7 +196,8 @@ impl Dns { }, ))); } - Ok(Either::B(self.ipv6_lookup_trusted(domain).await?)) + + Ok(Either::B(self.ipv6_lookup_trusted(name).await?)) } /// Performs a 'AAAA' DNS record lookup. @@ -141,23 +206,16 @@ impl Dns { /// consulting the overwrites first. pub async fn ipv6_lookup_trusted( &self, - domain: Domain, + name: impl TryIntoName, ) -> Result, OpaqueError> { + let name = Name::fqdn_from_domain(name)?; + Ok(self .resolver - .ipv6_lookup(domain_str_as_fqdn(domain)?) + .ipv6_lookup(name.0) .await .context("lookup IPv6 address(es)")? .into_iter() .map(|AAAA(ip)| ip)) } } - -fn domain_str_as_fqdn(domain: Domain) -> Result { - let mut name = domain - .to_string() - .into_name() - .context("turn domain into FQDN")?; - name.set_fqdn(true); - Ok(name) -} diff --git a/rama-core/src/lib.rs b/rama-core/src/lib.rs index a2842911..bb80acf6 100644 --- a/rama-core/src/lib.rs +++ b/rama-core/src/lib.rs @@ -1,5 +1,12 @@ //! `async fn serve(&self, Context, Request) -> Result` //! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: +//! //! # rama service //! //! Heavily inspired by [tower-service](https://docs.rs/tower-service/0.3.0/tower_service/trait.Service.html) @@ -9,10 +16,55 @@ //! too restrictive and difficult to work with, for the use cases we have in Rama. //! See for more information regarding this and more. +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + pub mod context; pub use context::Context; -pub mod error; +pub use ::rama_error as error; pub mod dns; pub mod graceful; @@ -27,7 +79,8 @@ pub use layer::Layer; pub mod combinators; pub mod matcher; -pub mod net; +#[cfg(feature = "telemetry")] +pub mod telemetry; #[macro_use] pub mod utils; diff --git a/src/telemetry/mod.rs b/rama-core/src/telemetry/mod.rs similarity index 100% rename from src/telemetry/mod.rs rename to rama-core/src/telemetry/mod.rs diff --git a/src/telemetry/opentelemetry.rs b/rama-core/src/telemetry/opentelemetry.rs similarity index 100% rename from src/telemetry/opentelemetry.rs rename to rama-core/src/telemetry/opentelemetry.rs diff --git a/rama-core/src/utils/macros/mod.rs b/rama-core/src/utils/macros/mod.rs deleted file mode 100644 index 0450c26c..00000000 --- a/rama-core/src/utils/macros/mod.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! Internal macros - -#[macro_use] -pub mod error; - -#[macro_use] -pub mod str; - -#[doc(hidden)] -#[macro_export] -macro_rules! __opaque_body { - ($(#[$m:meta])* pub type $name:ident = $actual:ty;) => { - $crate::__opaque_body! { - $(#[$m])* pub type $name<> = $actual; - } - }; - - ($(#[$m:meta])* pub type $name:ident<$($param:ident),*> = $actual:ty;) => { - pin_project_lite::pin_project! { - $(#[$m])* - pub struct $name<$($param),*> { - #[pin] - pub(crate) inner: $actual - } - } - - impl<$($param),*> $name<$($param),*> { - pub(crate) fn new(inner: $actual) -> Self { - Self { inner } - } - } - - impl<$($param),*> http_body::Body for $name<$($param),*> { - type Data = <$actual as http_body::Body>::Data; - type Error = <$actual as http_body::Body>::Error; - - #[inline] - fn poll_frame( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll, Self::Error>>> { - self.project().inner.poll_frame(cx) - } - - #[inline] - fn is_end_stream(&self) -> bool { - http_body::Body::is_end_stream(&self.inner) - } - - #[inline] - fn size_hint(&self) -> http_body::SizeHint { - http_body::Body::size_hint(&self.inner) - } - } - }; -} -pub use crate::__opaque_body as opaque_body; - -#[doc(hidden)] -#[macro_export] -macro_rules! __all_the_tuples_minus_one_no_last_special_case { - ($name:ident) => { - $name!(T1); - $name!(T1, T2); - $name!(T1, T2, T3); - $name!(T1, T2, T3, T4); - $name!(T1, T2, T3, T4, T5); - $name!(T1, T2, T3, T4, T5, T6); - $name!(T1, T2, T3, T4, T5, T6, T7); - $name!(T1, T2, T3, T4, T5, T6, T7, T8); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); - }; -} -pub use crate::__all_the_tuples_minus_one_no_last_special_case as all_the_tuples_minus_one_no_last_special_case; - -#[doc(hidden)] -#[macro_export] -macro_rules! __all_the_tuples_no_last_special_case { - ($name:ident) => { - $crate::__all_the_tuples_minus_one_no_last_special_case!($name); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); - }; -} -pub use __all_the_tuples_no_last_special_case as all_the_tuples_no_last_special_case; - -#[doc(hidden)] -#[macro_export] -macro_rules! __match_ignore_ascii_case_str { - (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)* $(,)?}) => { - $crate::__match_ignore_ascii_case_str!(match ($s) { - $caseA $(| $caseAVar)* $(if $condA)? => $retA, - $($caseB $(| $caseBVar)* $(if $condB)? => $retB,)* - _ => panic!("{}", format!("failed to match {}", $s)), - }) - }; - (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)*, _ => $fallback:expr $(,)? }) => { - { - let s = ($s).trim(); - if $($condA &&)? (s.eq_ignore_ascii_case($caseA) $(|| s.eq_ignore_ascii_case($caseAVar))*) { - $retA - } - $( - else if $($condB &&)? (s.eq_ignore_ascii_case($caseB) $(|| s.eq_ignore_ascii_case($caseBVar))*) { - $retB - } - )* - else { - $fallback - } - } - }; -} -pub use __match_ignore_ascii_case_str as match_ignore_ascii_case_str; - -#[doc(hidden)] -#[macro_export] -macro_rules! __define_inner_service_accessors { - () => { - /// Gets a reference to the underlying service. - pub fn get_ref(&self) -> &S { - &self.inner - } - - /// Consumes `self`, returning the underlying service. - pub fn into_inner(self) -> S { - self.inner - } - }; -} -pub use __define_inner_service_accessors as define_inner_service_accessors; - -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_deref { - ($ident:ident) => { - impl std::ops::Deref for $ident { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl std::ops::DerefMut for $ident { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - }; - - ($ident:ident: $ty:ty) => { - impl std::ops::Deref for $ident { - type Target = $ty; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl std::ops::DerefMut for $ident { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - }; -} -pub use __impl_deref as impl_deref; - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn match_ignore_ascii_case_str_happy_simple() { - let s = "hello"; - let result = match_ignore_ascii_case_str!(match (s) { - "hello" => true, - _ => false, - }); - assert!(result); - } - - #[test] - fn match_ignore_ascii_case_str_happy_mixed_case() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "hello" => true, - _ => false, - }); - assert!(result); - } - - #[test] - fn match_ignore_ascii_case_str_happy_multiple_cases() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "world" => 1, - "hello" => 2, - "!" => 3, - _ => 4, - }); - assert_eq!(result, 2); - } - - #[test] - fn match_ignore_ascii_case_str_happy_variants() { - let result = match_ignore_ascii_case_str!(match ("world") { - "?" => 1, - "you" | "world" | "there" => 2, - "!" => 3, - _ => 4, - }); - assert_eq!(result, 2); - } - - #[test] - fn match_ignore_ascii_case_str_happy_fallback() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "world" => 1, - "!" => 2, - _ => 3, - }); - assert_eq!(result, 3); - } - - #[test] - fn match_ignore_ascii_case_str_condition() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "world" => 1, - "hello" if s.len() == 4 => 2, - "hello" => 3, - "!" => 4, - _ => 5, - }); - assert_eq!(result, 3); - } - - #[test] - fn match_ignore_ascii_case_str_happy_variants_condition() { - let result = match_ignore_ascii_case_str!(match ("world") { - "?" => 1, - "you" | "world" | "there" if false => 2, - "you" | "world" | "there" if "world".len() == 5 => 3, - "!" => 4, - _ => 5, - }); - - assert_eq!(result, 3); - } - - #[test] - #[should_panic] - fn match_ignore_ascii_case_str_panic() { - match_ignore_ascii_case_str!(match ("hello") { - "world" => (), - }) - } -} diff --git a/rama-core/src/utils/mod.rs b/rama-core/src/utils/mod.rs index 71785123..957a4220 100644 --- a/rama-core/src/utils/mod.rs +++ b/rama-core/src/utils/mod.rs @@ -1,8 +1,7 @@ //! Utilities in service of the `rama-core` project. -#[macro_use] #[doc(hidden)] -pub mod macros; +pub use ::rama_macros as macros; pub mod backoff; pub mod future; diff --git a/rama-error/Cargo.toml b/rama-error/Cargo.toml new file mode 100644 index 00000000..bd716a24 --- /dev/null +++ b/rama-error/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rama-error" +description = "error types and utilities for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[dependencies] + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-error/README.md b/rama-error/README.md new file mode 100644 index 00000000..1e1a16c3 --- /dev/null +++ b/rama-error/README.md @@ -0,0 +1,49 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-error.svg +[crates-url]: https://crates.io/crates/rama-error +[docs-badge]: https://img.shields.io/docsrs/rama-error/latest +[docs-url]: https://docs.rs/rama-error/latest/rama_error/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-error + +Error types and utilities for `rama`. + +Crate used by the end-user `rama` crate and `rama` "http" crate authors alike. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-core/src/error/ext/backtrace.rs b/rama-error/src/ext/backtrace.rs similarity index 100% rename from rama-core/src/error/ext/backtrace.rs rename to rama-error/src/ext/backtrace.rs diff --git a/rama-core/src/error/ext/context.rs b/rama-error/src/ext/context.rs similarity index 100% rename from rama-core/src/error/ext/context.rs rename to rama-error/src/ext/context.rs diff --git a/rama-core/src/error/ext/mod.rs b/rama-error/src/ext/mod.rs similarity index 99% rename from rama-core/src/error/ext/mod.rs rename to rama-error/src/ext/mod.rs index 1b5c2745..f41a373e 100644 --- a/rama-core/src/error/ext/mod.rs +++ b/rama-error/src/ext/mod.rs @@ -206,7 +206,7 @@ mod private { #[cfg(test)] mod tests { use super::*; - use crate::error::BoxError; + use crate::BoxError; #[test] fn message_error_context() { diff --git a/rama-core/src/error/ext/wrapper.rs b/rama-error/src/ext/wrapper.rs similarity index 99% rename from rama-core/src/error/ext/wrapper.rs rename to rama-error/src/ext/wrapper.rs index 9f5af1c6..93f24452 100644 --- a/rama-core/src/error/ext/wrapper.rs +++ b/rama-error/src/ext/wrapper.rs @@ -1,4 +1,4 @@ -use crate::error::BoxError; +use crate::BoxError; use std::fmt::{self, Debug, Display}; #[repr(transparent)] diff --git a/rama-core/src/error/mod.rs b/rama-error/src/lib.rs similarity index 84% rename from rama-core/src/error/mod.rs rename to rama-error/src/lib.rs index 6394ee26..a4a6841e 100644 --- a/rama-core/src/error/mod.rs +++ b/rama-error/src/lib.rs @@ -1,5 +1,14 @@ //! Error utilities for rama and its users. //! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: +//! +//! # Errors +//! //! Errors in Rust are a bit ambiguous: //! //! - the infamous `Result` is a type that can either be `Ok(T)` or `Err(E)`, where `E` is @@ -166,6 +175,51 @@ //! you can use [the `thiserror` crate](https://docs.rs/thiserror), //! or even [the `anyhow` crate](https://docs.rs/anyhow). All is possible. +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + use std::error::Error as StdError; /// Alias for a type-erased error type. diff --git a/rama-core/src/error/macros.rs b/rama-error/src/macros.rs similarity index 77% rename from rama-core/src/error/macros.rs rename to rama-error/src/macros.rs index 77524c2c..072b92af 100644 --- a/rama-core/src/error/macros.rs +++ b/rama-error/src/macros.rs @@ -16,12 +16,12 @@ #[doc(hidden)] macro_rules! __error { ($msg:literal $(,)?) => ({ - $crate::error::OpaqueError::from_display($msg) + $crate::OpaqueError::from_display($msg) }); ($fmt:literal, $($arg:tt),+ $(,)?) => ({ - $crate::error::OpaqueError::from_display(format!($fmt, $($arg)*)) + $crate::OpaqueError::from_display(format!($fmt, $($arg)*)) }); ($err:expr $(,)?) => ({ - $crate::error::OpaqueError::from_std($err) + $crate::OpaqueError::from_std($err) }); } diff --git a/rama-http-backend/Cargo.toml b/rama-http-backend/Cargo.toml new file mode 100644 index 00000000..123ade10 --- /dev/null +++ b/rama-http-backend/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "rama-http-backend" +description = "error types and utilities for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[dependencies] +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-http-backend/README.md b/rama-http-backend/README.md new file mode 100644 index 00000000..c59fa832 --- /dev/null +++ b/rama-http-backend/README.md @@ -0,0 +1,50 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-http-backend.svg +[crates-url]: https://crates.io/crates/rama-http-backend +[docs-badge]: https://img.shields.io/docsrs/rama-http-backend/latest +[docs-url]: https://docs.rs/rama-http-backend/latest/rama_http_backend/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-http-backend + +Default http backend for `rama`, providing the http protocol support, +and actual underlying client/server driver logic (atop of tokio). + +Crate used by the end-user `rama` crate. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-http-backend/src/lib.rs b/rama-http-backend/src/lib.rs new file mode 100644 index 00000000..ac6b11f5 --- /dev/null +++ b/rama-http-backend/src/lib.rs @@ -0,0 +1,53 @@ +//! Default rama http backend, permanently forked from Hyper et-al. +//! +//! Crate used by the end-user `rama` crate. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] diff --git a/rama-http-types/Cargo.toml b/rama-http-types/Cargo.toml new file mode 100644 index 00000000..9565e164 --- /dev/null +++ b/rama-http-types/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "rama-http-types" +description = "rama http type defintions and high level utilities" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[dependencies] +bytes = { workspace = true } +const_format = { workspace = true } +futures-core = { workspace = true } +futures-lite = { workspace = true } +headers = { workspace = true } +http = { workspace = true } +http-body = { workspace = true } +http-body-util = { workspace = true } +mime = { workspace = true } +mime_guess = { workspace = true } +paste = { workspace = true } +pin-project-lite = { workspace = true } +rama-error = { version = "0.2.0-alpha.2", path = "../rama-error" } +rama-macros = { version = "0.2.0-alpha.2", path = "../rama-macros" } +serde = { workspace = true, features = ["derive"] } +serde_html_form = { workspace = true } +serde_json = { workspace = true } +sync_wrapper = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +tokio = { workspace = true, features = ["full"] } +tokio-test = { workspace = true } + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-http-types/README.md b/rama-http-types/README.md new file mode 100644 index 00000000..b31722e1 --- /dev/null +++ b/rama-http-types/README.md @@ -0,0 +1,49 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-http-types.svg +[crates-url]: https://crates.io/crates/rama-http-types +[docs-badge]: https://img.shields.io/docsrs/rama-http-types/latest +[docs-url]: https://docs.rs/rama-http-types/latest/rama_http_types/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-http-types + +Http types and utilities. + +Crate used by the end-user `rama` crate and `rama` "http" crate authors alike. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/src/http/body.rs b/rama-http-types/src/body.rs similarity index 94% rename from src/http/body.rs rename to rama-http-types/src/body.rs index 40a9b42d..a8253127 100644 --- a/src/http/body.rs +++ b/rama-http-types/src/body.rs @@ -1,22 +1,18 @@ //! HTTP body utilities. -use crate::{ - error::OpaqueError, - http::dep::{ - http_body::{Body as _, Frame}, - http_body_util::BodyExt, - }, +use crate::dep::{ + http_body::{self, Body as _, Frame}, + http_body_util::{self, BodyExt}, }; use bytes::Bytes; use futures_core::TryStream; use futures_lite::stream::Stream; use pin_project_lite::pin_project; +use rama_error::{BoxError, OpaqueError}; use std::pin::Pin; use std::task::{Context, Poll}; use sync_wrapper::SyncWrapper; -use crate::error::BoxError; - type BoxBody = http_body_util::combinators::BoxBody; fn boxed(body: B) -> BoxBody @@ -57,7 +53,7 @@ impl Body { where B: http_body::Body> + Send + Sync + 'static, { - Self::new(crate::http::dep::http_body_util::Limited::new(body, limit)) + Self::new(crate::dep::http_body_util::Limited::new(body, limit)) } /// Create an empty body. @@ -79,9 +75,7 @@ impl Body { /// Create a new [`Body`] from a [`Stream`] with a maximum size limit. pub fn limited(self, limit: usize) -> Self { - Self::new(crate::http::dep::http_body_util::Limited::new( - self.0, limit, - )) + Self::new(crate::dep::http_body_util::Limited::new(self.0, limit)) } /// Convert the body into a [`Stream`] of data frames. diff --git a/src/http/body_ext.rs b/rama-http-types/src/body_ext.rs similarity index 77% rename from src/http/body_ext.rs rename to rama-http-types/src/body_ext.rs index 91b28844..96401c7b 100644 --- a/src/http/body_ext.rs +++ b/rama-http-types/src/body_ext.rs @@ -1,10 +1,10 @@ -use crate::error::{BoxError, ErrorContext, OpaqueError}; -use crate::http::dep::http_body_util::BodyExt; +use crate::dep::http_body_util::BodyExt; +use rama_error::{BoxError, ErrorContext, OpaqueError}; use std::future::Future; /// An extension trait for [`Body`] that provides methods to extract data from it. /// -/// [`Body`]: crate::http::Body +/// [`Body`]: crate::Body pub trait BodyExtractExt: private::Sealed { /// Try to deserialize the (contained) body as a JSON object. fn try_into_json( @@ -15,11 +15,9 @@ pub trait BodyExtractExt: private::Sealed { fn try_into_string(self) -> impl Future> + Send; } -impl BodyExtractExt for crate::http::Response +impl BodyExtractExt for crate::Response where - Body: crate::http::dep::http_body::Body> - + Send - + 'static, + Body: crate::dep::http_body::Body> + Send + 'static, { async fn try_into_json( self, @@ -44,11 +42,9 @@ where } } -impl BodyExtractExt for crate::http::Request +impl BodyExtractExt for crate::Request where - Body: crate::http::dep::http_body::Body> - + Send - + 'static, + Body: crate::dep::http_body::Body> + Send + 'static, { async fn try_into_json( self, @@ -72,7 +68,7 @@ where } } -impl + Send + 'static> BodyExtractExt for B { +impl + Send + 'static> BodyExtractExt for B { async fn try_into_json( self, ) -> Result { @@ -90,7 +86,7 @@ impl + Send + 'static> BodyExtractExt for B { mod private { pub trait Sealed {} - impl Sealed for crate::http::Response {} - impl Sealed for crate::http::Request {} - impl + Send + 'static> Sealed for B {} + impl Sealed for crate::Response {} + impl Sealed for crate::Request {} + impl + Send + 'static> Sealed for B {} } diff --git a/src/http/body_limit.rs b/rama-http-types/src/body_limit.rs similarity index 97% rename from src/http/body_limit.rs rename to rama-http-types/src/body_limit.rs index 08f0dcf9..2bddfd34 100644 --- a/src/http/body_limit.rs +++ b/rama-http-types/src/body_limit.rs @@ -4,7 +4,7 @@ /// such that http services used can apply the limit when found in that [`Context`]. /// /// [`Context`]: crate::Context` -/// [`BodyLimitLayer`]: crate::http::layer::body_limit::BodyLimitLayer +/// [`BodyLimitLayer`]: crate::layer::body_limit::BodyLimitLayer #[derive(Debug, Clone, Copy)] pub struct BodyLimit { kind: Option, diff --git a/src/http/headers/ext.rs b/rama-http-types/src/headers/ext.rs similarity index 84% rename from src/http/headers/ext.rs rename to rama-http-types/src/headers/ext.rs index 21d9bcd3..8e284348 100644 --- a/src/http/headers/ext.rs +++ b/rama-http-types/src/headers/ext.rs @@ -5,7 +5,7 @@ //! is merged and published to crates.io. use super::Header; -use crate::http::HeaderValue; +use crate::HeaderValue; /// An external trait adding helper methods to types which implement [`Header`] trait. pub trait HeaderExt: Header + self::sealed::Sealed { @@ -26,7 +26,7 @@ where mod sealed { pub trait Sealed {} - impl Sealed for H {} + impl Sealed for H {} } #[cfg(test)] @@ -35,7 +35,7 @@ mod tests { #[test] fn encode_header() { - let header_value = crate::http::headers::AcceptRanges::bytes().encode_to_value(); + let header_value = crate::headers::AcceptRanges::bytes().encode_to_value(); assert_eq!(header_value, HeaderValue::from_static("bytes")); } } diff --git a/rama-http-types/src/headers/mod.rs b/rama-http-types/src/headers/mod.rs new file mode 100644 index 00000000..3ef13e84 --- /dev/null +++ b/rama-http-types/src/headers/mod.rs @@ -0,0 +1,87 @@ +//! typed http headers +//! +//! rama has the opinion that headers should be strongly-typed, +//! because that’s why we’re using Rust in the first place. To set or get any header, +//! an object must implement the Header trait from this module. +//! Several common headers are already provided, such as Host, ContentType, UserAgent, and others. +//! +//! ## Why typed? +//! +//! Or, why not stringly-typed? Types give the following advantages: +//! - More difficult to typo, since typos in types should be caught by the compiler +//! - Parsing to a proper type by default +//! +//! ## Defining Custom Headers +//! +//! ### Implementing the [`Header`] trait +//! +//! Consider a Do Not Track header. It can be true or false, +//! but it represents that via the numerals 1 and 0. +//! +//! ```rust +//! use rama_http_types::{headers::Header, HeaderName, HeaderValue}; +//! +//! struct Dnt(bool); +//! +//! impl Header for Dnt { +//! fn name() -> &'static HeaderName { +//! &http::header::DNT +//! } +//! +//! fn decode<'i, I>(values: &mut I) -> Result +//! where +//! I: Iterator, +//! { +//! let value = values +//! .next() +//! .ok_or_else(headers::Error::invalid)?; +//! +//! if value == "0" { +//! Ok(Dnt(false)) +//! } else if value == "1" { +//! Ok(Dnt(true)) +//! } else { +//! Err(headers::Error::invalid()) +//! } +//! } +//! +//! fn encode(&self, values: &mut E) +//! where +//! E: Extend, +//! { +//! let s = if self.0 { +//! "1" +//! } else { +//! "0" +//! }; +//! +//! let value = HeaderValue::from_static(s); +//! +//! values.extend(std::iter::once(value)); +//! } +//! } +//! ``` + +pub use headers::{Header, HeaderMapExt}; + +pub use headers::{ + AcceptRanges, AccessControlAllowCredentials, AccessControlAllowHeaders, + AccessControlAllowMethods, AccessControlAllowOrigin, AccessControlExposeHeaders, + AccessControlMaxAge, AccessControlRequestHeaders, AccessControlRequestMethod, Age, Allow, + Authorization, CacheControl, Connection, ContentDisposition, ContentEncoding, ContentLength, + ContentLocation, ContentRange, ContentType, Cookie, Date, ETag, Error, Expect, Expires, Host, + IfMatch, IfModifiedSince, IfNoneMatch, IfRange, IfUnmodifiedSince, LastModified, Location, + Origin, Pragma, ProxyAuthorization, Range, Referer, ReferrerPolicy, RetryAfter, + SecWebsocketAccept, SecWebsocketKey, SecWebsocketVersion, Server, SetCookie, + StrictTransportSecurity, Te, TransferEncoding, Upgrade, UserAgent, Vary, +}; + +pub mod authorization { + //! Authorization header and types. + + pub use headers::authorization::Credentials; + pub use headers::authorization::{Authorization, Basic, Bearer}; +} + +mod ext; +pub use ext::HeaderExt; diff --git a/src/http/mod.rs b/rama-http-types/src/lib.rs similarity index 58% rename from src/http/mod.rs rename to rama-http-types/src/lib.rs index a8063d47..41029b6a 100644 --- a/src/http/mod.rs +++ b/rama-http-types/src/lib.rs @@ -1,4 +1,58 @@ -//! Rama http modules. +//! rama http types and minimal utilities +//! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] pub(crate) mod body; #[doc(inline)] @@ -12,14 +66,6 @@ mod body_ext; #[doc(inline)] pub use body_ext::BodyExtractExt; -mod request_context; -#[doc(inline)] -pub use request_context::RequestContext; - -pub mod utils; - -pub mod headers; - /// Type alias for [`http::Request`] whose body type /// defaults to [`Body`], the most common body type used with rama. pub type Request = http::Request; @@ -27,18 +73,7 @@ pub type Request = http::Request; pub mod response; pub use response::{IntoResponse, Response}; -pub mod matcher; - -pub mod layer; -pub mod service; - -pub mod server; - -pub mod client; - -pub mod io; - -pub mod executor; +pub mod headers; pub mod dep { //! Dependencies for rama http modules. @@ -100,7 +135,7 @@ pub mod dep { pub mod header { //! HTTP header types - pub use crate::http::dep::http::header::*; + pub use crate::dep::http::header::*; macro_rules! static_header { ($($name_bytes:literal),+ $(,)?) => { @@ -129,18 +164,19 @@ pub mod header { ]; /// Static Header Value that is can be used as `User-Agent` or `Server` header. - pub static RAMA_ID_HEADER_VALUE: HeaderValue = - HeaderValue::from_static(const_format::formatcp!( - "{}/{}", - crate::utils::info::NAME, - crate::utils::info::VERSION, - )); + pub static RAMA_ID_HEADER_VALUE: HeaderValue = HeaderValue::from_static( + const_format::formatcp!("{}/{}", super::NAME, super::VERSION,), + ); } -pub use self::dep::http::header::HeaderMap; -pub use self::dep::http::header::HeaderName; -pub use self::dep::http::header::HeaderValue; +pub use self::dep::http::header::{HeaderMap, HeaderName, HeaderValue}; pub use self::dep::http::method::Method; pub use self::dep::http::status::StatusCode; pub use self::dep::http::uri::{Scheme, Uri}; pub use self::dep::http::version::Version; + +/// The name of the crate. +const NAME: &str = "rama"; + +/// The version of the crate. +const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/http/response/append_headers.rs b/rama-http-types/src/response/append_headers.rs similarity index 96% rename from src/http/response/append_headers.rs rename to rama-http-types/src/response/append_headers.rs index 3dd55db4..178e3dfe 100644 --- a/src/http/response/append_headers.rs +++ b/rama-http-types/src/response/append_headers.rs @@ -1,6 +1,6 @@ use super::{IntoResponse, IntoResponseParts, Response, ResponseParts, TryIntoHeaderError}; -use crate::utils::macros::impl_deref; -use http::header::{HeaderName, HeaderValue}; +use crate::{HeaderName, HeaderValue}; +use rama_macros::impl_deref; use std::fmt; /// Append headers to a response. diff --git a/src/http/response/form.rs b/rama-http-types/src/response/form.rs similarity index 87% rename from src/http/response/form.rs rename to rama-http-types/src/response/form.rs index fcde92e8..60e66d9d 100644 --- a/src/http/response/form.rs +++ b/rama-http-types/src/response/form.rs @@ -1,19 +1,19 @@ use std::fmt; -use crate::error::OpaqueError; -use crate::http::dep::http::header::CONTENT_TYPE; -use crate::http::dep::http::StatusCode; -use crate::http::dep::mime; -use crate::http::response::{IntoResponse, Response}; -use crate::http::Body; -use crate::utils::macros::impl_deref; +use crate::dep::http::header::CONTENT_TYPE; +use crate::dep::http::StatusCode; +use crate::dep::mime; +use crate::response::{IntoResponse, Response}; +use crate::Body; +use rama_error::OpaqueError; +use rama_macros::impl_deref; use serde::Serialize; /// Wrapper used to create Form Http [`Response`]s, /// as well as to extract Form from Http [`Request`] bodies. /// -/// [`Request`]: crate::http::Request -/// [`Response`]: crate::http::Response +/// [`Request`]: crate::Request +/// [`Response`]: crate::Response /// /// # Examples /// ## Creating a Form Response diff --git a/src/http/response/html.rs b/rama-http-types/src/response/html.rs similarity index 88% rename from src/http/response/html.rs rename to rama-http-types/src/response/html.rs index 040e48f9..741cf81f 100644 --- a/src/http/response/html.rs +++ b/rama-http-types/src/response/html.rs @@ -1,5 +1,5 @@ -use crate::http::{header, Body, HeaderValue, IntoResponse, Response}; -use crate::utils::macros::impl_deref; +use crate::{header, Body, HeaderValue, IntoResponse, Response}; +use rama_macros::impl_deref; use std::fmt; /// An HTML response. diff --git a/src/http/response/into_response.rs b/rama-http-types/src/response/into_response.rs similarity index 98% rename from src/http/response/into_response.rs rename to rama-http-types/src/response/into_response.rs index 4e7a8493..c3f20a60 100644 --- a/src/http/response/into_response.rs +++ b/rama-http-types/src/response/into_response.rs @@ -1,13 +1,15 @@ use super::{IntoResponseParts, Response, ResponseParts}; -use crate::http::dep::mime; -use crate::utils::macros::all_the_tuples_no_last_special_case; -use crate::{error::BoxError, http::Body}; -use bytes::{buf::Chain, Buf, Bytes, BytesMut}; -use http::{ +use crate::dep::http_body::{Frame, SizeHint}; +use crate::dep::mime; +use crate::Body; +use crate::{ + dep::http::Extensions, header::{self, HeaderMap, HeaderName, HeaderValue}, - Extensions, StatusCode, + StatusCode, }; -use http_body::{Frame, SizeHint}; +use bytes::{buf::Chain, Buf, Bytes, BytesMut}; +use rama_error::BoxError; +use rama_macros::all_the_tuples_no_last_special_case; use std::{ borrow::Cow, convert::Infallible, diff --git a/src/http/response/into_response_parts.rs b/rama-http-types/src/response/into_response_parts.rs similarity index 98% rename from src/http/response/into_response_parts.rs rename to rama-http-types/src/response/into_response_parts.rs index 6ab07152..407c531e 100644 --- a/src/http/response/into_response_parts.rs +++ b/rama-http-types/src/response/into_response_parts.rs @@ -1,9 +1,10 @@ use super::{IntoResponse, Response}; -use crate::utils::macros::all_the_tuples_no_last_special_case; -use http::{ +use crate::{ + dep::http::Extensions, header::{HeaderMap, HeaderName, HeaderValue}, - Extensions, StatusCode, + StatusCode, }; +use rama_macros::all_the_tuples_no_last_special_case; use std::{convert::Infallible, fmt}; /// Trait for adding headers and extensions to a response. diff --git a/src/http/response/json.rs b/rama-http-types/src/response/json.rs similarity index 90% rename from src/http/response/json.rs rename to rama-http-types/src/response/json.rs index 0c03fd15..8ff1923c 100644 --- a/src/http/response/json.rs +++ b/rama-http-types/src/response/json.rs @@ -1,24 +1,22 @@ -use crate::http::response::{IntoResponse, Response}; -use crate::utils::macros::impl_deref; +use crate::response::{IntoResponse, Response}; use crate::{ - error::OpaqueError, - http::{ - dep::http::{ - header::{self, HeaderValue}, - StatusCode, - }, - Body, + dep::http::{ + header::{self, HeaderValue}, + StatusCode, }, + Body, }; use bytes::{BufMut, BytesMut}; +use rama_error::OpaqueError; +use rama_macros::impl_deref; use serde::Serialize; use std::fmt; /// Wrapper used to create Json Http [`Response`]s, /// as well as to extract Json from Http [`Request`] bodies. /// -/// [`Request`]: crate::http::Request -/// [`Response`]: crate::http::Response +/// [`Request`]: crate::Request +/// [`Response`]: crate::Response /// /// # Examples /// diff --git a/src/http/response/mod.rs b/rama-http-types/src/response/mod.rs similarity index 97% rename from src/http/response/mod.rs rename to rama-http-types/src/response/mod.rs index 7f5eb455..d2914c46 100644 --- a/src/http/response/mod.rs +++ b/rama-http-types/src/response/mod.rs @@ -1,8 +1,8 @@ //! Types and traits for generating responses. //! -//! See [`crate::http::response`] for more details. +//! See [`crate::response`] for more details. -use crate::http::Body; +use crate::Body; mod append_headers; mod into_response; diff --git a/src/http/response/redirect.rs b/rama-http-types/src/response/redirect.rs similarity index 94% rename from src/http/response/redirect.rs rename to rama-http-types/src/response/redirect.rs index 7c1da97e..e709cf36 100644 --- a/src/http/response/redirect.rs +++ b/rama-http-types/src/response/redirect.rs @@ -1,5 +1,5 @@ use super::IntoResponse; -use crate::http::{header, HeaderValue, Response, StatusCode}; +use crate::{header, HeaderValue, Response, StatusCode}; #[derive(Debug, Clone)] /// Utility struct to easily create a redirect response. diff --git a/rama-http/Cargo.toml b/rama-http/Cargo.toml new file mode 100644 index 00000000..4ee54e20 --- /dev/null +++ b/rama-http/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "rama-http" +description = "rama http layers, services and other utilities" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = [] +compression = ["dep:async-compression"] + +[dependencies] +async-compression = { workspace = true, features = [ + "tokio", + "brotli", + "zlib", + "gzip", + "zstd", +], optional = true } +bytes = { workspace = true } +const_format = { workspace = true } +futures-core = { workspace = true } +futures-lite = { workspace = true } +headers = { workspace = true } +http = { workspace = true } +http-body = { workspace = true } +http-body-util = { workspace = true } +mime = { workspace = true } +mime_guess = { workspace = true } +paste = { workspace = true } +pin-project-lite = { workspace = true } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } +serde = { workspace = true, features = ["derive"] } +serde_html_form = { workspace = true } +serde_json = { workspace = true } +sync_wrapper = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +tokio = { workspace = true, features = ["full"] } +tokio-test = { workspace = true } + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-http/README.md b/rama-http/README.md new file mode 100644 index 00000000..e69de29b diff --git a/src/http/client/conn.rs b/rama-http/src/client/conn.rs similarity index 100% rename from src/http/client/conn.rs rename to rama-http/src/client/conn.rs diff --git a/src/http/client/error.rs b/rama-http/src/client/error.rs similarity index 100% rename from src/http/client/error.rs rename to rama-http/src/client/error.rs diff --git a/src/http/client/ext.rs b/rama-http/src/client/ext.rs similarity index 100% rename from src/http/client/ext.rs rename to rama-http/src/client/ext.rs diff --git a/src/http/client/mod.rs b/rama-http/src/client/mod.rs similarity index 100% rename from src/http/client/mod.rs rename to rama-http/src/client/mod.rs diff --git a/src/http/client/svc.rs b/rama-http/src/client/svc.rs similarity index 100% rename from src/http/client/svc.rs rename to rama-http/src/client/svc.rs diff --git a/src/http/executor.rs b/rama-http/src/executor.rs similarity index 100% rename from src/http/executor.rs rename to rama-http/src/executor.rs diff --git a/src/http/headers/common/accept.rs b/rama-http/src/headers/common/accept.rs similarity index 93% rename from src/http/headers/common/accept.rs rename to rama-http/src/headers/common/accept.rs index 05a56c2c..f013dc7b 100644 --- a/src/http/headers/common/accept.rs +++ b/rama-http/src/headers/common/accept.rs @@ -1,6 +1,6 @@ -use crate::http::headers::{self, Header, QualityValue}; -use crate::http::{HeaderName, HeaderValue}; -use mime::{self, Mime}; +use crate::dep::mime::{self, Mime}; +use crate::headers::{self, Header, QualityValue}; +use crate::{HeaderName, HeaderValue}; use std::iter::FromIterator; fn qitem(mime: Mime) -> QualityValue { @@ -87,13 +87,13 @@ pub struct Accept(Vec>); impl Header for Accept { fn name() -> &'static HeaderName { - &crate::http::header::ACCEPT + &crate::header::ACCEPT } fn decode<'i, I: Iterator>( values: &mut I, ) -> Result { - crate::http::headers::util::csv::from_comma_delimited(values).map(Accept) + crate::headers::util::csv::from_comma_delimited(values).map(Accept) } fn encode>(&self, values: &mut E) { @@ -110,7 +110,7 @@ impl Header for Accept { let s = format!( "{}", Format(|f: &mut fmt::Formatter<'_>| { - crate::http::headers::util::csv::fmt_comma_delimited(&mut *f, self.0.iter()) + crate::headers::util::csv::fmt_comma_delimited(&mut *f, self.0.iter()) }) ); values.extend(Some(HeaderValue::from_str(&s).unwrap())) @@ -156,13 +156,12 @@ impl Accept { #[cfg(test)] mod tests { use super::*; - - use { + use crate::dep::{ http::HeaderValue, mime::{TEXT_HTML, TEXT_PLAIN, TEXT_PLAIN_UTF_8}, }; - use crate::http::headers::Quality; + use crate::headers::Quality; macro_rules! test_header { ($name: ident, $input: expr, $expected: expr) => { diff --git a/src/http/headers/common/mod.rs b/rama-http/src/headers/common/mod.rs similarity index 100% rename from src/http/headers/common/mod.rs rename to rama-http/src/headers/common/mod.rs diff --git a/src/http/headers/forwarded/exotic_forward_ip.rs b/rama-http/src/headers/forwarded/exotic_forward_ip.rs similarity index 95% rename from src/http/headers/forwarded/exotic_forward_ip.rs rename to rama-http/src/headers/forwarded/exotic_forward_ip.rs index f341f633..265ac321 100644 --- a/src/http/headers/forwarded/exotic_forward_ip.rs +++ b/rama-http/src/headers/forwarded/exotic_forward_ip.rs @@ -1,9 +1,9 @@ -use crate::error::{ErrorContext, OpaqueError}; -use crate::http::header::{CF_CONNECTING_IP, CLIENT_IP, TRUE_CLIENT_IP, X_CLIENT_IP, X_REAL_IP}; -use crate::http::headers::Header; -use crate::http::{HeaderName, HeaderValue}; -use crate::net::forwarded::{ForwardedElement, NodeId}; +use crate::header::{CF_CONNECTING_IP, CLIENT_IP, TRUE_CLIENT_IP, X_CLIENT_IP, X_REAL_IP}; +use crate::headers::Header; +use crate::{HeaderName, HeaderValue}; use paste::paste; +use rama_core::error::{ErrorContext, OpaqueError}; +use rama_core::net::forwarded::{ForwardedElement, NodeId}; use std::fmt; use std::net::{IpAddr, Ipv6Addr}; @@ -96,7 +96,7 @@ macro_rules! exotic_forward_ip_headers { values .next() .and_then(|value| value.to_str().ok().and_then(|s| s.parse().ok())) - .ok_or_else(crate::http::headers::Error::invalid)?, + .ok_or_else(crate::headers::Error::invalid)?, )) } diff --git a/src/http/headers/forwarded/mod.rs b/rama-http/src/headers/forwarded/mod.rs similarity index 90% rename from src/http/headers/forwarded/mod.rs rename to rama-http/src/headers/forwarded/mod.rs index e94a8a85..32e3ece5 100644 --- a/src/http/headers/forwarded/mod.rs +++ b/rama-http/src/headers/forwarded/mod.rs @@ -1,5 +1,5 @@ -pub use crate::net::forwarded::Forwarded; -use crate::net::forwarded::ForwardedElement; +pub use rama_core::net::forwarded::Forwarded; +use rama_core::net::forwarded::ForwardedElement; mod via; #[doc(inline)] @@ -23,9 +23,7 @@ pub use exotic_forward_ip::{CFConnectingIp, ClientIp, TrueClientIp, XClientIp, X /// A trait for types headers that is used by middleware /// which supports headers that can be converted into and from Forward data. -pub trait ForwardHeader: - crate::http::headers::Header + IntoIterator -{ +pub trait ForwardHeader: crate::headers::Header + IntoIterator { /// Try to convert the given iterator of `ForwardedElement` into the header. /// /// `None` is returned if the conversion fails. diff --git a/src/http/headers/forwarded/via.rs b/rama-http/src/headers/forwarded/via.rs similarity index 96% rename from src/http/headers/forwarded/via.rs rename to rama-http/src/headers/forwarded/via.rs index 6cee1b96..e7a92b62 100644 --- a/src/http/headers/forwarded/via.rs +++ b/rama-http/src/headers/forwarded/via.rs @@ -1,7 +1,7 @@ -use crate::error::{ErrorContext, OpaqueError}; -use crate::http::headers::{self, Header}; -use crate::http::{HeaderName, HeaderValue}; -use crate::net::forwarded::{ForwardedElement, ForwardedProtocol, ForwardedVersion, NodeId}; +use crate::headers::{self, Header}; +use crate::{HeaderName, HeaderValue}; +use rama_core::error::{ErrorContext, OpaqueError}; +use rama_core::net::forwarded::{ForwardedElement, ForwardedProtocol, ForwardedVersion, NodeId}; /// The Via general header is added by proxies, both forward and reverse. /// @@ -50,13 +50,13 @@ impl From for ForwardedElement { impl Header for Via { fn name() -> &'static HeaderName { - &crate::http::header::VIA + &crate::header::VIA } fn decode<'i, I: Iterator>( values: &mut I, ) -> Result { - crate::http::headers::util::csv::from_comma_delimited(values).map(Via) + crate::headers::util::csv::from_comma_delimited(values).map(Via) } fn encode>(&self, values: &mut E) { @@ -73,7 +73,7 @@ impl Header for Via { let s = format!( "{}", Format(|f: &mut fmt::Formatter<'_>| { - crate::http::headers::util::csv::fmt_comma_delimited(&mut *f, self.0.iter()) + crate::headers::util::csv::fmt_comma_delimited(&mut *f, self.0.iter()) }) ); values.extend(Some(HeaderValue::from_str(&s).unwrap())) diff --git a/src/http/headers/forwarded/x_forwarded_for.rs b/rama-http/src/headers/forwarded/x_forwarded_for.rs similarity index 94% rename from src/http/headers/forwarded/x_forwarded_for.rs rename to rama-http/src/headers/forwarded/x_forwarded_for.rs index 261d5d39..89fe00fe 100644 --- a/src/http/headers/forwarded/x_forwarded_for.rs +++ b/rama-http/src/headers/forwarded/x_forwarded_for.rs @@ -1,6 +1,6 @@ -use crate::http::headers::{self, Header}; -use crate::http::{HeaderName, HeaderValue}; -use crate::net::forwarded::ForwardedElement; +use crate::headers::{self, Header}; +use crate::{HeaderName, HeaderValue}; +use rama_core::net::forwarded::ForwardedElement; use std::iter::FromIterator; use std::net::IpAddr; @@ -27,13 +27,13 @@ pub struct XForwardedFor(Vec); impl Header for XForwardedFor { fn name() -> &'static HeaderName { - &crate::http::header::X_FORWARDED_FOR + &crate::header::X_FORWARDED_FOR } fn decode<'i, I: Iterator>( values: &mut I, ) -> Result { - crate::http::headers::util::csv::from_comma_delimited(values).map(XForwardedFor) + crate::headers::util::csv::from_comma_delimited(values).map(XForwardedFor) } fn encode>(&self, values: &mut E) { @@ -50,7 +50,7 @@ impl Header for XForwardedFor { let s = format!( "{}", Format(|f: &mut fmt::Formatter<'_>| { - crate::http::headers::util::csv::fmt_comma_delimited(&mut *f, self.0.iter()) + crate::headers::util::csv::fmt_comma_delimited(&mut *f, self.0.iter()) }) ); values.extend(Some(HeaderValue::from_str(&s).unwrap())) diff --git a/src/http/headers/forwarded/x_forwarded_host.rs b/rama-http/src/headers/forwarded/x_forwarded_host.rs similarity index 94% rename from src/http/headers/forwarded/x_forwarded_host.rs rename to rama-http/src/headers/forwarded/x_forwarded_host.rs index 35cbe285..6f6793cc 100644 --- a/src/http/headers/forwarded/x_forwarded_host.rs +++ b/rama-http/src/headers/forwarded/x_forwarded_host.rs @@ -1,7 +1,7 @@ -use crate::http::headers::{self, Header}; -use crate::http::{HeaderName, HeaderValue}; -use crate::net::address::Host; -use crate::net::forwarded::{ForwardedAuthority, ForwardedElement}; +use crate::headers::{self, Header}; +use crate::{HeaderName, HeaderValue}; +use rama_core::net::address::Host; +use rama_core::net::forwarded::{ForwardedAuthority, ForwardedElement}; /// The X-Forwarded-Host (XFH) header is a de-facto standard header for identifying the /// original host requested by the client in the Host HTTP request header. @@ -29,7 +29,7 @@ pub struct XForwardedHost(ForwardedAuthority); impl Header for XForwardedHost { fn name() -> &'static HeaderName { - &crate::http::header::X_FORWARDED_HOST + &crate::header::X_FORWARDED_HOST } fn decode<'i, I: Iterator>( @@ -39,7 +39,7 @@ impl Header for XForwardedHost { values .next() .and_then(|value| value.to_str().ok().and_then(|s| s.parse().ok())) - .ok_or_else(crate::http::headers::Error::invalid)?, + .ok_or_else(crate::headers::Error::invalid)?, )) } diff --git a/src/http/headers/forwarded/x_forwarded_proto.rs b/rama-http/src/headers/forwarded/x_forwarded_proto.rs similarity index 93% rename from src/http/headers/forwarded/x_forwarded_proto.rs rename to rama-http/src/headers/forwarded/x_forwarded_proto.rs index 6afa9d5e..0a9a8686 100644 --- a/src/http/headers/forwarded/x_forwarded_proto.rs +++ b/rama-http/src/headers/forwarded/x_forwarded_proto.rs @@ -1,6 +1,6 @@ -use crate::http::headers::{self, Header}; -use crate::http::{HeaderName, HeaderValue}; -use crate::net::forwarded::{ForwardedElement, ForwardedProtocol}; +use crate::headers::{self, Header}; +use crate::{HeaderName, HeaderValue}; +use rama_core::net::forwarded::{ForwardedElement, ForwardedProtocol}; /// The X-Forwarded-Proto (XFP) header is a de-facto standard header for /// identifying the protocol (HTTP or HTTPS) that a client used to connect to your proxy or load balancer. @@ -28,7 +28,7 @@ pub struct XForwardedProto(ForwardedProtocol); impl Header for XForwardedProto { fn name() -> &'static HeaderName { - &crate::http::header::X_FORWARDED_PROTO + &crate::header::X_FORWARDED_PROTO } fn decode<'i, I: Iterator>( @@ -38,7 +38,7 @@ impl Header for XForwardedProto { values .next() .and_then(|value| value.to_str().ok().and_then(|s| s.parse().ok())) - .ok_or_else(crate::http::headers::Error::invalid)?, + .ok_or_else(crate::headers::Error::invalid)?, )) } diff --git a/src/http/headers/mod.rs b/rama-http/src/headers/mod.rs similarity index 94% rename from src/http/headers/mod.rs rename to rama-http/src/headers/mod.rs index 4e80a199..f5dcbc5d 100644 --- a/src/http/headers/mod.rs +++ b/rama-http/src/headers/mod.rs @@ -19,7 +19,7 @@ //! but it represents that via the numerals 1 and 0. //! //! ```rust -//! use rama::http::{headers::Header, HeaderName, HeaderValue}; +//! use rama_http::{headers::Header, HeaderName, HeaderValue}; //! //! struct Dnt(bool); //! @@ -62,9 +62,9 @@ //! } //! ``` -pub use headers::{Header, HeaderMapExt}; +pub use rama_http_types::headers::{Header, HeaderMapExt}; -pub use headers::{ +pub use rama_http_types::headers::{ AcceptRanges, AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowMethods, AccessControlAllowOrigin, AccessControlExposeHeaders, AccessControlMaxAge, AccessControlRequestHeaders, AccessControlRequestMethod, Age, Allow, @@ -94,8 +94,7 @@ pub mod authorization { pub use headers::authorization::{Authorization, Basic, Bearer}; } -mod ext; -pub use ext::HeaderExt; +pub use rama_http_types::HeaderExt; pub(crate) mod util; pub use util::quality_value::{Quality, QualityValue}; diff --git a/src/http/headers/util/csv.rs b/rama-http/src/headers/util/csv.rs similarity index 95% rename from src/http/headers/util/csv.rs rename to rama-http/src/headers/util/csv.rs index 06819f90..b91f3567 100644 --- a/src/http/headers/util/csv.rs +++ b/rama-http/src/headers/util/csv.rs @@ -4,8 +4,8 @@ use std::fmt; -use crate::http::headers::Error; -use crate::http::HeaderValue; +use crate::headers::Error; +use crate::HeaderValue; /// Reads a comma-delimited raw header into a Vec. pub(crate) fn from_comma_delimited<'i, I, T, E>(values: &mut I) -> Result diff --git a/src/http/headers/util/mod.rs b/rama-http/src/headers/util/mod.rs similarity index 100% rename from src/http/headers/util/mod.rs rename to rama-http/src/headers/util/mod.rs diff --git a/src/http/headers/util/quality_value.rs b/rama-http/src/headers/util/quality_value.rs similarity index 94% rename from src/http/headers/util/quality_value.rs rename to rama-http/src/headers/util/quality_value.rs index d5056346..c0328b13 100644 --- a/src/http/headers/util/quality_value.rs +++ b/rama-http/src/headers/util/quality_value.rs @@ -88,8 +88,8 @@ impl fmt::Display for QualityValue { } impl str::FromStr for QualityValue { - type Err = crate::http::headers::Error; - fn from_str(s: &str) -> Result, crate::http::headers::Error> { + type Err = crate::headers::Error; + fn from_str(s: &str) -> Result, crate::headers::Error> { // Set defaults used if parsing fails. let mut raw_item = s; let mut quality = 1f32; @@ -97,12 +97,12 @@ impl str::FromStr for QualityValue { let mut parts = s.rsplitn(2, ';').map(|x| x.trim()); if let (Some(first), Some(second), None) = (parts.next(), parts.next(), parts.next()) { if first.len() < 2 { - return Err(crate::http::headers::Error::invalid()); + return Err(crate::headers::Error::invalid()); } if first.starts_with("q=") || first.starts_with("Q=") { let q_part = &first[2..]; if q_part.len() > 5 { - return Err(crate::http::headers::Error::invalid()); + return Err(crate::headers::Error::invalid()); } match q_part.parse::() { Ok(q_value) => { @@ -110,17 +110,17 @@ impl str::FromStr for QualityValue { quality = q_value; raw_item = second; } else { - return Err(crate::http::headers::Error::invalid()); + return Err(crate::headers::Error::invalid()); } } - Err(_) => return Err(crate::http::headers::Error::invalid()), + Err(_) => return Err(crate::headers::Error::invalid()), } } } match raw_item.parse::() { // we already checked above that the quality is within range Ok(item) => Ok(QualityValue::new(item, from_f32(quality))), - Err(_) => Err(crate::http::headers::Error::invalid()), + Err(_) => Err(crate::headers::Error::invalid()), } } } diff --git a/src/http/io/mod.rs b/rama-http/src/io/mod.rs similarity index 100% rename from src/http/io/mod.rs rename to rama-http/src/io/mod.rs diff --git a/src/http/io/request.rs b/rama-http/src/io/request.rs similarity index 100% rename from src/http/io/request.rs rename to rama-http/src/io/request.rs diff --git a/src/http/io/response.rs b/rama-http/src/io/response.rs similarity index 100% rename from src/http/io/response.rs rename to rama-http/src/io/response.rs diff --git a/src/http/layer/auth/add_authorization.rs b/rama-http/src/layer/auth/add_authorization.rs similarity index 100% rename from src/http/layer/auth/add_authorization.rs rename to rama-http/src/layer/auth/add_authorization.rs diff --git a/src/http/layer/auth/async_require_authorization.rs b/rama-http/src/layer/auth/async_require_authorization.rs similarity index 100% rename from src/http/layer/auth/async_require_authorization.rs rename to rama-http/src/layer/auth/async_require_authorization.rs diff --git a/src/http/layer/auth/mod.rs b/rama-http/src/layer/auth/mod.rs similarity index 100% rename from src/http/layer/auth/mod.rs rename to rama-http/src/layer/auth/mod.rs diff --git a/src/http/layer/auth/require_authorization.rs b/rama-http/src/layer/auth/require_authorization.rs similarity index 100% rename from src/http/layer/auth/require_authorization.rs rename to rama-http/src/layer/auth/require_authorization.rs diff --git a/src/http/layer/body_limit.rs b/rama-http/src/layer/body_limit.rs similarity index 100% rename from src/http/layer/body_limit.rs rename to rama-http/src/layer/body_limit.rs diff --git a/src/http/layer/catch_panic.rs b/rama-http/src/layer/catch_panic.rs similarity index 100% rename from src/http/layer/catch_panic.rs rename to rama-http/src/layer/catch_panic.rs diff --git a/src/http/layer/classify/grpc_errors_as_failures.rs b/rama-http/src/layer/classify/grpc_errors_as_failures.rs similarity index 100% rename from src/http/layer/classify/grpc_errors_as_failures.rs rename to rama-http/src/layer/classify/grpc_errors_as_failures.rs diff --git a/src/http/layer/classify/map_failure_class.rs b/rama-http/src/layer/classify/map_failure_class.rs similarity index 100% rename from src/http/layer/classify/map_failure_class.rs rename to rama-http/src/layer/classify/map_failure_class.rs diff --git a/src/http/layer/classify/mod.rs b/rama-http/src/layer/classify/mod.rs similarity index 100% rename from src/http/layer/classify/mod.rs rename to rama-http/src/layer/classify/mod.rs diff --git a/src/http/layer/classify/status_in_range_is_error.rs b/rama-http/src/layer/classify/status_in_range_is_error.rs similarity index 100% rename from src/http/layer/classify/status_in_range_is_error.rs rename to rama-http/src/layer/classify/status_in_range_is_error.rs diff --git a/src/http/layer/compression/body.rs b/rama-http/src/layer/compression/body.rs similarity index 100% rename from src/http/layer/compression/body.rs rename to rama-http/src/layer/compression/body.rs diff --git a/src/http/layer/compression/layer.rs b/rama-http/src/layer/compression/layer.rs similarity index 100% rename from src/http/layer/compression/layer.rs rename to rama-http/src/layer/compression/layer.rs diff --git a/src/http/layer/compression/mod.rs b/rama-http/src/layer/compression/mod.rs similarity index 100% rename from src/http/layer/compression/mod.rs rename to rama-http/src/layer/compression/mod.rs diff --git a/src/http/layer/compression/pin_project_cfg.rs b/rama-http/src/layer/compression/pin_project_cfg.rs similarity index 100% rename from src/http/layer/compression/pin_project_cfg.rs rename to rama-http/src/layer/compression/pin_project_cfg.rs diff --git a/src/http/layer/compression/predicate.rs b/rama-http/src/layer/compression/predicate.rs similarity index 100% rename from src/http/layer/compression/predicate.rs rename to rama-http/src/layer/compression/predicate.rs diff --git a/src/http/layer/compression/service.rs b/rama-http/src/layer/compression/service.rs similarity index 100% rename from src/http/layer/compression/service.rs rename to rama-http/src/layer/compression/service.rs diff --git a/src/http/layer/cors/allow_credentials.rs b/rama-http/src/layer/cors/allow_credentials.rs similarity index 100% rename from src/http/layer/cors/allow_credentials.rs rename to rama-http/src/layer/cors/allow_credentials.rs diff --git a/src/http/layer/cors/allow_headers.rs b/rama-http/src/layer/cors/allow_headers.rs similarity index 100% rename from src/http/layer/cors/allow_headers.rs rename to rama-http/src/layer/cors/allow_headers.rs diff --git a/src/http/layer/cors/allow_methods.rs b/rama-http/src/layer/cors/allow_methods.rs similarity index 100% rename from src/http/layer/cors/allow_methods.rs rename to rama-http/src/layer/cors/allow_methods.rs diff --git a/src/http/layer/cors/allow_origin.rs b/rama-http/src/layer/cors/allow_origin.rs similarity index 100% rename from src/http/layer/cors/allow_origin.rs rename to rama-http/src/layer/cors/allow_origin.rs diff --git a/src/http/layer/cors/allow_private_network.rs b/rama-http/src/layer/cors/allow_private_network.rs similarity index 100% rename from src/http/layer/cors/allow_private_network.rs rename to rama-http/src/layer/cors/allow_private_network.rs diff --git a/src/http/layer/cors/expose_headers.rs b/rama-http/src/layer/cors/expose_headers.rs similarity index 100% rename from src/http/layer/cors/expose_headers.rs rename to rama-http/src/layer/cors/expose_headers.rs diff --git a/src/http/layer/cors/max_age.rs b/rama-http/src/layer/cors/max_age.rs similarity index 100% rename from src/http/layer/cors/max_age.rs rename to rama-http/src/layer/cors/max_age.rs diff --git a/src/http/layer/cors/mod.rs b/rama-http/src/layer/cors/mod.rs similarity index 100% rename from src/http/layer/cors/mod.rs rename to rama-http/src/layer/cors/mod.rs diff --git a/src/http/layer/cors/tests.rs b/rama-http/src/layer/cors/tests.rs similarity index 100% rename from src/http/layer/cors/tests.rs rename to rama-http/src/layer/cors/tests.rs diff --git a/src/http/layer/cors/vary.rs b/rama-http/src/layer/cors/vary.rs similarity index 100% rename from src/http/layer/cors/vary.rs rename to rama-http/src/layer/cors/vary.rs diff --git a/src/http/layer/decompression/body.rs b/rama-http/src/layer/decompression/body.rs similarity index 100% rename from src/http/layer/decompression/body.rs rename to rama-http/src/layer/decompression/body.rs diff --git a/src/http/layer/decompression/layer.rs b/rama-http/src/layer/decompression/layer.rs similarity index 100% rename from src/http/layer/decompression/layer.rs rename to rama-http/src/layer/decompression/layer.rs diff --git a/src/http/layer/decompression/mod.rs b/rama-http/src/layer/decompression/mod.rs similarity index 100% rename from src/http/layer/decompression/mod.rs rename to rama-http/src/layer/decompression/mod.rs diff --git a/src/http/layer/decompression/request/layer.rs b/rama-http/src/layer/decompression/request/layer.rs similarity index 100% rename from src/http/layer/decompression/request/layer.rs rename to rama-http/src/layer/decompression/request/layer.rs diff --git a/src/http/layer/decompression/request/mod.rs b/rama-http/src/layer/decompression/request/mod.rs similarity index 100% rename from src/http/layer/decompression/request/mod.rs rename to rama-http/src/layer/decompression/request/mod.rs diff --git a/src/http/layer/decompression/request/service.rs b/rama-http/src/layer/decompression/request/service.rs similarity index 100% rename from src/http/layer/decompression/request/service.rs rename to rama-http/src/layer/decompression/request/service.rs diff --git a/src/http/layer/decompression/service.rs b/rama-http/src/layer/decompression/service.rs similarity index 100% rename from src/http/layer/decompression/service.rs rename to rama-http/src/layer/decompression/service.rs diff --git a/src/http/layer/dns/dns_map/layer.rs b/rama-http/src/layer/dns/dns_map/layer.rs similarity index 100% rename from src/http/layer/dns/dns_map/layer.rs rename to rama-http/src/layer/dns/dns_map/layer.rs diff --git a/src/http/layer/dns/dns_map/mod.rs b/rama-http/src/layer/dns/dns_map/mod.rs similarity index 100% rename from src/http/layer/dns/dns_map/mod.rs rename to rama-http/src/layer/dns/dns_map/mod.rs diff --git a/src/http/layer/dns/dns_map/service.rs b/rama-http/src/layer/dns/dns_map/service.rs similarity index 100% rename from src/http/layer/dns/dns_map/service.rs rename to rama-http/src/layer/dns/dns_map/service.rs diff --git a/src/http/layer/dns/dns_resolve/layer.rs b/rama-http/src/layer/dns/dns_resolve/layer.rs similarity index 100% rename from src/http/layer/dns/dns_resolve/layer.rs rename to rama-http/src/layer/dns/dns_resolve/layer.rs diff --git a/src/http/layer/dns/dns_resolve/mod.rs b/rama-http/src/layer/dns/dns_resolve/mod.rs similarity index 100% rename from src/http/layer/dns/dns_resolve/mod.rs rename to rama-http/src/layer/dns/dns_resolve/mod.rs diff --git a/src/http/layer/dns/dns_resolve/service.rs b/rama-http/src/layer/dns/dns_resolve/service.rs similarity index 100% rename from src/http/layer/dns/dns_resolve/service.rs rename to rama-http/src/layer/dns/dns_resolve/service.rs diff --git a/src/http/layer/dns/dns_resolve/username_parser.rs b/rama-http/src/layer/dns/dns_resolve/username_parser.rs similarity index 100% rename from src/http/layer/dns/dns_resolve/username_parser.rs rename to rama-http/src/layer/dns/dns_resolve/username_parser.rs diff --git a/src/http/layer/dns/mod.rs b/rama-http/src/layer/dns/mod.rs similarity index 100% rename from src/http/layer/dns/mod.rs rename to rama-http/src/layer/dns/mod.rs diff --git a/src/http/layer/error_handling.rs b/rama-http/src/layer/error_handling.rs similarity index 100% rename from src/http/layer/error_handling.rs rename to rama-http/src/layer/error_handling.rs diff --git a/src/http/layer/follow_redirect/mod.rs b/rama-http/src/layer/follow_redirect/mod.rs similarity index 100% rename from src/http/layer/follow_redirect/mod.rs rename to rama-http/src/layer/follow_redirect/mod.rs diff --git a/src/http/layer/follow_redirect/policy/and.rs b/rama-http/src/layer/follow_redirect/policy/and.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/and.rs rename to rama-http/src/layer/follow_redirect/policy/and.rs diff --git a/src/http/layer/follow_redirect/policy/clone_body_fn.rs b/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/clone_body_fn.rs rename to rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs diff --git a/src/http/layer/follow_redirect/policy/filter_credentials.rs b/rama-http/src/layer/follow_redirect/policy/filter_credentials.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/filter_credentials.rs rename to rama-http/src/layer/follow_redirect/policy/filter_credentials.rs diff --git a/src/http/layer/follow_redirect/policy/limited.rs b/rama-http/src/layer/follow_redirect/policy/limited.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/limited.rs rename to rama-http/src/layer/follow_redirect/policy/limited.rs diff --git a/src/http/layer/follow_redirect/policy/mod.rs b/rama-http/src/layer/follow_redirect/policy/mod.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/mod.rs rename to rama-http/src/layer/follow_redirect/policy/mod.rs diff --git a/src/http/layer/follow_redirect/policy/or.rs b/rama-http/src/layer/follow_redirect/policy/or.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/or.rs rename to rama-http/src/layer/follow_redirect/policy/or.rs diff --git a/src/http/layer/follow_redirect/policy/redirect_fn.rs b/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/redirect_fn.rs rename to rama-http/src/layer/follow_redirect/policy/redirect_fn.rs diff --git a/src/http/layer/follow_redirect/policy/same_origin.rs b/rama-http/src/layer/follow_redirect/policy/same_origin.rs similarity index 100% rename from src/http/layer/follow_redirect/policy/same_origin.rs rename to rama-http/src/layer/follow_redirect/policy/same_origin.rs diff --git a/src/http/layer/forwarded/get_forwarded.rs b/rama-http/src/layer/forwarded/get_forwarded.rs similarity index 97% rename from src/http/layer/forwarded/get_forwarded.rs rename to rama-http/src/layer/forwarded/get_forwarded.rs index f20de7f3..8eb7fdcb 100644 --- a/src/http/layer/forwarded/get_forwarded.rs +++ b/rama-http/src/layer/forwarded/get_forwarded.rs @@ -1,9 +1,10 @@ -use crate::http::headers::{ +use crate::headers::{ ForwardHeader, HeaderMapExt, Via, XForwardedFor, XForwardedHost, XForwardedProto, }; -use crate::net::forwarded::ForwardedElement; -use crate::utils::macros::all_the_tuples_no_last_special_case; -use crate::{http::Request, net::forwarded::Forwarded, Context, Layer, Service}; +use crate::Request; +use rama_core::net::forwarded::ForwardedElement; +use rama_core::utils::macros::all_the_tuples_no_last_special_case; +use rama_core::{net::forwarded::Forwarded, Context, Layer, Service}; use std::fmt; use std::future::Future; use std::marker::PhantomData; @@ -347,11 +348,11 @@ all_the_tuples_no_last_special_case!(get_forwarded_service_for_tuple); mod tests { use super::*; use crate::{ + headers::{ClientIp, TrueClientIp, XClientIp, XRealIp}, + IntoResponse, Response, StatusCode, + }; + use rama_core::{ error::OpaqueError, - http::{ - headers::{ClientIp, TrueClientIp, XClientIp, XRealIp}, - IntoResponse, Response, StatusCode, - }, net::forwarded::{ForwardedProtocol, ForwardedVersion}, service::service_fn, Layer, diff --git a/src/http/layer/forwarded/mod.rs b/rama-http/src/layer/forwarded/mod.rs similarity index 100% rename from src/http/layer/forwarded/mod.rs rename to rama-http/src/layer/forwarded/mod.rs diff --git a/src/http/layer/forwarded/set_forwarded.rs b/rama-http/src/layer/forwarded/set_forwarded.rs similarity index 99% rename from src/http/layer/forwarded/set_forwarded.rs rename to rama-http/src/layer/forwarded/set_forwarded.rs index ecba6b58..ed197275 100644 --- a/src/http/layer/forwarded/set_forwarded.rs +++ b/rama-http/src/layer/forwarded/set_forwarded.rs @@ -1,13 +1,13 @@ -use crate::error::BoxError; -use crate::http::headers::{ +use crate::headers::{ ForwardHeader, HeaderMapExt, Via, XForwardedFor, XForwardedHost, XForwardedProto, }; -use crate::http::{Request, RequestContext}; use crate::net::address::Domain; use crate::net::forwarded::{Forwarded, ForwardedElement, NodeId}; use crate::stream::SocketInfo; use crate::utils::macros::all_the_tuples_no_last_special_case; use crate::{Context, Layer, Service}; +use crate::{Request, RequestContext}; +use rama_core::error::BoxError; use std::fmt; use std::marker::PhantomData; diff --git a/src/http/layer/header_config.rs b/rama-http/src/layer/header_config.rs similarity index 100% rename from src/http/layer/header_config.rs rename to rama-http/src/layer/header_config.rs diff --git a/src/http/layer/header_option_value.rs b/rama-http/src/layer/header_option_value.rs similarity index 100% rename from src/http/layer/header_option_value.rs rename to rama-http/src/layer/header_option_value.rs diff --git a/src/http/layer/map_request_body.rs b/rama-http/src/layer/map_request_body.rs similarity index 100% rename from src/http/layer/map_request_body.rs rename to rama-http/src/layer/map_request_body.rs diff --git a/src/http/layer/map_response_body.rs b/rama-http/src/layer/map_response_body.rs similarity index 100% rename from src/http/layer/map_response_body.rs rename to rama-http/src/layer/map_response_body.rs diff --git a/src/http/layer/mod.rs b/rama-http/src/layer/mod.rs similarity index 96% rename from src/http/layer/mod.rs rename to rama-http/src/layer/mod.rs index bfca9a8e..6c1da0b1 100644 --- a/src/http/layer/mod.rs +++ b/rama-http/src/layer/mod.rs @@ -24,7 +24,6 @@ pub mod cors; pub mod dns; pub mod error_handling; pub mod follow_redirect; -pub mod forwarded; pub mod header_config; pub mod header_option_value; pub mod map_request_body; @@ -42,9 +41,12 @@ pub mod set_status; pub mod timeout; pub mod trace; pub mod traffic_writer; +pub mod ua; pub mod upgrade; pub mod validate_request; +pub use ::rama_http_types::layer::forwarded; + #[cfg(feature = "telemetry")] pub mod opentelemetry; diff --git a/src/http/layer/normalize_path.rs b/rama-http/src/layer/normalize_path.rs similarity index 100% rename from src/http/layer/normalize_path.rs rename to rama-http/src/layer/normalize_path.rs diff --git a/src/http/layer/opentelemetry.rs b/rama-http/src/layer/opentelemetry.rs similarity index 100% rename from src/http/layer/opentelemetry.rs rename to rama-http/src/layer/opentelemetry.rs diff --git a/src/http/layer/propagate_headers.rs b/rama-http/src/layer/propagate_headers.rs similarity index 100% rename from src/http/layer/propagate_headers.rs rename to rama-http/src/layer/propagate_headers.rs diff --git a/src/http/layer/proxy_auth.rs b/rama-http/src/layer/proxy_auth.rs similarity index 100% rename from src/http/layer/proxy_auth.rs rename to rama-http/src/layer/proxy_auth.rs diff --git a/src/http/layer/remove_header/mod.rs b/rama-http/src/layer/remove_header/mod.rs similarity index 100% rename from src/http/layer/remove_header/mod.rs rename to rama-http/src/layer/remove_header/mod.rs diff --git a/src/http/layer/remove_header/request.rs b/rama-http/src/layer/remove_header/request.rs similarity index 100% rename from src/http/layer/remove_header/request.rs rename to rama-http/src/layer/remove_header/request.rs diff --git a/src/http/layer/remove_header/response.rs b/rama-http/src/layer/remove_header/response.rs similarity index 100% rename from src/http/layer/remove_header/response.rs rename to rama-http/src/layer/remove_header/response.rs diff --git a/src/http/layer/request_id.rs b/rama-http/src/layer/request_id.rs similarity index 100% rename from src/http/layer/request_id.rs rename to rama-http/src/layer/request_id.rs diff --git a/src/http/layer/required_header/mod.rs b/rama-http/src/layer/required_header/mod.rs similarity index 100% rename from src/http/layer/required_header/mod.rs rename to rama-http/src/layer/required_header/mod.rs diff --git a/src/http/layer/required_header/request.rs b/rama-http/src/layer/required_header/request.rs similarity index 100% rename from src/http/layer/required_header/request.rs rename to rama-http/src/layer/required_header/request.rs diff --git a/src/http/layer/required_header/response.rs b/rama-http/src/layer/required_header/response.rs similarity index 100% rename from src/http/layer/required_header/response.rs rename to rama-http/src/layer/required_header/response.rs diff --git a/src/http/layer/retry/body.rs b/rama-http/src/layer/retry/body.rs similarity index 100% rename from src/http/layer/retry/body.rs rename to rama-http/src/layer/retry/body.rs diff --git a/src/http/layer/retry/layer.rs b/rama-http/src/layer/retry/layer.rs similarity index 100% rename from src/http/layer/retry/layer.rs rename to rama-http/src/layer/retry/layer.rs diff --git a/src/http/layer/retry/managed.rs b/rama-http/src/layer/retry/managed.rs similarity index 100% rename from src/http/layer/retry/managed.rs rename to rama-http/src/layer/retry/managed.rs diff --git a/src/http/layer/retry/mod.rs b/rama-http/src/layer/retry/mod.rs similarity index 100% rename from src/http/layer/retry/mod.rs rename to rama-http/src/layer/retry/mod.rs diff --git a/src/http/layer/retry/policy.rs b/rama-http/src/layer/retry/policy.rs similarity index 100% rename from src/http/layer/retry/policy.rs rename to rama-http/src/layer/retry/policy.rs diff --git a/src/http/layer/retry/tests.rs b/rama-http/src/layer/retry/tests.rs similarity index 100% rename from src/http/layer/retry/tests.rs rename to rama-http/src/layer/retry/tests.rs diff --git a/src/http/layer/sensitive_headers.rs b/rama-http/src/layer/sensitive_headers.rs similarity index 100% rename from src/http/layer/sensitive_headers.rs rename to rama-http/src/layer/sensitive_headers.rs diff --git a/src/http/layer/set_header/mod.rs b/rama-http/src/layer/set_header/mod.rs similarity index 100% rename from src/http/layer/set_header/mod.rs rename to rama-http/src/layer/set_header/mod.rs diff --git a/src/http/layer/set_header/request.rs b/rama-http/src/layer/set_header/request.rs similarity index 100% rename from src/http/layer/set_header/request.rs rename to rama-http/src/layer/set_header/request.rs diff --git a/src/http/layer/set_header/response.rs b/rama-http/src/layer/set_header/response.rs similarity index 100% rename from src/http/layer/set_header/response.rs rename to rama-http/src/layer/set_header/response.rs diff --git a/src/http/layer/set_status.rs b/rama-http/src/layer/set_status.rs similarity index 100% rename from src/http/layer/set_status.rs rename to rama-http/src/layer/set_status.rs diff --git a/src/http/layer/timeout.rs b/rama-http/src/layer/timeout.rs similarity index 100% rename from src/http/layer/timeout.rs rename to rama-http/src/layer/timeout.rs diff --git a/src/http/layer/trace/body.rs b/rama-http/src/layer/trace/body.rs similarity index 100% rename from src/http/layer/trace/body.rs rename to rama-http/src/layer/trace/body.rs diff --git a/src/http/layer/trace/layer.rs b/rama-http/src/layer/trace/layer.rs similarity index 100% rename from src/http/layer/trace/layer.rs rename to rama-http/src/layer/trace/layer.rs diff --git a/src/http/layer/trace/make_span.rs b/rama-http/src/layer/trace/make_span.rs similarity index 100% rename from src/http/layer/trace/make_span.rs rename to rama-http/src/layer/trace/make_span.rs diff --git a/src/http/layer/trace/mod.rs b/rama-http/src/layer/trace/mod.rs similarity index 100% rename from src/http/layer/trace/mod.rs rename to rama-http/src/layer/trace/mod.rs diff --git a/src/http/layer/trace/on_body_chunk.rs b/rama-http/src/layer/trace/on_body_chunk.rs similarity index 100% rename from src/http/layer/trace/on_body_chunk.rs rename to rama-http/src/layer/trace/on_body_chunk.rs diff --git a/src/http/layer/trace/on_eos.rs b/rama-http/src/layer/trace/on_eos.rs similarity index 100% rename from src/http/layer/trace/on_eos.rs rename to rama-http/src/layer/trace/on_eos.rs diff --git a/src/http/layer/trace/on_failure.rs b/rama-http/src/layer/trace/on_failure.rs similarity index 100% rename from src/http/layer/trace/on_failure.rs rename to rama-http/src/layer/trace/on_failure.rs diff --git a/src/http/layer/trace/on_request.rs b/rama-http/src/layer/trace/on_request.rs similarity index 100% rename from src/http/layer/trace/on_request.rs rename to rama-http/src/layer/trace/on_request.rs diff --git a/src/http/layer/trace/on_response.rs b/rama-http/src/layer/trace/on_response.rs similarity index 100% rename from src/http/layer/trace/on_response.rs rename to rama-http/src/layer/trace/on_response.rs diff --git a/src/http/layer/trace/service.rs b/rama-http/src/layer/trace/service.rs similarity index 100% rename from src/http/layer/trace/service.rs rename to rama-http/src/layer/trace/service.rs diff --git a/src/http/layer/traffic_writer/mod.rs b/rama-http/src/layer/traffic_writer/mod.rs similarity index 100% rename from src/http/layer/traffic_writer/mod.rs rename to rama-http/src/layer/traffic_writer/mod.rs diff --git a/src/http/layer/traffic_writer/request.rs b/rama-http/src/layer/traffic_writer/request.rs similarity index 100% rename from src/http/layer/traffic_writer/request.rs rename to rama-http/src/layer/traffic_writer/request.rs diff --git a/src/http/layer/traffic_writer/response.rs b/rama-http/src/layer/traffic_writer/response.rs similarity index 100% rename from src/http/layer/traffic_writer/response.rs rename to rama-http/src/layer/traffic_writer/response.rs diff --git a/src/ua/layer.rs b/rama-http/src/layer/ua.rs similarity index 90% rename from src/ua/layer.rs rename to rama-http/src/layer/ua.rs index 22fc8aa9..ba549a4c 100644 --- a/src/ua/layer.rs +++ b/rama-http/src/layer/ua.rs @@ -25,27 +25,6 @@ pub struct UserAgentClassifier { overwrite_header: Option, } -/// Information that can be used to overwrite the [`UserAgent`] of a [`Request`]. -/// -/// Used by the [`UserAgentClassifier`] to overwrite the specified -/// information duing the classification of the [`UserAgent`]. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct UserAgentOverwrites { - /// Overwrite the [`UserAgent`] of the [`Request`] with a custom value. - /// - /// This value will be used instead of - /// [the 'User-Agent' http header](crate::http::headers::UserAgent) value. - /// - /// This is useful in case you cannot set the User-Agent header in your request. - pub ua: Option, - /// Overwrite the [`HttpAgent`] of the [`Request`] with a custom value. - pub http: Option, - /// Overwrite the [`TlsAgent`] of the [`Request`] with a custom value. - pub tls: Option, - /// Preserve the original [`UserAgent`] header of the [`Request`]. - pub preserve_ua: Option, -} - impl UserAgentClassifier { /// Create a new [`UserAgentClassifier`] [`Service`]. pub const fn new(inner: S, overwrite_header: Option) -> Self { diff --git a/src/http/layer/upgrade/layer.rs b/rama-http/src/layer/upgrade/layer.rs similarity index 100% rename from src/http/layer/upgrade/layer.rs rename to rama-http/src/layer/upgrade/layer.rs diff --git a/src/http/layer/upgrade/mod.rs b/rama-http/src/layer/upgrade/mod.rs similarity index 100% rename from src/http/layer/upgrade/mod.rs rename to rama-http/src/layer/upgrade/mod.rs diff --git a/src/http/layer/upgrade/service.rs b/rama-http/src/layer/upgrade/service.rs similarity index 100% rename from src/http/layer/upgrade/service.rs rename to rama-http/src/layer/upgrade/service.rs diff --git a/src/http/layer/upgrade/upgraded.rs b/rama-http/src/layer/upgrade/upgraded.rs similarity index 100% rename from src/http/layer/upgrade/upgraded.rs rename to rama-http/src/layer/upgrade/upgraded.rs diff --git a/src/http/layer/util/compression.rs b/rama-http/src/layer/util/compression.rs similarity index 100% rename from src/http/layer/util/compression.rs rename to rama-http/src/layer/util/compression.rs diff --git a/src/http/layer/util/content_encoding.rs b/rama-http/src/layer/util/content_encoding.rs similarity index 100% rename from src/http/layer/util/content_encoding.rs rename to rama-http/src/layer/util/content_encoding.rs diff --git a/src/http/layer/util/mod.rs b/rama-http/src/layer/util/mod.rs similarity index 100% rename from src/http/layer/util/mod.rs rename to rama-http/src/layer/util/mod.rs diff --git a/src/http/layer/validate_request/accept_header.rs b/rama-http/src/layer/validate_request/accept_header.rs similarity index 100% rename from src/http/layer/validate_request/accept_header.rs rename to rama-http/src/layer/validate_request/accept_header.rs diff --git a/src/http/layer/validate_request/mod.rs b/rama-http/src/layer/validate_request/mod.rs similarity index 100% rename from src/http/layer/validate_request/mod.rs rename to rama-http/src/layer/validate_request/mod.rs diff --git a/src/http/layer/validate_request/validate.rs b/rama-http/src/layer/validate_request/validate.rs similarity index 100% rename from src/http/layer/validate_request/validate.rs rename to rama-http/src/layer/validate_request/validate.rs diff --git a/src/http/layer/validate_request/validate_fn.rs b/rama-http/src/layer/validate_request/validate_fn.rs similarity index 100% rename from src/http/layer/validate_request/validate_fn.rs rename to rama-http/src/layer/validate_request/validate_fn.rs diff --git a/src/http/layer/validate_request/validate_request_header.rs b/rama-http/src/layer/validate_request/validate_request_header.rs similarity index 100% rename from src/http/layer/validate_request/validate_request_header.rs rename to rama-http/src/layer/validate_request/validate_request_header.rs diff --git a/rama-http/src/lib.rs b/rama-http/src/lib.rs new file mode 100644 index 00000000..9a95f27e --- /dev/null +++ b/rama-http/src/lib.rs @@ -0,0 +1,87 @@ +//! rama http services, layers and utilities +//! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +pub use ::rama_http_types::{ + header, headers, + response::{self, IntoResponse, Response}, + utils, Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, + Method, Request, RequestContext, Scheme, StatusCode, Uri, Version, +}; + +pub mod matcher; + +pub mod layer; +pub mod service; + +pub mod server; + +pub mod client; + +pub mod io; + +pub mod executor; + +pub mod dep { + //! Dependencies for rama http modules. + //! + //! Exported for your convenience. + + pub use ::rama_http_types::dep::{http, http_body, http_body_util, mime, mime_guess}; +} + +mod request_context; +#[doc(inline)] +pub use request_context::RequestContext; diff --git a/src/http/matcher/domain.rs b/rama-http/src/matcher/domain.rs similarity index 100% rename from src/http/matcher/domain.rs rename to rama-http/src/matcher/domain.rs diff --git a/src/http/matcher/header.rs b/rama-http/src/matcher/header.rs similarity index 100% rename from src/http/matcher/header.rs rename to rama-http/src/matcher/header.rs diff --git a/src/http/matcher/method.rs b/rama-http/src/matcher/method.rs similarity index 100% rename from src/http/matcher/method.rs rename to rama-http/src/matcher/method.rs diff --git a/src/http/matcher/mod.rs b/rama-http/src/matcher/mod.rs similarity index 100% rename from src/http/matcher/mod.rs rename to rama-http/src/matcher/mod.rs diff --git a/src/http/matcher/path/de.rs b/rama-http/src/matcher/path/de.rs similarity index 100% rename from src/http/matcher/path/de.rs rename to rama-http/src/matcher/path/de.rs diff --git a/src/http/matcher/path/mod.rs b/rama-http/src/matcher/path/mod.rs similarity index 100% rename from src/http/matcher/path/mod.rs rename to rama-http/src/matcher/path/mod.rs diff --git a/src/http/matcher/uri.rs b/rama-http/src/matcher/uri.rs similarity index 100% rename from src/http/matcher/uri.rs rename to rama-http/src/matcher/uri.rs diff --git a/src/http/matcher/version.rs b/rama-http/src/matcher/version.rs similarity index 100% rename from src/http/matcher/version.rs rename to rama-http/src/matcher/version.rs diff --git a/src/http/request_context.rs b/rama-http/src/request_context.rs similarity index 98% rename from src/http/request_context.rs rename to rama-http/src/request_context.rs index 1c7d1245..adf57ea2 100644 --- a/src/http/request_context.rs +++ b/rama-http/src/request_context.rs @@ -1,13 +1,15 @@ use super::{dep::http::request::Parts, Request, Version}; -use crate::error::OpaqueError; -use crate::http::Uri; -use crate::net::forwarded::Forwarded; -use crate::net::{ +use crate::Uri; +use rama_core::error::OpaqueError; +use rama_core::net::forwarded::Forwarded; +use rama_core::net::{ address::{Authority, Host}, Protocol, }; -use crate::stream::transport::{TransportContext, TransportProtocol, TryRefIntoTransportContext}; -use crate::Context; +use rama_core::stream::transport::{ + TransportContext, TransportProtocol, TryRefIntoTransportContext, +}; +use rama_core::Context; #[cfg(feature = "tls")] use crate::tls::SecureTransport; diff --git a/src/http/server/hyper_conn.rs b/rama-http/src/server/hyper_conn.rs similarity index 100% rename from src/http/server/hyper_conn.rs rename to rama-http/src/server/hyper_conn.rs diff --git a/src/http/server/mod.rs b/rama-http/src/server/mod.rs similarity index 100% rename from src/http/server/mod.rs rename to rama-http/src/server/mod.rs diff --git a/src/http/server/service.rs b/rama-http/src/server/service.rs similarity index 100% rename from src/http/server/service.rs rename to rama-http/src/server/service.rs diff --git a/src/http/server/svc_hyper.rs b/rama-http/src/server/svc_hyper.rs similarity index 100% rename from src/http/server/svc_hyper.rs rename to rama-http/src/server/svc_hyper.rs diff --git a/src/http/service/fs/mod.rs b/rama-http/src/service/fs/mod.rs similarity index 100% rename from src/http/service/fs/mod.rs rename to rama-http/src/service/fs/mod.rs diff --git a/src/http/service/fs/serve_dir/future.rs b/rama-http/src/service/fs/serve_dir/future.rs similarity index 100% rename from src/http/service/fs/serve_dir/future.rs rename to rama-http/src/service/fs/serve_dir/future.rs diff --git a/src/http/service/fs/serve_dir/headers.rs b/rama-http/src/service/fs/serve_dir/headers.rs similarity index 100% rename from src/http/service/fs/serve_dir/headers.rs rename to rama-http/src/service/fs/serve_dir/headers.rs diff --git a/src/http/service/fs/serve_dir/mod.rs b/rama-http/src/service/fs/serve_dir/mod.rs similarity index 100% rename from src/http/service/fs/serve_dir/mod.rs rename to rama-http/src/service/fs/serve_dir/mod.rs diff --git a/src/http/service/fs/serve_dir/open_file.rs b/rama-http/src/service/fs/serve_dir/open_file.rs similarity index 100% rename from src/http/service/fs/serve_dir/open_file.rs rename to rama-http/src/service/fs/serve_dir/open_file.rs diff --git a/src/http/service/fs/serve_dir/tests.rs b/rama-http/src/service/fs/serve_dir/tests.rs similarity index 100% rename from src/http/service/fs/serve_dir/tests.rs rename to rama-http/src/service/fs/serve_dir/tests.rs diff --git a/src/http/service/fs/serve_file.rs b/rama-http/src/service/fs/serve_file.rs similarity index 100% rename from src/http/service/fs/serve_file.rs rename to rama-http/src/service/fs/serve_file.rs diff --git a/src/http/service/mod.rs b/rama-http/src/service/mod.rs similarity index 100% rename from src/http/service/mod.rs rename to rama-http/src/service/mod.rs diff --git a/src/http/service/redirect.rs b/rama-http/src/service/redirect.rs similarity index 100% rename from src/http/service/redirect.rs rename to rama-http/src/service/redirect.rs diff --git a/src/http/service/web/endpoint/extract/authority.rs b/rama-http/src/service/web/endpoint/extract/authority.rs similarity index 100% rename from src/http/service/web/endpoint/extract/authority.rs rename to rama-http/src/service/web/endpoint/extract/authority.rs diff --git a/src/http/service/web/endpoint/extract/body/bytes.rs b/rama-http/src/service/web/endpoint/extract/body/bytes.rs similarity index 100% rename from src/http/service/web/endpoint/extract/body/bytes.rs rename to rama-http/src/service/web/endpoint/extract/body/bytes.rs diff --git a/src/http/service/web/endpoint/extract/body/form.rs b/rama-http/src/service/web/endpoint/extract/body/form.rs similarity index 100% rename from src/http/service/web/endpoint/extract/body/form.rs rename to rama-http/src/service/web/endpoint/extract/body/form.rs diff --git a/src/http/service/web/endpoint/extract/body/json.rs b/rama-http/src/service/web/endpoint/extract/body/json.rs similarity index 100% rename from src/http/service/web/endpoint/extract/body/json.rs rename to rama-http/src/service/web/endpoint/extract/body/json.rs diff --git a/src/http/service/web/endpoint/extract/body/mod.rs b/rama-http/src/service/web/endpoint/extract/body/mod.rs similarity index 100% rename from src/http/service/web/endpoint/extract/body/mod.rs rename to rama-http/src/service/web/endpoint/extract/body/mod.rs diff --git a/src/http/service/web/endpoint/extract/body/text.rs b/rama-http/src/service/web/endpoint/extract/body/text.rs similarity index 100% rename from src/http/service/web/endpoint/extract/body/text.rs rename to rama-http/src/service/web/endpoint/extract/body/text.rs diff --git a/src/http/service/web/endpoint/extract/context.rs b/rama-http/src/service/web/endpoint/extract/context.rs similarity index 100% rename from src/http/service/web/endpoint/extract/context.rs rename to rama-http/src/service/web/endpoint/extract/context.rs diff --git a/src/http/service/web/endpoint/extract/dns.rs b/rama-http/src/service/web/endpoint/extract/dns.rs similarity index 100% rename from src/http/service/web/endpoint/extract/dns.rs rename to rama-http/src/service/web/endpoint/extract/dns.rs diff --git a/src/http/service/web/endpoint/extract/extension.rs b/rama-http/src/service/web/endpoint/extract/extension.rs similarity index 100% rename from src/http/service/web/endpoint/extract/extension.rs rename to rama-http/src/service/web/endpoint/extract/extension.rs diff --git a/src/http/service/web/endpoint/extract/host.rs b/rama-http/src/service/web/endpoint/extract/host.rs similarity index 100% rename from src/http/service/web/endpoint/extract/host.rs rename to rama-http/src/service/web/endpoint/extract/host.rs diff --git a/src/http/service/web/endpoint/extract/method.rs b/rama-http/src/service/web/endpoint/extract/method.rs similarity index 100% rename from src/http/service/web/endpoint/extract/method.rs rename to rama-http/src/service/web/endpoint/extract/method.rs diff --git a/src/http/service/web/endpoint/extract/mod.rs b/rama-http/src/service/web/endpoint/extract/mod.rs similarity index 100% rename from src/http/service/web/endpoint/extract/mod.rs rename to rama-http/src/service/web/endpoint/extract/mod.rs diff --git a/src/http/service/web/endpoint/extract/path.rs b/rama-http/src/service/web/endpoint/extract/path.rs similarity index 100% rename from src/http/service/web/endpoint/extract/path.rs rename to rama-http/src/service/web/endpoint/extract/path.rs diff --git a/src/http/service/web/endpoint/extract/query.rs b/rama-http/src/service/web/endpoint/extract/query.rs similarity index 100% rename from src/http/service/web/endpoint/extract/query.rs rename to rama-http/src/service/web/endpoint/extract/query.rs diff --git a/src/http/service/web/endpoint/extract/request.rs b/rama-http/src/service/web/endpoint/extract/request.rs similarity index 100% rename from src/http/service/web/endpoint/extract/request.rs rename to rama-http/src/service/web/endpoint/extract/request.rs diff --git a/src/http/service/web/endpoint/extract/state.rs b/rama-http/src/service/web/endpoint/extract/state.rs similarity index 100% rename from src/http/service/web/endpoint/extract/state.rs rename to rama-http/src/service/web/endpoint/extract/state.rs diff --git a/src/http/service/web/endpoint/extract/typed_header.rs b/rama-http/src/service/web/endpoint/extract/typed_header.rs similarity index 100% rename from src/http/service/web/endpoint/extract/typed_header.rs rename to rama-http/src/service/web/endpoint/extract/typed_header.rs diff --git a/src/http/service/web/endpoint/mod.rs b/rama-http/src/service/web/endpoint/mod.rs similarity index 100% rename from src/http/service/web/endpoint/mod.rs rename to rama-http/src/service/web/endpoint/mod.rs diff --git a/src/http/service/web/endpoint/service.rs b/rama-http/src/service/web/endpoint/service.rs similarity index 100% rename from src/http/service/web/endpoint/service.rs rename to rama-http/src/service/web/endpoint/service.rs diff --git a/src/http/service/web/k8s.rs b/rama-http/src/service/web/k8s.rs similarity index 100% rename from src/http/service/web/k8s.rs rename to rama-http/src/service/web/k8s.rs diff --git a/src/http/service/web/mod.rs b/rama-http/src/service/web/mod.rs similarity index 100% rename from src/http/service/web/mod.rs rename to rama-http/src/service/web/mod.rs diff --git a/src/http/service/web/service.rs b/rama-http/src/service/web/service.rs similarity index 100% rename from src/http/service/web/service.rs rename to rama-http/src/service/web/service.rs diff --git a/src/http/utils/header_value.rs b/rama-http/src/utils/header_value.rs similarity index 97% rename from src/http/utils/header_value.rs rename to rama-http/src/utils/header_value.rs index 785fc879..c50912ee 100644 --- a/src/http/utils/header_value.rs +++ b/rama-http/src/utils/header_value.rs @@ -1,4 +1,4 @@ -use crate::http::{header::AsHeaderName, HeaderMap, Request, Response}; +use crate::{header::AsHeaderName, HeaderMap, Request, Response}; /// Utility trait for getting header values from a request or response. pub trait HeaderValueGetter { diff --git a/src/http/utils/mod.rs b/rama-http/src/utils/mod.rs similarity index 100% rename from src/http/utils/mod.rs rename to rama-http/src/utils/mod.rs diff --git a/src/utils/macros/http_error.rs b/rama-http/src/utils/utils/macros/http_error.rs similarity index 100% rename from src/utils/macros/http_error.rs rename to rama-http/src/utils/utils/macros/http_error.rs diff --git a/src/utils/macros/mod.rs b/rama-http/src/utils/utils/macros/mod.rs similarity index 100% rename from src/utils/macros/mod.rs rename to rama-http/src/utils/utils/macros/mod.rs diff --git a/src/utils/mod.rs b/rama-http/src/utils/utils/mod.rs similarity index 100% rename from src/utils/mod.rs rename to rama-http/src/utils/utils/mod.rs diff --git a/rama-macros-proc/Cargo.toml b/rama-macros-proc/Cargo.toml new file mode 100644 index 00000000..7a4b49ba --- /dev/null +++ b/rama-macros-proc/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "rama-macros-proc" +description = "procedural macros in function of the rama proxy modules crate" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { workspace = true, features = ["full", "parsing"] } + +[dev-dependencies] +rama = { path = ".." } +syn = { workspace = true, features = ["full", "extra-traits"] } +trybuild = { workspace = true } + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-macros-proc/README.md b/rama-macros-proc/README.md new file mode 100644 index 00000000..f14fe554 --- /dev/null +++ b/rama-macros-proc/README.md @@ -0,0 +1,50 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-macros-proc.svg +[crates-url]: https://crates.io/crates/rama-macros-proc +[docs-badge]: https://img.shields.io/docsrs/rama-macros-proc/latest +[docs-url]: https://docs.rs/rama-macros-proc/latest/rama_macros_proc/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-macros-proc + +`rama-macros-proc` contains the procedural macros used by `rama`. + +Exposed via the `rama-macros`, `rama-core` and `rama` crates. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-macros/src/as_ref.rs b/rama-macros-proc/src/as_ref.rs similarity index 100% rename from rama-macros/src/as_ref.rs rename to rama-macros-proc/src/as_ref.rs diff --git a/rama-macros/src/attr_parsing.rs b/rama-macros-proc/src/attr_parsing.rs similarity index 100% rename from rama-macros/src/attr_parsing.rs rename to rama-macros-proc/src/attr_parsing.rs diff --git a/rama-macros-proc/src/lib.rs b/rama-macros-proc/src/lib.rs new file mode 100644 index 00000000..d659c012 --- /dev/null +++ b/rama-macros-proc/src/lib.rs @@ -0,0 +1,115 @@ +//! Macros for [`rama`]. +//! +//! [`rama`]: https://crates.io/crates/rama + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +use proc_macro::TokenStream; +use quote::{quote, ToTokens}; +use syn::parse::Parse; + +mod as_ref; +mod attr_parsing; +mod type_parsing; + +/// Derive an implementation of [`AsRef`] for each field in a struct. +/// +/// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html +#[proc_macro_derive(AsRef, attributes(as_ref))] +pub fn derive_as_ref(item: TokenStream) -> TokenStream { + expand_with(item, as_ref::expand) +} + +fn expand_with(input: TokenStream, f: F) -> TokenStream +where + F: FnOnce(I) -> syn::Result, + I: Parse, + K: ToTokens, +{ + expand(syn::parse(input).and_then(f)) +} + +fn expand(result: syn::Result) -> TokenStream +where + T: ToTokens, +{ + match result { + Ok(tokens) => { + let tokens = (quote! { #tokens }).into(); + if std::env::var_os("RAMA_MACROS_DEBUG").is_some() { + eprintln!("{tokens}"); + } + tokens + } + Err(err) => err.into_compile_error().into(), + } +} + +#[cfg(test)] +fn run_ui_tests(directory: &str) { + let t = trybuild::TestCases::new(); + + if let Some(path) = std::env::var("RAMA_TEST_ONLY") + .as_ref() + .ok() + .and_then(|s| s.strip_prefix("rama-macros/")) + { + if !path.contains(&format!("/{directory}/")) { + return; + } + + if path.contains("/fail/") { + t.compile_fail(path); + } else if path.contains("/pass/") { + t.pass(path); + } else { + panic!() + } + } else { + t.compile_fail(format!("tests/{directory}/fail/*.rs")); + t.pass(format!("tests/{directory}/pass/*.rs")); + } +} diff --git a/rama-macros/src/type_parsing.rs b/rama-macros-proc/src/type_parsing.rs similarity index 100% rename from rama-macros/src/type_parsing.rs rename to rama-macros-proc/src/type_parsing.rs diff --git a/rama-macros/tests/as_ref/fail/generics.rs b/rama-macros-proc/tests/as_ref/fail/generics.rs similarity index 100% rename from rama-macros/tests/as_ref/fail/generics.rs rename to rama-macros-proc/tests/as_ref/fail/generics.rs diff --git a/rama-macros/tests/as_ref/fail/generics.stderr b/rama-macros-proc/tests/as_ref/fail/generics.stderr similarity index 100% rename from rama-macros/tests/as_ref/fail/generics.stderr rename to rama-macros-proc/tests/as_ref/fail/generics.stderr diff --git a/rama-macros/tests/as_ref/fail/wrap_ambiguity.rs b/rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.rs similarity index 100% rename from rama-macros/tests/as_ref/fail/wrap_ambiguity.rs rename to rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.rs diff --git a/rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr b/rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.stderr similarity index 100% rename from rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr rename to rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.stderr diff --git a/rama-macros/tests/as_ref/fail/wrap_no_arc.rs b/rama-macros-proc/tests/as_ref/fail/wrap_no_arc.rs similarity index 100% rename from rama-macros/tests/as_ref/fail/wrap_no_arc.rs rename to rama-macros-proc/tests/as_ref/fail/wrap_no_arc.rs diff --git a/rama-macros/tests/as_ref/fail/wrap_no_arc.stderr b/rama-macros-proc/tests/as_ref/fail/wrap_no_arc.stderr similarity index 100% rename from rama-macros/tests/as_ref/fail/wrap_no_arc.stderr rename to rama-macros-proc/tests/as_ref/fail/wrap_no_arc.stderr diff --git a/rama-macros/tests/as_ref/pass/basic.rs b/rama-macros-proc/tests/as_ref/pass/basic.rs similarity index 100% rename from rama-macros/tests/as_ref/pass/basic.rs rename to rama-macros-proc/tests/as_ref/pass/basic.rs diff --git a/rama-macros/tests/as_ref/pass/reference-types.rs b/rama-macros-proc/tests/as_ref/pass/reference-types.rs similarity index 100% rename from rama-macros/tests/as_ref/pass/reference-types.rs rename to rama-macros-proc/tests/as_ref/pass/reference-types.rs diff --git a/rama-macros/tests/as_ref/pass/skip.rs b/rama-macros-proc/tests/as_ref/pass/skip.rs similarity index 100% rename from rama-macros/tests/as_ref/pass/skip.rs rename to rama-macros-proc/tests/as_ref/pass/skip.rs diff --git a/rama-macros/tests/as_ref/pass/wrap.rs b/rama-macros-proc/tests/as_ref/pass/wrap.rs similarity index 100% rename from rama-macros/tests/as_ref/pass/wrap.rs rename to rama-macros-proc/tests/as_ref/pass/wrap.rs diff --git a/rama-macros/tests/as_ref/pass/wrap_skip.rs b/rama-macros-proc/tests/as_ref/pass/wrap_skip.rs similarity index 100% rename from rama-macros/tests/as_ref/pass/wrap_skip.rs rename to rama-macros-proc/tests/as_ref/pass/wrap_skip.rs diff --git a/rama-macros/Cargo.toml b/rama-macros/Cargo.toml index eeb5c7c6..5cd56611 100644 --- a/rama-macros/Cargo.toml +++ b/rama-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rama-macros" -description = "procedural macros in function of the rama proxy modules crate" +description = "macros in function of rama" version = { workspace = true } license = { workspace = true } edition = { workspace = true } @@ -10,18 +10,10 @@ categories = { workspace = true } authors = { workspace = true } rust-version = { workspace = true } -[lib] -proc-macro = true - [dependencies] -proc-macro2 = { workspace = true } -quote = { workspace = true } -syn = { workspace = true, features = ["full", "parsing"] } +rama-macros-proc = { version = "0.2.0-alpha.2", path = "../rama-macros-proc" } [dev-dependencies] -rama = { path = ".." } -syn = { workspace = true, features = ["full", "extra-traits"] } -trybuild = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-macros/README.md b/rama-macros/README.md index 67fddc73..5abe6a60 100644 --- a/rama-macros/README.md +++ b/rama-macros/README.md @@ -12,10 +12,10 @@ [![GitHub Sponsors][ghs-badge]][ghs-url] [![Paypal Donation][paypal-badge]][paypal-url] -[crates-badge]: https://img.shields.io/crates/v/rama.svg -[crates-url]: https://crates.io/crates/rama/0.2.0-alpha.1 -[docs-badge]: https://img.shields.io/docsrs/rama/latest -[docs-url]: https://docs.rs/rama/latest/rama/index.html +[crates-badge]: https://img.shields.io/crates/v/rama-macros.svg +[crates-url]: https://crates.io/crates/rama-macros +[docs-badge]: https://img.shields.io/docsrs/rama-macros/latest +[docs-url]: https://docs.rs/rama-macros/latest/rama_macros/index.html [license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg [license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT [license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg @@ -40,4 +40,9 @@ The reasons behind the creation of rama can be read in [the "Why Rama" chapter]( ## rama-macros -`rama-macros` contains the procedural macros used by `rama`. +`rama-macros` contains the macros used by `rama`. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-core/src/utils/macros/error.rs b/rama-macros/src/error.rs similarity index 100% rename from rama-core/src/utils/macros/error.rs rename to rama-macros/src/error.rs diff --git a/rama-macros/src/lib.rs b/rama-macros/src/lib.rs index dc609a9a..79179f21 100644 --- a/rama-macros/src/lib.rs +++ b/rama-macros/src/lib.rs @@ -1,10 +1,20 @@ -//! Macros for [`rama`]. +//! macros crate for rama //! -//! [`rama`]: https://crates.io/crates/rama/0.2.0-alpha.1 +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] #![warn( clippy::all, - clippy::dbg_macro, clippy::todo, clippy::empty_enum, clippy::enum_glob_use, @@ -44,69 +54,265 @@ #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] -use proc_macro::TokenStream; -use quote::{quote, ToTokens}; -use syn::parse::Parse; +pub use ::rama_macros_proc::AsRef; + +#[doc(hidden)] +#[macro_use] +pub mod error; + +#[doc(hidden)] +#[macro_use] +pub mod str; + +#[doc(hidden)] +#[macro_export] +macro_rules! opaque_body { + ($(#[$m:meta])* pub type $name:ident = $actual:ty;) => { + $crate::__opaque_body! { + $(#[$m])* pub type $name<> = $actual; + } + }; + + ($(#[$m:meta])* pub type $name:ident<$($param:ident),*> = $actual:ty;) => { + pin_project_lite::pin_project! { + $(#[$m])* + pub struct $name<$($param),*> { + #[pin] + pub(crate) inner: $actual + } + } + + impl<$($param),*> $name<$($param),*> { + pub(crate) fn new(inner: $actual) -> Self { + Self { inner } + } + } + + impl<$($param),*> http_body::Body for $name<$($param),*> { + type Data = <$actual as http_body::Body>::Data; + type Error = <$actual as http_body::Body>::Error; -mod as_ref; -mod attr_parsing; -mod type_parsing; + #[inline] + fn poll_frame( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll, Self::Error>>> { + self.project().inner.poll_frame(cx) + } + + #[inline] + fn is_end_stream(&self) -> bool { + http_body::Body::is_end_stream(&self.inner) + } + + #[inline] + fn size_hint(&self) -> http_body::SizeHint { + http_body::Body::size_hint(&self.inner) + } + } + }; +} -/// Derive an implementation of [`AsRef`] for each field in a struct. -/// -/// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html -#[proc_macro_derive(AsRef, attributes(as_ref))] -pub fn derive_as_ref(item: TokenStream) -> TokenStream { - expand_with(item, as_ref::expand) +#[doc(hidden)] +#[macro_export] +macro_rules! all_the_tuples_minus_one_no_last_special_case { + ($name:ident) => { + $name!(T1); + $name!(T1, T2); + $name!(T1, T2, T3); + $name!(T1, T2, T3, T4); + $name!(T1, T2, T3, T4, T5); + $name!(T1, T2, T3, T4, T5, T6); + $name!(T1, T2, T3, T4, T5, T6, T7); + $name!(T1, T2, T3, T4, T5, T6, T7, T8); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); + }; } -fn expand_with(input: TokenStream, f: F) -> TokenStream -where - F: FnOnce(I) -> syn::Result, - I: Parse, - K: ToTokens, -{ - expand(syn::parse(input).and_then(f)) +#[doc(hidden)] +#[macro_export] +macro_rules! all_the_tuples_no_last_special_case { + ($name:ident) => { + $crate::all_the_tuples_minus_one_no_last_special_case!($name); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); + }; } -fn expand(result: syn::Result) -> TokenStream -where - T: ToTokens, -{ - match result { - Ok(tokens) => { - let tokens = (quote! { #tokens }).into(); - if std::env::var_os("RAMA_MACROS_DEBUG").is_some() { - eprintln!("{tokens}"); +#[doc(hidden)] +#[macro_export] +macro_rules! match_ignore_ascii_case_str { + (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)* $(,)?}) => { + $crate::match_ignore_ascii_case_str!(match ($s) { + $caseA $(| $caseAVar)* $(if $condA)? => $retA, + $($caseB $(| $caseBVar)* $(if $condB)? => $retB,)* + _ => panic!("{}", format!("failed to match {}", $s)), + }) + }; + (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)*, _ => $fallback:expr $(,)? }) => { + { + let s = ($s).trim(); + if $($condA &&)? (s.eq_ignore_ascii_case($caseA) $(|| s.eq_ignore_ascii_case($caseAVar))*) { + $retA + } + $( + else if $($condB &&)? (s.eq_ignore_ascii_case($caseB) $(|| s.eq_ignore_ascii_case($caseBVar))*) { + $retB + } + )* + else { + $fallback } - tokens } - Err(err) => err.into_compile_error().into(), - } + }; } -#[cfg(test)] -fn run_ui_tests(directory: &str) { - let t = trybuild::TestCases::new(); - - if let Some(path) = std::env::var("RAMA_TEST_ONLY") - .as_ref() - .ok() - .and_then(|s| s.strip_prefix("rama-macros/")) - { - if !path.contains(&format!("/{directory}/")) { - return; +#[doc(hidden)] +#[macro_export] +macro_rules! define_inner_service_accessors { + () => { + /// Gets a reference to the underlying service. + pub fn get_ref(&self) -> &S { + &self.inner } - if path.contains("/fail/") { - t.compile_fail(path); - } else if path.contains("/pass/") { - t.pass(path); - } else { - panic!() + /// Consumes `self`, returning the underlying service. + pub fn into_inner(self) -> S { + self.inner + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! impl_deref { + ($ident:ident) => { + impl std::ops::Deref for $ident { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } } - } else { - t.compile_fail(format!("tests/{directory}/fail/*.rs")); - t.pass(format!("tests/{directory}/pass/*.rs")); + + impl std::ops::DerefMut for $ident { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + }; + + ($ident:ident: $ty:ty) => { + impl std::ops::Deref for $ident { + type Target = $ty; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for $ident { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + }; +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn match_ignore_ascii_case_str_happy_simple() { + let s = "hello"; + let result = match_ignore_ascii_case_str!(match (s) { + "hello" => true, + _ => false, + }); + assert!(result); + } + + #[test] + fn match_ignore_ascii_case_str_happy_mixed_case() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "hello" => true, + _ => false, + }); + assert!(result); + } + + #[test] + fn match_ignore_ascii_case_str_happy_multiple_cases() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "world" => 1, + "hello" => 2, + "!" => 3, + _ => 4, + }); + assert_eq!(result, 2); + } + + #[test] + fn match_ignore_ascii_case_str_happy_variants() { + let result = match_ignore_ascii_case_str!(match ("world") { + "?" => 1, + "you" | "world" | "there" => 2, + "!" => 3, + _ => 4, + }); + assert_eq!(result, 2); + } + + #[test] + fn match_ignore_ascii_case_str_happy_fallback() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "world" => 1, + "!" => 2, + _ => 3, + }); + assert_eq!(result, 3); + } + + #[test] + fn match_ignore_ascii_case_str_condition() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "world" => 1, + "hello" if s.len() == 4 => 2, + "hello" => 3, + "!" => 4, + _ => 5, + }); + assert_eq!(result, 3); + } + + #[test] + fn match_ignore_ascii_case_str_happy_variants_condition() { + let result = match_ignore_ascii_case_str!(match ("world") { + "?" => 1, + "you" | "world" | "there" if false => 2, + "you" | "world" | "there" if "world".len() == 5 => 3, + "!" => 4, + _ => 5, + }); + + assert_eq!(result, 3); + } + + #[test] + #[should_panic] + fn match_ignore_ascii_case_str_panic() { + match_ignore_ascii_case_str!(match ("hello") { + "world" => (), + }) } } diff --git a/rama-core/src/utils/macros/str.rs b/rama-macros/src/str.rs similarity index 93% rename from rama-core/src/utils/macros/str.rs rename to rama-macros/src/str.rs index 27b4bec7..6ffe7d79 100644 --- a/rama-core/src/utils/macros/str.rs +++ b/rama-macros/src/str.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub struct EqIgnoreAsciiCase(pub T1, pub T2); pub const fn eq_ignore_ascii_case(lhs: &[u8], rhs: &[u8]) -> bool { @@ -38,7 +39,7 @@ impl EqIgnoreAsciiCase<&[u8; N1], &[u8; N2]> { #[macro_export] macro_rules! __eq_ignore_ascii_case { ($lhs:expr, $rhs:expr) => { - $crate::utils::macros::str::EqIgnoreAsciiCase($lhs, $rhs).const_eval() + $crate::str::EqIgnoreAsciiCase($lhs, $rhs).const_eval() }; } pub use crate::__eq_ignore_ascii_case as eq_ignore_ascii_case; diff --git a/rama-net/Cargo.toml b/rama-net/Cargo.toml new file mode 100644 index 00000000..e19a4484 --- /dev/null +++ b/rama-net/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "rama-net" +description = "rama network types and utilities" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = [] +full = ["http"] +http = ["dep:rama-http-types", "rama-core/http"] + +[dependencies] +base64 = { workspace = true } +futures-lite = { workspace = true } +headers = { workspace = true } +hickory-resolver = { workspace = true } +ipnet = { workspace = true } +bytes = { workspace = true } +opentelemetry = { workspace = true, optional = true } +opentelemetry-semantic-conventions = { workspace = true, optional = true } +opentelemetry_sdk = { workspace = true, optional = true } +parking_lot = { workspace = true } +paste = { workspace = true } +pin-project-lite = { workspace = true } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } +serde = { workspace = true, features = ["derive"] } +tokio = { workspace = true, features = ["macros", "fs", "io-std"] } +tokio-graceful = { workspace = true } +tracing = { workspace = true } +venndb = { workspace = true, optional = true } + +[dev-dependencies] +quickcheck = { workspace = true } +tokio = { workspace = true, features = ["full"] } +tokio-test = { workspace = true } + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-net/README.md b/rama-net/README.md new file mode 100644 index 00000000..98532c06 --- /dev/null +++ b/rama-net/README.md @@ -0,0 +1,52 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-net.svg +[crates-url]: https://crates.io/crates/rama-net +[docs-badge]: https://img.shields.io/docsrs/rama-net/latest +[docs-url]: https://docs.rs/rama-net/latest/rama_net/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-net + +Rama network types and utilities. + +Protocols such as tcp, http, tls, etc are not explicitly implemented here, +see the relevant `rama` crates for this. + +Crate used by the end-user `rama` crate and `rama` crate authors alike. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-core/src/net/address/authority.rs b/rama-net/src/address/authority.rs similarity index 98% rename from rama-core/src/net/address/authority.rs rename to rama-net/src/address/authority.rs index 2d46e3b9..805970a9 100644 --- a/rama-core/src/net/address/authority.rs +++ b/rama-net/src/address/authority.rs @@ -1,12 +1,14 @@ use super::{Domain, Host}; -use crate::error::{ErrorContext, ErrorExt, OpaqueError}; -use http::HeaderValue; +use rama_core::error::{ErrorContext, ErrorExt, OpaqueError}; use std::net::{Ipv4Addr, Ipv6Addr}; use std::{ fmt, net::{IpAddr, SocketAddr}, }; +#[cfg(feature = "http")] +use rama_http_types::HeaderValue; + /// A [`Host`] with an associated port. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Authority { @@ -156,6 +158,7 @@ impl TryFrom<&str> for Authority { } } +#[cfg(feature = "http")] impl TryFrom for Authority { type Error = OpaqueError; @@ -164,6 +167,7 @@ impl TryFrom for Authority { } } +#[cfg(feature = "http")] impl TryFrom<&HeaderValue> for Authority { type Error = OpaqueError; diff --git a/rama-core/src/net/address/domain.rs b/rama-net/src/address/domain.rs similarity index 99% rename from rama-core/src/net/address/domain.rs rename to rama-net/src/address/domain.rs index 2a00eb92..ce058499 100644 --- a/rama-core/src/net/address/domain.rs +++ b/rama-net/src/address/domain.rs @@ -1,5 +1,5 @@ use super::Host; -use crate::error::{ErrorContext, OpaqueError}; +use rama_core::error::{ErrorContext, OpaqueError}; use std::{borrow::Cow, cmp::Ordering, fmt, iter::repeat}; /// A domain. diff --git a/rama-core/src/net/address/host.rs b/rama-net/src/address/host.rs similarity index 98% rename from rama-core/src/net/address/host.rs rename to rama-net/src/address/host.rs index 364712ea..a9a51feb 100644 --- a/rama-core/src/net/address/host.rs +++ b/rama-net/src/address/host.rs @@ -1,11 +1,13 @@ use super::Domain; -use crate::error::{ErrorContext, OpaqueError}; -use http::HeaderValue; +use rama_core::error::{ErrorContext, OpaqueError}; use std::{ fmt, net::{IpAddr, Ipv6Addr}, }; +#[cfg(feature = "http")] +use rama_http_types::HeaderValue; + /// Either a [`Domain`] or an [`IpAddr`]. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Host { @@ -106,6 +108,7 @@ impl TryFrom<&str> for Host { } } +#[cfg(feature = "http")] impl TryFrom for Host { type Error = OpaqueError; @@ -114,6 +117,7 @@ impl TryFrom for Host { } } +#[cfg(feature = "http")] impl TryFrom<&HeaderValue> for Host { type Error = OpaqueError; diff --git a/rama-core/src/net/address/mod.rs b/rama-net/src/address/mod.rs similarity index 100% rename from rama-core/src/net/address/mod.rs rename to rama-net/src/address/mod.rs diff --git a/rama-core/src/net/address/proxy.rs b/rama-net/src/address/proxy.rs similarity index 98% rename from rama-core/src/net/address/proxy.rs rename to rama-net/src/address/proxy.rs index 2c021681..ce643b6c 100644 --- a/rama-core/src/net/address/proxy.rs +++ b/rama-net/src/address/proxy.rs @@ -1,8 +1,6 @@ use super::{Authority, Host}; -use crate::{ - error::{ErrorContext, OpaqueError}, - net::{proto::try_to_extract_protocol_from_uri_scheme, user::ProxyCredential, Protocol}, -}; +use rama_core::error::{ErrorContext, OpaqueError}; +use crate::{proto::try_to_extract_protocol_from_uri_scheme, user::ProxyCredential, Protocol}; use std::{fmt::Display, str::FromStr}; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/rama-core/src/net/asn.rs b/rama-net/src/asn.rs similarity index 99% rename from rama-core/src/net/asn.rs rename to rama-net/src/asn.rs index 45097332..d0c57949 100644 --- a/rama-core/src/net/asn.rs +++ b/rama-net/src/asn.rs @@ -110,6 +110,7 @@ impl fmt::Display for Asn { } } +#[cfg(feature = "venndb")] impl venndb::Any for Asn { fn is_any(&self) -> bool { self.0 == AsnData::Unspecified diff --git a/rama-core/src/net/client/conn.rs b/rama-net/src/client/conn.rs similarity index 98% rename from rama-core/src/net/client/conn.rs rename to rama-net/src/client/conn.rs index 4f34f944..c9358d89 100644 --- a/rama-core/src/net/client/conn.rs +++ b/rama-net/src/client/conn.rs @@ -1,4 +1,4 @@ -use crate::{error::BoxError, Context, Service}; +use rama_core::{error::BoxError, Context, Service}; use std::{fmt, future::Future, net::SocketAddr}; /// The established connection to a server returned for the http client to be used. diff --git a/rama-core/src/net/client/mod.rs b/rama-net/src/client/mod.rs similarity index 100% rename from rama-core/src/net/client/mod.rs rename to rama-net/src/client/mod.rs diff --git a/rama-core/src/net/forwarded/element/mod.rs b/rama-net/src/forwarded/element/mod.rs similarity index 98% rename from rama-core/src/net/forwarded/element/mod.rs rename to rama-net/src/forwarded/element/mod.rs index aa7d2413..b243aa3d 100644 --- a/rama-core/src/net/forwarded/element/mod.rs +++ b/rama-net/src/forwarded/element/mod.rs @@ -1,13 +1,13 @@ use super::{ForwardedProtocol, ForwardedVersion, NodeId}; -use crate::{ - error::{ErrorContext, OpaqueError}, - net::address::{Authority, Host}, -}; -use http::HeaderValue; +use rama_core::error::{ErrorContext, OpaqueError}; +use crate::address::{Authority, Host}; use std::fmt; use std::net::SocketAddr; use std::{collections::HashMap, net::IpAddr}; +#[cfg(feature = "http")] +use rama_http_types::HeaderValue; + mod parser; #[doc(inline)] pub(crate) use parser::{parse_one_plus_forwarded_elements, parse_single_forwarded_element}; @@ -338,6 +338,7 @@ impl TryFrom<&str> for ForwardedElement { } } +#[cfg(feature = "http")] impl TryFrom for ForwardedElement { type Error = OpaqueError; @@ -346,6 +347,7 @@ impl TryFrom for ForwardedElement { } } +#[cfg(feature = "http")] impl TryFrom<&HeaderValue> for ForwardedElement { type Error = OpaqueError; diff --git a/rama-core/src/net/forwarded/element/parser.rs b/rama-net/src/forwarded/element/parser.rs similarity index 98% rename from rama-core/src/net/forwarded/element/parser.rs rename to rama-net/src/forwarded/element/parser.rs index 70394ce6..8c464fd2 100644 --- a/rama-core/src/net/forwarded/element/parser.rs +++ b/rama-net/src/forwarded/element/parser.rs @@ -1,8 +1,8 @@ use super::ExtensionValue; use super::{ForwardedElement, NodeId}; -use crate::error::{ErrorContext, OpaqueError}; -use crate::net::forwarded::ForwardedProtocol; -use crate::utils::macros::match_ignore_ascii_case_str; +use rama_core::error::{ErrorContext, OpaqueError}; +use crate::forwarded::ForwardedProtocol; +use rama_core::utils::macros::match_ignore_ascii_case_str; pub(crate) fn parse_single_forwarded_element( bytes: &[u8], diff --git a/rama-core/src/net/forwarded/mod.rs b/rama-net/src/forwarded/mod.rs similarity index 98% rename from rama-core/src/net/forwarded/mod.rs rename to rama-net/src/forwarded/mod.rs index 205263be..9064bc8e 100644 --- a/rama-core/src/net/forwarded/mod.rs +++ b/rama-net/src/forwarded/mod.rs @@ -2,12 +2,13 @@ //! //! RFC: -use crate::error::OpaqueError; -use headers::Header; -use http::HeaderValue; +use rama_core::error::OpaqueError; use std::net::IpAddr; use std::{fmt, net::SocketAddr}; +#[cfg(feature = "http")] +use rama_http_types::{HeaderValue, headers::{self, Header}, HeaderName, header::FORWARDED}; + mod obfuscated; #[doc(inline)] use obfuscated::{ObfNode, ObfPort}; @@ -180,6 +181,7 @@ impl TryFrom<&str> for Forwarded { } } +#[cfg(feature = "http")] impl TryFrom for Forwarded { type Error = OpaqueError; @@ -189,6 +191,7 @@ impl TryFrom for Forwarded { } } +#[cfg(feature = "http")] impl TryFrom<&HeaderValue> for Forwarded { type Error = OpaqueError; @@ -216,9 +219,10 @@ impl TryFrom<&[u8]> for Forwarded { } } +#[cfg(feature = "http")] impl Header for Forwarded { - fn name() -> &'static http::HeaderName { - &http::header::FORWARDED + fn name() -> &'static HeaderName { + &FORWARDED } fn decode<'i, I>(values: &mut I) -> Result diff --git a/rama-core/src/net/forwarded/node.rs b/rama-net/src/forwarded/node.rs similarity index 99% rename from rama-core/src/net/forwarded/node.rs rename to rama-net/src/forwarded/node.rs index 7da5ded3..41d7b430 100644 --- a/rama-core/src/net/forwarded/node.rs +++ b/rama-net/src/forwarded/node.rs @@ -1,8 +1,6 @@ use super::{ObfNode, ObfPort}; -use crate::{ - error::{ErrorContext, OpaqueError}, - net::address::{Authority, Domain, Host}, -}; +use rama_core::error::{ErrorContext, OpaqueError}; +use crate::address::{Authority, Domain, Host}; use std::{ fmt, net::{IpAddr, Ipv6Addr, SocketAddr}, diff --git a/rama-core/src/net/forwarded/obfuscated.rs b/rama-net/src/forwarded/obfuscated.rs similarity index 99% rename from rama-core/src/net/forwarded/obfuscated.rs rename to rama-net/src/forwarded/obfuscated.rs index feef58a3..c6378f8b 100644 --- a/rama-core/src/net/forwarded/obfuscated.rs +++ b/rama-net/src/forwarded/obfuscated.rs @@ -1,4 +1,4 @@ -use crate::error::{ErrorContext, OpaqueError}; +use rama_core::error::{ErrorContext, OpaqueError}; use std::{borrow::Cow, fmt}; macro_rules! create_obf_type { diff --git a/rama-core/src/net/forwarded/proto.rs b/rama-net/src/forwarded/proto.rs similarity index 96% rename from rama-core/src/net/forwarded/proto.rs rename to rama-net/src/forwarded/proto.rs index 48765457..331f2e69 100644 --- a/rama-core/src/net/forwarded/proto.rs +++ b/rama-net/src/forwarded/proto.rs @@ -1,5 +1,5 @@ -use crate::net::Protocol; -use crate::utils::macros::str::eq_ignore_ascii_case; +use crate::Protocol; +use rama_core::utils::macros::{str::eq_ignore_ascii_case, error::static_str_error}; use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -79,7 +79,7 @@ impl From for Protocol { } } -crate::utils::macros::error::static_str_error! { +static_str_error! { #[doc = "unknown protocol"] pub struct UnknownProtocol; } @@ -116,7 +116,7 @@ impl TryFrom<&Protocol> for ForwardedProtocol { } } -crate::utils::macros::error::static_str_error! { +static_str_error! { #[doc = "invalid forwarded protocol string"] pub struct InvalidProtocolStr; } diff --git a/rama-core/src/net/forwarded/version.rs b/rama-net/src/forwarded/version.rs similarity index 87% rename from rama-core/src/net/forwarded/version.rs rename to rama-net/src/forwarded/version.rs index f1e48515..915e8b95 100644 --- a/rama-core/src/net/forwarded/version.rs +++ b/rama-net/src/forwarded/version.rs @@ -1,4 +1,5 @@ -use http::Version; +#[cfg(feature = "http")] +use rama_http_types::Version; #[derive(Debug, PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)] /// Version of the forwarded protocol. @@ -30,20 +31,21 @@ impl ForwardedVersion { pub const HTTP_3: ForwardedVersion = ForwardedVersion(VersionKind::H3); } +#[cfg(feature = "http")] impl ForwardedVersion { /// Returns this [`ForwardedVersion`] as a [`Version`] if it is defined as http. pub fn as_http(&self) -> Option { Some(match self.0 { - VersionKind::Http09 => http::Version::HTTP_09, - VersionKind::Http10 => http::Version::HTTP_10, - VersionKind::Http11 => http::Version::HTTP_11, - VersionKind::H2 => http::Version::HTTP_2, - VersionKind::H3 => http::Version::HTTP_3, + VersionKind::Http09 => Version::HTTP_09, + VersionKind::Http10 => Version::HTTP_10, + VersionKind::Http11 => Version::HTTP_11, + VersionKind::H2 => Version::HTTP_2, + VersionKind::H3 => Version::HTTP_3, }) } } -crate::utils::macros::error::static_str_error! { +rama_core::utils::macros::error::static_str_error! { #[doc = "invalid forwarded version"] pub struct InvalidForwardedVersion; } diff --git a/rama-net/src/lib.rs b/rama-net/src/lib.rs new file mode 100644 index 00000000..26787c2a --- /dev/null +++ b/rama-net/src/lib.rs @@ -0,0 +1,68 @@ +//! Rama network types and utilities. +//! +//! Protocols such as tcp, http, tls, etc are not explicitly implemented here, +//! see the relevant `rama` crates for this. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +pub mod address; +pub mod asn; +pub mod client; +pub mod forwarded; +pub mod stream; +pub mod user; + +pub(crate) mod proto; +#[doc(inline)] +pub use proto::Protocol; + +#[cfg(feature = "http")] +pub mod transport; diff --git a/rama-core/src/net/mod.rs b/rama-net/src/mod.rs similarity index 100% rename from rama-core/src/net/mod.rs rename to rama-net/src/mod.rs diff --git a/rama-core/src/net/proto.rs b/rama-net/src/proto.rs similarity index 99% rename from rama-core/src/net/proto.rs rename to rama-net/src/proto.rs index 7a9e39b8..b97f24f2 100644 --- a/rama-core/src/net/proto.rs +++ b/rama-net/src/proto.rs @@ -2,8 +2,8 @@ use std::borrow::Cow; use std::cmp::min; use std::str::FromStr; -use crate::error::{ErrorContext, OpaqueError}; -use crate::utils::macros::str::eq_ignore_ascii_case; +use rama_core::error::{ErrorContext, OpaqueError}; +use rama_core::utils::macros::str::eq_ignore_ascii_case; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] /// Web protocols that are relevant to Rama. @@ -193,7 +193,7 @@ impl Protocol { } } -crate::utils::macros::error::static_str_error! { +rama_core::utils::macros::error::static_str_error! { #[doc = "invalid protocol string"] pub struct InvalidProtocolStr; } diff --git a/src/stream/layer/http/body_limit.rs b/rama-net/src/stream/layer/http/body_limit.rs similarity index 96% rename from src/stream/layer/http/body_limit.rs rename to rama-net/src/stream/layer/http/body_limit.rs index f0c11f12..f13cc570 100644 --- a/src/stream/layer/http/body_limit.rs +++ b/rama-net/src/stream/layer/http/body_limit.rs @@ -1,6 +1,8 @@ -use crate::utils::macros::define_inner_service_accessors; -use crate::{http::BodyLimit, stream::Stream, Context, Layer, Service}; +use rama_core::utils::macros::define_inner_service_accessors; +use crate::stream::Stream; +use rama_core::{Context, Layer, Service}; use std::fmt; +use rama_http_types::BodyLimit; /// Limit the size of the request and/or response bodies. /// diff --git a/src/stream/layer/http/mod.rs b/rama-net/src/stream/layer/http/mod.rs similarity index 100% rename from src/stream/layer/http/mod.rs rename to rama-net/src/stream/layer/http/mod.rs diff --git a/src/stream/layer/mod.rs b/rama-net/src/stream/layer/mod.rs similarity index 94% rename from src/stream/layer/mod.rs rename to rama-net/src/stream/layer/mod.rs index 49477442..13f7ab5e 100644 --- a/src/stream/layer/mod.rs +++ b/rama-net/src/stream/layer/mod.rs @@ -9,6 +9,7 @@ pub use tracker::{ OutgoingBytesTrackerLayer, OutgoingBytesTrackerService, }; +#[cfg(feature = "http")] pub mod http; #[cfg(feature = "telemetry")] diff --git a/src/stream/layer/opentelemetry.rs b/rama-net/src/stream/layer/opentelemetry.rs similarity index 97% rename from src/stream/layer/opentelemetry.rs rename to rama-net/src/stream/layer/opentelemetry.rs index 3e50677e..229c9e47 100644 --- a/src/stream/layer/opentelemetry.rs +++ b/rama-net/src/stream/layer/opentelemetry.rs @@ -7,7 +7,7 @@ use crate::telemetry::opentelemetry::{ metrics::{Histogram, Meter, UpDownCounter}, semantic_conventions, KeyValue, }; -use crate::utils::macros::define_inner_service_accessors; +use rama_core::utils::macros::define_inner_service_accessors; use crate::{stream::SocketInfo, Context, Layer, Service}; use semantic_conventions::trace::{CLIENT_ADDRESS, CLIENT_PORT, NETWORK_TRANSPORT, NETWORK_TYPE}; use std::{fmt, sync::Arc, time::SystemTime}; @@ -71,8 +71,8 @@ impl Default for NetworkMetricsLayer { /// construct meters for this crate fn get_versioned_meter() -> Meter { global::meter_with_version( - crate::utils::info::NAME, - Some(crate::utils::info::VERSION), + rama_core::utils::info::NAME, + Some(rama_core::utils::info::VERSION), Some(semantic_conventions::SCHEMA_URL), None, ) diff --git a/src/stream/layer/tracker/bytes.rs b/rama-net/src/stream/layer/tracker/bytes.rs similarity index 100% rename from src/stream/layer/tracker/bytes.rs rename to rama-net/src/stream/layer/tracker/bytes.rs diff --git a/src/stream/layer/tracker/incoming.rs b/rama-net/src/stream/layer/tracker/incoming.rs similarity index 94% rename from src/stream/layer/tracker/incoming.rs rename to rama-net/src/stream/layer/tracker/incoming.rs index 2049c558..d4203dcb 100644 --- a/src/stream/layer/tracker/incoming.rs +++ b/rama-net/src/stream/layer/tracker/incoming.rs @@ -1,6 +1,7 @@ use super::bytes::BytesRWTracker; -use crate::utils::macros::define_inner_service_accessors; -use crate::{stream::Stream, Context, Layer, Service}; +use rama_core::utils::macros::define_inner_service_accessors; +use crate::stream::Stream; +use rama_core::{Context, Layer, Service}; use std::{fmt, future::Future}; /// A [`Service`] that wraps a [`Service`]'s input IO [`Stream`] with an atomic R/W tracker. diff --git a/src/stream/layer/tracker/mod.rs b/rama-net/src/stream/layer/tracker/mod.rs similarity index 100% rename from src/stream/layer/tracker/mod.rs rename to rama-net/src/stream/layer/tracker/mod.rs diff --git a/src/stream/layer/tracker/outgoing.rs b/rama-net/src/stream/layer/tracker/outgoing.rs similarity index 94% rename from src/stream/layer/tracker/outgoing.rs rename to rama-net/src/stream/layer/tracker/outgoing.rs index 1d38c1d2..cef2b1e0 100644 --- a/src/stream/layer/tracker/outgoing.rs +++ b/rama-net/src/stream/layer/tracker/outgoing.rs @@ -1,10 +1,10 @@ use super::bytes::BytesRWTracker; -use crate::utils::macros::define_inner_service_accessors; +use rama_core::utils::macros::define_inner_service_accessors; use crate::{ - net::client::{ConnectorService, EstablishedClientConnection}, + client::{ConnectorService, EstablishedClientConnection}, stream::Stream, - Context, Layer, Service, }; +use rama_core::{Context, Layer, Service}; use std::fmt; /// A [`Service`] that wraps a [`Service`]'s output IO [`Stream`] with an atomic R/W tracker. diff --git a/src/stream/matcher/ip.rs b/rama-net/src/stream/matcher/ip.rs similarity index 97% rename from src/stream/matcher/ip.rs rename to rama-net/src/stream/matcher/ip.rs index 25205440..1f8e2783 100644 --- a/src/stream/matcher/ip.rs +++ b/rama-net/src/stream/matcher/ip.rs @@ -1,7 +1,9 @@ -use http::Request; - use crate::stream::dep::ipnet::{IpNet, Ipv4Net, Ipv6Net}; -use crate::{context::Extensions, stream::SocketInfo, Context}; +use rama_core::{context::Extensions, Context}; +use crate::stream::SocketInfo; + +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on whether or not the [`IpNet`] contains the [`SocketAddr`] of the peer. @@ -38,6 +40,7 @@ impl IpNetMatcher { } } +#[cfg(feature = "http")] impl crate::matcher::Matcher> for IpNetMatcher { fn matches( &self, @@ -144,9 +147,8 @@ mod private { #[cfg(test)] mod test { - use crate::{http::Body, matcher::Matcher}; + use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; const SUBNET_IPV4: &str = "192.168.0.0/24"; @@ -167,6 +169,7 @@ mod test { } } + #[cfg(feature = "http")] #[test] fn test_ip_net_matcher_http() { let matcher = IpNetMatcher::new([127, 0, 0, 1]); @@ -175,7 +178,7 @@ mod test { let req = Request::builder() .method("GET") .uri("/hello") - .body(Body::empty()) + .body(()) .unwrap(); // test #1: no match: test with no socket info registered diff --git a/src/stream/matcher/loopback.rs b/rama-net/src/stream/matcher/loopback.rs similarity index 96% rename from src/stream/matcher/loopback.rs rename to rama-net/src/stream/matcher/loopback.rs index c274c9c0..0d08a8b4 100644 --- a/src/stream/matcher/loopback.rs +++ b/rama-net/src/stream/matcher/loopback.rs @@ -1,6 +1,8 @@ -use http::Request; +use rama_core::{context::Extensions, Context}; +use crate::stream::SocketInfo; -use crate::{context::Extensions, stream::SocketInfo, Context}; +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on the ip part of the [`SocketAddr`] of the peer, @@ -43,6 +45,7 @@ impl Default for LoopbackMatcher { } } +#[cfg(feature = "http")] impl crate::matcher::Matcher> for LoopbackMatcher { fn matches( &self, @@ -75,11 +78,11 @@ where #[cfg(test)] mod test { - use crate::{http::Body, matcher::Matcher}; + use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; + #[cfg(feature = "http")] #[test] fn test_loopback_matcher_http() { let matcher = LoopbackMatcher::new(); @@ -88,7 +91,7 @@ mod test { let req = Request::builder() .method("GET") .uri("/hello") - .body(Body::empty()) + .body(()) .unwrap(); // test #1: no match: test with no socket info registered diff --git a/src/stream/matcher/mod.rs b/rama-net/src/stream/matcher/mod.rs similarity index 99% rename from src/stream/matcher/mod.rs rename to rama-net/src/stream/matcher/mod.rs index 27893263..66b5e9ff 100644 --- a/src/stream/matcher/mod.rs +++ b/rama-net/src/stream/matcher/mod.rs @@ -26,9 +26,12 @@ mod ip; #[doc(inline)] pub use ip::IpNetMatcher; -use crate::{context::Extensions, http::Request, matcher::IteratorMatcherExt, Context}; +use rama_core::{context::Extensions, matcher::IteratorMatcherExt, Context}; use std::{fmt, sync::Arc}; +#[cfg(feature = "http")] +use rama_http_types::Request; + /// A matcher to match on a [`Socket`]. /// /// [`Socket`]: crate::stream::Socket @@ -431,6 +434,7 @@ impl SocketMatcher { } } +#[cfg(feature = "http")] impl crate::matcher::Matcher> for SocketMatcherKind> where @@ -456,6 +460,7 @@ where } } +#[cfg(feature = "http")] impl crate::matcher::Matcher> for SocketMatcher> where @@ -511,7 +516,7 @@ where } } -#[cfg(test)] +#[cfg(all(test, feature = "http"))] mod test { use itertools::Itertools; diff --git a/src/stream/matcher/port.rs b/rama-net/src/stream/matcher/port.rs similarity index 95% rename from src/stream/matcher/port.rs rename to rama-net/src/stream/matcher/port.rs index 8cd93ab0..714e2b0b 100644 --- a/src/stream/matcher/port.rs +++ b/rama-net/src/stream/matcher/port.rs @@ -1,6 +1,8 @@ -use http::Request; +use rama_core::{context::Extensions, Context}; +use crate::stream::SocketInfo; -use crate::{context::Extensions, stream::SocketInfo, Context}; +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on the port part of the [`SocketAddr`] of the peer. @@ -41,6 +43,7 @@ impl PortMatcher { } } +#[cfg(feature = "http")] impl crate::matcher::Matcher> for PortMatcher { fn matches( &self, @@ -73,11 +76,11 @@ where #[cfg(test)] mod test { - use crate::{http::Body, matcher::Matcher}; + use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; + #[cfg(feature = "http")] #[test] fn test_port_matcher_http() { let matcher = PortMatcher::new(8080); @@ -86,7 +89,7 @@ mod test { let req = Request::builder() .method("GET") .uri("/hello") - .body(Body::empty()) + .body(()) .unwrap(); // test #1: no match: test with no socket info registered diff --git a/src/stream/matcher/private_ip.rs b/rama-net/src/stream/matcher/private_ip.rs similarity index 97% rename from src/stream/matcher/private_ip.rs rename to rama-net/src/stream/matcher/private_ip.rs index e267cea9..85c1d07b 100644 --- a/src/stream/matcher/private_ip.rs +++ b/rama-net/src/stream/matcher/private_ip.rs @@ -1,7 +1,9 @@ -use http::Request; - use crate::stream::dep::ipnet::IpNet; -use crate::{context::Extensions, stream::SocketInfo, Context}; +use rama_core::{context::Extensions, Context}; +use crate::stream::SocketInfo; + +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on the ip part of the [`SocketAddr`] of the peer, @@ -115,6 +117,7 @@ impl Default for PrivateIpNetMatcher { } } +#[cfg(feature = "http")] impl crate::matcher::Matcher> for PrivateIpNetMatcher { fn matches( &self, @@ -153,11 +156,11 @@ where #[cfg(test)] mod test { - use crate::{http::Body, matcher::Matcher}; + use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; + #[cfg(feature = "http")] #[test] fn test_local_ip_net_matcher_http() { let matcher = PrivateIpNetMatcher::new(); @@ -166,7 +169,7 @@ mod test { let req = Request::builder() .method("GET") .uri("/hello") - .body(Body::empty()) + .body(()) .unwrap(); // test #1: no match: test with no socket info registered diff --git a/src/stream/matcher/socket.rs b/rama-net/src/stream/matcher/socket.rs similarity index 96% rename from src/stream/matcher/socket.rs rename to rama-net/src/stream/matcher/socket.rs index e015f940..1339d007 100644 --- a/src/stream/matcher/socket.rs +++ b/rama-net/src/stream/matcher/socket.rs @@ -1,8 +1,10 @@ -use http::Request; - -use crate::{context::Extensions, stream::SocketInfo, Context}; +use rama_core::{context::Extensions, Context}; +use crate::stream::SocketInfo; use std::net::SocketAddr; +#[cfg(feature = "http")] +use rama_http_types::Request; + #[derive(Debug, Clone)] /// Matcher based on the [`SocketAddr`] of the peer. pub struct SocketAddressMatcher { @@ -66,6 +68,7 @@ where } } +#[cfg(feature = "http")] #[cfg(test)] mod test { use crate::{http::Body, matcher::Matcher}; diff --git a/src/stream/mod.rs b/rama-net/src/stream/mod.rs similarity index 97% rename from src/stream/mod.rs rename to rama-net/src/stream/mod.rs index cd2b8dbe..d4eb8554 100644 --- a/src/stream/mod.rs +++ b/rama-net/src/stream/mod.rs @@ -7,8 +7,6 @@ pub mod matcher; pub mod layer; pub mod service; -pub mod transport; - mod read; #[doc(inline)] pub use read::{ChainReader, HeapReader}; diff --git a/src/stream/read.rs b/rama-net/src/stream/read.rs similarity index 100% rename from src/stream/read.rs rename to rama-net/src/stream/read.rs diff --git a/src/stream/service/echo.rs b/rama-net/src/stream/service/echo.rs similarity index 95% rename from src/stream/service/echo.rs rename to rama-net/src/stream/service/echo.rs index a82e0098..01de9cb0 100644 --- a/src/stream/service/echo.rs +++ b/rama-net/src/stream/service/echo.rs @@ -1,6 +1,7 @@ //! An async service which echoes the incoming bytes back on the same stream. -use crate::{error::BoxError, stream::Stream, Context, Service}; +use rama_core::{error::BoxError, Context, Service}; +use crate::stream::Stream; /// An async service which echoes the incoming bytes back on the same stream. /// diff --git a/src/stream/service/mod.rs b/rama-net/src/stream/service/mod.rs similarity index 100% rename from src/stream/service/mod.rs rename to rama-net/src/stream/service/mod.rs diff --git a/src/stream/socket.rs b/rama-net/src/stream/socket.rs similarity index 100% rename from src/stream/socket.rs rename to rama-net/src/stream/socket.rs diff --git a/src/stream/transport.rs b/rama-net/src/transport.rs similarity index 94% rename from src/stream/transport.rs rename to rama-net/src/transport.rs index ba25cb5f..1368ee7e 100644 --- a/src/stream/transport.rs +++ b/rama-net/src/transport.rs @@ -2,11 +2,9 @@ //! //! See [`TransportContext`] for the centerpiece of this module. -use crate::{ - http::Version, - net::{address::Authority, Protocol}, - Context, -}; +use crate::{address::Authority, Protocol}; +use rama_core::Context; +use rama_http_types::Version; #[derive(Debug, Clone, PartialEq, Eq)] /// The context as relevant to the transport layer, diff --git a/rama-core/src/net/user/auth.rs b/rama-net/src/user/auth.rs similarity index 93% rename from rama-core/src/net/user/auth.rs rename to rama-net/src/user/auth.rs index d00cf8d4..1b2874f7 100644 --- a/rama-core/src/net/user/auth.rs +++ b/rama-net/src/user/auth.rs @@ -1,15 +1,12 @@ //! types and utilities for authorising users. -use crate::{ - context::Extensions, - net::user::{Basic, UserId}, - utils::username::{parse_username, UsernameLabelParser}, -}; -use headers::authorization::Credentials; +use crate::user::{Basic, UserId}; +use rama_core::context::Extensions; +use rama_core::utils::username::{parse_username, UsernameLabelParser}; use std::future::Future; -// TODO: do not rely on http Credentials in core crate, -// instead perhaps have our own trait that we can then also implement in case http is defined? +// TODO: decouple this from http +use rama_http_types::headers::authorization::Credentials; /// The `Authority` trait is used to determine if a set of [`Credential`]s are authorized. /// diff --git a/rama-core/src/net/user/credentials/basic.rs b/rama-net/src/user/credentials/basic.rs similarity index 99% rename from rama-core/src/net/user/credentials/basic.rs rename to rama-net/src/user/credentials/basic.rs index a30929f0..30a7c459 100644 --- a/rama-core/src/net/user/credentials/basic.rs +++ b/rama-net/src/user/credentials/basic.rs @@ -1,4 +1,4 @@ -use crate::error::{ErrorContext, OpaqueError}; +use rama_core::error::{ErrorContext, OpaqueError}; use base64::engine::general_purpose::STANDARD as ENGINE; use base64::Engine; use headers::authorization; diff --git a/rama-core/src/net/user/credentials/bearer.rs b/rama-net/src/user/credentials/bearer.rs similarity index 98% rename from rama-core/src/net/user/credentials/bearer.rs rename to rama-net/src/user/credentials/bearer.rs index 932f1d2e..b35eb8d2 100644 --- a/rama-core/src/net/user/credentials/bearer.rs +++ b/rama-net/src/user/credentials/bearer.rs @@ -1,4 +1,4 @@ -use crate::error::{ErrorContext, OpaqueError}; +use rama_core::error::{ErrorContext, OpaqueError}; use headers::authorization; use std::borrow::Cow; diff --git a/rama-core/src/net/user/credentials/mod.rs b/rama-net/src/user/credentials/mod.rs similarity index 100% rename from rama-core/src/net/user/credentials/mod.rs rename to rama-net/src/user/credentials/mod.rs diff --git a/rama-core/src/net/user/credentials/proxy.rs b/rama-net/src/user/credentials/proxy.rs similarity index 97% rename from rama-core/src/net/user/credentials/proxy.rs rename to rama-net/src/user/credentials/proxy.rs index 81a62079..e8954964 100644 --- a/rama-core/src/net/user/credentials/proxy.rs +++ b/rama-net/src/user/credentials/proxy.rs @@ -1,8 +1,10 @@ use super::{Basic, Bearer}; -use crate::error::{ErrorContext, OpaqueError}; -use http::HeaderValue; +use rama_core::error::{ErrorContext, OpaqueError}; use std::borrow::Cow; +#[cfg(feature = "http")] +use rama_http_types::HeaderValue; + #[derive(Debug, Clone, PartialEq, Eq)] /// Proxy credentials. pub enum ProxyCredential { @@ -53,6 +55,7 @@ impl ProxyCredential { } } + #[cfg(feature = "http")] /// View this [`ProxyCredential`] as a [`HeaderValue`] pub fn as_header_value(&self) -> HeaderValue { match self { diff --git a/rama-core/src/net/user/id.rs b/rama-net/src/user/id.rs similarity index 100% rename from rama-core/src/net/user/id.rs rename to rama-net/src/user/id.rs diff --git a/rama-core/src/net/user/mod.rs b/rama-net/src/user/mod.rs similarity index 81% rename from rama-core/src/net/user/mod.rs rename to rama-net/src/user/mod.rs index 091194b1..d0172c30 100644 --- a/rama-core/src/net/user/mod.rs +++ b/rama-net/src/user/mod.rs @@ -10,4 +10,6 @@ mod credentials; #[doc(inline)] pub use credentials::{Basic, Bearer, ProxyCredential}; +// todo: decouple from http +#[cfg(feature = "http")] pub mod auth; diff --git a/rama-proxy/Cargo.toml b/rama-proxy/Cargo.toml new file mode 100644 index 00000000..c32a3d3d --- /dev/null +++ b/rama-proxy/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "rama-proxy" +description = "proxy protocols and upstream proxy support for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = ["memory-db", "csv"] +memory-db = ["dep:venndb", "rama-core/venndb"] +live-update = ["dep:arc-swap"] +csv = [] + +[dependencies] +arc-swap = { workspace = true, optional = true } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +venndb = { workspace = true, optional = true } + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-proxy/README.md b/rama-proxy/README.md new file mode 100644 index 00000000..c58e031e --- /dev/null +++ b/rama-proxy/README.md @@ -0,0 +1,50 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-proxy.svg +[crates-url]: https://crates.io/crates/rama-proxy +[docs-badge]: https://img.shields.io/docsrs/rama-proxy/latest +[docs-url]: https://docs.rs/rama-proxy/latest/rama_proxy/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-proxy + +User-Agent (UA) support for `rama`. + +This crate only focusses on the majority user-agents within +the web space. Feature requests are welcome, but keep this scope in mind. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/src/proxy/http/client/layer/mod.rs b/rama-proxy/src/http/client/layer/mod.rs similarity index 100% rename from src/proxy/http/client/layer/mod.rs rename to rama-proxy/src/http/client/layer/mod.rs diff --git a/src/proxy/http/client/layer/proxy_address.rs b/rama-proxy/src/http/client/layer/proxy_address.rs similarity index 100% rename from src/proxy/http/client/layer/proxy_address.rs rename to rama-proxy/src/http/client/layer/proxy_address.rs diff --git a/src/proxy/http/client/layer/proxy_auth_header.rs b/rama-proxy/src/http/client/layer/proxy_auth_header.rs similarity index 100% rename from src/proxy/http/client/layer/proxy_auth_header.rs rename to rama-proxy/src/http/client/layer/proxy_auth_header.rs diff --git a/src/proxy/http/client/layer/proxy_connector/connector.rs b/rama-proxy/src/http/client/layer/proxy_connector/connector.rs similarity index 100% rename from src/proxy/http/client/layer/proxy_connector/connector.rs rename to rama-proxy/src/http/client/layer/proxy_connector/connector.rs diff --git a/src/proxy/http/client/layer/proxy_connector/layer.rs b/rama-proxy/src/http/client/layer/proxy_connector/layer.rs similarity index 100% rename from src/proxy/http/client/layer/proxy_connector/layer.rs rename to rama-proxy/src/http/client/layer/proxy_connector/layer.rs diff --git a/src/proxy/http/client/layer/proxy_connector/mod.rs b/rama-proxy/src/http/client/layer/proxy_connector/mod.rs similarity index 100% rename from src/proxy/http/client/layer/proxy_connector/mod.rs rename to rama-proxy/src/http/client/layer/proxy_connector/mod.rs diff --git a/src/proxy/http/client/layer/proxy_connector/service.rs b/rama-proxy/src/http/client/layer/proxy_connector/service.rs similarity index 100% rename from src/proxy/http/client/layer/proxy_connector/service.rs rename to rama-proxy/src/http/client/layer/proxy_connector/service.rs diff --git a/src/proxy/http/client/mod.rs b/rama-proxy/src/http/client/mod.rs similarity index 100% rename from src/proxy/http/client/mod.rs rename to rama-proxy/src/http/client/mod.rs diff --git a/src/proxy/http/mod.rs b/rama-proxy/src/http/mod.rs similarity index 100% rename from src/proxy/http/mod.rs rename to rama-proxy/src/http/mod.rs diff --git a/src/proxy/mod.rs b/rama-proxy/src/lib.rs similarity index 65% rename from src/proxy/mod.rs rename to rama-proxy/src/lib.rs index 50b23c15..27057ea5 100644 --- a/src/proxy/mod.rs +++ b/rama-proxy/src/lib.rs @@ -1,4 +1,4 @@ -//! Upstream proxy types and utilities. +//! proxy protocols and upstream proxy support. //! //! See the [`ProxyFilter`] for more information on how to select a proxy, //! and the [`ProxyDB`] trait for how to implement a proxy database. @@ -10,6 +10,11 @@ //! The [`ProxyDB`] is used by Connection Pools to connect via a proxy, //! in case a [`ProxyFilter`] is present in the [`Context`]'s [`Extensions`]. //! +//! # Proxy Protocols +//! +//! - use [`http`] for http proxy support; +//! - use [`pp`] for HaProxy (Proxy Protocol) support; +//! //! # DB Live Reloads //! //! [`ProxyDB`] implementations like the [`MemoryProxyDB`] feel static in nature, and they are. @@ -26,8 +31,8 @@ //! task and wrap the reader in a [`ProxyDB`] implementation. This way you can live reload based upon //! a signal, or more realistically, every x minutes. //! -//! [`Context`]: crate::Context -//! [`Extensions`]: crate::context::Extensions +//! [`Context`]: rama_core::Context +//! [`Extensions`]: rama_core::context::Extensions mod username; @@ -37,10 +42,21 @@ pub mod http; pub mod pp; mod proxydb; + +#[doc(inline)] +pub use proxydb::{Proxy, ProxyDB, ProxyFilter, ProxyID, ProxyQueryPredicate, StringFilter}; + +#[cfg(feature = "live-update")] +#[doc(inline)] +pub use proxydb::{proxy_db_updater, LiveUpdateProxyDB, LiveUpdateProxyDBSetter}; + +#[cfg(feature = "memory-db")] #[doc(inline)] pub use proxydb::{ - layer, proxy_db_updater, LiveUpdateProxyDB, LiveUpdateProxyDBSetter, MemoryProxyDB, - MemoryProxyDBInsertError, MemoryProxyDBInsertErrorKind, MemoryProxyDBQueryError, - MemoryProxyDBQueryErrorKind, Proxy, ProxyCsvRowReader, ProxyCsvRowReaderError, - ProxyCsvRowReaderErrorKind, ProxyDB, ProxyFilter, ProxyID, ProxyQueryPredicate, StringFilter, + MemoryProxyDB, MemoryProxyDBInsertError, MemoryProxyDBInsertErrorKind, MemoryProxyDBQueryError, + MemoryProxyDBQueryErrorKind, }; + +#[cfg(feature = "csv")] +#[doc(inline)] +pub use proxydb::{ProxyCsvRowReader, ProxyCsvRowReaderError, ProxyCsvRowReaderErrorKind}; diff --git a/src/proxy/pp/client/layer.rs b/rama-proxy/src/pp/client/layer.rs similarity index 100% rename from src/proxy/pp/client/layer.rs rename to rama-proxy/src/pp/client/layer.rs diff --git a/src/proxy/pp/client/mod.rs b/rama-proxy/src/pp/client/mod.rs similarity index 100% rename from src/proxy/pp/client/mod.rs rename to rama-proxy/src/pp/client/mod.rs diff --git a/src/proxy/pp/mod.rs b/rama-proxy/src/pp/mod.rs similarity index 100% rename from src/proxy/pp/mod.rs rename to rama-proxy/src/pp/mod.rs diff --git a/src/proxy/pp/protocol/ip.rs b/rama-proxy/src/pp/protocol/ip.rs similarity index 100% rename from src/proxy/pp/protocol/ip.rs rename to rama-proxy/src/pp/protocol/ip.rs diff --git a/src/proxy/pp/protocol/mod.rs b/rama-proxy/src/pp/protocol/mod.rs similarity index 100% rename from src/proxy/pp/protocol/mod.rs rename to rama-proxy/src/pp/protocol/mod.rs diff --git a/src/proxy/pp/protocol/v1/error.rs b/rama-proxy/src/pp/protocol/v1/error.rs similarity index 100% rename from src/proxy/pp/protocol/v1/error.rs rename to rama-proxy/src/pp/protocol/v1/error.rs diff --git a/src/proxy/pp/protocol/v1/mod.rs b/rama-proxy/src/pp/protocol/v1/mod.rs similarity index 100% rename from src/proxy/pp/protocol/v1/mod.rs rename to rama-proxy/src/pp/protocol/v1/mod.rs diff --git a/src/proxy/pp/protocol/v1/model.rs b/rama-proxy/src/pp/protocol/v1/model.rs similarity index 100% rename from src/proxy/pp/protocol/v1/model.rs rename to rama-proxy/src/pp/protocol/v1/model.rs diff --git a/src/proxy/pp/protocol/v2/builder.rs b/rama-proxy/src/pp/protocol/v2/builder.rs similarity index 100% rename from src/proxy/pp/protocol/v2/builder.rs rename to rama-proxy/src/pp/protocol/v2/builder.rs diff --git a/src/proxy/pp/protocol/v2/error.rs b/rama-proxy/src/pp/protocol/v2/error.rs similarity index 100% rename from src/proxy/pp/protocol/v2/error.rs rename to rama-proxy/src/pp/protocol/v2/error.rs diff --git a/src/proxy/pp/protocol/v2/mod.rs b/rama-proxy/src/pp/protocol/v2/mod.rs similarity index 100% rename from src/proxy/pp/protocol/v2/mod.rs rename to rama-proxy/src/pp/protocol/v2/mod.rs diff --git a/src/proxy/pp/protocol/v2/model.rs b/rama-proxy/src/pp/protocol/v2/model.rs similarity index 100% rename from src/proxy/pp/protocol/v2/model.rs rename to rama-proxy/src/pp/protocol/v2/model.rs diff --git a/src/proxy/pp/server/layer.rs b/rama-proxy/src/pp/server/layer.rs similarity index 100% rename from src/proxy/pp/server/layer.rs rename to rama-proxy/src/pp/server/layer.rs diff --git a/src/proxy/pp/server/mod.rs b/rama-proxy/src/pp/server/mod.rs similarity index 100% rename from src/proxy/pp/server/mod.rs rename to rama-proxy/src/pp/server/mod.rs diff --git a/rama-proxy/src/proxydb/csv.rs b/rama-proxy/src/proxydb/csv.rs new file mode 100644 index 00000000..ce5b0a94 --- /dev/null +++ b/rama-proxy/src/proxydb/csv.rs @@ -0,0 +1,526 @@ +#[derive(Debug)] +/// A CSV Reader that can be used to create a [`MemoryProxyDB`] from a CSV file or raw data. +/// +/// [`MemoryProxyDB`]: crate::proxy::proxydb::MemoryProxyDB +pub struct ProxyCsvRowReader { + data: ProxyCsvRowReaderData, +} + +impl ProxyCsvRowReader { + /// Create a new [`ProxyCsvRowReader`] from the given CSV file. + pub async fn open(path: impl AsRef) -> Result { + let file = tokio::fs::File::open(path).await?; + let reader = BufReader::new(file); + let lines = reader.lines(); + Ok(ProxyCsvRowReader { + data: ProxyCsvRowReaderData::File(lines), + }) + } + + /// Create a new [`ProxyCsvRowReader`] from the given CSV data. + pub fn raw(data: impl AsRef) -> Self { + let lines: Vec<_> = data.as_ref().lines().rev().map(str::to_owned).collect(); + ProxyCsvRowReader { + data: ProxyCsvRowReaderData::Raw(lines), + } + } + + /// Read the next row from the CSV file. + pub async fn next(&mut self) -> Result, ProxyCsvRowReaderError> { + match &mut self.data { + ProxyCsvRowReaderData::File(lines) => { + let line = lines.next_line().await?; + match line { + Some(line) => Ok(Some(match parse_csv_row(&line) { + Some(proxy) => proxy, + None => { + return Err(ProxyCsvRowReaderError { + kind: ProxyCsvRowReaderErrorKind::InvalidRow(line), + }); + } + })), + None => Ok(None), + } + } + ProxyCsvRowReaderData::Raw(lines) => match lines.pop() { + Some(line) => Ok(Some(match parse_csv_row(&line) { + Some(proxy) => proxy, + None => { + return Err(ProxyCsvRowReaderError { + kind: ProxyCsvRowReaderErrorKind::InvalidRow(line), + }); + } + })), + None => Ok(None), + }, + } + } +} + +fn strip_csv_quotes(p: &str) -> &str { + p.strip_prefix('"') + .and_then(|p| p.strip_suffix('"')) + .unwrap_or(p) +} + +fn parse_csv_row(row: &str) -> Option { + let mut iter = row.split(',').map(strip_csv_quotes); + + let id = iter.next().and_then(|s| s.try_into().ok())?; + + let tcp = iter.next().and_then(parse_csv_bool)?; + let udp = iter.next().and_then(parse_csv_bool)?; + let http = iter.next().and_then(parse_csv_bool)?; + let https = iter.next().and_then(parse_csv_bool)?; + let socks5 = iter.next().and_then(parse_csv_bool)?; + let socks5h = iter.next().and_then(parse_csv_bool)?; + let datacenter = iter.next().and_then(parse_csv_bool)?; + let residential = iter.next().and_then(parse_csv_bool)?; + let mobile = iter.next().and_then(parse_csv_bool)?; + let mut address = iter.next().and_then(|s| { + if s.is_empty() { + None + } else { + ProxyAddress::try_from(s).ok() + } + })?; + let pool_id = parse_csv_opt_string_filter(iter.next()?); + let continent = parse_csv_opt_string_filter(iter.next()?); + let country = parse_csv_opt_string_filter(iter.next()?); + let state = parse_csv_opt_string_filter(iter.next()?); + let city = parse_csv_opt_string_filter(iter.next()?); + let carrier = parse_csv_opt_string_filter(iter.next()?); + let asn = parse_csv_opt_asn(iter.next()?).ok()?; + + // support header format or cleartext format + if let Some(value) = iter.next() { + if !value.is_empty() { + let credential = ProxyCredential::try_from_header_str(value) + .or_else(|_| ProxyCredential::try_from_clear_str(value.to_owned())) + .ok()?; + address.credential = Some(credential); + } + } + + // Ensure there are no more values in the row + if iter.next().is_some() { + return None; + } + + Some(Proxy { + id, + address, + tcp, + udp, + http, + https, + socks5, + socks5h, + datacenter, + residential, + mobile, + pool_id, + continent, + country, + state, + city, + carrier, + asn, + }) +} + +fn parse_csv_bool(value: &str) -> Option { + match_ignore_ascii_case_str! { + match(value) { + "true" | "1" => Some(true), + "" | "false" | "0" | "null" | "nil" => Some(false), + _ => None, + } + } +} + +fn parse_csv_opt_string_filter(value: &str) -> Option { + if value.is_empty() { + None + } else { + Some(StringFilter::from(value)) + } +} + +fn parse_csv_opt_asn(value: &str) -> Result, InvalidAsn> { + if value.is_empty() { + Ok(None) + } else { + Asn::try_from(value).map(Some) + } +} + +#[derive(Debug)] +enum ProxyCsvRowReaderData { + File(Lines>), + Raw(Vec), +} + +#[derive(Debug)] +/// An error that can occur when reading a Proxy CSV row. +pub struct ProxyCsvRowReaderError { + kind: ProxyCsvRowReaderErrorKind, +} + +#[derive(Debug)] +/// The kind of error that can occur when reading a Proxy CSV row. +pub enum ProxyCsvRowReaderErrorKind { + /// An I/O error occurred while reading the CSV row. + IoError(std::io::Error), + /// The CSV row is invalid, and could not be parsed. + InvalidRow(String), +} + +impl std::fmt::Display for ProxyCsvRowReaderError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.kind { + ProxyCsvRowReaderErrorKind::IoError(err) => write!(f, "I/O error: {}", err), + ProxyCsvRowReaderErrorKind::InvalidRow(row) => write!(f, "Invalid row: {}", row), + } + } +} + +impl std::error::Error for ProxyCsvRowReaderError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self.kind { + ProxyCsvRowReaderErrorKind::IoError(err) => Some(err), + ProxyCsvRowReaderErrorKind::InvalidRow(_) => None, + } + } +} + +impl From for ProxyCsvRowReaderError { + fn from(err: std::io::Error) -> Self { + Self { + kind: ProxyCsvRowReaderErrorKind::IoError(err), + } + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use itertools::Itertools; + + use crate::net::Protocol; + + use super::*; + + #[test] + fn test_parse_csv_bool() { + for (input, output) in &[ + ("1", Some(true)), + ("true", Some(true)), + ("True", Some(true)), + ("TRUE", Some(true)), + ("0", Some(false)), + ("false", Some(false)), + ("False", Some(false)), + ("FALSE", Some(false)), + ("null", Some(false)), + ("nil", Some(false)), + ("NULL", Some(false)), + ("NIL", Some(false)), + ("", Some(false)), + ("invalid", None), + ] { + assert_eq!(parse_csv_bool(input), *output); + } + } + + #[test] + fn test_parse_csv_opt_string_filter() { + for (input, output) in [ + ("", None), + ("value", Some("value")), + ("*", Some("*")), + ("Foo", Some("foo")), + (" ok ", Some("ok")), + (" NO ", Some("no")), + ] { + assert_eq!( + parse_csv_opt_string_filter(input) + .as_ref() + .map(|f| f.as_ref()), + output, + ); + } + } + + #[test] + fn test_parse_csv_opt_string_filter_is_any() { + let filter = parse_csv_opt_string_filter("*").unwrap(); + assert!(venndb::Any::is_any(&filter)); + } + + #[test] + fn test_parse_csv_row_happy_path() { + for (input, output) in [ + // most minimal + ( + "id,,,,,,,,,,authority,,,,,,,,", + Proxy { + id: NonEmptyString::from_static("id"), + address: ProxyAddress::from_str("authority").unwrap(), + tcp: false, + udp: false, + http: false, + https: false, + socks5: false, + socks5h: false, + datacenter: false, + residential: false, + mobile: false, + pool_id: None, + continent: None, + country: None, + state: None, + city: None, + carrier: None, + asn: None, + }, + ), + // more happy row tests + ( + "id,true,false,true,,false,,true,false,true,authority,pool_id,,country,,city,carrier,,Basic dXNlcm5hbWU6cGFzc3dvcmQ=", + Proxy { + id: NonEmptyString::from_static("id"), + address: ProxyAddress::from_str("username:password@authority").unwrap(), + tcp: true, + udp: false, + http: true, + https: false, + socks5: false, + socks5h: false, + datacenter: true, + residential: false, + mobile: true, + pool_id: Some("pool_id".into()), + continent: None, + country: Some("country".into()), + state: None, + city: Some("city".into()), + carrier: Some("carrier".into()), + asn: None, + }, + ), + ( + "123,1,0,False,,True,,null,false,true,host:1234,,americas,*,*,*,carrier,13335,", + Proxy { + id: NonEmptyString::from_static("123"), + address: ProxyAddress::from_str("host:1234").unwrap(), + tcp: true, + udp: false, + http: false, + https: false, + socks5: true, + socks5h: false, + datacenter: false, + residential: false, + mobile: true, + pool_id: None, + continent: Some("americas".into()), + country: Some("*".into()), + state: Some("*".into()), + city: Some("*".into()), + carrier: Some("carrier".into()), + asn: Some(Asn::from_static(13335)), + }, + ), + ( + "123,1,0,False,,True,,null,false,true,host:1234,,europe,*,,*,carrier,0", + Proxy { + id: NonEmptyString::from_static("123"), + address: ProxyAddress::from_str("host:1234").unwrap(), + tcp: true, + udp: false, + http: false, + https: false, + socks5: true, + socks5h: false, + datacenter: false, + residential: false, + mobile: true, + pool_id: None, + continent: Some("europe".into()), + country: Some("*".into()), + state: None, + city: Some("*".into()), + carrier: Some("carrier".into()), + asn: Some(Asn::unspecified()), + }, + ), + ( + "foo,1,0,1,,0,,1,0,0,bar,baz,,US,,,,", + Proxy { + id: NonEmptyString::from_static("foo"), + address: ProxyAddress::from_str("bar").unwrap(), + tcp: true, + udp: false, + http: true, + https: false, + socks5: false, + socks5h: false, + datacenter: true, + residential: false, + mobile: false, + pool_id: Some("baz".into()), + continent: None, + country: Some("us".into()), + state: None, + city: None, + carrier: None, + asn: None, + }, + ), + ] { + let proxy = parse_csv_row(input).unwrap(); + assert_eq!(proxy.id, output.id); + assert_eq!(proxy.address, output.address); + assert_eq!(proxy.tcp, output.tcp); + assert_eq!(proxy.udp, output.udp); + assert_eq!(proxy.http, output.http); + assert_eq!(proxy.socks5, output.socks5); + assert_eq!(proxy.datacenter, output.datacenter); + assert_eq!(proxy.residential, output.residential); + assert_eq!(proxy.mobile, output.mobile); + assert_eq!(proxy.pool_id, output.pool_id); + assert_eq!(proxy.continent, output.continent); + assert_eq!(proxy.country, output.country); + assert_eq!(proxy.state, output.state); + assert_eq!(proxy.city, output.city); + assert_eq!(proxy.carrier, output.carrier); + assert_eq!(proxy.asn, output.asn); + } + } + + #[test] + fn test_parse_csv_row_mistakes() { + for input in [ + // garbage rows + "", + ",", + ",,,,,,", + ",,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,", + // too many rows + "id,true,false,true,false,true,false,true,authority,pool_id,continent,country,state,city,carrier,15169,Basic dXNlcm5hbWU6cGFzc3dvcmQ=,", + // missing authority + "id,,,,,,,,,,,,,,,,", + // missing proxy id + ",,,,,,,,authority,,,,,,,,", + // invalid bool values + "id,foo,,,,,,,,,authority,,,,,,,,", + "id,,foo,,,,,,,,authority,,,,,,,,", + "id,,,foo,,,,,,,authority,,,,,,,,", + "id,,,,,foo,,,,,authority,,,,,,,,", + "id,,,,,,foo,,,,authority,,,,,,,,", + "id,,,,,,,,foo,,authority,,,,,,,,", + "id,,,,,,,foo,authority,,,,,,,,", + // invalid credentials + "id,,,,,,,,authority,,,,,:foo", + ] { + assert!(parse_csv_row(input).is_none(), "input: {}", input); + } + } + + #[tokio::test] + async fn test_proxy_csv_row_reader_happy_one_row() { + let mut reader = ProxyCsvRowReader::raw("id,true,false,true,,false,,true,false,true,authority,pool_id,continent,country,state,city,carrier,13335,Basic dXNlcm5hbWU6cGFzc3dvcmQ="); + let proxy = reader.next().await.unwrap().unwrap(); + + assert_eq!(proxy.id, "id"); + assert_eq!( + proxy.address, + ProxyAddress::from_str("username:password@authority").unwrap() + ); + assert!(proxy.tcp); + assert!(!proxy.udp); + assert!(proxy.http); + assert!(!proxy.socks5); + assert!(proxy.datacenter); + assert!(!proxy.residential); + assert!(proxy.mobile); + assert_eq!(proxy.pool_id, Some("pool_id".into())); + assert_eq!(proxy.continent, Some("continent".into())); + assert_eq!(proxy.country, Some("country".into())); + assert_eq!(proxy.state, Some("state".into())); + assert_eq!(proxy.city, Some("city".into())); + assert_eq!(proxy.carrier, Some("carrier".into())); + assert_eq!(proxy.asn, Some(Asn::from_static(13335))); + + // no more rows to read + assert!(reader.next().await.unwrap().is_none()); + } + + #[tokio::test] + async fn test_proxy_csv_row_reader_happy_multi_row() { + let mut reader = ProxyCsvRowReader::raw("id,true,false,false,true,true,false,true,false,true,authority,pool_id,continent,country,state,city,carrier,42,Basic dXNlcm5hbWU6cGFzc3dvcmQ=\nid2,1,0,0,0,0,0,1,0,0,authority2,pool_id2,continent2,country2,state2,city2,carrier2,1"); + + let proxy = reader.next().await.unwrap().unwrap(); + assert_eq!(proxy.id, "id"); + assert_eq!( + proxy.address, + ProxyAddress::from_str("username:password@authority").unwrap() + ); + assert!(proxy.tcp); + assert!(!proxy.udp); + assert!(!proxy.http); + assert!(proxy.https); + assert!(proxy.socks5); + assert!(!proxy.socks5h); + assert!(proxy.datacenter); + assert!(!proxy.residential); + assert!(proxy.mobile); + assert_eq!(proxy.pool_id, Some("pool_id".into())); + assert_eq!(proxy.continent, Some("continent".into())); + assert_eq!(proxy.country, Some("country".into())); + assert_eq!(proxy.state, Some("state".into())); + assert_eq!(proxy.city, Some("city".into())); + assert_eq!(proxy.carrier, Some("carrier".into())); + assert_eq!(proxy.asn, Some(Asn::from_static(42))); + + let proxy = reader.next().await.unwrap().unwrap(); + + assert_eq!(proxy.id, "id2"); + assert_eq!(proxy.address, ProxyAddress::from_str("authority2").unwrap()); + assert!(proxy.tcp); + assert!(!proxy.udp); + assert!(!proxy.http); + assert!(!proxy.https); + assert!(!proxy.socks5); + assert!(!proxy.socks5h); + assert!(proxy.datacenter); + assert!(!proxy.residential); + assert!(!proxy.mobile); + assert_eq!(proxy.pool_id, Some("pool_id2".into())); + assert_eq!(proxy.continent, Some("continent2".into())); + assert_eq!(proxy.country, Some("country2".into())); + assert_eq!(proxy.city, Some("city2".into())); + assert_eq!(proxy.state, Some("state2".into())); + assert_eq!(proxy.carrier, Some("carrier2".into())); + assert_eq!(proxy.asn, Some(Asn::from_static(1))); + + // no more rows to read + assert!(reader.next().await.unwrap().is_none()); + } + + #[tokio::test] + async fn test_proxy_csv_row_reader_failure_empty_data() { + let mut reader = ProxyCsvRowReader::raw(""); + assert!(reader.next().await.unwrap().is_none()); + } + + #[tokio::test] + async fn test_proxy_csv_row_reader_failure_invalid_row() { + let mut reader = ProxyCsvRowReader::raw(",,,,,,,,,,,"); + assert!(reader.next().await.is_err()); + } +} diff --git a/src/proxy/proxydb/internal.rs b/rama-proxy/src/proxydb/internal.rs similarity index 98% rename from src/proxy/proxydb/internal.rs rename to rama-proxy/src/proxydb/internal.rs index 80a5b945..01b26db2 100644 --- a/src/proxy/proxydb/internal.rs +++ b/rama-proxy/src/proxydb/internal.rs @@ -15,13 +15,16 @@ use tokio::{ fs::File, io::{AsyncBufReadExt, BufReader, Lines}, }; + +#[cfg(feature = "memory-db")] use venndb::VennDB; #[derive(Debug, Clone, Deserialize, VennDB)] -#[venndb(validator = proxydb_insert_validator)] +#[cfg_attr(feature = "memory-db", derive(VennDB))] +#[cfg_attr(feature = "memory-db", venndb(validator = proxydb_insert_validator))] /// The selected proxy to use to connect to the proxy. pub struct Proxy { - #[venndb(key)] + #[cfg_attr(feature = "memory-db", venndb(key))] /// Unique identifier of the proxy. pub id: NonEmptyString, @@ -55,31 +58,31 @@ pub struct Proxy { /// Proxy's IP originates from a mobile network. pub mobile: bool, - #[venndb(filter, any)] + #[cfg_attr(feature = "memory-db", venndb(filter, any))] /// Pool ID of the proxy. pub pool_id: Option, - #[venndb(filter, any)] + #[cfg_attr(feature = "memory-db", venndb(filter, any))] /// Continent of the proxy. pub continent: Option, - #[venndb(filter, any)] + #[cfg_attr(feature = "memory-db", venndb(filter, any))] /// Country of the proxy. pub country: Option, - #[venndb(filter, any)] + #[cfg_attr(feature = "memory-db", venndb(filter, any))] /// State of the proxy. pub state: Option, - #[venndb(filter, any)] + #[cfg_attr(feature = "memory-db", venndb(filter, any))] /// City of the proxy. pub city: Option, - #[venndb(filter, any)] + #[cfg_attr(feature = "memory-db", venndb(filter, any))] /// Mobile carrier of the proxy. pub carrier: Option, - #[venndb(filter, any)] + #[cfg_attr(feature = "memory-db", venndb(filter, any))] /// Autonomous System Number (ASN). pub asn: Option, } diff --git a/src/proxy/proxydb/layer.rs b/rama-proxy/src/proxydb/layer.rs similarity index 100% rename from src/proxy/proxydb/layer.rs rename to rama-proxy/src/proxydb/layer.rs diff --git a/src/proxy/proxydb/mod.rs b/rama-proxy/src/proxydb/mod.rs similarity index 99% rename from src/proxy/proxydb/mod.rs rename to rama-proxy/src/proxydb/mod.rs index 35f41ea1..8f0232f9 100644 --- a/src/proxy/proxydb/mod.rs +++ b/rama-proxy/src/proxydb/mod.rs @@ -12,7 +12,13 @@ mod update; pub use update::{proxy_db_updater, LiveUpdateProxyDB, LiveUpdateProxyDBSetter}; mod internal; -pub use internal::{Proxy, ProxyCsvRowReader, ProxyCsvRowReaderError, ProxyCsvRowReaderErrorKind}; +pub use internal::Proxy; + +#[cfg(feature = "csv")] +mod csv; + +#[cfg(feature = "csv")] +pub use csv::{ProxyCsvRowReader, ProxyCsvRowReaderError, ProxyCsvRowReaderErrorKind}; pub mod layer; diff --git a/src/proxy/proxydb/str.rs b/rama-proxy/src/proxydb/str.rs similarity index 100% rename from src/proxy/proxydb/str.rs rename to rama-proxy/src/proxydb/str.rs diff --git a/src/proxy/proxydb/test_proxydb_rows.csv b/rama-proxy/src/proxydb/test_proxydb_rows.csv similarity index 100% rename from src/proxy/proxydb/test_proxydb_rows.csv rename to rama-proxy/src/proxydb/test_proxydb_rows.csv diff --git a/src/proxy/proxydb/update.rs b/rama-proxy/src/proxydb/update.rs similarity index 100% rename from src/proxy/proxydb/update.rs rename to rama-proxy/src/proxydb/update.rs diff --git a/src/proxy/username.rs b/rama-proxy/src/username.rs similarity index 100% rename from src/proxy/username.rs rename to rama-proxy/src/username.rs diff --git a/rama-tls/Cargo.toml b/rama-tls/Cargo.toml new file mode 100644 index 00000000..1018b328 --- /dev/null +++ b/rama-tls/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "rama-tls" +description = "user-agent (UA) support for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = [] +rustls = ["dep:rustls", "dep:rustls-native-certs", "dep:rustls-pemfile", "dep:rustls-pki-types", "dep:webpki-roots", "dep:tokio-rustls"] +boring = ["dep:boring", "dep:tokio-boring", "nom"] +rustls-ring = ["rustls", "tokio-rustls/ring", "rustls/ring"] + +[dependencies] +boring = { workspace = true, optional = true } +nom = { workspace = true, optional = true } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rcgen = { workspace = true } +rustls = { workspace = true, optional = true } +rustls-native-certs = { workspace = true, optional = true } +rustls-pemfile = { workspace = true, optional = true } +rustls-pki-types = { workspace = true, optional = true } +tokio-boring = { workspace = true, optional = true } +tokio-rustls = { workspace = true, optional = true } +webpki-roots = { workspace = true, optional = true } + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-tls/README.md b/rama-tls/README.md new file mode 100644 index 00000000..dce14a54 --- /dev/null +++ b/rama-tls/README.md @@ -0,0 +1,50 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-tls.svg +[crates-url]: https://crates.io/crates/rama-tls +[docs-badge]: https://img.shields.io/docsrs/rama-tls/latest +[docs-url]: https://docs.rs/rama-tls/latest/rama_tls/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-tls + +User-Agent (UA) support for `rama`. + +This crate only focusses on the majority user-agents within +the web space. Feature requests are welcome, but keep this scope in mind. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/src/tls/backend/boring/client/http.rs b/rama-tls/src/backend/boring/client/http.rs similarity index 100% rename from src/tls/backend/boring/client/http.rs rename to rama-tls/src/backend/boring/client/http.rs diff --git a/src/tls/backend/boring/client/mod.rs b/rama-tls/src/backend/boring/client/mod.rs similarity index 100% rename from src/tls/backend/boring/client/mod.rs rename to rama-tls/src/backend/boring/client/mod.rs diff --git a/src/tls/backend/boring/mod.rs b/rama-tls/src/backend/boring/mod.rs similarity index 100% rename from src/tls/backend/boring/mod.rs rename to rama-tls/src/backend/boring/mod.rs diff --git a/src/tls/backend/boring/server/config.rs b/rama-tls/src/backend/boring/server/config.rs similarity index 100% rename from src/tls/backend/boring/server/config.rs rename to rama-tls/src/backend/boring/server/config.rs diff --git a/src/tls/backend/boring/server/layer.rs b/rama-tls/src/backend/boring/server/layer.rs similarity index 100% rename from src/tls/backend/boring/server/layer.rs rename to rama-tls/src/backend/boring/server/layer.rs diff --git a/src/tls/backend/boring/server/mod.rs b/rama-tls/src/backend/boring/server/mod.rs similarity index 100% rename from src/tls/backend/boring/server/mod.rs rename to rama-tls/src/backend/boring/server/mod.rs diff --git a/src/tls/backend/boring/server/service.rs b/rama-tls/src/backend/boring/server/service.rs similarity index 100% rename from src/tls/backend/boring/server/service.rs rename to rama-tls/src/backend/boring/server/service.rs diff --git a/src/tls/backend/mod.rs b/rama-tls/src/backend/mod.rs similarity index 100% rename from src/tls/backend/mod.rs rename to rama-tls/src/backend/mod.rs diff --git a/src/tls/backend/rustls/client/http.rs b/rama-tls/src/backend/rustls/client/http.rs similarity index 100% rename from src/tls/backend/rustls/client/http.rs rename to rama-tls/src/backend/rustls/client/http.rs diff --git a/src/tls/backend/rustls/client/mod.rs b/rama-tls/src/backend/rustls/client/mod.rs similarity index 100% rename from src/tls/backend/rustls/client/mod.rs rename to rama-tls/src/backend/rustls/client/mod.rs diff --git a/src/tls/backend/rustls/mod.rs b/rama-tls/src/backend/rustls/mod.rs similarity index 100% rename from src/tls/backend/rustls/mod.rs rename to rama-tls/src/backend/rustls/mod.rs diff --git a/src/tls/backend/rustls/server/client_config.rs b/rama-tls/src/backend/rustls/server/client_config.rs similarity index 100% rename from src/tls/backend/rustls/server/client_config.rs rename to rama-tls/src/backend/rustls/server/client_config.rs diff --git a/src/tls/backend/rustls/server/layer.rs b/rama-tls/src/backend/rustls/server/layer.rs similarity index 100% rename from src/tls/backend/rustls/server/layer.rs rename to rama-tls/src/backend/rustls/server/layer.rs diff --git a/src/tls/backend/rustls/server/mod.rs b/rama-tls/src/backend/rustls/server/mod.rs similarity index 100% rename from src/tls/backend/rustls/server/mod.rs rename to rama-tls/src/backend/rustls/server/mod.rs diff --git a/src/tls/backend/rustls/server/service.rs b/rama-tls/src/backend/rustls/server/service.rs similarity index 100% rename from src/tls/backend/rustls/server/service.rs rename to rama-tls/src/backend/rustls/server/service.rs diff --git a/src/tls/backend/rustls/verify.rs b/rama-tls/src/backend/rustls/verify.rs similarity index 100% rename from src/tls/backend/rustls/verify.rs rename to rama-tls/src/backend/rustls/verify.rs diff --git a/src/tls/client/hello/boring.rs b/rama-tls/src/client/hello/boring.rs similarity index 100% rename from src/tls/client/hello/boring.rs rename to rama-tls/src/client/hello/boring.rs diff --git a/src/tls/client/hello/mod.rs b/rama-tls/src/client/hello/mod.rs similarity index 100% rename from src/tls/client/hello/mod.rs rename to rama-tls/src/client/hello/mod.rs diff --git a/src/tls/client/hello/rustls.rs b/rama-tls/src/client/hello/rustls.rs similarity index 100% rename from src/tls/client/hello/rustls.rs rename to rama-tls/src/client/hello/rustls.rs diff --git a/src/tls/client/mod.rs b/rama-tls/src/client/mod.rs similarity index 100% rename from src/tls/client/mod.rs rename to rama-tls/src/client/mod.rs diff --git a/src/tls/client/parser.rs b/rama-tls/src/client/parser.rs similarity index 100% rename from src/tls/client/parser.rs rename to rama-tls/src/client/parser.rs diff --git a/src/tls/enums/mod.rs b/rama-tls/src/enums/mod.rs similarity index 100% rename from src/tls/enums/mod.rs rename to rama-tls/src/enums/mod.rs diff --git a/src/tls/enums/rustls.rs b/rama-tls/src/enums/rustls.rs similarity index 100% rename from src/tls/enums/rustls.rs rename to rama-tls/src/enums/rustls.rs diff --git a/src/tls/mod.rs b/rama-tls/src/lib.rs similarity index 50% rename from src/tls/mod.rs rename to rama-tls/src/lib.rs index 2faff8ac..df1afdc4 100644 --- a/src/tls/mod.rs +++ b/rama-tls/src/lib.rs @@ -1,4 +1,58 @@ //! TLS module for Rama. +//! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] mod enums; use client::ClientHello; diff --git a/rama-ua/Cargo.toml b/rama-ua/Cargo.toml new file mode 100644 index 00000000..79350c63 --- /dev/null +++ b/rama-ua/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "rama-ua" +description = "user-agent (UA) support for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[dependencies] +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +serde = { workspace = true, features = ["derive"] } + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-ua/README.md b/rama-ua/README.md new file mode 100644 index 00000000..60dd7b93 --- /dev/null +++ b/rama-ua/README.md @@ -0,0 +1,50 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-ua.svg +[crates-url]: https://crates.io/crates/rama-ua +[docs-badge]: https://img.shields.io/docsrs/rama-ua/latest +[docs-url]: https://docs.rs/rama-ua/latest/rama_ua/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-ua + +User-Agent (UA) support for `rama`. + +This crate only focusses on the majority user-agents within +the web space. Feature requests are welcome, but keep this scope in mind. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/src/ua/info.rs b/rama-ua/src/info.rs similarity index 99% rename from src/ua/info.rs rename to rama-ua/src/info.rs index 107c8518..bfbb1fa5 100644 --- a/src/ua/info.rs +++ b/rama-ua/src/info.rs @@ -1,6 +1,6 @@ use super::parse_http_user_agent_header; -use crate::error::{error, OpaqueError}; -use crate::utils::macros::match_ignore_ascii_case_str; +use rama_core::match_ignore_ascii_case_str; +use rama_core::{error, OpaqueError}; use serde::{Deserialize, Deserializer, Serialize}; use std::{convert::Infallible, fmt, str::FromStr}; diff --git a/src/ua/mod.rs b/rama-ua/src/lib.rs similarity index 59% rename from src/ua/mod.rs rename to rama-ua/src/lib.rs index 818fad65..691638dc 100644 --- a/src/ua/mod.rs +++ b/rama-ua/src/lib.rs @@ -7,6 +7,15 @@ //! Learn more about User Agents (UA) and why Rama supports it //! at . //! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: +//! //! # Remarks //! //! We classify only the majority User Agents, and we do not classify all User Agents: @@ -74,6 +83,51 @@ //! # } //! ``` +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + mod info; pub use info::{ DeviceKind, HttpAgent, PlatformKind, TlsAgent, UserAgent, UserAgentInfo, UserAgentKind, @@ -82,8 +136,26 @@ pub use info::{ mod parse; use parse::parse_http_user_agent_header; -mod layer; -pub use layer::{UserAgentClassifier, UserAgentClassifierLayer, UserAgentOverwrites}; +/// Information that can be used to overwrite the [`UserAgent`] of a [`Request`]. +/// +/// Used by the [`UserAgentClassifier`] to overwrite the specified +/// information duing the classification of the [`UserAgent`]. +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct UserAgentOverwrites { + /// Overwrite the [`UserAgent`] of the [`Request`] with a custom value. + /// + /// This value will be used instead of + /// [the 'User-Agent' http header](crate::http::headers::UserAgent) value. + /// + /// This is useful in case you cannot set the User-Agent header in your request. + pub ua: Option, + /// Overwrite the [`HttpAgent`] of the [`Request`] with a custom value. + pub http: Option, + /// Overwrite the [`TlsAgent`] of the [`Request`] with a custom value. + pub tls: Option, + /// Preserve the original [`UserAgent`] header of the [`Request`]. + pub preserve_ua: Option, +} #[cfg(test)] mod parse_tests; diff --git a/src/ua/parse.rs b/rama-ua/src/parse.rs similarity index 100% rename from src/ua/parse.rs rename to rama-ua/src/parse.rs diff --git a/src/ua/parse_tests.rs b/rama-ua/src/parse_tests.rs similarity index 100% rename from src/ua/parse_tests.rs rename to rama-ua/src/parse_tests.rs diff --git a/src/lib.rs b/src/lib.rs index b284d424..626ba719 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,28 +274,29 @@ #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] -#[cfg(feature = "telemetry")] -pub mod telemetry; - pub use ::rama_core::{ - combinators, context, dns, error, graceful, layer, matcher, net, rt, service, Context, Layer, - Service, + combinators, context, dns, error, graceful, layer, matcher, net, rt, service, stream, Context, + Layer, Service, }; -pub mod stream; - pub mod tcp; +#[cfg(feature = "telemetry")] +pub use ::rama_core::telemetry; + #[cfg(feature = "tls")] -pub mod tls; +pub use ::rama_tls as tls; + +#[cfg(feature = "http")] +pub use ::rama_http as http; -pub mod http; +// TODO: integrate http-backend in here somehow... -pub mod proxy; -pub mod ua; +#[cfg(feature = "proxy")] +pub use ::rama_proxy as proxy; + +#[cfg(feature = "ua")] +pub use ::rama_ua as ua; #[cfg(feature = "cli")] pub mod cli; - -#[macro_use] -pub mod utils; From 0f5ca8d6f4a85e391b2f2dea9e8341350f718df0 Mon Sep 17 00:00:00 2001 From: glendc Date: Tue, 3 Sep 2024 10:09:00 +0200 Subject: [PATCH 02/24] fix: rama-utils, rama-http-types, rama-macros, rama-core --- Cargo.lock | 23 +- Cargo.toml | 5 +- rama-core/Cargo.toml | 1 + rama-core/src/context/mod.rs | 3 +- rama-core/src/context/state.rs | 3 +- rama-core/src/dns/mod.rs | 47 ++- rama-core/src/layer/add_extension.rs | 2 +- rama-core/src/layer/consume_err.rs | 2 +- rama-core/src/layer/get_extension.rs | 2 +- rama-core/src/layer/hijack.rs | 2 +- rama-core/src/layer/limit/mod.rs | 2 +- .../src/layer/limit/policy/concurrent.rs | 71 +--- rama-core/src/layer/map_err.rs | 2 +- rama-core/src/layer/map_request.rs | 2 +- rama-core/src/layer/map_response.rs | 2 +- rama-core/src/layer/map_result.rs | 2 +- rama-core/src/layer/map_state.rs | 2 +- rama-core/src/layer/timeout/mod.rs | 2 +- rama-core/src/layer/trace_err.rs | 2 +- rama-core/src/lib.rs | 5 +- rama-core/src/matcher/mod.rs | 2 +- rama-core/src/matcher/op_and.rs | 2 +- rama-core/src/matcher/op_or.rs | 2 +- rama-core/src/service/svc.rs | 4 +- rama-core/src/{utils => }/username/compose.rs | 2 +- rama-core/src/{utils => }/username/mod.rs | 0 rama-core/src/{utils => }/username/parse.rs | 4 +- rama-core/src/utils/mod.rs | 15 - rama-http-types/Cargo.toml | 2 +- rama-http-types/src/lib.rs | 2 +- .../src/response/append_headers.rs | 10 +- rama-http-types/src/response/form.rs | 8 +- rama-http-types/src/response/html.rs | 2 +- rama-http-types/src/response/into_response.rs | 2 +- .../src/response/into_response_parts.rs | 10 +- rama-http-types/src/response/json.rs | 13 +- rama-http-types/src/response/mod.rs | 14 +- rama-http/src/client/conn.rs | 2 +- rama-http/src/client/ext.rs | 4 +- rama-http/src/layer/auth/add_authorization.rs | 2 +- .../layer/auth/async_require_authorization.rs | 2 +- rama-http/src/layer/body_limit.rs | 2 +- rama-http/src/layer/catch_panic.rs | 2 +- rama-http/src/layer/compression/service.rs | 2 +- rama-http/src/layer/cors/mod.rs | 2 +- .../layer/decompression/request/service.rs | 2 +- rama-http/src/layer/decompression/service.rs | 2 +- rama-http/src/layer/dns/dns_map/service.rs | 2 +- rama-http/src/layer/dns/dns_resolve/mod.rs | 6 +- .../src/layer/dns/dns_resolve/service.rs | 2 +- .../layer/dns/dns_resolve/username_parser.rs | 2 +- rama-http/src/layer/error_handling.rs | 2 +- rama-http/src/layer/follow_redirect/mod.rs | 2 +- .../src/layer/forwarded/set_forwarded.rs | 2 +- rama-http/src/layer/header_config.rs | 2 +- rama-http/src/layer/header_option_value.rs | 2 +- rama-http/src/layer/map_request_body.rs | 2 +- rama-http/src/layer/map_response_body.rs | 2 +- rama-http/src/layer/normalize_path.rs | 2 +- rama-http/src/layer/opentelemetry.rs | 6 +- rama-http/src/layer/propagate_headers.rs | 2 +- rama-http/src/layer/proxy_auth.rs | 6 +- rama-http/src/layer/remove_header/request.rs | 2 +- rama-http/src/layer/remove_header/response.rs | 2 +- rama-http/src/layer/request_id.rs | 2 +- .../src/layer/required_header/request.rs | 2 +- .../src/layer/required_header/response.rs | 2 +- rama-http/src/layer/retry/mod.rs | 2 +- rama-http/src/layer/sensitive_headers.rs | 2 +- rama-http/src/layer/set_header/request.rs | 2 +- rama-http/src/layer/set_header/response.rs | 2 +- rama-http/src/layer/set_status.rs | 2 +- rama-http/src/layer/timeout.rs | 2 +- rama-http/src/layer/trace/on_eos.rs | 2 +- rama-http/src/layer/trace/on_failure.rs | 2 +- rama-http/src/layer/trace/on_response.rs | 2 +- rama-http/src/layer/trace/service.rs | 2 +- rama-http/src/layer/traffic_writer/request.rs | 2 +- .../src/layer/traffic_writer/response.rs | 2 +- rama-http/src/layer/ua.rs | 6 +- rama-http/src/layer/upgrade/service.rs | 2 +- rama-http/src/layer/util/content_encoding.rs | 2 +- .../validate_request_header.rs | 2 +- rama-http/src/matcher/path/mod.rs | 2 +- rama-http/src/server/hyper_conn.rs | 2 +- .../service/web/endpoint/extract/authority.rs | 2 +- .../web/endpoint/extract/body/bytes.rs | 2 +- .../service/web/endpoint/extract/body/form.rs | 2 +- .../service/web/endpoint/extract/body/json.rs | 2 +- .../service/web/endpoint/extract/body/mod.rs | 2 +- .../service/web/endpoint/extract/body/text.rs | 2 +- .../service/web/endpoint/extract/extension.rs | 2 +- .../src/service/web/endpoint/extract/host.rs | 2 +- .../src/service/web/endpoint/extract/path.rs | 2 +- .../src/service/web/endpoint/extract/query.rs | 2 +- rama-http/src/service/web/endpoint/service.rs | 2 +- rama-macros-proc/src/lib.rs | 115 ------- rama-macros/Cargo.toml | 12 +- rama-macros/README.md | 4 +- .../src/as_ref.rs | 0 .../src/attr_parsing.rs | 0 rama-macros/src/lib.rs | 309 +++--------------- .../src/type_parsing.rs | 0 .../tests/as_ref/fail/generics.rs | 0 .../tests/as_ref/fail/generics.stderr | 0 .../tests/as_ref/fail/wrap_ambiguity.rs | 0 .../tests/as_ref/fail/wrap_ambiguity.stderr | 0 .../tests/as_ref/fail/wrap_no_arc.rs | 0 .../tests/as_ref/fail/wrap_no_arc.stderr | 0 .../tests/as_ref/pass/basic.rs | 0 .../tests/as_ref/pass/reference-types.rs | 0 .../tests/as_ref/pass/skip.rs | 0 .../tests/as_ref/pass/wrap.rs | 0 .../tests/as_ref/pass/wrap_skip.rs | 0 .../client/layer/proxy_connector/connector.rs | 4 +- .../client/layer/proxy_connector/service.rs | 2 +- rama-proxy/src/proxydb/internal.rs | 2 +- rama-proxy/src/proxydb/layer.rs | 2 +- rama-proxy/src/username.rs | 6 +- rama-tls/src/backend/boring/client/http.rs | 4 +- rama-tls/src/backend/boring/server/service.rs | 2 +- rama-tls/src/backend/rustls/client/http.rs | 4 +- rama-tls/src/backend/rustls/server/layer.rs | 4 +- rama-tls/src/backend/rustls/server/service.rs | 6 +- {rama-macros-proc => rama-utils}/Cargo.toml | 19 +- {rama-macros-proc => rama-utils}/README.md | 16 +- .../src}/backoff/exponential.rs | 3 +- .../utils => rama-utils/src}/backoff/mod.rs | 27 ++ .../src/utils => rama-utils/src}/future.rs | 0 .../src/utils => rama-utils/src}/info.rs | 0 .../src/utils => rama-utils/src}/latency.rs | 0 rama-utils/src/lib.rs | 73 +++++ .../src => rama-utils/src/macros}/error.rs | 0 rama-utils/src/macros/mod.rs | 268 +++++++++++++++ .../src => rama-utils/src/macros}/str.rs | 0 .../src/utils => rama-utils/src}/rng.rs | 0 .../src/utils => rama-utils/src}/str.rs | 2 +- .../src}/test_helpers/mod.rs | 0 src/cli/args.rs | 2 +- src/cli/forward.rs | 2 +- src/context.rs | 63 ++++ src/lib.rs | 4 +- src/tcp/client/service/forward.rs | 2 +- 143 files changed, 700 insertions(+), 669 deletions(-) rename rama-core/src/{utils => }/username/compose.rs (99%) rename rama-core/src/{utils => }/username/mod.rs (100%) rename rama-core/src/{utils => }/username/parse.rs (99%) delete mode 100644 rama-core/src/utils/mod.rs delete mode 100644 rama-macros-proc/src/lib.rs rename {rama-macros-proc => rama-macros}/src/as_ref.rs (100%) rename {rama-macros-proc => rama-macros}/src/attr_parsing.rs (100%) rename {rama-macros-proc => rama-macros}/src/type_parsing.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/fail/generics.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/fail/generics.stderr (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/fail/wrap_ambiguity.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/fail/wrap_ambiguity.stderr (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/fail/wrap_no_arc.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/fail/wrap_no_arc.stderr (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/pass/basic.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/pass/reference-types.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/pass/skip.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/pass/wrap.rs (100%) rename {rama-macros-proc => rama-macros}/tests/as_ref/pass/wrap_skip.rs (100%) rename {rama-macros-proc => rama-utils}/Cargo.toml (54%) rename {rama-macros-proc => rama-utils}/README.md (83%) rename {rama-core/src/utils => rama-utils/src}/backoff/exponential.rs (99%) rename {rama-core/src/utils => rama-utils/src}/backoff/mod.rs (73%) rename {rama-core/src/utils => rama-utils/src}/future.rs (100%) rename {rama-core/src/utils => rama-utils/src}/info.rs (100%) rename {rama-core/src/utils => rama-utils/src}/latency.rs (100%) create mode 100644 rama-utils/src/lib.rs rename {rama-macros/src => rama-utils/src/macros}/error.rs (100%) create mode 100644 rama-utils/src/macros/mod.rs rename {rama-macros/src => rama-utils/src/macros}/str.rs (100%) rename {rama-core/src/utils => rama-utils/src}/rng.rs (100%) rename {rama-core/src/utils => rama-utils/src}/str.rs (98%) rename {rama-core/src/utils => rama-utils/src}/test_helpers/mod.rs (100%) create mode 100644 src/context.rs diff --git a/Cargo.lock b/Cargo.lock index 311a2de8..edc60e48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1769,6 +1769,7 @@ dependencies = [ "pin-project-lite", "rama-core", "rama-http", + "rama-macros", "rama-proxy", "rama-tls", "rama-ua", @@ -1823,6 +1824,7 @@ dependencies = [ "rama-error", "rama-http-types", "rama-macros", + "rama-utils", "serde", "tokio", "tokio-graceful", @@ -1895,7 +1897,7 @@ dependencies = [ "paste", "pin-project-lite", "rama-error", - "rama-macros", + "rama-utils", "serde", "serde_html_form", "serde_json", @@ -1908,13 +1910,6 @@ dependencies = [ [[package]] name = "rama-macros" version = "0.2.0-alpha.2" -dependencies = [ - "rama-macros-proc", -] - -[[package]] -name = "rama-macros-proc" -version = "0.2.0-alpha.2" dependencies = [ "proc-macro2", "quote", @@ -1984,6 +1979,18 @@ dependencies = [ "serde", ] +[[package]] +name = "rama-utils" +version = "0.2.0-alpha.2" +dependencies = [ + "parking_lot", + "pin-project-lite", + "quickcheck", + "serde", + "tokio", + "tokio-test", +] + [[package]] name = "rand" version = "0.8.5" diff --git a/Cargo.toml b/Cargo.toml index e4dd9eff..1b48bb8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,18 +2,18 @@ members = [ ".", "fuzz", - "rama-cli", + "rama-utils", "rama-core", "rama-error", "rama-http", "rama-http-backend", "rama-http-types", "rama-macros", - "rama-macros-proc", "rama-net", "rama-proxy", "rama-tls", "rama-ua", + "rama-cli", ] [workspace.package] @@ -175,6 +175,7 @@ parking_lot = { workspace = true } paste = { workspace = true } percent-encoding = { workspace = true } pin-project-lite = { workspace = true } +rama-macros = { version = "0.2.0-alpha.2", path = "rama-macros" } rama-core = { version = "0.2.0-alpha.2", path = "rama-core" } rama-http = { version = "0.2.0-alpha.2", path = "rama-http", optional = true } rama-proxy = { version = "0.2.0-alpha.2", path = "rama-proxy", optional = true } diff --git a/rama-core/Cargo.toml b/rama-core/Cargo.toml index baa06859..0eb96eec 100644 --- a/rama-core/Cargo.toml +++ b/rama-core/Cargo.toml @@ -34,6 +34,7 @@ paste = { workspace = true } pin-project-lite = { workspace = true } rama-error = { version = "0.2.0-alpha.2", path = "../rama-error" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-macros = { version = "0.2.0-alpha.2", path = "../rama-macros" } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } diff --git a/rama-core/src/context/mod.rs b/rama-core/src/context/mod.rs index 5fe95c49..a37e55a9 100644 --- a/rama-core/src/context/mod.rs +++ b/rama-core/src/context/mod.rs @@ -30,7 +30,6 @@ //! //! [`rama`]: crate //! -//! //! ## State Wraps //! //! [`rama`] was built from the ground up to operate on and between different layers of the network stack. @@ -118,7 +117,7 @@ use crate::{dns::Dns, rt::Executor}; use std::{fmt, future::Future, sync::Arc}; use tokio::task::JoinHandle; -pub use rama_macros::AsRef; +pub use ::rama_macros::AsRef; mod extensions; #[doc(inline)] diff --git a/rama-core/src/context/state.rs b/rama-core/src/context/state.rs index f4f0cb6f..2918c1e9 100644 --- a/rama-core/src/context/state.rs +++ b/rama-core/src/context/state.rs @@ -1,11 +1,10 @@ #[cfg(test)] mod test { + use crate::context::AsRef; use std::ops::Deref; use std::sync::atomic::AtomicU64; use std::sync::Arc; - use crate::context::AsRef; - struct Database; #[derive(AsRef)] diff --git a/rama-core/src/dns/mod.rs b/rama-core/src/dns/mod.rs index 81c8021f..29b81e77 100644 --- a/rama-core/src/dns/mod.rs +++ b/rama-core/src/dns/mod.rs @@ -5,20 +5,20 @@ //! //! [`Context::dns`]: crate::Context::dns -use std::{ - collections::HashMap, - net::{IpAddr, Ipv4Addr, Ipv6Addr}, - sync::Arc, - fmt, +use crate::{ + combinators::Either, + error::{ErrorContext, OpaqueError}, }; use hickory_resolver::{ config::{ResolverConfig, ResolverOpts}, proto::rr::rdata::{A, AAAA}, Name as DnsName, TokioAsyncResolver, }; -use crate::{ - combinators::Either, - error::{ErrorContext, OpaqueError}, +use std::{ + collections::HashMap, + fmt, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, + sync::Arc, }; #[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -45,15 +45,16 @@ pub trait TryIntoName: Sized { fn try_into_name(self) -> Result; } -impl TryIntoName for Name -{ +impl TryIntoName for Name { fn try_into_name(self) -> Result { Ok(self) } } impl TryIntoName for T -where T: TryInto { +where + T: TryInto, +{ fn try_into_name(self) -> Result { self.try_into() } @@ -62,21 +63,27 @@ where T: TryInto { impl<'a> TryIntoName for &'a str { /// Performs a utf8, IDNA or punycode, translation of the `str` into `Name` fn try_into_name(self) -> Result { - DnsName::from_utf8(self).map(Name).context("try to convert &'a str into domain") + DnsName::from_utf8(self) + .map(Name) + .context("try to convert &'a str into domain") } } impl TryIntoName for String { /// Performs a utf8, IDNA or punycode, translation of the `String` into `Name` fn try_into_name(self) -> Result { - DnsName::from_utf8(self).map(Name).context("try to convert String into domain") + DnsName::from_utf8(self) + .map(Name) + .context("try to convert String into domain") } } impl TryIntoName for &String { /// Performs a utf8, IDNA or punycode, translation of the `&String` into `Name` fn try_into_name(self) -> Result { - DnsName::from_utf8(self).map(Name).context("try to convert &String into domain") + DnsName::from_utf8(self) + .map(Name) + .context("try to convert &String into domain") } } @@ -142,11 +149,7 @@ impl Dns { ) -> Result, OpaqueError> { let name = Name::fqdn_from_domain(name)?; - if let Some(addresses) = self - .overwrites - .as_ref() - .and_then(|cache| cache.get(&name)) - { + if let Some(addresses) = self.overwrites.as_ref().and_then(|cache| cache.get(&name)) { return Ok(Either::A(addresses.clone().into_iter().filter_map( |ip| match ip { IpAddr::V4(ip) => Some(ip), @@ -184,11 +187,7 @@ impl Dns { ) -> Result, OpaqueError> { let name = Name::fqdn_from_domain(name)?; - if let Some(addresses) = self - .overwrites - .as_ref() - .and_then(|cache| cache.get(&name)) - { + if let Some(addresses) = self.overwrites.as_ref().and_then(|cache| cache.get(&name)) { return Ok(Either::A(addresses.clone().into_iter().filter_map( |ip| match ip { IpAddr::V4(_) => None, diff --git a/rama-core/src/layer/add_extension.rs b/rama-core/src/layer/add_extension.rs index b37a3cf6..22466104 100644 --- a/rama-core/src/layer/add_extension.rs +++ b/rama-core/src/layer/add_extension.rs @@ -51,8 +51,8 @@ //! # } //! ``` -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// [`Layer`] for adding some shareable value to incoming [Context]. diff --git a/rama-core/src/layer/consume_err.rs b/rama-core/src/layer/consume_err.rs index 6676e585..fa315e9d 100644 --- a/rama-core/src/layer/consume_err.rs +++ b/rama-core/src/layer/consume_err.rs @@ -1,5 +1,5 @@ -use crate::utils::macros::define_inner_service_accessors; use crate::{error::BoxError, Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{convert::Infallible, fmt}; use sealed::{DefaulResponse, StaticResponse, Trace}; diff --git a/rama-core/src/layer/get_extension.rs b/rama-core/src/layer/get_extension.rs index 0d5fca25..f0347682 100644 --- a/rama-core/src/layer/get_extension.rs +++ b/rama-core/src/layer/get_extension.rs @@ -2,8 +2,8 @@ //! //! [Context]: https://docs.rs/rama/latest/rama/context/struct.Context.html -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, future::Future, marker::PhantomData}; /// [`Layer`] for adding some shareable value to incoming [Context]. diff --git a/rama-core/src/layer/hijack.rs b/rama-core/src/layer/hijack.rs index 8bd0b4e4..4a15257d 100644 --- a/rama-core/src/layer/hijack.rs +++ b/rama-core/src/layer/hijack.rs @@ -7,8 +7,8 @@ //! [`Service`]: crate //! [`Matcher`]: crate::matcher::Matcher -use crate::utils::macros::define_inner_service_accessors; use crate::{context::Extensions, matcher::Matcher, Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; /// Middleware to hijack request to a [`Service`] which match using a [`Matcher`]. /// diff --git a/rama-core/src/layer/limit/mod.rs b/rama-core/src/layer/limit/mod.rs index bba0b17c..7dff282d 100644 --- a/rama-core/src/layer/limit/mod.rs +++ b/rama-core/src/layer/limit/mod.rs @@ -5,8 +5,8 @@ use std::fmt; use crate::error::BoxError; -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Service}; +use rama_utils::macros::define_inner_service_accessors; pub mod policy; use policy::UnlimitedPolicy; diff --git a/rama-core/src/layer/limit/policy/concurrent.rs b/rama-core/src/layer/limit/policy/concurrent.rs index 57668974..19ca4fc8 100644 --- a/rama-core/src/layer/limit/policy/concurrent.rs +++ b/rama-core/src/layer/limit/policy/concurrent.rs @@ -24,9 +24,9 @@ //! ``` use super::{Policy, PolicyOutput, PolicyResult}; -use crate::utils::backoff::Backoff; use crate::Context; use parking_lot::Mutex; +use rama_utils::backoff::Backoff; use std::fmt; use std::sync::Arc; @@ -141,49 +141,6 @@ where } } -impl Policy for ConcurrentPolicy, C> -where - B: Backoff, - C: ConcurrentTracker, - State: Send + Sync + 'static, - Request: Send + 'static, -{ - type Guard = C::Guard; - type Error = C::Error; - - async fn check( - &self, - ctx: Context, - request: Request, - ) -> PolicyResult { - let tracker_err = match self.tracker.try_access() { - Ok(guard) => { - return PolicyResult { - ctx, - request, - output: PolicyOutput::Ready(guard), - } - } - Err(err) => err, - }; - let output = match &self.backoff { - Some(backoff) => { - if !backoff.next_backoff().await { - PolicyOutput::Abort(tracker_err) - } else { - PolicyOutput::Retry - } - } - None => PolicyOutput::Abort(tracker_err), - }; - PolicyResult { - ctx, - request, - output, - } - } -} - /// The error that indicates the request is aborted, /// because the concurrent request limit is reached. #[derive(Debug)] @@ -197,32 +154,6 @@ impl std::fmt::Display for LimitReached { impl std::error::Error for LimitReached {} -impl Policy for ConcurrentPolicy<(), C> -where - State: Send + Sync + 'static, - Request: Send + 'static, - C: ConcurrentTracker, -{ - type Guard = C::Guard; - type Error = C::Error; - - async fn check( - &self, - ctx: Context, - request: Request, - ) -> PolicyResult { - let output = match self.tracker.try_access() { - Ok(guard) => PolicyOutput::Ready(guard), - Err(err) => PolicyOutput::Abort(err), - }; - PolicyResult { - ctx, - request, - output, - } - } -} - /// The tracker trait that can be implemented to provide custom concurrent request tracking. /// /// By default [`ConcurrentCounter`] is provided, but in case you need multi-instance tracking, diff --git a/rama-core/src/layer/map_err.rs b/rama-core/src/layer/map_err.rs index d1b5263d..c749c742 100644 --- a/rama-core/src/layer/map_err.rs +++ b/rama-core/src/layer/map_err.rs @@ -1,5 +1,5 @@ -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Maps this service's error value to a different value. diff --git a/rama-core/src/layer/map_request.rs b/rama-core/src/layer/map_request.rs index 49d23206..07be3123 100644 --- a/rama-core/src/layer/map_request.rs +++ b/rama-core/src/layer/map_request.rs @@ -1,5 +1,5 @@ -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; use std::future::Future; diff --git a/rama-core/src/layer/map_response.rs b/rama-core/src/layer/map_response.rs index 611e70b7..4da7213d 100644 --- a/rama-core/src/layer/map_response.rs +++ b/rama-core/src/layer/map_response.rs @@ -1,5 +1,5 @@ -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Maps this service's response value to a different value. diff --git a/rama-core/src/layer/map_result.rs b/rama-core/src/layer/map_result.rs index 804d2f5f..eddfba75 100644 --- a/rama-core/src/layer/map_result.rs +++ b/rama-core/src/layer/map_result.rs @@ -1,5 +1,5 @@ -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Maps this service's result type (`Result`) diff --git a/rama-core/src/layer/map_state.rs b/rama-core/src/layer/map_state.rs index fd9fae10..bdb2ea35 100644 --- a/rama-core/src/layer/map_state.rs +++ b/rama-core/src/layer/map_state.rs @@ -1,5 +1,5 @@ -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{future::Future, sync::Arc}; /// Middleware that can be used to map the state, diff --git a/rama-core/src/layer/timeout/mod.rs b/rama-core/src/layer/timeout/mod.rs index 6f3c86bd..59e8fec8 100644 --- a/rama-core/src/layer/timeout/mod.rs +++ b/rama-core/src/layer/timeout/mod.rs @@ -4,8 +4,8 @@ //! will be aborted. use super::{LayerErrorFn, LayerErrorStatic, MakeLayerError}; -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, time::Duration}; mod error; diff --git a/rama-core/src/layer/trace_err.rs b/rama-core/src/layer/trace_err.rs index b971359e..f4bf1109 100644 --- a/rama-core/src/layer/trace_err.rs +++ b/rama-core/src/layer/trace_err.rs @@ -1,5 +1,5 @@ -use crate::utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Service which traces the error using [`tracing`], diff --git a/rama-core/src/lib.rs b/rama-core/src/lib.rs index bb80acf6..f3cec128 100644 --- a/rama-core/src/lib.rs +++ b/rama-core/src/lib.rs @@ -79,8 +79,7 @@ pub use layer::Layer; pub mod combinators; pub mod matcher; +pub mod username; + #[cfg(feature = "telemetry")] pub mod telemetry; - -#[macro_use] -pub mod utils; diff --git a/rama-core/src/matcher/mod.rs b/rama-core/src/matcher/mod.rs index 308b4c26..54879616 100644 --- a/rama-core/src/matcher/mod.rs +++ b/rama-core/src/matcher/mod.rs @@ -13,9 +13,9 @@ //! [`Context`]: crate::Context use super::{context::Extensions, Context}; -use crate::utils::macros::all_the_tuples_no_last_special_case; use crate::Service; use paste::paste; +use rama_utils::macros::all_the_tuples_no_last_special_case; mod op_or; #[doc(inline)] diff --git a/rama-core/src/matcher/op_and.rs b/rama-core/src/matcher/op_and.rs index 312a2410..2fb9126b 100644 --- a/rama-core/src/matcher/op_and.rs +++ b/rama-core/src/matcher/op_and.rs @@ -1,6 +1,6 @@ use super::Matcher; -use crate::utils::macros::all_the_tuples_no_last_special_case; use crate::{context::Extensions, Context}; +use rama_utils::macros::all_the_tuples_no_last_special_case; /// A matcher that matches if all of the inner matchers match. pub struct And(T); diff --git a/rama-core/src/matcher/op_or.rs b/rama-core/src/matcher/op_or.rs index 4a28c117..9cca03a4 100644 --- a/rama-core/src/matcher/op_or.rs +++ b/rama-core/src/matcher/op_or.rs @@ -1,6 +1,6 @@ use super::Matcher; -use crate::utils::macros::all_the_tuples_no_last_special_case; use crate::{context::Extensions, Context}; +use rama_utils::macros::all_the_tuples_no_last_special_case; /// A matcher that matches if any of the inner matchers match. pub struct Or(T); diff --git a/rama-core/src/service/svc.rs b/rama-core/src/service/svc.rs index 2dbe5476..36022a6e 100644 --- a/rama-core/src/service/svc.rs +++ b/rama-core/src/service/svc.rs @@ -220,7 +220,7 @@ mod tests { #[test] fn assert_send() { - use crate::utils::test_helpers::*; + use rama_utils::test_helpers::*; assert_send::(); assert_send::(); @@ -229,7 +229,7 @@ mod tests { #[test] fn assert_sync() { - use crate::utils::test_helpers::*; + use rama_utils::test_helpers::*; assert_sync::(); assert_sync::(); diff --git a/rama-core/src/utils/username/compose.rs b/rama-core/src/username/compose.rs similarity index 99% rename from rama-core/src/utils/username/compose.rs rename to rama-core/src/username/compose.rs index fd0bd3c1..c50a6a11 100644 --- a/rama-core/src/utils/username/compose.rs +++ b/rama-core/src/username/compose.rs @@ -1,4 +1,4 @@ -use crate::utils::macros::all_the_tuples_no_last_special_case; +use rama_utils::macros::all_the_tuples_no_last_special_case; use std::{ fmt::{self, Write}, sync::Arc, diff --git a/rama-core/src/utils/username/mod.rs b/rama-core/src/username/mod.rs similarity index 100% rename from rama-core/src/utils/username/mod.rs rename to rama-core/src/username/mod.rs diff --git a/rama-core/src/utils/username/parse.rs b/rama-core/src/username/parse.rs similarity index 99% rename from rama-core/src/utils/username/parse.rs rename to rama-core/src/username/parse.rs index 4fdf3311..9b37c4b6 100644 --- a/rama-core/src/utils/username/parse.rs +++ b/rama-core/src/username/parse.rs @@ -1,7 +1,7 @@ +use super::DEFAULT_USERNAME_LABEL_SEPARATOR; use crate::context::Extensions; use crate::error::{BoxError, OpaqueError}; -use crate::utils::macros::all_the_tuples_no_last_special_case; -use crate::utils::username::DEFAULT_USERNAME_LABEL_SEPARATOR; +use rama_utils::macros::all_the_tuples_no_last_special_case; use std::{convert::Infallible, fmt}; /// Parse a username, extracting the username (first part) diff --git a/rama-core/src/utils/mod.rs b/rama-core/src/utils/mod.rs deleted file mode 100644 index 957a4220..00000000 --- a/rama-core/src/utils/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Utilities in service of the `rama-core` project. - -#[doc(hidden)] -pub use ::rama_macros as macros; - -pub mod backoff; -pub mod future; -pub mod info; -pub mod latency; -pub mod rng; -pub mod str; -pub mod username; - -#[doc(hidden)] -pub mod test_helpers; diff --git a/rama-http-types/Cargo.toml b/rama-http-types/Cargo.toml index 9565e164..2426e2e1 100644 --- a/rama-http-types/Cargo.toml +++ b/rama-http-types/Cargo.toml @@ -24,7 +24,7 @@ mime_guess = { workspace = true } paste = { workspace = true } pin-project-lite = { workspace = true } rama-error = { version = "0.2.0-alpha.2", path = "../rama-error" } -rama-macros = { version = "0.2.0-alpha.2", path = "../rama-macros" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } serde_json = { workspace = true } diff --git a/rama-http-types/src/lib.rs b/rama-http-types/src/lib.rs index 41029b6a..a5000eb7 100644 --- a/rama-http-types/src/lib.rs +++ b/rama-http-types/src/lib.rs @@ -71,7 +71,7 @@ pub use body_ext::BodyExtractExt; pub type Request = http::Request; pub mod response; -pub use response::{IntoResponse, Response}; +pub use response::{IntoResponse, IntoResponseParts, Response}; pub mod headers; diff --git a/rama-http-types/src/response/append_headers.rs b/rama-http-types/src/response/append_headers.rs index 178e3dfe..ea1ebf2c 100644 --- a/rama-http-types/src/response/append_headers.rs +++ b/rama-http-types/src/response/append_headers.rs @@ -1,6 +1,6 @@ use super::{IntoResponse, IntoResponseParts, Response, ResponseParts, TryIntoHeaderError}; use crate::{HeaderName, HeaderValue}; -use rama_macros::impl_deref; +use rama_utils::macros::impl_deref; use std::fmt; /// Append headers to a response. @@ -9,15 +9,15 @@ use std::fmt; /// existing `content-type` headers. If instead you want to append headers, use `AppendHeaders`: /// /// ```rust -/// use rama::{ -/// http::response::{AppendHeaders, IntoResponse}, -/// http::header::SET_COOKIE, +/// use rama_http_types::{ +/// response::{AppendHeaders, IntoResponse}, +/// header::SET_COOKIE, /// }; /// /// async fn handler() -> impl IntoResponse { /// // something that sets the `set-cookie` header /// let set_some_cookies = /* ... */ -/// # rama::http::HeaderMap::new(); +/// # rama_http_types::HeaderMap::new(); /// /// ( /// set_some_cookies, diff --git a/rama-http-types/src/response/form.rs b/rama-http-types/src/response/form.rs index 60e66d9d..2927da03 100644 --- a/rama-http-types/src/response/form.rs +++ b/rama-http-types/src/response/form.rs @@ -6,7 +6,7 @@ use crate::dep::mime; use crate::response::{IntoResponse, Response}; use crate::Body; use rama_error::OpaqueError; -use rama_macros::impl_deref; +use rama_utils::macros::impl_deref; use serde::Serialize; /// Wrapper used to create Form Http [`Response`]s, @@ -20,7 +20,7 @@ use serde::Serialize; /// /// ``` /// use serde::Serialize; -/// use rama::http::{ +/// use rama_http_types::{ /// IntoResponse, /// response::Form /// }; @@ -44,9 +44,7 @@ use serde::Serialize; /// ## Extracting Form from a Request /// /// ``` -/// use rama::http::service::web::extract::{ -/// Form -/// }; +/// use rama_http_types::response::Form; /// /// #[derive(Debug, serde::Deserialize)] /// struct Input { diff --git a/rama-http-types/src/response/html.rs b/rama-http-types/src/response/html.rs index 741cf81f..3819194f 100644 --- a/rama-http-types/src/response/html.rs +++ b/rama-http-types/src/response/html.rs @@ -1,5 +1,5 @@ use crate::{header, Body, HeaderValue, IntoResponse, Response}; -use rama_macros::impl_deref; +use rama_utils::macros::impl_deref; use std::fmt; /// An HTML response. diff --git a/rama-http-types/src/response/into_response.rs b/rama-http-types/src/response/into_response.rs index c3f20a60..d72283ca 100644 --- a/rama-http-types/src/response/into_response.rs +++ b/rama-http-types/src/response/into_response.rs @@ -9,7 +9,7 @@ use crate::{ }; use bytes::{buf::Chain, Buf, Bytes, BytesMut}; use rama_error::BoxError; -use rama_macros::all_the_tuples_no_last_special_case; +use rama_utils::macros::all_the_tuples_no_last_special_case; use std::{ borrow::Cow, convert::Infallible, diff --git a/rama-http-types/src/response/into_response_parts.rs b/rama-http-types/src/response/into_response_parts.rs index 407c531e..675aa69a 100644 --- a/rama-http-types/src/response/into_response_parts.rs +++ b/rama-http-types/src/response/into_response_parts.rs @@ -1,10 +1,10 @@ -use super::{IntoResponse, Response}; use crate::{ dep::http::Extensions, header::{HeaderMap, HeaderName, HeaderValue}, + response::{IntoResponse, Response}, StatusCode, }; -use rama_macros::all_the_tuples_no_last_special_case; +use rama_utils::macros::all_the_tuples_no_last_special_case; use std::{convert::Infallible, fmt}; /// Trait for adding headers and extensions to a response. @@ -12,9 +12,9 @@ use std::{convert::Infallible, fmt}; /// # Example /// /// ```rust -/// use rama::{ -/// http::response::{ResponseParts, IntoResponse, IntoResponseParts, Response}, -/// http::{StatusCode, HeaderName, HeaderValue}, +/// use rama_http_types::{ +/// response::{ResponseParts, IntoResponse, IntoResponseParts, Response}, +/// StatusCode, HeaderName, HeaderValue, /// }; /// /// // Hypothetical helper type for setting a single header diff --git a/rama-http-types/src/response/json.rs b/rama-http-types/src/response/json.rs index 8ff1923c..6364491a 100644 --- a/rama-http-types/src/response/json.rs +++ b/rama-http-types/src/response/json.rs @@ -8,7 +8,7 @@ use crate::{ }; use bytes::{BufMut, BytesMut}; use rama_error::OpaqueError; -use rama_macros::impl_deref; +use rama_utils::macros::impl_deref; use serde::Serialize; use std::fmt; @@ -24,11 +24,7 @@ use std::fmt; /// /// ``` /// use serde_json::json; -/// use rama::http::{ -/// IntoResponse, -/// // re-exported also as rama::http::service::web::extract::Json -/// response::Json, -/// }; +/// use rama_http_types::{IntoResponse, response::Json}; /// /// async fn handler() -> impl IntoResponse { /// Json(json!({ @@ -43,10 +39,7 @@ use std::fmt; /// /// ``` /// use serde_json::json; -/// use rama::http::service::web::extract::{ -/// // re-exported from rama::http::response::Json -/// Json, -/// }; +/// use rama_http_types::response::Json; /// /// #[derive(Debug, serde::Deserialize)] /// struct Input { diff --git a/rama-http-types/src/response/mod.rs b/rama-http-types/src/response/mod.rs index d2914c46..3b62c8ef 100644 --- a/rama-http-types/src/response/mod.rs +++ b/rama-http-types/src/response/mod.rs @@ -44,9 +44,9 @@ pub type Response = http::Response; /// # Example /// /// ``` -/// use rama::{ -/// http::response::{IntoResponse, Response}, -/// http::StatusCode, +/// use rama_http_types::{ +/// response::{IntoResponse, Response}, +/// StatusCode, /// }; /// /// // two fallible functions with different error types @@ -82,7 +82,7 @@ pub type Response = http::Response; /// } /// /// // we can combine them using `rama::http::response::Result` and still use `?` -/// async fn handler() -> rama::http::response::Result<&'static str> { +/// async fn handler() -> rama_http_types::response::Result<&'static str> { /// // the errors are automatically converted to `ErrorResponse` /// try_something()?; /// try_something_else()?; @@ -96,9 +96,9 @@ pub type Response = http::Response; /// Since `rama::http::response::Result` has a default error type you only have to specify the `Ok` type: /// /// ``` -/// use rama::{ -/// http::response::{IntoResponse, Response, Result}, -/// http::StatusCode, +/// use rama_http_types::{ +/// response::{IntoResponse, Response, Result}, +/// StatusCode, /// }; /// /// // `Result` automatically uses `ErrorResponse` as the error type. diff --git a/rama-http/src/client/conn.rs b/rama-http/src/client/conn.rs index b3a29d0c..5daacdfd 100644 --- a/rama-http/src/client/conn.rs +++ b/rama-http/src/client/conn.rs @@ -1,6 +1,6 @@ use super::{svc::SendRequest, HttpClientService}; use crate::http::executor::HyperExecutor; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::{BoxError, OpaqueError}, http::{dep::http_body, Request, Version}, diff --git a/rama-http/src/client/ext.rs b/rama-http/src/client/ext.rs index 74c3467c..35818af6 100644 --- a/rama-http/src/client/ext.rs +++ b/rama-http/src/client/ext.rs @@ -702,8 +702,8 @@ mod test { ua.to_str().unwrap(), format!( "{}/{}", - crate::utils::info::NAME, - crate::utils::info::VERSION + rama_utils::info::NAME, + rama_utils::info::VERSION ) ); diff --git a/rama-http/src/layer/auth/add_authorization.rs b/rama-http/src/layer/auth/add_authorization.rs index b15e9236..bc0d95f5 100644 --- a/rama-http/src/layer/auth/add_authorization.rs +++ b/rama-http/src/layer/auth/add_authorization.rs @@ -41,7 +41,7 @@ //! ``` use crate::http::{HeaderValue, Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use base64::Engine as _; use std::convert::TryFrom; diff --git a/rama-http/src/layer/auth/async_require_authorization.rs b/rama-http/src/layer/auth/async_require_authorization.rs index c3419a23..a87e05cc 100644 --- a/rama-http/src/layer/auth/async_require_authorization.rs +++ b/rama-http/src/layer/auth/async_require_authorization.rs @@ -119,7 +119,7 @@ use std::future::Future; use crate::http::{Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::Context; use crate::{Layer, Service}; diff --git a/rama-http/src/layer/body_limit.rs b/rama-http/src/layer/body_limit.rs index 62622db2..6c7c0fdf 100644 --- a/rama-http/src/layer/body_limit.rs +++ b/rama-http/src/layer/body_limit.rs @@ -31,7 +31,7 @@ use crate::http::dep::http_body_util::Limited; use crate::http::Request; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::fmt; diff --git a/rama-http/src/layer/catch_panic.rs b/rama-http/src/layer/catch_panic.rs index ee13db9f..9be612ec 100644 --- a/rama-http/src/layer/catch_panic.rs +++ b/rama-http/src/layer/catch_panic.rs @@ -87,7 +87,7 @@ //! ``` use crate::http::{Body, HeaderValue, Request, Response, StatusCode}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use futures_lite::future::FutureExt; use std::fmt; diff --git a/rama-http/src/layer/compression/service.rs b/rama-http/src/layer/compression/service.rs index 391812a6..aa5e44e5 100644 --- a/rama-http/src/layer/compression/service.rs +++ b/rama-http/src/layer/compression/service.rs @@ -6,7 +6,7 @@ use crate::http::dep::http_body::Body; use crate::http::layer::util::compression::WrapBody; use crate::http::layer::util::{compression::AcceptEncoding, content_encoding::Encoding}; use crate::http::{header, Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Service}; /// Compress response bodies of the underlying service. diff --git a/rama-http/src/layer/cors/mod.rs b/rama-http/src/layer/cors/mod.rs index e71f56e0..2596b5d1 100644 --- a/rama-http/src/layer/cors/mod.rs +++ b/rama-http/src/layer/cors/mod.rs @@ -50,7 +50,7 @@ use crate::http::dep::http::{ header::{self, HeaderName}, HeaderMap, HeaderValue, Method, Request, Response, }; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use bytes::{BufMut, BytesMut}; use std::{array, fmt, mem}; diff --git a/rama-http/src/layer/decompression/request/service.rs b/rama-http/src/layer/decompression/request/service.rs index 39f494a0..dab904e9 100644 --- a/rama-http/src/layer/decompression/request/service.rs +++ b/rama-http/src/layer/decompression/request/service.rs @@ -10,7 +10,7 @@ use crate::http::layer::{ util::content_encoding::SupportedEncodings, }; use crate::http::{header, HeaderValue, Request, Response, StatusCode}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Service}; use bytes::Buf; diff --git a/rama-http/src/layer/decompression/service.rs b/rama-http/src/layer/decompression/service.rs index 6db79677..f3e0ea89 100644 --- a/rama-http/src/layer/decompression/service.rs +++ b/rama-http/src/layer/decompression/service.rs @@ -10,7 +10,7 @@ use crate::http::{ header::{self, ACCEPT_ENCODING}, Request, Response, }; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Service}; /// Decompresses response bodies of the underlying service. diff --git a/rama-http/src/layer/dns/dns_map/service.rs b/rama-http/src/layer/dns/dns_map/service.rs index 7bfadfed..542ca669 100644 --- a/rama-http/src/layer/dns/dns_map/service.rs +++ b/rama-http/src/layer/dns/dns_map/service.rs @@ -1,7 +1,7 @@ use std::fmt; use super::DnsMap; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::OpaqueError, http::{ diff --git a/rama-http/src/layer/dns/dns_resolve/mod.rs b/rama-http/src/layer/dns/dns_resolve/mod.rs index 63b0059b..fbe14ee3 100644 --- a/rama-http/src/layer/dns/dns_resolve/mod.rs +++ b/rama-http/src/layer/dns/dns_resolve/mod.rs @@ -7,8 +7,8 @@ use crate::error::{ErrorExt, OpaqueError}; use crate::http::HeaderValue; -use crate::utils::macros::match_ignore_ascii_case_str; -use crate::utils::username::{ComposeError, Composer, UsernameLabelWriter}; +use rama_utils::macros::match_ignore_ascii_case_str; +use rama_utils::username::{ComposeError, Composer, UsernameLabelWriter}; use std::fmt; mod service; @@ -120,7 +120,7 @@ impl UsernameLabelWriter for DnsResolveMode { mod tests { use super::*; use crate::context::Extensions; - use crate::utils::username::{compose_username, parse_username}; + use rama_utils::username::{compose_username, parse_username}; #[test] fn parse_username_label_compose_parse_dns_resolve_mode() { diff --git a/rama-http/src/layer/dns/dns_resolve/service.rs b/rama-http/src/layer/dns/dns_resolve/service.rs index f620bffa..b64318dc 100644 --- a/rama-http/src/layer/dns/dns_resolve/service.rs +++ b/rama-http/src/layer/dns/dns_resolve/service.rs @@ -1,7 +1,7 @@ use std::fmt; use super::DnsResolveMode; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::OpaqueError, http::{HeaderName, Request}, diff --git a/rama-http/src/layer/dns/dns_resolve/username_parser.rs b/rama-http/src/layer/dns/dns_resolve/username_parser.rs index 1f349576..1bbfbf56 100644 --- a/rama-http/src/layer/dns/dns_resolve/username_parser.rs +++ b/rama-http/src/layer/dns/dns_resolve/username_parser.rs @@ -63,7 +63,7 @@ impl UsernameLabelParser for DnsResolveModeUsernameParser { #[cfg(test)] mod tests { use super::*; - use crate::utils::username::parse_username; + use rama_utils::username::parse_username; #[test] fn test_username_dns_resolve_mod_config() { diff --git a/rama-http/src/layer/error_handling.rs b/rama-http/src/layer/error_handling.rs index 068a7205..1f4af653 100644 --- a/rama-http/src/layer/error_handling.rs +++ b/rama-http/src/layer/error_handling.rs @@ -44,7 +44,7 @@ //! # } //! ``` -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ http::{IntoResponse, Request, Response}, Context, Layer, Service, diff --git a/rama-http/src/layer/follow_redirect/mod.rs b/rama-http/src/layer/follow_redirect/mod.rs index 1c6b74a6..0873e4da 100644 --- a/rama-http/src/layer/follow_redirect/mod.rs +++ b/rama-http/src/layer/follow_redirect/mod.rs @@ -101,7 +101,7 @@ pub mod policy; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ http::{dep::http_body::Body, header::LOCATION, Method, Request, Response, StatusCode, Uri}, Context, Layer, Service, diff --git a/rama-http/src/layer/forwarded/set_forwarded.rs b/rama-http/src/layer/forwarded/set_forwarded.rs index ed197275..3ae6ed25 100644 --- a/rama-http/src/layer/forwarded/set_forwarded.rs +++ b/rama-http/src/layer/forwarded/set_forwarded.rs @@ -4,7 +4,7 @@ use crate::headers::{ use crate::net::address::Domain; use crate::net::forwarded::{Forwarded, ForwardedElement, NodeId}; use crate::stream::SocketInfo; -use crate::utils::macros::all_the_tuples_no_last_special_case; +use rama_utils::macros::all_the_tuples_no_last_special_case; use crate::{Context, Layer, Service}; use crate::{Request, RequestContext}; use rama_core::error::BoxError; diff --git a/rama-http/src/layer/header_config.rs b/rama-http/src/layer/header_config.rs index b981260f..eb1d034a 100644 --- a/rama-http/src/layer/header_config.rs +++ b/rama-http/src/layer/header_config.rs @@ -43,7 +43,7 @@ //! ``` use crate::http::{header::AsHeaderName, HeaderName}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use serde::de::DeserializeOwned; use std::{fmt, marker::PhantomData}; diff --git a/rama-http/src/layer/header_option_value.rs b/rama-http/src/layer/header_option_value.rs index 934bc8e4..4a3fe4b5 100644 --- a/rama-http/src/layer/header_option_value.rs +++ b/rama-http/src/layer/header_option_value.rs @@ -3,7 +3,7 @@ //! the header with the given [`HeaderName`] is present //! and has a bool-like value. -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::BoxError, http::{utils::HeaderValueGetter, Request}, diff --git a/rama-http/src/layer/map_request_body.rs b/rama-http/src/layer/map_request_body.rs index 232d08b9..26c0bc27 100644 --- a/rama-http/src/layer/map_request_body.rs +++ b/rama-http/src/layer/map_request_body.rs @@ -57,7 +57,7 @@ //! ``` use crate::http::{Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::fmt; diff --git a/rama-http/src/layer/map_response_body.rs b/rama-http/src/layer/map_response_body.rs index f6b4a512..11149324 100644 --- a/rama-http/src/layer/map_response_body.rs +++ b/rama-http/src/layer/map_response_body.rs @@ -81,7 +81,7 @@ //! ``` use crate::http::{Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::fmt; diff --git a/rama-http/src/layer/normalize_path.rs b/rama-http/src/layer/normalize_path.rs index 5e629392..fcf3d600 100644 --- a/rama-http/src/layer/normalize_path.rs +++ b/rama-http/src/layer/normalize_path.rs @@ -38,7 +38,7 @@ //! ``` use crate::http::{Request, Response, Uri}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::borrow::Cow; use std::fmt; diff --git a/rama-http/src/layer/opentelemetry.rs b/rama-http/src/layer/opentelemetry.rs index 95dc7eb1..bb34523d 100644 --- a/rama-http/src/layer/opentelemetry.rs +++ b/rama-http/src/layer/opentelemetry.rs @@ -2,7 +2,7 @@ //! //! [`Layer`]: crate::Layer -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ http::RequestContext, telemetry::opentelemetry::{ @@ -119,8 +119,8 @@ impl Default for RequestMetricsLayer { /// construct meters for this crate fn get_versioned_meter() -> Meter { global::meter_with_version( - crate::utils::info::NAME, - Some(crate::utils::info::VERSION), + rama_utils::info::NAME, + Some(rama_utils::info::VERSION), Some(semantic_conventions::SCHEMA_URL), None, ) diff --git a/rama-http/src/layer/propagate_headers.rs b/rama-http/src/layer/propagate_headers.rs index c6cedbd2..ec678549 100644 --- a/rama-http/src/layer/propagate_headers.rs +++ b/rama-http/src/layer/propagate_headers.rs @@ -36,7 +36,7 @@ //! ``` use crate::http::{header::HeaderName, Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; /// Layer that applies [`PropagateHeader`] which propagates headers from requests to responses. diff --git a/rama-http/src/layer/proxy_auth.rs b/rama-http/src/layer/proxy_auth.rs index 57953e2b..2e1e958a 100644 --- a/rama-http/src/layer/proxy_auth.rs +++ b/rama-http/src/layer/proxy_auth.rs @@ -6,7 +6,7 @@ use crate::http::header::PROXY_AUTHENTICATE; use crate::http::headers::{authorization::Credentials, HeaderMapExt, ProxyAuthorization}; use crate::http::{Request, Response, StatusCode}; use crate::net::user::auth::Authority; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::fmt; use std::marker::PhantomData; @@ -58,9 +58,9 @@ impl ProxyAuthLayer { /// /// You can provide your own extractor by implementing the [`UsernameLabelParser`] trait. /// - /// [`UsernameOpaqueLabelParser`]: crate::utils::username::UsernameOpaqueLabelParser + /// [`UsernameOpaqueLabelParser`]: rama_utils::username::UsernameOpaqueLabelParser /// [`ProxyFilterUsernameParser`]: crate::proxy::ProxyFilterUsernameParser - /// [`UsernameLabelParser`]: crate::utils::username::UsernameLabelParser + /// [`UsernameLabelParser`]: rama_utils::username::UsernameLabelParser pub fn with_labels(self) -> ProxyAuthLayer { ProxyAuthLayer { proxy_auth: self.proxy_auth, diff --git a/rama-http/src/layer/remove_header/request.rs b/rama-http/src/layer/remove_header/request.rs index b70a7618..bba538ea 100644 --- a/rama-http/src/layer/remove_header/request.rs +++ b/rama-http/src/layer/remove_header/request.rs @@ -29,7 +29,7 @@ //! ``` use crate::http::{HeaderName, Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::{borrow::Cow, fmt, future::Future}; diff --git a/rama-http/src/layer/remove_header/response.rs b/rama-http/src/layer/remove_header/response.rs index 56dd0729..344e049e 100644 --- a/rama-http/src/layer/remove_header/response.rs +++ b/rama-http/src/layer/remove_header/response.rs @@ -29,7 +29,7 @@ //! ``` use crate::http::{HeaderName, Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::{borrow::Cow, fmt}; diff --git a/rama-http/src/layer/request_id.rs b/rama-http/src/layer/request_id.rs index bc833dcd..7abf423c 100644 --- a/rama-http/src/layer/request_id.rs +++ b/rama-http/src/layer/request_id.rs @@ -63,7 +63,7 @@ use crate::http::{ header::{HeaderName, HeaderValue}, Request, Response, }; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use uuid::Uuid; diff --git a/rama-http/src/layer/required_header/request.rs b/rama-http/src/layer/required_header/request.rs index bdf56537..ac7ca5fa 100644 --- a/rama-http/src/layer/required_header/request.rs +++ b/rama-http/src/layer/required_header/request.rs @@ -5,7 +5,7 @@ use crate::error::ErrorContext; use crate::http::RequestContext; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::BoxError, http::{ diff --git a/rama-http/src/layer/required_header/response.rs b/rama-http/src/layer/required_header/response.rs index 843fa6f9..33df5813 100644 --- a/rama-http/src/layer/required_header/response.rs +++ b/rama-http/src/layer/required_header/response.rs @@ -10,7 +10,7 @@ use crate::http::{ header::{DATE, SERVER}, headers::{Date, HeaderMapExt}, }; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::{fmt, time::SystemTime}; diff --git a/rama-http/src/layer/retry/mod.rs b/rama-http/src/layer/retry/mod.rs index dcd73ac1..0135565c 100644 --- a/rama-http/src/layer/retry/mod.rs +++ b/rama-http/src/layer/retry/mod.rs @@ -4,7 +4,7 @@ use crate::error::BoxError; use crate::http::dep::http_body::Body as HttpBody; use crate::http::dep::http_body_util::BodyExt; use crate::http::Request; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Service}; mod layer; diff --git a/rama-http/src/layer/sensitive_headers.rs b/rama-http/src/layer/sensitive_headers.rs index 2022cf16..e31a492d 100644 --- a/rama-http/src/layer/sensitive_headers.rs +++ b/rama-http/src/layer/sensitive_headers.rs @@ -39,7 +39,7 @@ //! ``` use crate::http::{HeaderName, Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::sync::Arc; diff --git a/rama-http/src/layer/set_header/request.rs b/rama-http/src/layer/set_header/request.rs index 7573b2ec..5cc6ce5c 100644 --- a/rama-http/src/layer/set_header/request.rs +++ b/rama-http/src/layer/set_header/request.rs @@ -88,7 +88,7 @@ use crate::http::{ headers::{Header, HeaderExt}, Request, Response, }; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::fmt; diff --git a/rama-http/src/layer/set_header/response.rs b/rama-http/src/layer/set_header/response.rs index 2e3fafce..e6ccbb33 100644 --- a/rama-http/src/layer/set_header/response.rs +++ b/rama-http/src/layer/set_header/response.rs @@ -97,7 +97,7 @@ use crate::http::{ headers::{Header, HeaderExt}, HeaderValue, Request, Response, }; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use std::fmt; diff --git a/rama-http/src/layer/set_status.rs b/rama-http/src/layer/set_status.rs index ee3cee7c..04141073 100644 --- a/rama-http/src/layer/set_status.rs +++ b/rama-http/src/layer/set_status.rs @@ -37,7 +37,7 @@ use std::fmt; use crate::http::{Request, Response, StatusCode}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; /// Layer that applies [`SetStatus`] which overrides the status codes. diff --git a/rama-http/src/layer/timeout.rs b/rama-http/src/layer/timeout.rs index 1ec8631e..f1663b4f 100644 --- a/rama-http/src/layer/timeout.rs +++ b/rama-http/src/layer/timeout.rs @@ -45,7 +45,7 @@ use std::fmt; use std::time::Duration; use crate::http::{Request, Response, StatusCode}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; /// Layer that applies the [`Timeout`] middleware which apply a timeout to requests. diff --git a/rama-http/src/layer/trace/on_eos.rs b/rama-http/src/layer/trace/on_eos.rs index 9e1e76d8..adceb0d4 100644 --- a/rama-http/src/layer/trace/on_eos.rs +++ b/rama-http/src/layer/trace/on_eos.rs @@ -1,7 +1,7 @@ use super::{Latency, DEFAULT_MESSAGE_LEVEL}; use crate::http::header::HeaderMap; use crate::http::layer::classify::grpc_errors_as_failures::ParsedGrpcStatus; -use crate::utils::latency::LatencyUnit; +use rama_utils::latency::LatencyUnit; use std::time::Duration; use tracing::{Level, Span}; diff --git a/rama-http/src/layer/trace/on_failure.rs b/rama-http/src/layer/trace/on_failure.rs index 51b77109..76814217 100644 --- a/rama-http/src/layer/trace/on_failure.rs +++ b/rama-http/src/layer/trace/on_failure.rs @@ -1,5 +1,5 @@ use super::{Latency, DEFAULT_ERROR_LEVEL}; -use crate::utils::latency::LatencyUnit; +use rama_utils::latency::LatencyUnit; use std::{fmt, time::Duration}; use tracing::{Level, Span}; diff --git a/rama-http/src/layer/trace/on_response.rs b/rama-http/src/layer/trace/on_response.rs index 07c538ae..20f2d298 100644 --- a/rama-http/src/layer/trace/on_response.rs +++ b/rama-http/src/layer/trace/on_response.rs @@ -1,6 +1,6 @@ use super::{Latency, DEFAULT_MESSAGE_LEVEL}; use crate::http::Response; -use crate::utils::latency::LatencyUnit; +use rama_utils::latency::LatencyUnit; use std::time::Duration; use tracing::Level; use tracing::Span; diff --git a/rama-http/src/layer/trace/service.rs b/rama-http/src/layer/trace/service.rs index 8629fcec..c3fae916 100644 --- a/rama-http/src/layer/trace/service.rs +++ b/rama-http/src/layer/trace/service.rs @@ -9,7 +9,7 @@ use crate::http::layer::classify::{ ServerErrorsAsFailures, SharedClassifier, }; use crate::http::{Request, Response}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Service}; use std::{fmt, time::Instant}; diff --git a/rama-http/src/layer/traffic_writer/request.rs b/rama-http/src/layer/traffic_writer/request.rs index b0c62165..0c890de3 100644 --- a/rama-http/src/layer/traffic_writer/request.rs +++ b/rama-http/src/layer/traffic_writer/request.rs @@ -5,7 +5,7 @@ use crate::http::dep::http_body_util::BodyExt; use crate::http::io::write_http_request; use crate::http::{Body, Request, Response}; use crate::rt::Executor; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use bytes::Bytes; use std::fmt::Debug; diff --git a/rama-http/src/layer/traffic_writer/response.rs b/rama-http/src/layer/traffic_writer/response.rs index 6d45e55a..fa2a08ac 100644 --- a/rama-http/src/layer/traffic_writer/response.rs +++ b/rama-http/src/layer/traffic_writer/response.rs @@ -5,7 +5,7 @@ use crate::http::dep::http_body_util::BodyExt; use crate::http::io::write_http_response; use crate::http::{Body, Request, Response}; use crate::rt::Executor; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{Context, Layer, Service}; use bytes::Bytes; use std::fmt::Debug; diff --git a/rama-http/src/layer/ua.rs b/rama-http/src/layer/ua.rs index ba549a4c..782faf64 100644 --- a/rama-http/src/layer/ua.rs +++ b/rama-http/src/layer/ua.rs @@ -1,5 +1,5 @@ use super::{HttpAgent, TlsAgent, UserAgent}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ http::{ headers::{self, HeaderMapExt}, @@ -181,8 +181,8 @@ mod tests { ua.header_str(), format!( "{}/{}", - crate::utils::info::NAME, - crate::utils::info::VERSION + rama_utils::info::NAME, + rama_utils::info::VERSION ) .as_str(), ); diff --git a/rama-http/src/layer/upgrade/service.rs b/rama-http/src/layer/upgrade/service.rs index 04ff0681..5a2bd50c 100644 --- a/rama-http/src/layer/upgrade/service.rs +++ b/rama-http/src/layer/upgrade/service.rs @@ -3,7 +3,7 @@ //! See [`UpgradeService`] for more details. use super::Upgraded; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ context::Extensions, http::Request, matcher::Matcher, service::BoxService, Context, Service, }; diff --git a/rama-http/src/layer/util/content_encoding.rs b/rama-http/src/layer/util/content_encoding.rs index 34767e98..7442191a 100644 --- a/rama-http/src/layer/util/content_encoding.rs +++ b/rama-http/src/layer/util/content_encoding.rs @@ -1,6 +1,6 @@ //! Types and functions for handling content encoding. -use crate::utils::macros::match_ignore_ascii_case_str; +use rama_utils::macros::match_ignore_ascii_case_str; pub(crate) trait SupportedEncodings: Copy { fn gzip(&self) -> bool; diff --git a/rama-http/src/layer/validate_request/validate_request_header.rs b/rama-http/src/layer/validate_request/validate_request_header.rs index 7fda6566..ce11a804 100644 --- a/rama-http/src/layer/validate_request/validate_request_header.rs +++ b/rama-http/src/layer/validate_request/validate_request_header.rs @@ -1,5 +1,5 @@ use super::{AcceptHeader, BoxValidateRequestFn, ValidateRequest}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ http::{Request, Response}, Context, Layer, Service, diff --git a/rama-http/src/matcher/path/mod.rs b/rama-http/src/matcher/path/mod.rs index 582a4bab..5be738f9 100644 --- a/rama-http/src/matcher/path/mod.rs +++ b/rama-http/src/matcher/path/mod.rs @@ -114,7 +114,7 @@ impl std::error::Error for UriParamsDeserializeError {} impl IntoResponse for UriParamsDeserializeError { fn into_response(self) -> crate::http::Response { - crate::utils::macros::log_http_rejection!( + rama_utils::macros::log_http_rejection!( rejection_type = UriParamsDeserializeError, body_text = self.body_text(), status = self.status(), diff --git a/rama-http/src/server/hyper_conn.rs b/rama-http/src/server/hyper_conn.rs index aa182844..7ba67b9b 100644 --- a/rama-http/src/server/hyper_conn.rs +++ b/rama-http/src/server/hyper_conn.rs @@ -3,7 +3,7 @@ use crate::http::executor::HyperExecutor; use crate::http::{IntoResponse, Request}; use crate::stream::Stream; use crate::tcp::utils::is_connection_error; -use crate::utils::future::Fuse; +use rama_utils::future::Fuse; use crate::Context; use crate::Service; use hyper::server::conn::http1::Builder as Http1Builder; diff --git a/rama-http/src/service/web/endpoint/extract/authority.rs b/rama-http/src/service/web/endpoint/extract/authority.rs index e9584e90..03248b60 100644 --- a/rama-http/src/service/web/endpoint/extract/authority.rs +++ b/rama-http/src/service/web/endpoint/extract/authority.rs @@ -2,7 +2,7 @@ use super::FromRequestParts; use crate::http::dep::http::request::Parts; use crate::http::RequestContext; use crate::net::address; -use crate::utils::macros::{define_http_rejection, impl_deref}; +use rama_utils::macros::{define_http_rejection, impl_deref}; use crate::Context; /// Extractor that resolves the authority of the request. diff --git a/rama-http/src/service/web/endpoint/extract/body/bytes.rs b/rama-http/src/service/web/endpoint/extract/body/bytes.rs index 2040112c..c7e78349 100644 --- a/rama-http/src/service/web/endpoint/extract/body/bytes.rs +++ b/rama-http/src/service/web/endpoint/extract/body/bytes.rs @@ -1,7 +1,7 @@ use crate::http::dep::http_body_util::BodyExt; use crate::http::service::web::extract::FromRequest; use crate::http::Request; -use crate::utils::macros::{define_http_rejection, impl_deref}; +use rama_utils::macros::{define_http_rejection, impl_deref}; use crate::Context; /// Extractor to get the response body, collected as [`Bytes`]. diff --git a/rama-http/src/service/web/endpoint/extract/body/form.rs b/rama-http/src/service/web/endpoint/extract/body/form.rs index 406e977a..120b90d3 100644 --- a/rama-http/src/service/web/endpoint/extract/body/form.rs +++ b/rama-http/src/service/web/endpoint/extract/body/form.rs @@ -2,7 +2,7 @@ use super::BytesRejection; use crate::http::dep::http_body_util::BodyExt; use crate::http::service::web::extract::FromRequest; use crate::http::{Method, Request}; -use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use rama_utils::macros::{composite_http_rejection, define_http_rejection}; use crate::Context; pub use crate::http::response::Form; diff --git a/rama-http/src/service/web/endpoint/extract/body/json.rs b/rama-http/src/service/web/endpoint/extract/body/json.rs index b6a155a0..74258635 100644 --- a/rama-http/src/service/web/endpoint/extract/body/json.rs +++ b/rama-http/src/service/web/endpoint/extract/body/json.rs @@ -2,7 +2,7 @@ use super::BytesRejection; use crate::http::dep::http_body_util::BodyExt; use crate::http::service::web::extract::FromRequest; use crate::http::Request; -use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use rama_utils::macros::{composite_http_rejection, define_http_rejection}; use crate::Context; pub use crate::http::response::Json; diff --git a/rama-http/src/service/web/endpoint/extract/body/mod.rs b/rama-http/src/service/web/endpoint/extract/body/mod.rs index 6d35b544..61af8db0 100644 --- a/rama-http/src/service/web/endpoint/extract/body/mod.rs +++ b/rama-http/src/service/web/endpoint/extract/body/mod.rs @@ -1,6 +1,6 @@ use super::FromRequest; use crate::http; -use crate::utils::macros::impl_deref; +use rama_utils::macros::impl_deref; use crate::Context; use std::convert::Infallible; diff --git a/rama-http/src/service/web/endpoint/extract/body/text.rs b/rama-http/src/service/web/endpoint/extract/body/text.rs index 0441b73a..5cb52980 100644 --- a/rama-http/src/service/web/endpoint/extract/body/text.rs +++ b/rama-http/src/service/web/endpoint/extract/body/text.rs @@ -2,7 +2,7 @@ use super::BytesRejection; use crate::http::dep::http_body_util::BodyExt; use crate::http::service::web::extract::FromRequest; use crate::http::Request; -use crate::utils::macros::{composite_http_rejection, define_http_rejection, impl_deref}; +use rama_utils::macros::{composite_http_rejection, define_http_rejection, impl_deref}; use crate::Context; /// Extractor to get the response body, collected as [`String`]. diff --git a/rama-http/src/service/web/endpoint/extract/extension.rs b/rama-http/src/service/web/endpoint/extract/extension.rs index 5f095df9..bc1279f7 100644 --- a/rama-http/src/service/web/endpoint/extract/extension.rs +++ b/rama-http/src/service/web/endpoint/extract/extension.rs @@ -1,6 +1,6 @@ use super::FromRequestParts; use crate::http::dep::http::request::Parts; -use crate::utils::macros::define_http_rejection; +use rama_utils::macros::define_http_rejection; use crate::Context; use std::ops::{Deref, DerefMut}; diff --git a/rama-http/src/service/web/endpoint/extract/host.rs b/rama-http/src/service/web/endpoint/extract/host.rs index 72ccfd72..14cf0cd8 100644 --- a/rama-http/src/service/web/endpoint/extract/host.rs +++ b/rama-http/src/service/web/endpoint/extract/host.rs @@ -2,7 +2,7 @@ use super::FromRequestParts; use crate::http::dep::http::request::Parts; use crate::http::RequestContext; use crate::net::address; -use crate::utils::macros::{define_http_rejection, impl_deref}; +use rama_utils::macros::{define_http_rejection, impl_deref}; use crate::Context; /// Extractor that resolves the hostname of the request. diff --git a/rama-http/src/service/web/endpoint/extract/path.rs b/rama-http/src/service/web/endpoint/extract/path.rs index c9d7e787..1b0f84db 100644 --- a/rama-http/src/service/web/endpoint/extract/path.rs +++ b/rama-http/src/service/web/endpoint/extract/path.rs @@ -1,7 +1,7 @@ use super::FromRequestParts; use crate::http::dep::http::request::Parts; use crate::http::matcher::{UriParams, UriParamsDeserializeError}; -use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use rama_utils::macros::{composite_http_rejection, define_http_rejection}; use crate::Context; use serde::de::DeserializeOwned; use std::ops::{Deref, DerefMut}; diff --git a/rama-http/src/service/web/endpoint/extract/query.rs b/rama-http/src/service/web/endpoint/extract/query.rs index 43a5473b..c8d696d0 100644 --- a/rama-http/src/service/web/endpoint/extract/query.rs +++ b/rama-http/src/service/web/endpoint/extract/query.rs @@ -1,6 +1,6 @@ use super::FromRequestParts; use crate::http::dep::http::request::Parts; -use crate::utils::macros::define_http_rejection; +use rama_utils::macros::define_http_rejection; use crate::Context; use serde::de::DeserializeOwned; diff --git a/rama-http/src/service/web/endpoint/service.rs b/rama-http/src/service/web/endpoint/service.rs index 928566cd..204b394c 100644 --- a/rama-http/src/service/web/endpoint/service.rs +++ b/rama-http/src/service/web/endpoint/service.rs @@ -1,7 +1,7 @@ use std::future::Future; use super::extract::{FromRequest, FromRequestParts}; -use crate::utils::macros::all_the_tuples_no_last_special_case; +use rama_utils::macros::all_the_tuples_no_last_special_case; use crate::{ http::{IntoResponse, Request, Response}, Context, diff --git a/rama-macros-proc/src/lib.rs b/rama-macros-proc/src/lib.rs deleted file mode 100644 index d659c012..00000000 --- a/rama-macros-proc/src/lib.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Macros for [`rama`]. -//! -//! [`rama`]: https://crates.io/crates/rama - -#![doc( - html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" -)] -#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] -#![warn( - clippy::all, - clippy::todo, - clippy::empty_enum, - clippy::enum_glob_use, - clippy::mem_forget, - clippy::unused_self, - clippy::filter_map_next, - clippy::needless_continue, - clippy::needless_borrow, - clippy::match_wildcard_for_single_variants, - clippy::if_let_mutex, - clippy::mismatched_target_os, - clippy::await_holding_lock, - clippy::match_on_vec_items, - clippy::imprecise_flops, - clippy::suboptimal_flops, - clippy::lossy_float_literal, - clippy::rest_pat_in_fully_bound_structs, - clippy::fn_params_excessive_bools, - clippy::exit, - clippy::inefficient_to_string, - clippy::linkedlist, - clippy::macro_use_imports, - clippy::option_option, - clippy::verbose_file_reads, - clippy::unnested_or_patterns, - clippy::str_to_string, - rust_2018_idioms, - future_incompatible, - nonstandard_style, - missing_debug_implementations, - missing_docs -)] -#![deny(unreachable_pub)] -#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] -#![forbid(unsafe_code)] -#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] -#![cfg_attr(test, allow(clippy::float_cmp))] -#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] - -use proc_macro::TokenStream; -use quote::{quote, ToTokens}; -use syn::parse::Parse; - -mod as_ref; -mod attr_parsing; -mod type_parsing; - -/// Derive an implementation of [`AsRef`] for each field in a struct. -/// -/// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html -#[proc_macro_derive(AsRef, attributes(as_ref))] -pub fn derive_as_ref(item: TokenStream) -> TokenStream { - expand_with(item, as_ref::expand) -} - -fn expand_with(input: TokenStream, f: F) -> TokenStream -where - F: FnOnce(I) -> syn::Result, - I: Parse, - K: ToTokens, -{ - expand(syn::parse(input).and_then(f)) -} - -fn expand(result: syn::Result) -> TokenStream -where - T: ToTokens, -{ - match result { - Ok(tokens) => { - let tokens = (quote! { #tokens }).into(); - if std::env::var_os("RAMA_MACROS_DEBUG").is_some() { - eprintln!("{tokens}"); - } - tokens - } - Err(err) => err.into_compile_error().into(), - } -} - -#[cfg(test)] -fn run_ui_tests(directory: &str) { - let t = trybuild::TestCases::new(); - - if let Some(path) = std::env::var("RAMA_TEST_ONLY") - .as_ref() - .ok() - .and_then(|s| s.strip_prefix("rama-macros/")) - { - if !path.contains(&format!("/{directory}/")) { - return; - } - - if path.contains("/fail/") { - t.compile_fail(path); - } else if path.contains("/pass/") { - t.pass(path); - } else { - panic!() - } - } else { - t.compile_fail(format!("tests/{directory}/fail/*.rs")); - t.pass(format!("tests/{directory}/pass/*.rs")); - } -} diff --git a/rama-macros/Cargo.toml b/rama-macros/Cargo.toml index 5cd56611..8b9214e9 100644 --- a/rama-macros/Cargo.toml +++ b/rama-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rama-macros" -description = "macros in function of rama" +description = "procedural macross for rama" version = { workspace = true } license = { workspace = true } edition = { workspace = true } @@ -10,10 +10,18 @@ categories = { workspace = true } authors = { workspace = true } rust-version = { workspace = true } +[lib] +proc-macro = true + [dependencies] -rama-macros-proc = { version = "0.2.0-alpha.2", path = "../rama-macros-proc" } +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { workspace = true, features = ["full", "parsing"] } [dev-dependencies] +rama = { path = ".." } +syn = { workspace = true, features = ["full", "extra-traits"] } +trybuild = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-macros/README.md b/rama-macros/README.md index 5abe6a60..23c180a1 100644 --- a/rama-macros/README.md +++ b/rama-macros/README.md @@ -40,7 +40,9 @@ The reasons behind the creation of rama can be read in [the "Why Rama" chapter]( ## rama-macros -`rama-macros` contains the macros used by `rama`. +`rama-macros` contains the procedural macros used by `rama`. + +Exposed in the `rama` crate, or you can use it directly. Learn more about `rama`: diff --git a/rama-macros-proc/src/as_ref.rs b/rama-macros/src/as_ref.rs similarity index 100% rename from rama-macros-proc/src/as_ref.rs rename to rama-macros/src/as_ref.rs diff --git a/rama-macros-proc/src/attr_parsing.rs b/rama-macros/src/attr_parsing.rs similarity index 100% rename from rama-macros-proc/src/attr_parsing.rs rename to rama-macros/src/attr_parsing.rs diff --git a/rama-macros/src/lib.rs b/rama-macros/src/lib.rs index 79179f21..d659c012 100644 --- a/rama-macros/src/lib.rs +++ b/rama-macros/src/lib.rs @@ -1,13 +1,6 @@ -//! macros crate for rama +//! Macros for [`rama`]. //! -//! # Rama -//! -//! Crate used by the end-user `rama` crate and `rama` crate authors alike. -//! -//! Learn more about `rama`: -//! -//! - Github: -//! - Book: +//! [`rama`]: https://crates.io/crates/rama #![doc( html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" @@ -54,265 +47,69 @@ #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] -pub use ::rama_macros_proc::AsRef; - -#[doc(hidden)] -#[macro_use] -pub mod error; +use proc_macro::TokenStream; +use quote::{quote, ToTokens}; +use syn::parse::Parse; -#[doc(hidden)] -#[macro_use] -pub mod str; - -#[doc(hidden)] -#[macro_export] -macro_rules! opaque_body { - ($(#[$m:meta])* pub type $name:ident = $actual:ty;) => { - $crate::__opaque_body! { - $(#[$m])* pub type $name<> = $actual; - } - }; - - ($(#[$m:meta])* pub type $name:ident<$($param:ident),*> = $actual:ty;) => { - pin_project_lite::pin_project! { - $(#[$m])* - pub struct $name<$($param),*> { - #[pin] - pub(crate) inner: $actual - } - } - - impl<$($param),*> $name<$($param),*> { - pub(crate) fn new(inner: $actual) -> Self { - Self { inner } - } - } - - impl<$($param),*> http_body::Body for $name<$($param),*> { - type Data = <$actual as http_body::Body>::Data; - type Error = <$actual as http_body::Body>::Error; - - #[inline] - fn poll_frame( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll, Self::Error>>> { - self.project().inner.poll_frame(cx) - } +mod as_ref; +mod attr_parsing; +mod type_parsing; - #[inline] - fn is_end_stream(&self) -> bool { - http_body::Body::is_end_stream(&self.inner) - } - - #[inline] - fn size_hint(&self) -> http_body::SizeHint { - http_body::Body::size_hint(&self.inner) - } - } - }; +/// Derive an implementation of [`AsRef`] for each field in a struct. +/// +/// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html +#[proc_macro_derive(AsRef, attributes(as_ref))] +pub fn derive_as_ref(item: TokenStream) -> TokenStream { + expand_with(item, as_ref::expand) } -#[doc(hidden)] -#[macro_export] -macro_rules! all_the_tuples_minus_one_no_last_special_case { - ($name:ident) => { - $name!(T1); - $name!(T1, T2); - $name!(T1, T2, T3); - $name!(T1, T2, T3, T4); - $name!(T1, T2, T3, T4, T5); - $name!(T1, T2, T3, T4, T5, T6); - $name!(T1, T2, T3, T4, T5, T6, T7); - $name!(T1, T2, T3, T4, T5, T6, T7, T8); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); - }; +fn expand_with(input: TokenStream, f: F) -> TokenStream +where + F: FnOnce(I) -> syn::Result, + I: Parse, + K: ToTokens, +{ + expand(syn::parse(input).and_then(f)) } -#[doc(hidden)] -#[macro_export] -macro_rules! all_the_tuples_no_last_special_case { - ($name:ident) => { - $crate::all_the_tuples_minus_one_no_last_special_case!($name); - $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); - }; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! match_ignore_ascii_case_str { - (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)* $(,)?}) => { - $crate::match_ignore_ascii_case_str!(match ($s) { - $caseA $(| $caseAVar)* $(if $condA)? => $retA, - $($caseB $(| $caseBVar)* $(if $condB)? => $retB,)* - _ => panic!("{}", format!("failed to match {}", $s)), - }) - }; - (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)*, _ => $fallback:expr $(,)? }) => { - { - let s = ($s).trim(); - if $($condA &&)? (s.eq_ignore_ascii_case($caseA) $(|| s.eq_ignore_ascii_case($caseAVar))*) { - $retA - } - $( - else if $($condB &&)? (s.eq_ignore_ascii_case($caseB) $(|| s.eq_ignore_ascii_case($caseBVar))*) { - $retB - } - )* - else { - $fallback +fn expand(result: syn::Result) -> TokenStream +where + T: ToTokens, +{ + match result { + Ok(tokens) => { + let tokens = (quote! { #tokens }).into(); + if std::env::var_os("RAMA_MACROS_DEBUG").is_some() { + eprintln!("{tokens}"); } + tokens } - }; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! define_inner_service_accessors { - () => { - /// Gets a reference to the underlying service. - pub fn get_ref(&self) -> &S { - &self.inner - } - - /// Consumes `self`, returning the underlying service. - pub fn into_inner(self) -> S { - self.inner - } - }; + Err(err) => err.into_compile_error().into(), + } } -#[doc(hidden)] -#[macro_export] -macro_rules! impl_deref { - ($ident:ident) => { - impl std::ops::Deref for $ident { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl std::ops::DerefMut for $ident { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - }; - - ($ident:ident: $ty:ty) => { - impl std::ops::Deref for $ident { - type Target = $ty; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } +#[cfg(test)] +fn run_ui_tests(directory: &str) { + let t = trybuild::TestCases::new(); + + if let Some(path) = std::env::var("RAMA_TEST_ONLY") + .as_ref() + .ok() + .and_then(|s| s.strip_prefix("rama-macros/")) + { + if !path.contains(&format!("/{directory}/")) { + return; } - impl std::ops::DerefMut for $ident { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } + if path.contains("/fail/") { + t.compile_fail(path); + } else if path.contains("/pass/") { + t.pass(path); + } else { + panic!() } - }; -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn match_ignore_ascii_case_str_happy_simple() { - let s = "hello"; - let result = match_ignore_ascii_case_str!(match (s) { - "hello" => true, - _ => false, - }); - assert!(result); - } - - #[test] - fn match_ignore_ascii_case_str_happy_mixed_case() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "hello" => true, - _ => false, - }); - assert!(result); - } - - #[test] - fn match_ignore_ascii_case_str_happy_multiple_cases() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "world" => 1, - "hello" => 2, - "!" => 3, - _ => 4, - }); - assert_eq!(result, 2); - } - - #[test] - fn match_ignore_ascii_case_str_happy_variants() { - let result = match_ignore_ascii_case_str!(match ("world") { - "?" => 1, - "you" | "world" | "there" => 2, - "!" => 3, - _ => 4, - }); - assert_eq!(result, 2); - } - - #[test] - fn match_ignore_ascii_case_str_happy_fallback() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "world" => 1, - "!" => 2, - _ => 3, - }); - assert_eq!(result, 3); - } - - #[test] - fn match_ignore_ascii_case_str_condition() { - let s = "HeLLo"; - let result = match_ignore_ascii_case_str!(match (s) { - "world" => 1, - "hello" if s.len() == 4 => 2, - "hello" => 3, - "!" => 4, - _ => 5, - }); - assert_eq!(result, 3); - } - - #[test] - fn match_ignore_ascii_case_str_happy_variants_condition() { - let result = match_ignore_ascii_case_str!(match ("world") { - "?" => 1, - "you" | "world" | "there" if false => 2, - "you" | "world" | "there" if "world".len() == 5 => 3, - "!" => 4, - _ => 5, - }); - - assert_eq!(result, 3); - } - - #[test] - #[should_panic] - fn match_ignore_ascii_case_str_panic() { - match_ignore_ascii_case_str!(match ("hello") { - "world" => (), - }) + } else { + t.compile_fail(format!("tests/{directory}/fail/*.rs")); + t.pass(format!("tests/{directory}/pass/*.rs")); } } diff --git a/rama-macros-proc/src/type_parsing.rs b/rama-macros/src/type_parsing.rs similarity index 100% rename from rama-macros-proc/src/type_parsing.rs rename to rama-macros/src/type_parsing.rs diff --git a/rama-macros-proc/tests/as_ref/fail/generics.rs b/rama-macros/tests/as_ref/fail/generics.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/fail/generics.rs rename to rama-macros/tests/as_ref/fail/generics.rs diff --git a/rama-macros-proc/tests/as_ref/fail/generics.stderr b/rama-macros/tests/as_ref/fail/generics.stderr similarity index 100% rename from rama-macros-proc/tests/as_ref/fail/generics.stderr rename to rama-macros/tests/as_ref/fail/generics.stderr diff --git a/rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.rs b/rama-macros/tests/as_ref/fail/wrap_ambiguity.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.rs rename to rama-macros/tests/as_ref/fail/wrap_ambiguity.rs diff --git a/rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.stderr b/rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr similarity index 100% rename from rama-macros-proc/tests/as_ref/fail/wrap_ambiguity.stderr rename to rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr diff --git a/rama-macros-proc/tests/as_ref/fail/wrap_no_arc.rs b/rama-macros/tests/as_ref/fail/wrap_no_arc.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/fail/wrap_no_arc.rs rename to rama-macros/tests/as_ref/fail/wrap_no_arc.rs diff --git a/rama-macros-proc/tests/as_ref/fail/wrap_no_arc.stderr b/rama-macros/tests/as_ref/fail/wrap_no_arc.stderr similarity index 100% rename from rama-macros-proc/tests/as_ref/fail/wrap_no_arc.stderr rename to rama-macros/tests/as_ref/fail/wrap_no_arc.stderr diff --git a/rama-macros-proc/tests/as_ref/pass/basic.rs b/rama-macros/tests/as_ref/pass/basic.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/pass/basic.rs rename to rama-macros/tests/as_ref/pass/basic.rs diff --git a/rama-macros-proc/tests/as_ref/pass/reference-types.rs b/rama-macros/tests/as_ref/pass/reference-types.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/pass/reference-types.rs rename to rama-macros/tests/as_ref/pass/reference-types.rs diff --git a/rama-macros-proc/tests/as_ref/pass/skip.rs b/rama-macros/tests/as_ref/pass/skip.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/pass/skip.rs rename to rama-macros/tests/as_ref/pass/skip.rs diff --git a/rama-macros-proc/tests/as_ref/pass/wrap.rs b/rama-macros/tests/as_ref/pass/wrap.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/pass/wrap.rs rename to rama-macros/tests/as_ref/pass/wrap.rs diff --git a/rama-macros-proc/tests/as_ref/pass/wrap_skip.rs b/rama-macros/tests/as_ref/pass/wrap_skip.rs similarity index 100% rename from rama-macros-proc/tests/as_ref/pass/wrap_skip.rs rename to rama-macros/tests/as_ref/pass/wrap_skip.rs diff --git a/rama-proxy/src/http/client/layer/proxy_connector/connector.rs b/rama-proxy/src/http/client/layer/proxy_connector/connector.rs index ef4e6bc9..89e9b743 100644 --- a/rama-proxy/src/http/client/layer/proxy_connector/connector.rs +++ b/rama-proxy/src/http/client/layer/proxy_connector/connector.rs @@ -75,8 +75,8 @@ impl InnerHttpProxyConnector { User-Agent: {ua_name}/{ua_version}\r\n\ ", authority = self.authority, - ua_name = crate::utils::info::NAME, - ua_version = crate::utils::info::VERSION, + ua_name = rama_utils::info::NAME, + ua_version = rama_utils::info::VERSION, ) .into_bytes(); if let Some(ref headers) = self.headers { diff --git a/rama-proxy/src/http/client/layer/proxy_connector/service.rs b/rama-proxy/src/http/client/layer/proxy_connector/service.rs index 82e87513..c57116b7 100644 --- a/rama-proxy/src/http/client/layer/proxy_connector/service.rs +++ b/rama-proxy/src/http/client/layer/proxy_connector/service.rs @@ -1,5 +1,5 @@ use super::InnerHttpProxyConnector; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::{BoxError, ErrorExt, OpaqueError}, http::headers::ProxyAuthorization, diff --git a/rama-proxy/src/proxydb/internal.rs b/rama-proxy/src/proxydb/internal.rs index 01b26db2..6e590d27 100644 --- a/rama-proxy/src/proxydb/internal.rs +++ b/rama-proxy/src/proxydb/internal.rs @@ -1,5 +1,5 @@ use super::{ProxyFilter, StringFilter}; -use crate::utils::macros::match_ignore_ascii_case_str; +use rama_utils::macros::match_ignore_ascii_case_str; use crate::{ net::{ address::ProxyAddress, diff --git a/rama-proxy/src/proxydb/layer.rs b/rama-proxy/src/proxydb/layer.rs index 32d69847..bfd11eec 100644 --- a/rama-proxy/src/proxydb/layer.rs +++ b/rama-proxy/src/proxydb/layer.rs @@ -202,7 +202,7 @@ //! ``` use super::{Proxy, ProxyDB, ProxyFilter, ProxyQueryPredicate}; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::{BoxError, ErrorContext, ErrorExt, OpaqueError}, net::{ diff --git a/rama-proxy/src/username.rs b/rama-proxy/src/username.rs index 6d86a4dc..f12cea2d 100644 --- a/rama-proxy/src/username.rs +++ b/rama-proxy/src/username.rs @@ -1,5 +1,5 @@ use super::ProxyFilter; -use crate::utils::macros::match_ignore_ascii_case_str; +use rama_utils::macros::match_ignore_ascii_case_str; use crate::{ context::Extensions, error::{error, OpaqueError}, @@ -172,8 +172,8 @@ impl UsernameLabelParser for ProxyFilterUsernameParser { impl UsernameLabelWriter for ProxyFilter { fn write_labels( &self, - composer: &mut crate::utils::username::Composer, - ) -> Result<(), crate::utils::username::ComposeError> { + composer: &mut rama_utils::username::Composer, + ) -> Result<(), rama_utils::username::ComposeError> { if let Some(id) = &self.id { composer.write_label("id")?; composer.write_label(id.as_str())?; diff --git a/rama-tls/src/backend/boring/client/http.rs b/rama-tls/src/backend/boring/client/http.rs index 134ec3eb..e8b64e95 100644 --- a/rama-tls/src/backend/boring/client/http.rs +++ b/rama-tls/src/backend/boring/client/http.rs @@ -458,14 +458,14 @@ mod tests { #[test] fn assert_send() { - use crate::utils::test_helpers::assert_send; + use rama_utils::test_helpers::assert_send; assert_send::(); } #[test] fn assert_sync() { - use crate::utils::test_helpers::assert_sync; + use rama_utils::test_helpers::assert_sync; assert_sync::(); } diff --git a/rama-tls/src/backend/boring/server/service.rs b/rama-tls/src/backend/boring/server/service.rs index 9115d592..c17c35bc 100644 --- a/rama-tls/src/backend/boring/server/service.rs +++ b/rama-tls/src/backend/boring/server/service.rs @@ -1,5 +1,5 @@ use super::ServerConfig; -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ error::{ErrorContext, ErrorExt, OpaqueError}, stream::Stream, diff --git a/rama-tls/src/backend/rustls/client/http.rs b/rama-tls/src/backend/rustls/client/http.rs index 61db29e6..311e6fdf 100644 --- a/rama-tls/src/backend/rustls/client/http.rs +++ b/rama-tls/src/backend/rustls/client/http.rs @@ -556,14 +556,14 @@ mod tests { #[test] fn assert_send() { - use crate::utils::test_helpers::assert_send; + use rama_utils::test_helpers::assert_send; assert_send::(); } #[test] fn assert_sync() { - use crate::utils::test_helpers::assert_sync; + use rama_utils::test_helpers::assert_sync; assert_sync::(); } diff --git a/rama-tls/src/backend/rustls/server/layer.rs b/rama-tls/src/backend/rustls/server/layer.rs index a23cead8..d4a95b53 100644 --- a/rama-tls/src/backend/rustls/server/layer.rs +++ b/rama-tls/src/backend/rustls/server/layer.rs @@ -61,7 +61,7 @@ mod tests { #[test] fn assert_send() { - use crate::utils::test_helpers::assert_send; + use rama_utils::test_helpers::assert_send; assert_send::>(); assert_send::>>(); @@ -69,7 +69,7 @@ mod tests { #[test] fn assert_sync() { - use crate::utils::test_helpers::assert_sync; + use rama_utils::test_helpers::assert_sync; assert_sync::>>(); } diff --git a/rama-tls/src/backend/rustls/server/service.rs b/rama-tls/src/backend/rustls/server/service.rs index ccc5c3ec..f05e1855 100644 --- a/rama-tls/src/backend/rustls/server/service.rs +++ b/rama-tls/src/backend/rustls/server/service.rs @@ -1,4 +1,4 @@ -use crate::utils::macros::define_inner_service_accessors; +use rama_utils::macros::define_inner_service_accessors; use crate::{ stream::Stream, tls::{ @@ -210,7 +210,7 @@ mod tests { #[test] fn assert_send() { - use crate::utils::test_helpers::assert_send; + use rama_utils::test_helpers::assert_send; assert_send::>(); assert_send::>>(); @@ -218,7 +218,7 @@ mod tests { #[test] fn assert_sync() { - use crate::utils::test_helpers::assert_sync; + use rama_utils::test_helpers::assert_sync; assert_sync::>(); assert_sync::>>(); diff --git a/rama-macros-proc/Cargo.toml b/rama-utils/Cargo.toml similarity index 54% rename from rama-macros-proc/Cargo.toml rename to rama-utils/Cargo.toml index 7a4b49ba..faddaf3e 100644 --- a/rama-macros-proc/Cargo.toml +++ b/rama-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "rama-macros-proc" -description = "procedural macros in function of the rama proxy modules crate" +name = "rama-utils" +description = "utilities crate for rama" version = { workspace = true } license = { workspace = true } edition = { workspace = true } @@ -10,18 +10,15 @@ categories = { workspace = true } authors = { workspace = true } rust-version = { workspace = true } -[lib] -proc-macro = true - [dependencies] -proc-macro2 = { workspace = true } -quote = { workspace = true } -syn = { workspace = true, features = ["full", "parsing"] } +parking_lot = { workspace = true } +pin-project-lite = { workspace = true } +tokio = { workspace = true, features = ["time", "macros"] } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] -rama = { path = ".." } -syn = { workspace = true, features = ["full", "extra-traits"] } -trybuild = { workspace = true } +tokio-test = { workspace = true } +quickcheck = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-macros-proc/README.md b/rama-utils/README.md similarity index 83% rename from rama-macros-proc/README.md rename to rama-utils/README.md index f14fe554..430ae3d1 100644 --- a/rama-macros-proc/README.md +++ b/rama-utils/README.md @@ -12,10 +12,10 @@ [![GitHub Sponsors][ghs-badge]][ghs-url] [![Paypal Donation][paypal-badge]][paypal-url] -[crates-badge]: https://img.shields.io/crates/v/rama-macros-proc.svg -[crates-url]: https://crates.io/crates/rama-macros-proc -[docs-badge]: https://img.shields.io/docsrs/rama-macros-proc/latest -[docs-url]: https://docs.rs/rama-macros-proc/latest/rama_macros_proc/index.html +[crates-badge]: https://img.shields.io/crates/v/rama-utils.svg +[crates-url]: https://crates.io/crates/rama-utils +[docs-badge]: https://img.shields.io/docsrs/rama-utils/latest +[docs-url]: https://docs.rs/rama-utils/latest/rama_utils/index.html [license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg [license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT [license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg @@ -38,11 +38,11 @@ πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). -## rama-macros-proc +## rama-utils -`rama-macros-proc` contains the procedural macros used by `rama`. - -Exposed via the `rama-macros`, `rama-core` and `rama` crates. +`rama-utils` contains utilities used by `rama`, +not really being part of one of the other crates, or used +by plenty of other crates. Learn more about `rama`: diff --git a/rama-core/src/utils/backoff/exponential.rs b/rama-utils/src/backoff/exponential.rs similarity index 99% rename from rama-core/src/utils/backoff/exponential.rs rename to rama-utils/src/backoff/exponential.rs index 71a2519a..5fdb391a 100644 --- a/rama-core/src/utils/backoff/exponential.rs +++ b/rama-utils/src/backoff/exponential.rs @@ -3,9 +3,8 @@ use std::fmt::{self, Display}; use std::time::Duration; use tokio::time; -use crate::utils::rng::{HasherRng, Rng}; - use super::Backoff; +use crate::rng::{HasherRng, Rng}; /// A jittered [exponential backoff] strategy. /// diff --git a/rama-core/src/utils/backoff/mod.rs b/rama-utils/src/backoff/mod.rs similarity index 73% rename from rama-core/src/utils/backoff/mod.rs rename to rama-utils/src/backoff/mod.rs index 31fe6295..09a8d42d 100644 --- a/rama-core/src/utils/backoff/mod.rs +++ b/rama-utils/src/backoff/mod.rs @@ -28,6 +28,33 @@ pub trait Backoff: Send + Sync + 'static { fn reset(&self) -> impl std::future::Future + Send + '_; } +impl Backoff for () { + async fn next_backoff(&self) -> bool { + false + } + + async fn reset(&self) {} +} + +impl Backoff for Option { + async fn next_backoff(&self) -> bool { + false + } + + async fn reset(&self) {} +} + +impl Backoff for std::sync::Arc { + #[inline] + fn next_backoff(&self) -> impl std::future::Future + Send + '_ { + (**self).next_backoff() + } + + fn reset(&self) -> impl std::future::Future + Send + '_ { + (**self).reset() + } +} + mod exponential; #[doc(inline)] pub use exponential::ExponentialBackoff; diff --git a/rama-core/src/utils/future.rs b/rama-utils/src/future.rs similarity index 100% rename from rama-core/src/utils/future.rs rename to rama-utils/src/future.rs diff --git a/rama-core/src/utils/info.rs b/rama-utils/src/info.rs similarity index 100% rename from rama-core/src/utils/info.rs rename to rama-utils/src/info.rs diff --git a/rama-core/src/utils/latency.rs b/rama-utils/src/latency.rs similarity index 100% rename from rama-core/src/utils/latency.rs rename to rama-utils/src/latency.rs diff --git a/rama-utils/src/lib.rs b/rama-utils/src/lib.rs new file mode 100644 index 00000000..8d024d9f --- /dev/null +++ b/rama-utils/src/lib.rs @@ -0,0 +1,73 @@ +//! utilities crate for rama +//! +//! `rama-utils` contains utilities used by `rama`, +//! not really being part of one of the other crates, or used +//! by plenty of other crates. +//! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +#[doc(hidden)] +#[macro_use] +pub mod macros; + +pub mod backoff; +pub mod future; +pub mod info; +pub mod latency; +pub mod rng; +pub mod str; + +#[doc(hidden)] +pub mod test_helpers; diff --git a/rama-macros/src/error.rs b/rama-utils/src/macros/error.rs similarity index 100% rename from rama-macros/src/error.rs rename to rama-utils/src/macros/error.rs diff --git a/rama-utils/src/macros/mod.rs b/rama-utils/src/macros/mod.rs new file mode 100644 index 00000000..56b90a96 --- /dev/null +++ b/rama-utils/src/macros/mod.rs @@ -0,0 +1,268 @@ +//! hidden rama macros 🀫 + +#[doc(hidden)] +#[macro_use] +pub mod error; + +#[doc(hidden)] +#[macro_use] +pub mod str; + +#[doc(hidden)] +#[macro_export] +macro_rules! __opaque_body { + ($(#[$m:meta])* pub type $name:ident = $actual:ty;) => { + $crate::__opaque_body! { + $(#[$m])* pub type $name<> = $actual; + } + }; + + ($(#[$m:meta])* pub type $name:ident<$($param:ident),*> = $actual:ty;) => { + pin_project_lite::pin_project! { + $(#[$m])* + pub struct $name<$($param),*> { + #[pin] + pub(crate) inner: $actual + } + } + + impl<$($param),*> $name<$($param),*> { + pub(crate) fn new(inner: $actual) -> Self { + Self { inner } + } + } + + impl<$($param),*> http_body::Body for $name<$($param),*> { + type Data = <$actual as http_body::Body>::Data; + type Error = <$actual as http_body::Body>::Error; + + #[inline] + fn poll_frame( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll, Self::Error>>> { + self.project().inner.poll_frame(cx) + } + + #[inline] + fn is_end_stream(&self) -> bool { + http_body::Body::is_end_stream(&self.inner) + } + + #[inline] + fn size_hint(&self) -> http_body::SizeHint { + http_body::Body::size_hint(&self.inner) + } + } + }; +} +pub use crate::__opaque_body as opaque_body; + +#[doc(hidden)] +#[macro_export] +macro_rules! __all_the_tuples_minus_one_no_last_special_case { + ($name:ident) => { + $name!(T1); + $name!(T1, T2); + $name!(T1, T2, T3); + $name!(T1, T2, T3, T4); + $name!(T1, T2, T3, T4, T5); + $name!(T1, T2, T3, T4, T5, T6); + $name!(T1, T2, T3, T4, T5, T6, T7); + $name!(T1, T2, T3, T4, T5, T6, T7, T8); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); + }; +} +pub use crate::__all_the_tuples_minus_one_no_last_special_case as all_the_tuples_minus_one_no_last_special_case; + +#[doc(hidden)] +#[macro_export] +macro_rules! __all_the_tuples_no_last_special_case { + ($name:ident) => { + $crate::macros::all_the_tuples_minus_one_no_last_special_case!($name); + $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); + }; +} +pub use crate::__all_the_tuples_no_last_special_case as all_the_tuples_no_last_special_case; + +#[doc(hidden)] +#[macro_export] +macro_rules! __match_ignore_ascii_case_str { + (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)* $(,)?}) => { + $crate::macros::match_ignore_ascii_case_str!(match ($s) { + $caseA $(| $caseAVar)* $(if $condA)? => $retA, + $($caseB $(| $caseBVar)* $(if $condB)? => $retB,)* + _ => panic!("{}", format!("failed to match {}", $s)), + }) + }; + (match ($s:expr) { $caseA:literal $(| $caseAVar:literal)* $(if $condA:expr)? => $retA:expr $(, $caseB:literal $(| $caseBVar:literal)* $(if $condB:expr)? => $retB:expr)*, _ => $fallback:expr $(,)? }) => { + { + let s = ($s).trim(); + if $($condA &&)? (s.eq_ignore_ascii_case($caseA) $(|| s.eq_ignore_ascii_case($caseAVar))*) { + $retA + } + $( + else if $($condB &&)? (s.eq_ignore_ascii_case($caseB) $(|| s.eq_ignore_ascii_case($caseBVar))*) { + $retB + } + )* + else { + $fallback + } + } + }; +} +pub use crate::__match_ignore_ascii_case_str as match_ignore_ascii_case_str; + +#[doc(hidden)] +#[macro_export] +macro_rules! __define_inner_service_accessors { + () => { + /// Gets a reference to the underlying service. + pub fn get_ref(&self) -> &S { + &self.inner + } + + /// Consumes `self`, returning the underlying service. + pub fn into_inner(self) -> S { + self.inner + } + }; +} +pub use crate::__define_inner_service_accessors as define_inner_service_accessors; + +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_deref { + ($ident:ident) => { + impl std::ops::Deref for $ident { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for $ident { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + }; + + ($ident:ident: $ty:ty) => { + impl std::ops::Deref for $ident { + type Target = $ty; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for $ident { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + }; +} +pub use crate::__impl_deref as impl_deref; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn match_ignore_ascii_case_str_happy_simple() { + let s = "hello"; + let result = match_ignore_ascii_case_str!(match (s) { + "hello" => true, + _ => false, + }); + assert!(result); + } + + #[test] + fn match_ignore_ascii_case_str_happy_mixed_case() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "hello" => true, + _ => false, + }); + assert!(result); + } + + #[test] + fn match_ignore_ascii_case_str_happy_multiple_cases() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "world" => 1, + "hello" => 2, + "!" => 3, + _ => 4, + }); + assert_eq!(result, 2); + } + + #[test] + fn match_ignore_ascii_case_str_happy_variants() { + let result = match_ignore_ascii_case_str!(match ("world") { + "?" => 1, + "you" | "world" | "there" => 2, + "!" => 3, + _ => 4, + }); + assert_eq!(result, 2); + } + + #[test] + fn match_ignore_ascii_case_str_happy_fallback() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "world" => 1, + "!" => 2, + _ => 3, + }); + assert_eq!(result, 3); + } + + #[test] + fn match_ignore_ascii_case_str_condition() { + let s = "HeLLo"; + let result = match_ignore_ascii_case_str!(match (s) { + "world" => 1, + "hello" if s.len() == 4 => 2, + "hello" => 3, + "!" => 4, + _ => 5, + }); + assert_eq!(result, 3); + } + + #[test] + fn match_ignore_ascii_case_str_happy_variants_condition() { + let result = match_ignore_ascii_case_str!(match ("world") { + "?" => 1, + "you" | "world" | "there" if false => 2, + "you" | "world" | "there" if "world".len() == 5 => 3, + "!" => 4, + _ => 5, + }); + + assert_eq!(result, 3); + } + + #[test] + #[should_panic] + fn match_ignore_ascii_case_str_panic() { + match_ignore_ascii_case_str!(match ("hello") { + "world" => (), + }) + } +} diff --git a/rama-macros/src/str.rs b/rama-utils/src/macros/str.rs similarity index 100% rename from rama-macros/src/str.rs rename to rama-utils/src/macros/str.rs diff --git a/rama-core/src/utils/rng.rs b/rama-utils/src/rng.rs similarity index 100% rename from rama-core/src/utils/rng.rs rename to rama-utils/src/rng.rs diff --git a/rama-core/src/utils/str.rs b/rama-utils/src/str.rs similarity index 98% rename from rama-core/src/utils/str.rs rename to rama-utils/src/str.rs index dac0a319..92bf3375 100644 --- a/rama-core/src/utils/str.rs +++ b/rama-utils/src/str.rs @@ -6,7 +6,7 @@ use std::{borrow::Cow, fmt}; /// A string which can never be empty. pub struct NonEmptyString(Cow<'static, str>); -crate::utils::macros::error::static_str_error! { +crate::macros::error::static_str_error! { #[doc = "empty string"] pub struct EmptyStringErr; } diff --git a/rama-core/src/utils/test_helpers/mod.rs b/rama-utils/src/test_helpers/mod.rs similarity index 100% rename from rama-core/src/utils/test_helpers/mod.rs rename to rama-utils/src/test_helpers/mod.rs diff --git a/src/cli/args.rs b/src/cli/args.rs index 23cf5e8f..64220cd8 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -1,6 +1,6 @@ //! build requests from command line arguments -use crate::utils::macros::match_ignore_ascii_case_str; +use rama_utils::macros::match_ignore_ascii_case_str; use crate::{ error::{ErrorContext, OpaqueError}, http::{ diff --git a/src/cli/forward.rs b/src/cli/forward.rs index 03922110..90a85e84 100644 --- a/src/cli/forward.rs +++ b/src/cli/forward.rs @@ -1,5 +1,5 @@ use crate::error::OpaqueError; -use crate::utils::macros::match_ignore_ascii_case_str; +use rama_utils::macros::match_ignore_ascii_case_str; use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 00000000..5a368d09 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,63 @@ +//! Context passed to and between services as input. +//! +//! # State +//! +//! [`rama`] supports two kinds of states: +//! +//! 1. type-safe state: this is the `S` generic parameter in [`Context`] and is to be used +//! as much as possible, given its existence and type properties can be validated at compile time +//! 2. dynamic state: these can be injected as [`Extensions`]s using methods such as [`Context::insert`] +//! +//! As a rule of thumb one should use the type-safe state (1) in case: +//! +//! - the state is always expected to exist at the point the middleware/service is called +//! - the state is specific to the app or middleware +//! - and the state can be constructed in a default/empty state +//! +//! The latter is important given the state is often created (or at least reserved) prior to +//! it is actually being populated by the relevant middleware. This is not the case for app-specific state +//! such as Database pools which are created since the start and shared among many different tasks. +//! +//! The rule could be be simplified to "if you need to `.unwrap()` you probably want type-safe state instead". +//! It's however just a guideline and not a hard rule. As maintainers of [`rama`] we'll do our best to respect it though, +//! and we recommend you to do the same. +//! +//! Any state that is optional, and especially optional state injected by middleware, can be inserted using extensions. +//! It is however important to try as much as possible to then also consume this state in an approach that deals +//! gracefully with its absence. Good examples of this are header-related inputs. Headers might be set or not, +//! and so absence of [`Extensions`]s that might be created as a result of these might reasonably not exist. +//! It might of course still mean the app returns an error response when it is absent, but it should not unwrap/panic. +//! +//! [`rama`]: crate +//! +//! ## State Wraps +//! +//! [`rama`] was built from the ground up to operate on and between different layers of the network stack. +//! This has also an impact on state. Because sure, typed state is nice, but state leakage is not. What do I mean with that? +//! +//! When creating a [`TcpListener`] with state you are essentially creating and injecting state, which will remain +//! as "read-only" for the enire life cycle of that [`TcpListener`] and to be made available for every incoming _tcp_ connection, +//! as well as the application requests (Http requests). This is great for stuff that is okay to share, but it is not desired +//! for state that you wish to have a narrower scope. Examples are state that are tied to a single _tcp_ connection and thus +//! you do not wish to keep a global cache for this, as it would either be shared or get overly complicated to ensure +//! you keep things separate and clean. +//! +//! The solution is to wrap your state. +//! +//! > Example: [http_conn_state.rs](https://github.com/plabayo/rama/tree/main/examples/http_conn_state.rs) +//! +//! The above example shows how can use the [`#as_ref(wrap)`] property within an `#[derive(AsRef)]` derived "state" struct, +//! to wrap in a type-safe manner the "app-global" state within the "conn-specific" (tcp) state. This allows you to have +//! state freshly created for each connection while still having ease of access to the global state. +//! +//! Note though that you do not need the `AsRef` macro or even trait implementation to get this kind of access in your +//! own app-specific leaf services. It is however useful β€” and at times even a requirement β€” in case you want your +//! middleware stack to also include generic middleware that expect `AsRef` trait bounds for type-safe access to +//! state from within a middleware. E.g. in case your middleware expects a data source for some specific data type, +//! it is of no use to have that middleware compile without knowing for sure that data source is made available +//! to that middleware. +//! +//! [`TcpListener`]: crate::tcp::server::TcpListener + +pub use ::rama_core::context as context; +pub use ::rama_macros::AsRef; diff --git a/src/lib.rs b/src/lib.rs index 626ba719..231b6cbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! | πŸ—οΈ web protocols | πŸ—οΈ Web Sockets (WS) (2) βΈ± πŸ—οΈ WSS (2) βΈ± ❌ Web Transport (3) βΈ± ❌ gRPC (3) | //! | βœ… [async-method trait](https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html) services | βœ… [Service] βΈ± βœ… [Layer] βΈ± βœ… [context] βΈ± βœ… [dyn dispatch](crate::service::BoxService) βΈ± βœ… [middleware](crate::layer) | //! | βœ… [telemetry][opentelemetry] | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry] βΈ± βœ… [http metrics](crate::http::layer::opentelemetry) βΈ± βœ… [transport metrics](crate::stream::layer::opentelemetry) | -//! | βœ… upstream [proxies](proxy) | βœ… [MemoryProxyDB](crate::proxy::MemoryProxyDB) βΈ± βœ… [L4 Username Config](crate::utils::username) βΈ± βœ… [Proxy Filters](crate::proxy::ProxyFilter) | +//! | βœ… upstream [proxies](proxy) | βœ… [MemoryProxyDB](crate::proxy::MemoryProxyDB) βΈ± βœ… [L4 Username Config](rama_utils::username) βΈ± βœ… [Proxy Filters](crate::proxy::ProxyFilter) | //! | πŸ—οΈ [User Agent (UA)](https://ramaproxy.org/book/intro/user_agent) | πŸ—οΈ Http Emulation (1) βΈ± πŸ—οΈ Tls Emulation (1) βΈ± βœ… [UA Parsing](crate::ua::UserAgent) | //! | βœ… utilities | βœ… [error handling](crate::error) βΈ± βœ… [graceful shutdown](crate::graceful) βΈ± πŸ—οΈ Connection Pool (2) βΈ± πŸ—οΈ IP2Loc (2) | //! | πŸ—οΈ [TUI](https://ratatui.rs/) | πŸ—οΈ traffic logger (2) βΈ± πŸ—οΈ curl export (2) βΈ± ❌ traffic intercept (3) βΈ± ❌ traffic replay (3) | @@ -275,7 +275,7 @@ #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] pub use ::rama_core::{ - combinators, context, dns, error, graceful, layer, matcher, net, rt, service, stream, Context, + combinators, dns, error, graceful, layer, matcher, net, rt, service, stream, Context, Layer, Service, }; diff --git a/src/tcp/client/service/forward.rs b/src/tcp/client/service/forward.rs index 44988afe..e9855053 100644 --- a/src/tcp/client/service/forward.rs +++ b/src/tcp/client/service/forward.rs @@ -3,7 +3,7 @@ use std::{fmt, ops::DerefMut}; use tokio::sync::Mutex; use super::TcpConnector; -use crate::utils::macros::impl_deref; +use rama_utils::macros::impl_deref; use crate::{ error::{BoxError, ErrorExt, OpaqueError}, net::{ From c5814a622da9d8c0dfe83d2830a7460bdc1c678c Mon Sep 17 00:00:00 2001 From: glendc Date: Tue, 3 Sep 2024 11:05:35 +0200 Subject: [PATCH 03/24] fix rama-error + rama-net (tests, check, fmt) --- Cargo.lock | 2 ++ rama-core/src/username/mod.rs | 2 +- rama-core/src/username/parse.rs | 21 ++----------- rama-error/src/ext/mod.rs | 12 ++++---- rama-error/src/lib.rs | 6 ++-- rama-error/src/macros.rs | 2 +- rama-http-types/src/lib.rs | 8 +---- rama-http/src/layer/dns/dns_resolve/mod.rs | 4 +-- .../layer/dns/dns_resolve/username_parser.rs | 2 +- rama-http/src/layer/proxy_auth.rs | 4 +-- rama-net/Cargo.toml | 3 ++ rama-net/src/address/proxy.rs | 4 +-- rama-net/src/forwarded/element/mod.rs | 4 +-- rama-net/src/forwarded/element/parser.rs | 4 +-- rama-net/src/forwarded/mod.rs | 8 +++-- rama-net/src/forwarded/node.rs | 2 +- rama-net/src/forwarded/proto.rs | 2 +- rama-net/src/forwarded/version.rs | 2 +- rama-net/src/proto.rs | 21 ++++++++----- rama-net/src/stream/layer/http/body_limit.rs | 4 +-- rama-net/src/stream/layer/opentelemetry.rs | 15 ++++++---- rama-net/src/stream/layer/tracker/incoming.rs | 2 +- rama-net/src/stream/layer/tracker/outgoing.rs | 2 +- rama-net/src/stream/matcher/ip.rs | 8 ++--- rama-net/src/stream/matcher/loopback.rs | 8 ++--- rama-net/src/stream/matcher/mod.rs | 30 +++++++++---------- rama-net/src/stream/matcher/port.rs | 8 ++--- rama-net/src/stream/matcher/private_ip.rs | 8 ++--- rama-net/src/stream/matcher/socket.rs | 9 +++--- rama-net/src/stream/service/echo.rs | 5 ++-- rama-net/src/user/auth.rs | 19 ++---------- rama-net/src/user/credentials/basic.rs | 23 +++++++------- rama-net/src/user/credentials/bearer.rs | 21 +++++++------ rama-proxy/src/username.rs | 4 +-- rama-utils/src/macros/str.rs | 2 +- src/lib.rs | 4 ++- 36 files changed, 140 insertions(+), 145 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index edc60e48..3457dcaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1928,6 +1928,7 @@ dependencies = [ "headers", "hickory-resolver", "ipnet", + "itertools 0.13.0", "opentelemetry", "opentelemetry-semantic-conventions", "opentelemetry_sdk", @@ -1937,6 +1938,7 @@ dependencies = [ "quickcheck", "rama-core", "rama-http-types", + "rama-utils", "serde", "tokio", "tokio-graceful", diff --git a/rama-core/src/username/mod.rs b/rama-core/src/username/mod.rs index d4938cac..871f9e1e 100644 --- a/rama-core/src/username/mod.rs +++ b/rama-core/src/username/mod.rs @@ -32,7 +32,7 @@ mod parse; #[doc(inline)] pub use parse::{ parse_username, parse_username_with_separator, ExclusiveUsernameParsers, UsernameLabelParser, - UsernameLabelParserVoid, UsernameLabelState, UsernameLabels, UsernameOpaqueLabelParser, + UsernameLabelState, UsernameLabels, UsernameOpaqueLabelParser, }; mod compose; diff --git a/rama-core/src/username/parse.rs b/rama-core/src/username/parse.rs index 9b37c4b6..21f169bc 100644 --- a/rama-core/src/username/parse.rs +++ b/rama-core/src/username/parse.rs @@ -206,22 +206,7 @@ macro_rules! username_label_parser_tuple_exclusive_labels_impl { all_the_tuples_no_last_special_case!(username_label_parser_tuple_exclusive_labels_impl); -#[derive(Debug, Clone, Default)] -#[non_exhaustive] -/// A [`UsernameLabelParser`] which does nothing and returns [`UsernameLabelState::Used`] for all labels. -/// -/// This is useful in case you want to allow labels to be ignored, -/// for locations where the parser-user fails on ignored labels. -pub struct UsernameLabelParserVoid; - -impl UsernameLabelParserVoid { - /// Create a new [`UsernameLabelParserVoid`]. - pub const fn new() -> Self { - Self - } -} - -impl UsernameLabelParser for UsernameLabelParserVoid { +impl UsernameLabelParser for () { type Error = Infallible; fn parse_label(&mut self, _label: &str) -> UsernameLabelState { @@ -360,8 +345,8 @@ mod test { fn test_parse_username_empty() { let mut ext = Extensions::default(); - assert!(parse_username(&mut ext, UsernameLabelParserVoid::new(), "",).is_err()); - assert!(parse_username(&mut ext, UsernameLabelParserVoid::new(), "-",).is_err()); + assert!(parse_username(&mut ext, (), "",).is_err()); + assert!(parse_username(&mut ext, (), "-",).is_err()); } #[test] diff --git a/rama-error/src/ext/mod.rs b/rama-error/src/ext/mod.rs index f41a373e..88e63ed1 100644 --- a/rama-error/src/ext/mod.rs +++ b/rama-error/src/ext/mod.rs @@ -13,7 +13,7 @@ pub use wrapper::OpaqueError; /// # Examples /// /// ``` -/// use rama_core::error::ErrorContext; +/// use rama_error::ErrorContext; /// /// let result = "hello".parse::().context("parse integer"); /// assert_eq!("parse integer\r\n β†ͺ invalid digit found in string", result.unwrap_err().to_string()); @@ -88,7 +88,7 @@ impl ErrorContext for Option { /// # Examples /// /// ``` -/// use rama_core::error::{BoxError, ErrorExt, ErrorContext}; +/// use rama_error::{BoxError, ErrorExt, ErrorContext}; /// /// #[derive(Debug)] /// struct CustomError; @@ -110,7 +110,7 @@ pub trait ErrorExt: private::SealedErrorExt { /// # Examples /// /// ``` - /// use rama_core::error::ErrorExt; + /// use rama_error::ErrorExt; /// /// let error = std::io::Error::new(std::io::ErrorKind::Other, "oh no!").context("do I/O"); /// assert_eq!(error.to_string(), "do I/O\r\n β†ͺ oh no!"); @@ -124,7 +124,7 @@ pub trait ErrorExt: private::SealedErrorExt { /// # Examples /// /// ``` - /// use rama_core::error::ErrorExt; + /// use rama_error::ErrorExt; /// /// let error = std::io::Error::new(std::io::ErrorKind::Other, "oh no!").with_context(|| format!( /// "do I/O ({})", 42, @@ -141,7 +141,7 @@ pub trait ErrorExt: private::SealedErrorExt { /// # Examples /// /// ``` - /// use rama_core::error::ErrorExt; + /// use rama_error::ErrorExt; /// /// let error = std::io::Error::new(std::io::ErrorKind::Other, "oh no!").backtrace(); /// println!("{}", error); @@ -153,7 +153,7 @@ pub trait ErrorExt: private::SealedErrorExt { /// # Examples /// /// ``` - /// use rama_core::error::ErrorExt; + /// use rama_error::ErrorExt; /// /// let error = std::io::Error::new(std::io::ErrorKind::Other, "oh no!").into_opaque(); /// assert_eq!(error.to_string(), "oh no!"); diff --git a/rama-error/src/lib.rs b/rama-error/src/lib.rs index a4a6841e..ebe05c83 100644 --- a/rama-error/src/lib.rs +++ b/rama-error/src/lib.rs @@ -71,7 +71,7 @@ //! ### `error` macro Example //! //! ```rust -//! use rama_core::error::{error, ErrorExt, OpaqueError}; +//! use rama_error::{error, ErrorExt, OpaqueError}; //! //! let error = error!("error").context("foo"); //! assert_eq!(error.to_string(), "foo\r\n β†ͺ error"); @@ -119,7 +119,7 @@ //! Option Example: //! //! ```rust -//! use rama_core::error::{ErrorContext, ErrorExt}; +//! use rama_error::{ErrorContext, ErrorExt}; //! //! let value = Some(42); //! let value = match value.context("value is None") { @@ -135,7 +135,7 @@ //! Result Example: //! //! ```rust -//! use rama_core::error::{ErrorContext, ErrorExt, OpaqueError}; +//! use rama_error::{ErrorContext, ErrorExt, OpaqueError}; //! //! let value: Result<_, OpaqueError> = Ok(42); //! let value = match value.context("get the answer") { diff --git a/rama-error/src/macros.rs b/rama-error/src/macros.rs index 072b92af..2d1ec056 100644 --- a/rama-error/src/macros.rs +++ b/rama-error/src/macros.rs @@ -6,7 +6,7 @@ /// ## Examples /// /// ``` -/// use rama_core::error::error; +/// use rama_error::error; /// /// let err = error!("An error occurred"); /// let err = error!("An error occurred: {}", 42); diff --git a/rama-http-types/src/lib.rs b/rama-http-types/src/lib.rs index a5000eb7..c0d56490 100644 --- a/rama-http-types/src/lib.rs +++ b/rama-http-types/src/lib.rs @@ -165,7 +165,7 @@ pub mod header { /// Static Header Value that is can be used as `User-Agent` or `Server` header. pub static RAMA_ID_HEADER_VALUE: HeaderValue = HeaderValue::from_static( - const_format::formatcp!("{}/{}", super::NAME, super::VERSION,), + const_format::formatcp!("{}/{}", rama_utils::info::NAME, rama_utils::info::VERSION), ); } @@ -174,9 +174,3 @@ pub use self::dep::http::method::Method; pub use self::dep::http::status::StatusCode; pub use self::dep::http::uri::{Scheme, Uri}; pub use self::dep::http::version::Version; - -/// The name of the crate. -const NAME: &str = "rama"; - -/// The version of the crate. -const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/rama-http/src/layer/dns/dns_resolve/mod.rs b/rama-http/src/layer/dns/dns_resolve/mod.rs index fbe14ee3..deaf5eca 100644 --- a/rama-http/src/layer/dns/dns_resolve/mod.rs +++ b/rama-http/src/layer/dns/dns_resolve/mod.rs @@ -8,7 +8,7 @@ use crate::error::{ErrorExt, OpaqueError}; use crate::http::HeaderValue; use rama_utils::macros::match_ignore_ascii_case_str; -use rama_utils::username::{ComposeError, Composer, UsernameLabelWriter}; +use rama_core::username::{ComposeError, Composer, UsernameLabelWriter}; use std::fmt; mod service; @@ -120,7 +120,7 @@ impl UsernameLabelWriter for DnsResolveMode { mod tests { use super::*; use crate::context::Extensions; - use rama_utils::username::{compose_username, parse_username}; + use rama_core::username::{compose_username, parse_username}; #[test] fn parse_username_label_compose_parse_dns_resolve_mode() { diff --git a/rama-http/src/layer/dns/dns_resolve/username_parser.rs b/rama-http/src/layer/dns/dns_resolve/username_parser.rs index 1bbfbf56..884b9a2a 100644 --- a/rama-http/src/layer/dns/dns_resolve/username_parser.rs +++ b/rama-http/src/layer/dns/dns_resolve/username_parser.rs @@ -63,7 +63,7 @@ impl UsernameLabelParser for DnsResolveModeUsernameParser { #[cfg(test)] mod tests { use super::*; - use rama_utils::username::parse_username; + use rama_core::username::parse_username; #[test] fn test_username_dns_resolve_mod_config() { diff --git a/rama-http/src/layer/proxy_auth.rs b/rama-http/src/layer/proxy_auth.rs index 2e1e958a..cdb2d82d 100644 --- a/rama-http/src/layer/proxy_auth.rs +++ b/rama-http/src/layer/proxy_auth.rs @@ -58,9 +58,9 @@ impl ProxyAuthLayer { /// /// You can provide your own extractor by implementing the [`UsernameLabelParser`] trait. /// - /// [`UsernameOpaqueLabelParser`]: rama_utils::username::UsernameOpaqueLabelParser + /// [`UsernameOpaqueLabelParser`]: rama_core::username::UsernameOpaqueLabelParser /// [`ProxyFilterUsernameParser`]: crate::proxy::ProxyFilterUsernameParser - /// [`UsernameLabelParser`]: rama_utils::username::UsernameLabelParser + /// [`UsernameLabelParser`]: rama_core::username::UsernameLabelParser pub fn with_labels(self) -> ProxyAuthLayer { ProxyAuthLayer { proxy_auth: self.proxy_auth, diff --git a/rama-net/Cargo.toml b/rama-net/Cargo.toml index e19a4484..c22eb6bb 100644 --- a/rama-net/Cargo.toml +++ b/rama-net/Cargo.toml @@ -14,6 +14,7 @@ rust-version = { workspace = true } default = [] full = ["http"] http = ["dep:rama-http-types", "rama-core/http"] +telemetry = ["rama-core/telemetry"] [dependencies] base64 = { workspace = true } @@ -29,6 +30,7 @@ parking_lot = { workspace = true } paste = { workspace = true } pin-project-lite = { workspace = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } @@ -40,6 +42,7 @@ venndb = { workspace = true, optional = true } quickcheck = { workspace = true } tokio = { workspace = true, features = ["full"] } tokio-test = { workspace = true } +itertools = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-net/src/address/proxy.rs b/rama-net/src/address/proxy.rs index ce643b6c..c276b73b 100644 --- a/rama-net/src/address/proxy.rs +++ b/rama-net/src/address/proxy.rs @@ -1,6 +1,6 @@ use super::{Authority, Host}; -use rama_core::error::{ErrorContext, OpaqueError}; use crate::{proto::try_to_extract_protocol_from_uri_scheme, user::ProxyCredential, Protocol}; +use rama_core::error::{ErrorContext, OpaqueError}; use std::{fmt::Display, str::FromStr}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -127,7 +127,7 @@ impl<'de> serde::Deserialize<'de> for ProxyAddress { #[cfg(test)] mod tests { use super::*; - use crate::net::{ + use crate::{ address::Host, user::{Basic, Bearer}, }; diff --git a/rama-net/src/forwarded/element/mod.rs b/rama-net/src/forwarded/element/mod.rs index b243aa3d..795c1d12 100644 --- a/rama-net/src/forwarded/element/mod.rs +++ b/rama-net/src/forwarded/element/mod.rs @@ -1,6 +1,6 @@ use super::{ForwardedProtocol, ForwardedVersion, NodeId}; -use rama_core::error::{ErrorContext, OpaqueError}; use crate::address::{Authority, Host}; +use rama_core::error::{ErrorContext, OpaqueError}; use std::fmt; use std::net::SocketAddr; use std::{collections::HashMap, net::IpAddr}; @@ -15,7 +15,7 @@ pub(crate) use parser::{parse_one_plus_forwarded_elements, parse_single_forwarde #[derive(Debug, Clone, PartialEq, Eq)] /// A single entry in the [`Forwarded`] chain. /// -/// [`Forwarded`]: crate::net::forwarded::Forwarded +/// [`Forwarded`]: crate::forwarded::Forwarded pub struct ForwardedElement { by_node: Option, for_node: Option, diff --git a/rama-net/src/forwarded/element/parser.rs b/rama-net/src/forwarded/element/parser.rs index 8c464fd2..30a49e8f 100644 --- a/rama-net/src/forwarded/element/parser.rs +++ b/rama-net/src/forwarded/element/parser.rs @@ -1,8 +1,8 @@ use super::ExtensionValue; use super::{ForwardedElement, NodeId}; -use rama_core::error::{ErrorContext, OpaqueError}; use crate::forwarded::ForwardedProtocol; -use rama_core::utils::macros::match_ignore_ascii_case_str; +use rama_core::error::{ErrorContext, OpaqueError}; +use rama_utils::macros::match_ignore_ascii_case_str; pub(crate) fn parse_single_forwarded_element( bytes: &[u8], diff --git a/rama-net/src/forwarded/mod.rs b/rama-net/src/forwarded/mod.rs index 9064bc8e..8b80e378 100644 --- a/rama-net/src/forwarded/mod.rs +++ b/rama-net/src/forwarded/mod.rs @@ -7,7 +7,11 @@ use std::net::IpAddr; use std::{fmt, net::SocketAddr}; #[cfg(feature = "http")] -use rama_http_types::{HeaderValue, headers::{self, Header}, HeaderName, header::FORWARDED}; +use rama_http_types::{ + header::FORWARDED, + headers::{self, Header}, + HeaderName, HeaderValue, +}; mod obfuscated; #[doc(inline)] @@ -267,7 +271,7 @@ impl Header for Forwarded { #[cfg(test)] mod tests { use super::*; - use crate::net::address::Host; + use crate::address::Host; #[test] fn test_forwarded_parse_invalid() { diff --git a/rama-net/src/forwarded/node.rs b/rama-net/src/forwarded/node.rs index 41d7b430..5620b2c6 100644 --- a/rama-net/src/forwarded/node.rs +++ b/rama-net/src/forwarded/node.rs @@ -1,6 +1,6 @@ use super::{ObfNode, ObfPort}; -use rama_core::error::{ErrorContext, OpaqueError}; use crate::address::{Authority, Domain, Host}; +use rama_core::error::{ErrorContext, OpaqueError}; use std::{ fmt, net::{IpAddr, Ipv6Addr, SocketAddr}, diff --git a/rama-net/src/forwarded/proto.rs b/rama-net/src/forwarded/proto.rs index 331f2e69..0c9cefa3 100644 --- a/rama-net/src/forwarded/proto.rs +++ b/rama-net/src/forwarded/proto.rs @@ -1,5 +1,5 @@ use crate::Protocol; -use rama_core::utils::macros::{str::eq_ignore_ascii_case, error::static_str_error}; +use rama_utils::macros::{error::static_str_error, str::eq_ignore_ascii_case}; use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/rama-net/src/forwarded/version.rs b/rama-net/src/forwarded/version.rs index 915e8b95..abc5d91d 100644 --- a/rama-net/src/forwarded/version.rs +++ b/rama-net/src/forwarded/version.rs @@ -45,7 +45,7 @@ impl ForwardedVersion { } } -rama_core::utils::macros::error::static_str_error! { +rama_utils::macros::error::static_str_error! { #[doc = "invalid forwarded version"] pub struct InvalidForwardedVersion; } diff --git a/rama-net/src/proto.rs b/rama-net/src/proto.rs index b97f24f2..c248bcbe 100644 --- a/rama-net/src/proto.rs +++ b/rama-net/src/proto.rs @@ -3,7 +3,10 @@ use std::cmp::min; use std::str::FromStr; use rama_core::error::{ErrorContext, OpaqueError}; -use rama_core::utils::macros::str::eq_ignore_ascii_case; +use rama_utils::macros::str::eq_ignore_ascii_case; + +#[cfg(feature = "http")] +use rama_http_types::Scheme; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] /// Web protocols that are relevant to Rama. @@ -193,7 +196,7 @@ impl Protocol { } } -rama_core::utils::macros::error::static_str_error! { +rama_utils::macros::error::static_str_error! { #[doc = "invalid protocol string"] pub struct InvalidProtocolStr; } @@ -255,17 +258,19 @@ impl FromStr for Protocol { } } -impl From for Protocol { +#[cfg(feature = "http")] +impl From for Protocol { #[inline] - fn from(s: http::uri::Scheme) -> Self { + fn from(s: Scheme) -> Self { s.as_str() .try_into() .expect("http crate Scheme is pre-validated by promise") } } -impl From<&http::uri::Scheme> for Protocol { - fn from(s: &http::uri::Scheme) -> Self { +#[cfg(feature = "http")] +impl From<&Scheme> for Protocol { + fn from(s: &Scheme) -> Self { s.as_str() .try_into() .expect("http crate Scheme is pre-validated by promise") @@ -434,6 +439,7 @@ mod tests { assert_eq!("custom".parse(), Ok(Protocol::from_static("custom"))); } + #[cfg(feature = "http")] #[test] fn test_from_http_scheme() { for s in [ @@ -441,7 +447,8 @@ mod tests { ] .iter() { - let uri = http::Uri::from_str(format!("{}://example.com", s).as_str()).unwrap(); + let uri = + rama_http_types::Uri::from_str(format!("{}://example.com", s).as_str()).unwrap(); assert_eq!(Protocol::from(uri.scheme().unwrap()), *s); } } diff --git a/rama-net/src/stream/layer/http/body_limit.rs b/rama-net/src/stream/layer/http/body_limit.rs index f13cc570..d6bb5559 100644 --- a/rama-net/src/stream/layer/http/body_limit.rs +++ b/rama-net/src/stream/layer/http/body_limit.rs @@ -1,8 +1,8 @@ -use rama_core::utils::macros::define_inner_service_accessors; use crate::stream::Stream; use rama_core::{Context, Layer, Service}; -use std::fmt; use rama_http_types::BodyLimit; +use rama_utils::macros::define_inner_service_accessors; +use std::fmt; /// Limit the size of the request and/or response bodies. /// diff --git a/rama-net/src/stream/layer/opentelemetry.rs b/rama-net/src/stream/layer/opentelemetry.rs index 229c9e47..975cc09f 100644 --- a/rama-net/src/stream/layer/opentelemetry.rs +++ b/rama-net/src/stream/layer/opentelemetry.rs @@ -2,14 +2,17 @@ //! //! [`Layer`]: crate::Layer -use crate::telemetry::opentelemetry::{ +use crate::stream::SocketInfo; +use rama_core::telemetry::opentelemetry::semantic_conventions::trace::{ + CLIENT_ADDRESS, CLIENT_PORT, NETWORK_TRANSPORT, NETWORK_TYPE, +}; +use rama_core::telemetry::opentelemetry::{ global, metrics::{Histogram, Meter, UpDownCounter}, semantic_conventions, KeyValue, }; -use rama_core::utils::macros::define_inner_service_accessors; -use crate::{stream::SocketInfo, Context, Layer, Service}; -use semantic_conventions::trace::{CLIENT_ADDRESS, CLIENT_PORT, NETWORK_TRANSPORT, NETWORK_TYPE}; +use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, sync::Arc, time::SystemTime}; const NETWORK_CONNECTION_DURATION: &str = "network.server.connection_duration"; @@ -71,8 +74,8 @@ impl Default for NetworkMetricsLayer { /// construct meters for this crate fn get_versioned_meter() -> Meter { global::meter_with_version( - rama_core::utils::info::NAME, - Some(rama_core::utils::info::VERSION), + rama_utils::info::NAME, + Some(rama_utils::info::VERSION), Some(semantic_conventions::SCHEMA_URL), None, ) diff --git a/rama-net/src/stream/layer/tracker/incoming.rs b/rama-net/src/stream/layer/tracker/incoming.rs index d4203dcb..d624c59c 100644 --- a/rama-net/src/stream/layer/tracker/incoming.rs +++ b/rama-net/src/stream/layer/tracker/incoming.rs @@ -1,7 +1,7 @@ use super::bytes::BytesRWTracker; -use rama_core::utils::macros::define_inner_service_accessors; use crate::stream::Stream; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, future::Future}; /// A [`Service`] that wraps a [`Service`]'s input IO [`Stream`] with an atomic R/W tracker. diff --git a/rama-net/src/stream/layer/tracker/outgoing.rs b/rama-net/src/stream/layer/tracker/outgoing.rs index cef2b1e0..5c160a53 100644 --- a/rama-net/src/stream/layer/tracker/outgoing.rs +++ b/rama-net/src/stream/layer/tracker/outgoing.rs @@ -1,10 +1,10 @@ use super::bytes::BytesRWTracker; -use rama_core::utils::macros::define_inner_service_accessors; use crate::{ client::{ConnectorService, EstablishedClientConnection}, stream::Stream, }; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// A [`Service`] that wraps a [`Service`]'s output IO [`Stream`] with an atomic R/W tracker. diff --git a/rama-net/src/stream/matcher/ip.rs b/rama-net/src/stream/matcher/ip.rs index 1f8e2783..16c90ebb 100644 --- a/rama-net/src/stream/matcher/ip.rs +++ b/rama-net/src/stream/matcher/ip.rs @@ -1,6 +1,6 @@ use crate::stream::dep::ipnet::{IpNet, Ipv4Net, Ipv6Net}; -use rama_core::{context::Extensions, Context}; use crate::stream::SocketInfo; +use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; @@ -41,7 +41,7 @@ impl IpNetMatcher { } #[cfg(feature = "http")] -impl crate::matcher::Matcher> for IpNetMatcher { +impl rama_core::matcher::Matcher> for IpNetMatcher { fn matches( &self, _ext: Option<&mut Extensions>, @@ -54,7 +54,7 @@ impl crate::matcher::Matcher> for IpNetMatcher } } -impl crate::matcher::Matcher for IpNetMatcher +impl rama_core::matcher::Matcher for IpNetMatcher where Socket: crate::stream::Socket, { @@ -147,9 +147,9 @@ mod private { #[cfg(test)] mod test { + use super::*; use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; const SUBNET_IPV4: &str = "192.168.0.0/24"; const SUBNET_IPV4_VALID_CASES: [&str; 2] = ["192.168.0.0/25", "192.168.0.1"]; diff --git a/rama-net/src/stream/matcher/loopback.rs b/rama-net/src/stream/matcher/loopback.rs index 0d08a8b4..97e3239a 100644 --- a/rama-net/src/stream/matcher/loopback.rs +++ b/rama-net/src/stream/matcher/loopback.rs @@ -1,5 +1,5 @@ -use rama_core::{context::Extensions, Context}; use crate::stream::SocketInfo; +use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; @@ -46,7 +46,7 @@ impl Default for LoopbackMatcher { } #[cfg(feature = "http")] -impl crate::matcher::Matcher> for LoopbackMatcher { +impl rama_core::matcher::Matcher> for LoopbackMatcher { fn matches( &self, _ext: Option<&mut Extensions>, @@ -59,7 +59,7 @@ impl crate::matcher::Matcher> for LoopbackMatc } } -impl crate::matcher::Matcher for LoopbackMatcher +impl rama_core::matcher::Matcher for LoopbackMatcher where Socket: crate::stream::Socket, { @@ -78,9 +78,9 @@ where #[cfg(test)] mod test { + use super::*; use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; #[cfg(feature = "http")] #[test] diff --git a/rama-net/src/stream/matcher/mod.rs b/rama-net/src/stream/matcher/mod.rs index 66b5e9ff..2efdb164 100644 --- a/rama-net/src/stream/matcher/mod.rs +++ b/rama-net/src/stream/matcher/mod.rs @@ -2,9 +2,9 @@ //! //! See [`service::matcher` module] for more information. //! -//! [`service::Matcher`]: crate::matcher::Matcher +//! [`service::Matcher`]: rama_core::matcher::Matcher //! [`Socket`]: crate::stream::Socket -//! [`service::matcher` module]: crate::matcher +//! [`service::matcher` module]: rama_core::matcher mod socket; #[doc(inline)] @@ -82,8 +82,8 @@ enum SocketMatcherKind { All(Vec>), /// `true` if no matchers are defined, or any of the defined matcher match. Any(Vec>), - /// A custom matcher that implements [`crate::matcher::Matcher`]. - Custom(Arc>), + /// A custom matcher that implements [`rama_core::matcher::Matcher`]. + Custom(Arc>), } impl Clone for SocketMatcherKind { @@ -366,10 +366,10 @@ impl SocketMatcher { /// Create a matcher that matches according to a custom predicate. /// - /// See [`crate::matcher::Matcher`] for more information. + /// See [`rama_core::matcher::Matcher`] for more information. pub fn custom(matcher: M) -> Self where - M: crate::matcher::Matcher, + M: rama_core::matcher::Matcher, { Self { kind: SocketMatcherKind::Custom(Arc::new(matcher)), @@ -379,20 +379,20 @@ impl SocketMatcher { /// Add a custom matcher to match on top of the existing set of [`SocketMatcher`] matchers. /// - /// See [`crate::matcher::Matcher`] for more information. + /// See [`rama_core::matcher::Matcher`] for more information. pub fn and_custom(self, matcher: M) -> Self where - M: crate::matcher::Matcher, + M: rama_core::matcher::Matcher, { self.and(Self::custom(matcher)) } /// Create a custom matcher to match as an alternative to the existing set of [`SocketMatcher`] matchers. /// - /// See [`crate::matcher::Matcher`] for more information. + /// See [`rama_core::matcher::Matcher`] for more information. pub fn or_custom(self, matcher: M) -> Self where - M: crate::matcher::Matcher, + M: rama_core::matcher::Matcher, { self.or(Self::custom(matcher)) } @@ -435,7 +435,7 @@ impl SocketMatcher { } #[cfg(feature = "http")] -impl crate::matcher::Matcher> +impl rama_core::matcher::Matcher> for SocketMatcherKind> where State: 'static, @@ -461,7 +461,7 @@ where } #[cfg(feature = "http")] -impl crate::matcher::Matcher> +impl rama_core::matcher::Matcher> for SocketMatcher> where State: 'static, @@ -482,7 +482,7 @@ where } } -impl crate::matcher::Matcher for SocketMatcherKind +impl rama_core::matcher::Matcher for SocketMatcherKind where Socket: crate::stream::Socket, State: 'static, @@ -501,7 +501,7 @@ where } } -impl crate::matcher::Matcher for SocketMatcher +impl rama_core::matcher::Matcher for SocketMatcher where Socket: crate::stream::Socket, State: 'static, @@ -520,7 +520,7 @@ where mod test { use itertools::Itertools; - use crate::matcher::Matcher; + use rama_core::matcher::Matcher; use super::*; diff --git a/rama-net/src/stream/matcher/port.rs b/rama-net/src/stream/matcher/port.rs index 714e2b0b..818f5109 100644 --- a/rama-net/src/stream/matcher/port.rs +++ b/rama-net/src/stream/matcher/port.rs @@ -1,5 +1,5 @@ -use rama_core::{context::Extensions, Context}; use crate::stream::SocketInfo; +use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; @@ -44,7 +44,7 @@ impl PortMatcher { } #[cfg(feature = "http")] -impl crate::matcher::Matcher> for PortMatcher { +impl rama_core::matcher::Matcher> for PortMatcher { fn matches( &self, _ext: Option<&mut Extensions>, @@ -57,7 +57,7 @@ impl crate::matcher::Matcher> for PortMatcher } } -impl crate::matcher::Matcher for PortMatcher +impl rama_core::matcher::Matcher for PortMatcher where Socket: crate::stream::Socket, { @@ -76,9 +76,9 @@ where #[cfg(test)] mod test { + use super::*; use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; #[cfg(feature = "http")] #[test] diff --git a/rama-net/src/stream/matcher/private_ip.rs b/rama-net/src/stream/matcher/private_ip.rs index 85c1d07b..3b01c74a 100644 --- a/rama-net/src/stream/matcher/private_ip.rs +++ b/rama-net/src/stream/matcher/private_ip.rs @@ -1,6 +1,6 @@ use crate::stream::dep::ipnet::IpNet; -use rama_core::{context::Extensions, Context}; use crate::stream::SocketInfo; +use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; @@ -118,7 +118,7 @@ impl Default for PrivateIpNetMatcher { } #[cfg(feature = "http")] -impl crate::matcher::Matcher> for PrivateIpNetMatcher { +impl rama_core::matcher::Matcher> for PrivateIpNetMatcher { fn matches( &self, _ext: Option<&mut Extensions>, @@ -134,7 +134,7 @@ impl crate::matcher::Matcher> for PrivateIpNet } } -impl crate::matcher::Matcher for PrivateIpNetMatcher +impl rama_core::matcher::Matcher for PrivateIpNetMatcher where Socket: crate::stream::Socket, { @@ -156,9 +156,9 @@ where #[cfg(test)] mod test { + use super::*; use rama_core::matcher::Matcher; use std::net::SocketAddr; - use super::*; #[cfg(feature = "http")] #[test] diff --git a/rama-net/src/stream/matcher/socket.rs b/rama-net/src/stream/matcher/socket.rs index 1339d007..7b988d9e 100644 --- a/rama-net/src/stream/matcher/socket.rs +++ b/rama-net/src/stream/matcher/socket.rs @@ -1,5 +1,5 @@ -use rama_core::{context::Extensions, Context}; use crate::stream::SocketInfo; +use rama_core::{context::Extensions, Context}; use std::net::SocketAddr; #[cfg(feature = "http")] @@ -38,7 +38,7 @@ impl SocketAddressMatcher { } } -impl crate::matcher::Matcher> for SocketAddressMatcher { +impl rama_core::matcher::Matcher> for SocketAddressMatcher { fn matches( &self, _ext: Option<&mut Extensions>, @@ -51,7 +51,7 @@ impl crate::matcher::Matcher> for SocketAddres } } -impl crate::matcher::Matcher for SocketAddressMatcher +impl rama_core::matcher::Matcher for SocketAddressMatcher where Socket: crate::stream::Socket, { @@ -71,7 +71,8 @@ where #[cfg(feature = "http")] #[cfg(test)] mod test { - use crate::{http::Body, matcher::Matcher}; + use rama_core::matcher::Matcher; + use rama_http_types::Body; use super::*; diff --git a/rama-net/src/stream/service/echo.rs b/rama-net/src/stream/service/echo.rs index 01de9cb0..f9240212 100644 --- a/rama-net/src/stream/service/echo.rs +++ b/rama-net/src/stream/service/echo.rs @@ -1,14 +1,15 @@ //! An async service which echoes the incoming bytes back on the same stream. -use rama_core::{error::BoxError, Context, Service}; use crate::stream::Stream; +use rama_core::{error::BoxError, Context, Service}; /// An async service which echoes the incoming bytes back on the same stream. /// /// # Example /// /// ```rust -/// use rama::{error::BoxError, Context, Service, stream::service::EchoService}; +/// use rama_core::{error::BoxError, Context, Service}; +/// use rama_net::stream::service::EchoService; /// /// # #[tokio::main] /// # async fn main() -> Result<(), BoxError> { diff --git a/rama-net/src/user/auth.rs b/rama-net/src/user/auth.rs index 1b2874f7..f6c99f6e 100644 --- a/rama-net/src/user/auth.rs +++ b/rama-net/src/user/auth.rs @@ -2,7 +2,7 @@ use crate::user::{Basic, UserId}; use rama_core::context::Extensions; -use rama_core::utils::username::{parse_username, UsernameLabelParser}; +use rama_core::username::{parse_username, UsernameLabelParser}; use std::future::Future; // TODO: decouple this from http @@ -44,17 +44,6 @@ where } } -impl AuthoritySync for Basic { - fn authorized(&self, ext: &mut Extensions, credentials: &Basic) -> bool { - if self == credentials { - ext.insert(UserId::Username(self.username().to_owned())); - true - } else { - false - } - } -} - impl AuthoritySync for Basic { fn authorized(&self, ext: &mut Extensions, credentials: &Basic) -> bool { let username = credentials.username(); @@ -111,10 +100,8 @@ where #[cfg(test)] mod test { use super::*; - use crate::{ - net::user::Basic, - utils::username::{UsernameLabels, UsernameOpaqueLabelParser}, - }; + use crate::user::Basic; + use rama_core::username::{UsernameLabels, UsernameOpaqueLabelParser}; #[tokio::test] async fn basic_authorization() { diff --git a/rama-net/src/user/credentials/basic.rs b/rama-net/src/user/credentials/basic.rs index 30a7c459..3a72875f 100644 --- a/rama-net/src/user/credentials/basic.rs +++ b/rama-net/src/user/credentials/basic.rs @@ -1,9 +1,12 @@ -use rama_core::error::{ErrorContext, OpaqueError}; use base64::engine::general_purpose::STANDARD as ENGINE; use base64::Engine; use headers::authorization; +use rama_core::error::{ErrorContext, OpaqueError}; use std::borrow::Cow; +#[cfg(feature = "http")] +use rama_http_types::HeaderValue; + #[derive(Debug, Clone)] /// Basic credentials. pub struct Basic { @@ -105,11 +108,11 @@ impl Basic { encoded } - /// View this [`Basic`] as a [`HeaderValue`][http::HeaderValue]. - pub fn as_header_value(&self) -> http::HeaderValue { + /// View this [`Basic`] as a [`HeaderValue`] + pub fn as_header_value(&self) -> HeaderValue { let encoded = self.as_header_string(); // we validate the inner value upon creation - http::HeaderValue::from_str(&encoded).expect("inner value should always be valid") + HeaderValue::from_str(&encoded).expect("inner value should always be valid") } /// Serialize this [`Basic`] credential as a clear (not encoded) string. @@ -163,12 +166,12 @@ const BASIC_SCHEME: &str = "Basic"; impl authorization::Credentials for Basic { const SCHEME: &'static str = BASIC_SCHEME; - fn decode(value: &http::HeaderValue) -> Option { + fn decode(value: &HeaderValue) -> Option { let value = value.to_str().ok()?; Self::try_from_header_str(value).ok() } - fn encode(&self) -> http::HeaderValue { + fn encode(&self) -> HeaderValue { self.as_header_value() } } @@ -214,7 +217,7 @@ mod tests { #[test] fn basic_decode() { - let auth = Basic::decode(&http::HeaderValue::from_static( + let auth = Basic::decode(&HeaderValue::from_static( "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", )) .unwrap(); @@ -224,7 +227,7 @@ mod tests { #[test] fn basic_decode_case_insensitive() { - let auth = Basic::decode(&http::HeaderValue::from_static( + let auth = Basic::decode(&HeaderValue::from_static( "basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", )) .unwrap(); @@ -234,7 +237,7 @@ mod tests { #[test] fn basic_decode_extra_whitespaces() { - let auth = Basic::decode(&http::HeaderValue::from_static( + let auth = Basic::decode(&HeaderValue::from_static( "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", )) .unwrap(); @@ -244,7 +247,7 @@ mod tests { #[test] fn basic_decode_no_password() { - let auth = Basic::decode(&http::HeaderValue::from_static("Basic QWxhZGRpbjo=")).unwrap(); + let auth = Basic::decode(&HeaderValue::from_static("Basic QWxhZGRpbjo=")).unwrap(); assert_eq!(auth.username(), "Aladdin"); assert_eq!(auth.password(), ""); } diff --git a/rama-net/src/user/credentials/bearer.rs b/rama-net/src/user/credentials/bearer.rs index b35eb8d2..020d5257 100644 --- a/rama-net/src/user/credentials/bearer.rs +++ b/rama-net/src/user/credentials/bearer.rs @@ -1,7 +1,10 @@ -use rama_core::error::{ErrorContext, OpaqueError}; use headers::authorization; +use rama_core::error::{ErrorContext, OpaqueError}; use std::borrow::Cow; +#[cfg(feature = "http")] +use rama_http_types::HeaderValue; + #[derive(Debug, Clone, PartialEq, Eq)] /// Bearer credentials. pub struct Bearer(Cow<'static, str>); @@ -53,11 +56,11 @@ impl Bearer { format!("{BEARER_SCHEME} {}", self.0) } - /// View this [`Bearer`] as a [`HeaderValue`][http::HeaderValue]. - pub fn as_header_value(&self) -> http::HeaderValue { + /// View this [`Bearer`] as a [`HeaderValue`]. + pub fn as_header_value(&self) -> HeaderValue { let encoded = self.as_header_string(); // we validate the inner value upon creation - http::HeaderValue::from_str(&encoded).expect("inner value should always be valid") + HeaderValue::from_str(&encoded).expect("inner value should always be valid") } /// Serialize this [`Bearer`] credential as a clear (not encoded) string. @@ -76,11 +79,11 @@ const BEARER_SCHEME: &str = "Bearer"; impl authorization::Credentials for Bearer { const SCHEME: &'static str = BEARER_SCHEME; - fn decode(value: &http::HeaderValue) -> Option { + fn decode(value: &HeaderValue) -> Option { Self::try_from_header_str(value.to_str().ok()?).ok() } - fn encode(&self) -> http::HeaderValue { + fn encode(&self) -> HeaderValue { self.as_header_value() } } @@ -112,19 +115,19 @@ mod tests { #[test] fn bearer_decode() { - let auth = Bearer::decode(&http::HeaderValue::from_static("Bearer foobar")).unwrap(); + let auth = Bearer::decode(&HeaderValue::from_static("Bearer foobar")).unwrap(); assert_eq!(auth.token(), "foobar"); } #[test] fn bearer_decode_case_insensitive() { - let auth = Bearer::decode(&http::HeaderValue::from_static("bearer foobar")).unwrap(); + let auth = Bearer::decode(&HeaderValue::from_static("bearer foobar")).unwrap(); assert_eq!(auth.token(), "foobar"); } #[test] fn bearer_decode_extra_whitespaces() { - let auth = Bearer::decode(&http::HeaderValue::from_static( + let auth = Bearer::decode(&HeaderValue::from_static( "Bearer QWxhZGRpbjpvcGVuIHNlc2FtZQ==", )) .unwrap(); diff --git a/rama-proxy/src/username.rs b/rama-proxy/src/username.rs index f12cea2d..7b1931e0 100644 --- a/rama-proxy/src/username.rs +++ b/rama-proxy/src/username.rs @@ -172,8 +172,8 @@ impl UsernameLabelParser for ProxyFilterUsernameParser { impl UsernameLabelWriter for ProxyFilter { fn write_labels( &self, - composer: &mut rama_utils::username::Composer, - ) -> Result<(), rama_utils::username::ComposeError> { + composer: &mut rama_core::username::Composer, + ) -> Result<(), rama_core::username::ComposeError> { if let Some(id) = &self.id { composer.write_label("id")?; composer.write_label(id.as_str())?; diff --git a/rama-utils/src/macros/str.rs b/rama-utils/src/macros/str.rs index 6ffe7d79..e9f7b10d 100644 --- a/rama-utils/src/macros/str.rs +++ b/rama-utils/src/macros/str.rs @@ -39,7 +39,7 @@ impl EqIgnoreAsciiCase<&[u8; N1], &[u8; N2]> { #[macro_export] macro_rules! __eq_ignore_ascii_case { ($lhs:expr, $rhs:expr) => { - $crate::str::EqIgnoreAsciiCase($lhs, $rhs).const_eval() + $crate::macros::str::EqIgnoreAsciiCase($lhs, $rhs).const_eval() }; } pub use crate::__eq_ignore_ascii_case as eq_ignore_ascii_case; diff --git a/src/lib.rs b/src/lib.rs index 231b6cbf..ec877ece 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! | πŸ—οΈ web protocols | πŸ—οΈ Web Sockets (WS) (2) βΈ± πŸ—οΈ WSS (2) βΈ± ❌ Web Transport (3) βΈ± ❌ gRPC (3) | //! | βœ… [async-method trait](https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html) services | βœ… [Service] βΈ± βœ… [Layer] βΈ± βœ… [context] βΈ± βœ… [dyn dispatch](crate::service::BoxService) βΈ± βœ… [middleware](crate::layer) | //! | βœ… [telemetry][opentelemetry] | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry] βΈ± βœ… [http metrics](crate::http::layer::opentelemetry) βΈ± βœ… [transport metrics](crate::stream::layer::opentelemetry) | -//! | βœ… upstream [proxies](proxy) | βœ… [MemoryProxyDB](crate::proxy::MemoryProxyDB) βΈ± βœ… [L4 Username Config](rama_utils::username) βΈ± βœ… [Proxy Filters](crate::proxy::ProxyFilter) | +//! | βœ… upstream [proxies](proxy) | βœ… [MemoryProxyDB](crate::proxy::MemoryProxyDB) βΈ± βœ… [L4 Username Config] βΈ± βœ… [Proxy Filters](crate::proxy::ProxyFilter) | //! | πŸ—οΈ [User Agent (UA)](https://ramaproxy.org/book/intro/user_agent) | πŸ—οΈ Http Emulation (1) βΈ± πŸ—οΈ Tls Emulation (1) βΈ± βœ… [UA Parsing](crate::ua::UserAgent) | //! | βœ… utilities | βœ… [error handling](crate::error) βΈ± βœ… [graceful shutdown](crate::graceful) βΈ± πŸ—οΈ Connection Pool (2) βΈ± πŸ—οΈ IP2Loc (2) | //! | πŸ—οΈ [TUI](https://ratatui.rs/) | πŸ—οΈ traffic logger (2) βΈ± πŸ—οΈ curl export (2) βΈ± ❌ traffic intercept (3) βΈ± ❌ traffic replay (3) | @@ -33,6 +33,8 @@ //! | πŸ—οΈ data scraping | πŸ—οΈ Html Processor (2) βΈ± ❌ Json Processor (3) | //! | ❌ browser | ❌ JS Engine (3) βΈ± ❌ [Web API](https://developer.mozilla.org/en-US/docs/Web/API) Emulation (3) | //! +//! [L4 Username Config]: https://docs.rs/rama-core/latest/rama_core/username/index.html +//! //! > πŸ—’οΈ _Footnotes_ //! > //! > * (1) Part of [`v0.2.0` milestone (ETA: 2024 mid Q3)](https://github.com/plabayo/rama/milestone/1) From 72598a1a8971eb8311324d055ac8f6106eab52bd Mon Sep 17 00:00:00 2001 From: glendc Date: Tue, 3 Sep 2024 11:10:45 +0200 Subject: [PATCH 04/24] integrate utils in rama, fix readmes and sort tomls --- Cargo.toml | 7 ++++--- rama-core/Cargo.toml | 2 +- rama-net/Cargo.toml | 6 +++--- rama-proxy/README.md | 5 +---- rama-tls/Cargo.toml | 2 +- rama-tls/README.md | 5 +---- rama-utils/Cargo.toml | 4 ++-- src/lib.rs | 2 ++ 8 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1b48bb8c..80526ffa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = [ ".", "fuzz", - "rama-utils", + "rama-cli", "rama-core", "rama-error", "rama-http", @@ -13,7 +13,7 @@ members = [ "rama-proxy", "rama-tls", "rama-ua", - "rama-cli", + "rama-utils", ] [workspace.package] @@ -175,12 +175,13 @@ parking_lot = { workspace = true } paste = { workspace = true } percent-encoding = { workspace = true } pin-project-lite = { workspace = true } -rama-macros = { version = "0.2.0-alpha.2", path = "rama-macros" } rama-core = { version = "0.2.0-alpha.2", path = "rama-core" } rama-http = { version = "0.2.0-alpha.2", path = "rama-http", optional = true } +rama-macros = { version = "0.2.0-alpha.2", path = "rama-macros" } rama-proxy = { version = "0.2.0-alpha.2", path = "rama-proxy", optional = true } rama-tls = { version = "0.2.0-alpha.2", path = "rama-tls", optional = true } rama-ua = { version = "0.2.0-alpha.2", path = "rama-ua", optional = true } +rama-utils = { version = "0.2.0-alpha.2", path = "rama-utils" } regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } diff --git a/rama-core/Cargo.toml b/rama-core/Cargo.toml index 0eb96eec..49533994 100644 --- a/rama-core/Cargo.toml +++ b/rama-core/Cargo.toml @@ -34,8 +34,8 @@ paste = { workspace = true } pin-project-lite = { workspace = true } rama-error = { version = "0.2.0-alpha.2", path = "../rama-error" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } -rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-macros = { version = "0.2.0-alpha.2", path = "../rama-macros" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } tokio-graceful = { workspace = true } diff --git a/rama-net/Cargo.toml b/rama-net/Cargo.toml index c22eb6bb..bdf826e6 100644 --- a/rama-net/Cargo.toml +++ b/rama-net/Cargo.toml @@ -18,11 +18,11 @@ telemetry = ["rama-core/telemetry"] [dependencies] base64 = { workspace = true } +bytes = { workspace = true } futures-lite = { workspace = true } headers = { workspace = true } hickory-resolver = { workspace = true } ipnet = { workspace = true } -bytes = { workspace = true } opentelemetry = { workspace = true, optional = true } opentelemetry-semantic-conventions = { workspace = true, optional = true } opentelemetry_sdk = { workspace = true, optional = true } @@ -30,8 +30,8 @@ parking_lot = { workspace = true } paste = { workspace = true } pin-project-lite = { workspace = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } -rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } tokio-graceful = { workspace = true } @@ -39,10 +39,10 @@ tracing = { workspace = true } venndb = { workspace = true, optional = true } [dev-dependencies] +itertools = { workspace = true } quickcheck = { workspace = true } tokio = { workspace = true, features = ["full"] } tokio-test = { workspace = true } -itertools = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-proxy/README.md b/rama-proxy/README.md index c58e031e..33936206 100644 --- a/rama-proxy/README.md +++ b/rama-proxy/README.md @@ -39,10 +39,7 @@ The reasons behind the creation of rama can be read in [the "Why Rama" chapter]( ## rama-proxy -User-Agent (UA) support for `rama`. - -This crate only focusses on the majority user-agents within -the web space. Feature requests are welcome, but keep this scope in mind. +Proxy protocols and upstream proxy support for rama. Learn more about `rama`: diff --git a/rama-tls/Cargo.toml b/rama-tls/Cargo.toml index 1018b328..007bd9c0 100644 --- a/rama-tls/Cargo.toml +++ b/rama-tls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rama-tls" -description = "user-agent (UA) support for rama" +description = "tls support for rama" version = { workspace = true } license = { workspace = true } edition = { workspace = true } diff --git a/rama-tls/README.md b/rama-tls/README.md index dce14a54..5ab2b2bf 100644 --- a/rama-tls/README.md +++ b/rama-tls/README.md @@ -39,10 +39,7 @@ The reasons behind the creation of rama can be read in [the "Why Rama" chapter]( ## rama-tls -User-Agent (UA) support for `rama`. - -This crate only focusses on the majority user-agents within -the web space. Feature requests are welcome, but keep this scope in mind. +Tls support for `rama`. Learn more about `rama`: diff --git a/rama-utils/Cargo.toml b/rama-utils/Cargo.toml index faddaf3e..8bada8fa 100644 --- a/rama-utils/Cargo.toml +++ b/rama-utils/Cargo.toml @@ -13,12 +13,12 @@ rust-version = { workspace = true } [dependencies] parking_lot = { workspace = true } pin-project-lite = { workspace = true } -tokio = { workspace = true, features = ["time", "macros"] } serde = { workspace = true, features = ["derive"] } +tokio = { workspace = true, features = ["time", "macros"] } [dev-dependencies] -tokio-test = { workspace = true } quickcheck = { workspace = true } +tokio-test = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/src/lib.rs b/src/lib.rs index ec877ece..cc74ffa1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -302,3 +302,5 @@ pub use ::rama_ua as ua; #[cfg(feature = "cli")] pub mod cli; + +pub use ::rama_utils as utils; From 47a531a27ed7601507a24033f9c066c1c3531deb Mon Sep 17 00:00:00 2001 From: glendc Date: Tue, 3 Sep 2024 14:24:10 +0200 Subject: [PATCH 05/24] fix rama-ua tests + a lot of rama-http already --- Cargo.lock | 11 ++ rama-http/Cargo.toml | 8 + rama-http/src/client/conn.rs | 2 +- rama-http/src/client/error.rs | 4 +- rama-http/src/client/ext.rs | 138 +++++++++--------- rama-http/src/client/svc.rs | 4 +- rama-http/src/layer/auth/add_authorization.rs | 16 +- .../layer/auth/async_require_authorization.rs | 12 +- .../src/layer/auth/require_authorization.rs | 10 +- rama-http/src/layer/body_limit.rs | 10 +- rama-http/src/layer/catch_panic.rs | 4 +- .../layer/classify/grpc_errors_as_failures.rs | 2 +- .../src/layer/classify/map_failure_class.rs | 2 +- rama-http/src/layer/classify/mod.rs | 2 +- rama-http/src/layer/compression/body.rs | 8 +- rama-http/src/layer/compression/layer.rs | 10 +- rama-http/src/layer/compression/mod.rs | 10 +- rama-http/src/layer/compression/service.rs | 12 +- rama-http/src/layer/cors/allow_credentials.rs | 2 +- rama-http/src/layer/cors/allow_headers.rs | 2 +- rama-http/src/layer/cors/allow_methods.rs | 2 +- rama-http/src/layer/cors/allow_origin.rs | 2 +- .../src/layer/cors/allow_private_network.rs | 8 +- rama-http/src/layer/cors/expose_headers.rs | 2 +- rama-http/src/layer/cors/max_age.rs | 2 +- rama-http/src/layer/cors/mod.rs | 8 +- rama-http/src/layer/cors/tests.rs | 4 +- rama-http/src/layer/cors/vary.rs | 2 +- rama-http/src/layer/decompression/body.rs | 8 +- rama-http/src/layer/decompression/layer.rs | 6 +- rama-http/src/layer/decompression/mod.rs | 6 +- .../src/layer/decompression/request/layer.rs | 6 +- .../src/layer/decompression/request/mod.rs | 6 +- .../layer/decompression/request/service.rs | 14 +- rama-http/src/layer/decompression/service.rs | 10 +- rama-http/src/layer/dns/dns_map/layer.rs | 5 +- rama-http/src/layer/dns/dns_map/mod.rs | 2 +- rama-http/src/layer/dns/dns_map/service.rs | 8 +- rama-http/src/layer/dns/dns_resolve/layer.rs | 5 +- rama-http/src/layer/dns/dns_resolve/mod.rs | 4 +- .../src/layer/dns/dns_resolve/service.rs | 5 +- .../layer/dns/dns_resolve/username_parser.rs | 7 +- rama-http/src/layer/error_handling.rs | 6 +- rama-http/src/layer/follow_redirect/mod.rs | 8 +- .../src/layer/follow_redirect/policy/and.rs | 5 +- .../follow_redirect/policy/clone_body_fn.rs | 3 +- .../policy/filter_credentials.rs | 10 +- .../layer/follow_redirect/policy/limited.rs | 5 +- .../src/layer/follow_redirect/policy/mod.rs | 6 +- .../src/layer/follow_redirect/policy/or.rs | 3 +- .../follow_redirect/policy/redirect_fn.rs | 3 +- .../follow_redirect/policy/same_origin.rs | 5 +- .../src/layer/forwarded/get_forwarded.rs | 10 +- .../src/layer/forwarded/set_forwarded.rs | 12 +- rama-http/src/layer/header_config.rs | 17 +-- rama-http/src/layer/header_option_value.rs | 13 +- rama-http/src/layer/map_request_body.rs | 8 +- rama-http/src/layer/map_response_body.rs | 8 +- rama-http/src/layer/normalize_path.rs | 4 +- rama-http/src/layer/propagate_headers.rs | 8 +- rama-http/src/layer/proxy_auth.rs | 10 +- rama-http/src/layer/remove_header/mod.rs | 2 +- rama-http/src/layer/remove_header/request.rs | 4 +- rama-http/src/layer/remove_header/response.rs | 4 +- rama-http/src/layer/request_id.rs | 8 +- .../src/layer/required_header/request.rs | 23 ++- .../src/layer/required_header/response.rs | 9 +- rama-http/src/layer/retry/body.rs | 8 +- rama-http/src/layer/retry/managed.rs | 8 +- rama-http/src/layer/retry/mod.rs | 10 +- rama-http/src/layer/retry/policy.rs | 3 +- rama-http/src/layer/retry/tests.rs | 4 +- rama-http/src/layer/sensitive_headers.rs | 16 +- rama-http/src/layer/set_header/mod.rs | 4 +- rama-http/src/layer/set_header/request.rs | 8 +- rama-http/src/layer/set_header/response.rs | 6 +- rama-http/src/layer/set_status.rs | 4 +- rama-http/src/layer/timeout.rs | 5 +- rama-http/src/layer/trace/body.rs | 4 +- rama-http/src/layer/trace/layer.rs | 7 +- rama-http/src/layer/trace/make_span.rs | 2 +- rama-http/src/layer/trace/mod.rs | 20 ++- rama-http/src/layer/trace/on_body_chunk.rs | 2 +- rama-http/src/layer/trace/on_eos.rs | 10 +- rama-http/src/layer/trace/on_failure.rs | 2 +- rama-http/src/layer/trace/on_request.rs | 8 +- rama-http/src/layer/trace/on_response.rs | 14 +- rama-http/src/layer/trace/service.rs | 10 +- rama-http/src/layer/traffic_writer/mod.rs | 8 +- rama-http/src/layer/traffic_writer/request.rs | 14 +- .../src/layer/traffic_writer/response.rs | 14 +- rama-http/src/layer/ua.rs | 59 ++++++-- rama-http/src/layer/upgrade/layer.rs | 5 +- rama-http/src/layer/upgrade/service.rs | 5 +- rama-http/src/layer/util/compression.rs | 7 +- .../layer/validate_request/accept_header.rs | 8 +- .../src/layer/validate_request/validate.rs | 6 +- .../src/layer/validate_request/validate_fn.rs | 6 +- .../validate_request_header.rs | 12 +- rama-http/src/lib.rs | 7 +- rama-http/src/matcher/domain.rs | 6 +- rama-http/src/matcher/header.rs | 6 +- rama-http/src/matcher/method.rs | 4 +- rama-http/src/matcher/mod.rs | 12 +- rama-http/src/matcher/path/mod.rs | 10 +- rama-http/src/matcher/uri.rs | 4 +- rama-http/src/matcher/version.rs | 4 +- rama-http/src/request_context.rs | 22 +-- rama-http/src/server/hyper_conn.rs | 6 +- rama-http/src/server/service.rs | 8 +- rama-http/src/server/svc_hyper.rs | 10 +- rama-http/src/service/fs/serve_dir/future.rs | 11 +- rama-http/src/service/fs/serve_dir/headers.rs | 2 +- rama-http/src/service/fs/serve_dir/mod.rs | 10 +- .../src/service/fs/serve_dir/open_file.rs | 4 +- rama-http/src/service/fs/serve_dir/tests.rs | 14 +- rama-http/src/service/fs/serve_file.rs | 22 +-- rama-http/src/service/redirect.rs | 6 +- .../service/web/endpoint/extract/authority.rs | 23 +-- .../web/endpoint/extract/body/bytes.rs | 13 +- .../service/web/endpoint/extract/body/form.rs | 18 +-- .../service/web/endpoint/extract/body/json.rs | 16 +- .../service/web/endpoint/extract/body/mod.rs | 7 +- .../service/web/endpoint/extract/body/text.rs | 12 +- .../service/web/endpoint/extract/context.rs | 4 +- .../src/service/web/endpoint/extract/dns.rs | 4 +- .../service/web/endpoint/extract/extension.rs | 6 +- .../src/service/web/endpoint/extract/host.rs | 23 +-- .../service/web/endpoint/extract/method.rs | 4 +- .../src/service/web/endpoint/extract/mod.rs | 4 +- .../src/service/web/endpoint/extract/path.rs | 12 +- .../src/service/web/endpoint/extract/query.rs | 6 +- .../service/web/endpoint/extract/request.rs | 4 +- .../src/service/web/endpoint/extract/state.rs | 4 +- .../web/endpoint/extract/typed_header.rs | 8 +- rama-http/src/service/web/endpoint/mod.rs | 12 +- rama-http/src/service/web/endpoint/service.rs | 7 +- rama-http/src/service/web/k8s.rs | 9 +- rama-http/src/service/web/service.rs | 22 +-- .../utils/{utils => }/macros/http_error.rs | 26 ++-- rama-http/src/utils/{utils => }/macros/mod.rs | 2 - rama-http/src/utils/mod.rs | 3 + rama-http/src/utils/utils/mod.rs | 9 -- rama-net/src/stream/matcher/ip.rs | 4 +- rama-net/src/stream/matcher/loopback.rs | 4 +- rama-net/src/stream/matcher/port.rs | 3 +- rama-net/src/stream/matcher/private_ip.rs | 3 +- rama-net/src/stream/matcher/socket.rs | 5 +- rama-net/src/user/credentials/basic.rs | 84 ++++++----- rama-net/src/user/credentials/bearer.rs | 8 +- rama-ua/Cargo.toml | 3 + rama-ua/src/info.rs | 8 +- rama-ua/src/lib.rs | 38 +---- rama-ua/src/parse_tests.rs | 2 +- 154 files changed, 742 insertions(+), 730 deletions(-) rename rama-http/src/utils/{utils => }/macros/http_error.rs (87%) rename rama-http/src/utils/{utils => }/macros/mod.rs (58%) delete mode 100644 rama-http/src/utils/utils/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 3457dcaf..50ee9d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1773,6 +1773,7 @@ dependencies = [ "rama-proxy", "rama-tls", "rama-ua", + "rama-utils", "regex", "rustversion", "serde", @@ -1850,6 +1851,7 @@ name = "rama-http" version = "0.2.0-alpha.2" dependencies = [ "async-compression", + "base64 0.22.1", "bytes", "const_format", "futures-core", @@ -1858,12 +1860,18 @@ dependencies = [ "http", "http-body", "http-body-util", + "http-range-header", + "httpdate", "mime", "mime_guess", "paste", "pin-project-lite", "rama-core", "rama-http-types", + "rama-net", + "rama-ua", + "rama-utils", + "regex", "serde", "serde_html_form", "serde_json", @@ -1978,7 +1986,10 @@ name = "rama-ua" version = "0.2.0-alpha.2" dependencies = [ "rama-core", + "rama-utils", "serde", + "serde_json", + "tokio", ] [[package]] diff --git a/rama-http/Cargo.toml b/rama-http/Cargo.toml index 4ee54e20..0af17436 100644 --- a/rama-http/Cargo.toml +++ b/rama-http/Cargo.toml @@ -34,13 +34,21 @@ mime = { workspace = true } mime_guess = { workspace = true } paste = { workspace = true } pin-project-lite = { workspace = true } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-ua = { version = "0.2.0-alpha.2", path = "../rama-ua" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } serde_json = { workspace = true } sync_wrapper = { workspace = true } tracing = { workspace = true } +regex = { workspace = true } +base64 = { workspace = true } +httpdate = { workspace = true } +tokio = { workspace = true, features = ["macros", "fs", "io-std"] } +http-range-header = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["full"] } diff --git a/rama-http/src/client/conn.rs b/rama-http/src/client/conn.rs index 5daacdfd..e436b2ad 100644 --- a/rama-http/src/client/conn.rs +++ b/rama-http/src/client/conn.rs @@ -1,5 +1,5 @@ use super::{svc::SendRequest, HttpClientService}; -use crate::http::executor::HyperExecutor; +use crate::executor::HyperExecutor; use rama_utils::macros::define_inner_service_accessors; use crate::{ error::{BoxError, OpaqueError}, diff --git a/rama-http/src/client/error.rs b/rama-http/src/client/error.rs index 3f16cf5c..f9778807 100644 --- a/rama-http/src/client/error.rs +++ b/rama-http/src/client/error.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use crate::error::{BoxError, OpaqueError}; -use crate::http::Uri; +use crate::Uri; // TODO: support perhaps also more context, such as tracing id, ... @@ -9,7 +9,7 @@ use crate::http::Uri; /// An opaque error type that encapsulates all possible errors that can occur when using the /// [`HttpClient`] service directly, as part of a stack or as a building block for other services. /// -/// [`HttpClient`]: crate::http::client::HttpClient +/// [`HttpClient`]: crate::client::HttpClient pub struct HttpClientError { inner: OpaqueError, uri: Option, diff --git a/rama-http/src/client/ext.rs b/rama-http/src/client/ext.rs index 35818af6..1a0ee8e3 100644 --- a/rama-http/src/client/ext.rs +++ b/rama-http/src/client/ext.rs @@ -23,7 +23,7 @@ pub trait HttpClientExt: /// /// This method fails whenever the supplied [`Url`] cannot be parsed. /// - /// [`Url`]: crate::http::Uri + /// [`Url`]: crate::Uri fn get(&self, url: impl IntoUrl) -> RequestBuilder; /// Convenience method to make a `POST` request to a URL. @@ -32,7 +32,7 @@ pub trait HttpClientExt: /// /// This method fails whenever the supplied [`Url`] cannot be parsed. /// - /// [`Url`]: crate::http::Uri + /// [`Url`]: crate::Uri fn post(&self, url: impl IntoUrl) -> RequestBuilder; /// Convenience method to make a `PUT` request to a URL. @@ -41,7 +41,7 @@ pub trait HttpClientExt: /// /// This method fails whenever the supplied [`Url`] cannot be parsed. /// - /// [`Url`]: crate::http::Uri + /// [`Url`]: crate::Uri fn put(&self, url: impl IntoUrl) -> RequestBuilder; /// Convenience method to make a `PATCH` request to a URL. @@ -50,7 +50,7 @@ pub trait HttpClientExt: /// /// This method fails whenever the supplied [`Url`] cannot be parsed. /// - /// [`Url`]: crate::http::Uri + /// [`Url`]: crate::Uri fn patch(&self, url: impl IntoUrl) -> RequestBuilder; /// Convenience method to make a `DELETE` request to a URL. @@ -59,7 +59,7 @@ pub trait HttpClientExt: /// /// This method fails whenever the supplied [`Url`] cannot be parsed. /// - /// [`Url`]: crate::http::Uri + /// [`Url`]: crate::Uri fn delete(&self, url: impl IntoUrl) -> RequestBuilder; /// Convenience method to make a `HEAD` request to a URL. @@ -74,9 +74,9 @@ pub trait HttpClientExt: /// Returns a [`RequestBuilder`], which will allow setting headers and /// the request body before sending. /// - /// [`Request`]: crate::http::Request - /// [`Method`]: crate::http::Method - /// [`Url`]: crate::http::Uri + /// [`Request`]: crate::Request + /// [`Method`]: crate::Method + /// [`Url`]: crate::Uri /// /// # Errors /// @@ -146,7 +146,7 @@ where } }; - let builder = crate::http::dep::http::request::Builder::new() + let builder = crate::dep::http::request::Builder::new() .method(method) .uri(uri); @@ -170,7 +170,7 @@ where /// /// This trait is β€œsealed”, such that only types within rama can implement it. /// -/// [`Url`]: crate::http::Uri +/// [`Url`]: crate::Uri pub trait IntoUrl: private::IntoUrlSealed {} impl IntoUrl for Uri {} @@ -182,11 +182,11 @@ impl IntoUrl for &String {} /// /// This trait is β€œsealed”, such that only types within rama can implement it. /// -/// [`HeaderName`]: crate::http::HeaderName +/// [`HeaderName`]: crate::HeaderName pub trait IntoHeaderName: private::IntoHeaderNameSealed {} -impl IntoHeaderName for crate::http::HeaderName {} -impl IntoHeaderName for Option {} +impl IntoHeaderName for crate::HeaderName {} +impl IntoHeaderName for Option {} impl IntoHeaderName for &str {} impl IntoHeaderName for String {} impl IntoHeaderName for &String {} @@ -196,10 +196,10 @@ impl IntoHeaderName for &[u8] {} /// /// This trait is β€œsealed”, such that only types within rama can implement it. /// -/// [`HeaderValue`]: crate::http::HeaderValue +/// [`HeaderValue`]: crate::HeaderValue pub trait IntoHeaderValue: private::IntoHeaderValueSealed {} -impl IntoHeaderValue for crate::http::HeaderValue {} +impl IntoHeaderValue for crate::HeaderValue {} impl IntoHeaderValue for &str {} impl IntoHeaderValue for String {} impl IntoHeaderValue for &String {} @@ -259,17 +259,17 @@ mod private { } pub trait IntoHeaderNameSealed { - fn into_header_name(self) -> Result; + fn into_header_name(self) -> Result; } impl IntoHeaderNameSealed for HeaderName { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { Ok(self) } } impl IntoHeaderNameSealed for Option { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { match self { Some(name) => Ok(name), None => Err(HttpClientError::from_display("Header name is required")), @@ -278,69 +278,69 @@ mod private { } impl IntoHeaderNameSealed for &str { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { let name = self - .parse::() + .parse::() .map_err(HttpClientError::from_std)?; Ok(name) } } impl IntoHeaderNameSealed for String { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { self.as_str().into_header_name() } } impl IntoHeaderNameSealed for &String { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { self.as_str().into_header_name() } } impl IntoHeaderNameSealed for &[u8] { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { let name = - crate::http::HeaderName::from_bytes(self).map_err(HttpClientError::from_std)?; + crate::HeaderName::from_bytes(self).map_err(HttpClientError::from_std)?; Ok(name) } } pub trait IntoHeaderValueSealed { - fn into_header_value(self) -> Result; + fn into_header_value(self) -> Result; } - impl IntoHeaderValueSealed for crate::http::HeaderValue { - fn into_header_value(self) -> Result { + impl IntoHeaderValueSealed for crate::HeaderValue { + fn into_header_value(self) -> Result { Ok(self) } } impl IntoHeaderValueSealed for &str { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { let value = self - .parse::() + .parse::() .map_err(HttpClientError::from_std)?; Ok(value) } } impl IntoHeaderValueSealed for String { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { self.as_str().into_header_value() } } impl IntoHeaderValueSealed for &String { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { self.as_str().into_header_value() } } impl IntoHeaderValueSealed for &[u8] { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { let value = - crate::http::HeaderValue::from_bytes(self).map_err(HttpClientError::from_std)?; + crate::HeaderValue::from_bytes(self).map_err(HttpClientError::from_std)?; Ok(value) } } @@ -376,8 +376,8 @@ where #[derive(Debug)] enum RequestBuilderState { - PreBody(crate::http::dep::http::request::Builder), - PostBody(crate::http::Request), + PreBody(crate::dep::http::request::Builder), + PostBody(crate::Request), Error(HttpClientError), } @@ -438,18 +438,18 @@ where /// Add a typed [`Header`] to this [`Request`]. /// - /// [`Header`]: crate::http::headers::Header + /// [`Header`]: crate::headers::Header pub fn typed_header(self, header: H) -> Self where - H: crate::http::headers::Header, + H: crate::headers::Header, { self.header(H::name().clone(), header.encode_to_value()) } /// Add all `Headers` from the [`HeaderMap`] to this [`Request`]. /// - /// [`HeaderMap`]: crate::http::HeaderMap - pub fn headers(mut self, headers: crate::http::HeaderMap) -> Self { + /// [`HeaderMap`]: crate::HeaderMap + pub fn headers(mut self, headers: crate::HeaderMap) -> Self { for (key, value) in headers.into_iter() { self = self.header(key, value); } @@ -463,7 +463,7 @@ where P: AsRef, { let header = - crate::http::headers::Authorization::basic(username.as_ref(), password.as_ref()); + crate::headers::Authorization::basic(username.as_ref(), password.as_ref()); self.typed_header(header) } @@ -472,7 +472,7 @@ where where T: AsRef, { - let header = match crate::http::headers::Authorization::bearer(token.as_ref()) { + let header = match crate::headers::Authorization::bearer(token.as_ref()) { Ok(header) => header, Err(err) => { self.state = match self.state { @@ -490,10 +490,10 @@ where /// Set the [`Request`]'s [`Body`]. /// - /// [`Body`]: crate::http::Body + /// [`Body`]: crate::Body pub fn body(mut self, body: T) -> Self where - T: TryInto>, + T: TryInto>, { self.state = match self.state { RequestBuilderState::PreBody(builder) => match body.try_into() { @@ -517,17 +517,17 @@ where /// Set the given value as a URL-Encoded Form [`Body`] in the [`Request`]. /// - /// [`Body`]: crate::http::Body + /// [`Body`]: crate::Body pub fn form(mut self, form: &T) -> Self { self.state = match self.state { RequestBuilderState::PreBody(mut builder) => match serde_html_form::to_string(form) { Ok(body) => { let builder = match builder.headers_mut() { Some(headers) => { - if !headers.contains_key(crate::http::header::CONTENT_TYPE) { + if !headers.contains_key(crate::header::CONTENT_TYPE) { headers.insert( - crate::http::header::CONTENT_TYPE, - crate::http::HeaderValue::from_static( + crate::header::CONTENT_TYPE, + crate::HeaderValue::from_static( "application/x-www-form-urlencoded", ), ); @@ -535,8 +535,8 @@ where builder } None => builder.header( - crate::http::header::CONTENT_TYPE, - crate::http::HeaderValue::from_static( + crate::header::CONTENT_TYPE, + crate::HeaderValue::from_static( "application/x-www-form-urlencoded", ), ), @@ -552,11 +552,11 @@ where Ok(body) => { if !req .headers() - .contains_key(crate::http::header::CONTENT_TYPE) + .contains_key(crate::header::CONTENT_TYPE) { req.headers_mut().insert( - crate::http::header::CONTENT_TYPE, - crate::http::HeaderValue::from_static( + crate::header::CONTENT_TYPE, + crate::HeaderValue::from_static( "application/x-www-form-urlencoded", ), ); @@ -573,24 +573,24 @@ where /// Set the given value as a JSON [`Body`] in the [`Request`]. /// - /// [`Body`]: crate::http::Body + /// [`Body`]: crate::Body pub fn json(mut self, json: &T) -> Self { self.state = match self.state { RequestBuilderState::PreBody(mut builder) => match serde_json::to_vec(json) { Ok(body) => { let builder = match builder.headers_mut() { Some(headers) => { - if !headers.contains_key(crate::http::header::CONTENT_TYPE) { + if !headers.contains_key(crate::header::CONTENT_TYPE) { headers.insert( - crate::http::header::CONTENT_TYPE, - crate::http::HeaderValue::from_static("application/json"), + crate::header::CONTENT_TYPE, + crate::HeaderValue::from_static("application/json"), ); } builder } None => builder.header( - crate::http::header::CONTENT_TYPE, - crate::http::HeaderValue::from_static("application/json"), + crate::header::CONTENT_TYPE, + crate::HeaderValue::from_static("application/json"), ), }; match builder.body(body.into()) { @@ -604,11 +604,11 @@ where Ok(body) => { if !req .headers() - .contains_key(crate::http::header::CONTENT_TYPE) + .contains_key(crate::header::CONTENT_TYPE) { req.headers_mut().insert( - crate::http::header::CONTENT_TYPE, - crate::http::HeaderValue::from_static("application/json"), + crate::header::CONTENT_TYPE, + crate::HeaderValue::from_static("application/json"), ); } *req.body_mut() = body.into(); @@ -623,8 +623,8 @@ where /// Set the http [`Version`] of this [`Request`]. /// - /// [`Version`]: crate::http::Version - pub fn version(mut self, version: crate::http::Version) -> Self { + /// [`Version`]: crate::Version + pub fn version(mut self, version: crate::Version) -> Self { match self.state { RequestBuilderState::PreBody(builder) => { self.state = RequestBuilderState::PreBody(builder.version(version)); @@ -650,7 +650,7 @@ where pub async fn send(self, ctx: Context) -> Result, HttpClientError> { let request = match self.state { RequestBuilderState::PreBody(builder) => builder - .body(crate::http::Body::empty()) + .body(crate::Body::empty()) .map_err(HttpClientError::from_std)?, RequestBuilderState::PostBody(request) => request, RequestBuilderState::Error(err) => return Err(err), @@ -690,13 +690,13 @@ mod test { ) -> Result where S: Send + Sync + 'static, - Body: crate::http::dep::http_body::Body + Body: crate::dep::http_body::Body + Send + 'static, { let ua = request .headers() - .get(crate::http::header::USER_AGENT) + .get(crate::header::USER_AGENT) .unwrap(); assert_eq!( ua.to_str().unwrap(), @@ -715,13 +715,13 @@ mod test { ) -> Result where E: Into, - Body: crate::http::dep::http_body::Body> + Body: crate::dep::http_body::Body> + Send + Sync + 'static, { match result { - Ok(response) => Ok(response.map(crate::http::Body::new)), + Ok(response) => Ok(response.map(crate::Body::new)), Err(err) => Err(err.into()), } } @@ -738,7 +738,7 @@ mod test { #[cfg(feature = "compression")] let builder = ( builder, - crate::http::layer::decompression::DecompressionLayer::new(), + crate::layer::decompression::DecompressionLayer::new(), ); ( diff --git a/rama-http/src/client/svc.rs b/rama-http/src/client/svc.rs index 699de2c0..ec4a16a6 100644 --- a/rama-http/src/client/svc.rs +++ b/rama-http/src/client/svc.rs @@ -49,7 +49,7 @@ where SendRequest::Http2(sender) => sender.lock().await.send_request(req).await, }?; - Ok(resp.map(crate::http::Body::new)) + Ok(resp.map(crate::Body::new)) } } @@ -94,7 +94,7 @@ fn sanitize_client_req_header( parts.headers.typed_insert(headers::Host::from(authority)); } - parts.uri = crate::http::Uri::from_parts(uri_parts)?; + parts.uri = crate::Uri::from_parts(uri_parts)?; Request::from_parts(parts, body) } else { req diff --git a/rama-http/src/layer/auth/add_authorization.rs b/rama-http/src/layer/auth/add_authorization.rs index bc0d95f5..31a6e382 100644 --- a/rama-http/src/layer/auth/add_authorization.rs +++ b/rama-http/src/layer/auth/add_authorization.rs @@ -40,9 +40,9 @@ //! # } //! ``` -use crate::http::{HeaderValue, Request, Response}; +use crate::{HeaderValue, Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use base64::Engine as _; use std::convert::TryFrom; use std::fmt; @@ -52,13 +52,13 @@ const BASE64: base64::engine::GeneralPurpose = base64::engine::general_purpose:: /// Layer that applies [`AddAuthorization`] which adds authorization to all requests using the /// [`Authorization`] header. /// -/// See the [module docs](crate::http::layer::auth::add_authorization) for an example. +/// See the [module docs](crate::layer::auth::add_authorization) for an example. /// /// You can also use [`SetRequestHeader`] if you have a use case that isn't supported by this /// middleware. /// /// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization -/// [`SetRequestHeader`]: crate::http::layer::set_header::SetRequestHeader +/// [`SetRequestHeader`]: crate::layer::set_header::SetRequestHeader #[derive(Debug, Clone)] pub struct AddAuthorizationLayer { value: Option, @@ -164,13 +164,13 @@ impl Layer for AddAuthorizationLayer { /// Middleware that adds authorization all requests using the [`Authorization`] header. /// -/// See the [module docs](crate::http::layer::auth::add_authorization) for an example. +/// See the [module docs](crate::layer::auth::add_authorization) for an example. /// /// You can also use [`SetRequestHeader`] if you have a use case that isn't supported by this /// middleware. /// /// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization -/// [`SetRequestHeader`]: crate::http::layer::set_header::SetRequestHeader +/// [`SetRequestHeader`]: crate::layer::set_header::SetRequestHeader pub struct AddAuthorization { inner: S, value: Option, @@ -302,8 +302,8 @@ mod tests { use super::*; use crate::error::BoxError; - use crate::http::layer::validate_request::ValidateRequestHeaderLayer; - use crate::http::{Body, Request, Response, StatusCode}; + use crate::layer::validate_request::ValidateRequestHeaderLayer; + use crate::{Body, Request, Response, StatusCode}; use crate::service::service_fn; use crate::{Context, Service}; use std::convert::Infallible; diff --git a/rama-http/src/layer/auth/async_require_authorization.rs b/rama-http/src/layer/auth/async_require_authorization.rs index a87e05cc..0a29ee28 100644 --- a/rama-http/src/layer/auth/async_require_authorization.rs +++ b/rama-http/src/layer/auth/async_require_authorization.rs @@ -117,16 +117,14 @@ //! ``` use std::future::Future; - -use crate::http::{Request, Response}; +use crate::{Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::Context; -use crate::{Layer, Service}; +use rama_core::{Context, Layer, Service}; /// Layer that applies [`AsyncRequireAuthorization`] which authorizes all requests using the /// [`Authorization`] header. /// -/// See the [module docs](crate::http::layer::auth::async_require_authorization) for an example. +/// See the [module docs](crate::layer::auth::async_require_authorization) for an example. /// /// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization #[derive(Debug, Clone)] @@ -154,7 +152,7 @@ where /// Middleware that authorizes all requests using the [`Authorization`] header. /// -/// See the [module docs](crate::http::layer::auth::async_require_authorization) for an example. +/// See the [module docs](crate::layer::auth::async_require_authorization) for an example. /// /// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization #[derive(Clone, Debug)] @@ -250,7 +248,7 @@ mod tests { use super::*; use crate::error::BoxError; - use crate::http::{header, Body, StatusCode}; + use crate::{header, Body, StatusCode}; use crate::service::service_fn; #[derive(Clone, Copy)] diff --git a/rama-http/src/layer/auth/require_authorization.rs b/rama-http/src/layer/auth/require_authorization.rs index b37deba0..7b92244d 100644 --- a/rama-http/src/layer/auth/require_authorization.rs +++ b/rama-http/src/layer/auth/require_authorization.rs @@ -55,14 +55,14 @@ use base64::Engine as _; use std::{fmt, marker::PhantomData}; -use crate::http::layer::validate_request::{ +use crate::layer::validate_request::{ ValidateRequest, ValidateRequestHeader, ValidateRequestHeaderLayer, }; -use crate::http::{ +use crate::{ header::{self, HeaderValue}, Request, Response, StatusCode, }; -use crate::Context; +use rama_core::Context; const BASE64: base64::engine::GeneralPurpose = base64::engine::general_purpose::STANDARD; @@ -264,8 +264,8 @@ mod tests { use super::*; use crate::error::BoxError; - use crate::http::layer::validate_request::ValidateRequestHeaderLayer; - use crate::http::{header, Body}; + use crate::layer::validate_request::ValidateRequestHeaderLayer; + use crate::{header, Body}; use crate::service::service_fn; use crate::{Context, Layer, Service}; diff --git a/rama-http/src/layer/body_limit.rs b/rama-http/src/layer/body_limit.rs index 6c7c0fdf..8b21e9a3 100644 --- a/rama-http/src/layer/body_limit.rs +++ b/rama-http/src/layer/body_limit.rs @@ -29,15 +29,15 @@ //! # } //! ``` -use crate::http::dep::http_body_util::Limited; -use crate::http::Request; +use crate::dep::http_body_util::Limited; +use crate::Request; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::fmt; /// Apply a limit to the request body's size. /// -/// See the [module docs](crate::http::layer::body_limit) for an example. +/// See the [module docs](crate::layer::body_limit) for an example. #[derive(Debug, Clone)] pub struct BodyLimitLayer { size: usize, @@ -60,7 +60,7 @@ impl Layer for BodyLimitLayer { /// Apply a transformation to the request body. /// -/// See the [module docs](crate::http::layer::body_limit) for an example. +/// See the [module docs](crate::layer::body_limit) for an example. #[derive(Clone)] pub struct BodyLimitService { inner: S, diff --git a/rama-http/src/layer/catch_panic.rs b/rama-http/src/layer/catch_panic.rs index 9be612ec..0279ddb1 100644 --- a/rama-http/src/layer/catch_panic.rs +++ b/rama-http/src/layer/catch_panic.rs @@ -86,9 +86,9 @@ //! # } //! ``` -use crate::http::{Body, HeaderValue, Request, Response, StatusCode}; +use crate::{Body, HeaderValue, Request, Response, StatusCode}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use futures_lite::future::FutureExt; use std::fmt; use std::{any::Any, panic::AssertUnwindSafe}; diff --git a/rama-http/src/layer/classify/grpc_errors_as_failures.rs b/rama-http/src/layer/classify/grpc_errors_as_failures.rs index 759a03cd..b40de1f0 100644 --- a/rama-http/src/layer/classify/grpc_errors_as_failures.rs +++ b/rama-http/src/layer/classify/grpc_errors_as_failures.rs @@ -1,5 +1,5 @@ use super::{ClassifiedResponse, ClassifyEos, ClassifyResponse, SharedClassifier}; -use crate::http::{HeaderMap, Response}; +use crate::{HeaderMap, Response}; use bitflags::bitflags; use std::{fmt, num::NonZeroI32}; diff --git a/rama-http/src/layer/classify/map_failure_class.rs b/rama-http/src/layer/classify/map_failure_class.rs index 60cd9b7d..e998b9a7 100644 --- a/rama-http/src/layer/classify/map_failure_class.rs +++ b/rama-http/src/layer/classify/map_failure_class.rs @@ -1,5 +1,5 @@ use super::{ClassifiedResponse, ClassifyEos, ClassifyResponse}; -use crate::http::{HeaderMap, Response}; +use crate::{HeaderMap, Response}; use std::fmt; /// Response classifier that transforms the failure class of some other diff --git a/rama-http/src/layer/classify/mod.rs b/rama-http/src/layer/classify/mod.rs index 0e9ab3a3..1e6e9972 100644 --- a/rama-http/src/layer/classify/mod.rs +++ b/rama-http/src/layer/classify/mod.rs @@ -1,6 +1,6 @@ //! Tools for classifying responses as either success or failure. -use crate::http::{HeaderMap, Request, Response, StatusCode}; +use crate::{HeaderMap, Request, Response, StatusCode}; use std::{convert::Infallible, fmt, marker::PhantomData}; pub(crate) mod grpc_errors_as_failures; diff --git a/rama-http/src/layer/compression/body.rs b/rama-http/src/layer/compression/body.rs index 83ec4de9..8a85826f 100644 --- a/rama-http/src/layer/compression/body.rs +++ b/rama-http/src/layer/compression/body.rs @@ -1,11 +1,11 @@ #![allow(unused_imports)] -use crate::error::BoxError; -use crate::http::dep::http_body::{Body, Frame}; -use crate::http::layer::util::compression::{ +use rama_core::error::BoxError; +use crate::dep::http_body::{Body, Frame}; +use crate::layer::util::compression::{ AsyncReadBody, BodyIntoStream, CompressionLevel, DecorateAsyncRead, WrapBody, }; -use crate::http::HeaderMap; +use crate::HeaderMap; use async_compression::tokio::bufread::{BrotliEncoder, GzipEncoder, ZlibEncoder, ZstdEncoder}; diff --git a/rama-http/src/layer/compression/layer.rs b/rama-http/src/layer/compression/layer.rs index b96ab98f..204ed7cb 100644 --- a/rama-http/src/layer/compression/layer.rs +++ b/rama-http/src/layer/compression/layer.rs @@ -1,14 +1,14 @@ use super::predicate::DefaultPredicate; use super::{Compression, Predicate}; -use crate::http::layer::util::compression::{AcceptEncoding, CompressionLevel}; -use crate::Layer; +use crate::layer::util::compression::{AcceptEncoding, CompressionLevel}; +use rama_core::Layer; /// Compress response bodies of the underlying service. /// /// This uses the `Accept-Encoding` header to pick an appropriate encoding and adds the /// `Content-Encoding` header to responses. /// -/// See the [module docs](crate::http::layer::compression) for more details. +/// See the [module docs](crate::layer::compression) for more details. #[derive(Clone, Debug, Default)] pub struct CompressionLayer

{ accept: AcceptEncoding, @@ -117,8 +117,8 @@ impl CompressionLayer { mod tests { use super::*; - use crate::http::dep::http_body_util::BodyExt; - use crate::http::{header::ACCEPT_ENCODING, Body, Request, Response}; + use crate::dep::http_body_util::BodyExt; + use crate::{header::ACCEPT_ENCODING, Body, Request, Response}; use crate::service::service_fn; use crate::{Context, Service}; use std::convert::Infallible; diff --git a/rama-http/src/layer/compression/mod.rs b/rama-http/src/layer/compression/mod.rs index c1654492..c2f471c7 100644 --- a/rama-http/src/layer/compression/mod.rs +++ b/rama-http/src/layer/compression/mod.rs @@ -88,19 +88,19 @@ pub use self::{ service::Compression, }; #[doc(inline)] -pub use crate::http::layer::util::compression::CompressionLevel; +pub use crate::layer::util::compression::CompressionLevel; #[cfg(test)] mod tests { use super::*; - use crate::http::layer::compression::predicate::SizeAbove; + use crate::layer::compression::predicate::SizeAbove; - use crate::http::dep::http_body_util::BodyExt; - use crate::http::header::{ + use crate::dep::http_body_util::BodyExt; + use crate::header::{ ACCEPT_ENCODING, ACCEPT_RANGES, CONTENT_ENCODING, CONTENT_RANGE, CONTENT_TYPE, RANGE, }; - use crate::http::{Body, HeaderValue, Request, Response}; + use crate::{Body, HeaderValue, Request, Response}; use crate::service::service_fn; use crate::{Context, Service}; use async_compression::tokio::write::{BrotliDecoder, BrotliEncoder}; diff --git a/rama-http/src/layer/compression/service.rs b/rama-http/src/layer/compression/service.rs index aa5e44e5..d281e959 100644 --- a/rama-http/src/layer/compression/service.rs +++ b/rama-http/src/layer/compression/service.rs @@ -2,19 +2,19 @@ use super::body::BodyInner; use super::predicate::{DefaultPredicate, Predicate}; use super::CompressionBody; use super::CompressionLevel; -use crate::http::dep::http_body::Body; -use crate::http::layer::util::compression::WrapBody; -use crate::http::layer::util::{compression::AcceptEncoding, content_encoding::Encoding}; -use crate::http::{header, Request, Response}; +use crate::dep::http_body::Body; +use crate::layer::util::compression::WrapBody; +use crate::layer::util::{compression::AcceptEncoding, content_encoding::Encoding}; +use crate::{header, Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Service}; +use rama_core::{Context, Service}; /// Compress response bodies of the underlying service. /// /// This uses the `Accept-Encoding` header to pick an appropriate encoding and adds the /// `Content-Encoding` header to responses. /// -/// See the [module docs](crate::http::layer::compression) for more details. +/// See the [module docs](crate::layer::compression) for more details. pub struct Compression { pub(crate) inner: S, pub(crate) accept: AcceptEncoding, diff --git a/rama-http/src/layer/cors/allow_credentials.rs b/rama-http/src/layer/cors/allow_credentials.rs index 57af2771..9c8e5beb 100644 --- a/rama-http/src/layer/cors/allow_credentials.rs +++ b/rama-http/src/layer/cors/allow_credentials.rs @@ -1,6 +1,6 @@ use std::{fmt, sync::Arc}; -use crate::http::dep::http::{ +use crate::dep::http::{ header::{self, HeaderName, HeaderValue}, request::Parts as RequestParts, }; diff --git a/rama-http/src/layer/cors/allow_headers.rs b/rama-http/src/layer/cors/allow_headers.rs index a1674533..3e9d6959 100644 --- a/rama-http/src/layer/cors/allow_headers.rs +++ b/rama-http/src/layer/cors/allow_headers.rs @@ -1,6 +1,6 @@ use std::{array, fmt}; -use crate::http::dep::http::{ +use crate::dep::http::{ header::{self, HeaderName, HeaderValue}, request::Parts as RequestParts, }; diff --git a/rama-http/src/layer/cors/allow_methods.rs b/rama-http/src/layer/cors/allow_methods.rs index 3193188d..b9e25510 100644 --- a/rama-http/src/layer/cors/allow_methods.rs +++ b/rama-http/src/layer/cors/allow_methods.rs @@ -1,6 +1,6 @@ use std::{array, fmt}; -use crate::http::dep::http::{ +use crate::dep::http::{ header::{self, HeaderName, HeaderValue}, request::Parts as RequestParts, Method, diff --git a/rama-http/src/layer/cors/allow_origin.rs b/rama-http/src/layer/cors/allow_origin.rs index fa6cf13d..c386f8b0 100644 --- a/rama-http/src/layer/cors/allow_origin.rs +++ b/rama-http/src/layer/cors/allow_origin.rs @@ -1,4 +1,4 @@ -use crate::http::dep::http::{ +use crate::dep::http::{ header::{self, HeaderName, HeaderValue}, request::Parts as RequestParts, }; diff --git a/rama-http/src/layer/cors/allow_private_network.rs b/rama-http/src/layer/cors/allow_private_network.rs index 2e304bb0..ed8c8a54 100644 --- a/rama-http/src/layer/cors/allow_private_network.rs +++ b/rama-http/src/layer/cors/allow_private_network.rs @@ -1,6 +1,6 @@ use std::{fmt, sync::Arc}; -use crate::http::dep::http::{ +use crate::dep::http::{ header::{HeaderName, HeaderValue}, request::Parts as RequestParts, }; @@ -114,11 +114,11 @@ mod tests { use super::AllowPrivateNetwork; use crate::error::BoxError; - use crate::http::dep::http::{ + use crate::dep::http::{ header::ORIGIN, request::Parts, HeaderName, HeaderValue, Request, Response, }; - use crate::http::layer::cors::CorsLayer; - use crate::http::Body; + use crate::layer::cors::CorsLayer; + use crate::Body; use crate::service::service_fn; use crate::{Context, Layer, Service}; diff --git a/rama-http/src/layer/cors/expose_headers.rs b/rama-http/src/layer/cors/expose_headers.rs index f0ecfdb9..7b26c63b 100644 --- a/rama-http/src/layer/cors/expose_headers.rs +++ b/rama-http/src/layer/cors/expose_headers.rs @@ -1,6 +1,6 @@ use std::{array, fmt}; -use crate::http::dep::http::{ +use crate::dep::http::{ header::{self, HeaderName, HeaderValue}, request::Parts as RequestParts, }; diff --git a/rama-http/src/layer/cors/max_age.rs b/rama-http/src/layer/cors/max_age.rs index 535dd349..b2a10180 100644 --- a/rama-http/src/layer/cors/max_age.rs +++ b/rama-http/src/layer/cors/max_age.rs @@ -1,6 +1,6 @@ use std::{fmt, sync::Arc, time::Duration}; -use crate::http::dep::http::{ +use crate::dep::http::{ header::{self, HeaderName, HeaderValue}, request::Parts as RequestParts, }; diff --git a/rama-http/src/layer/cors/mod.rs b/rama-http/src/layer/cors/mod.rs index 2596b5d1..9fd37dde 100644 --- a/rama-http/src/layer/cors/mod.rs +++ b/rama-http/src/layer/cors/mod.rs @@ -46,12 +46,12 @@ #![allow(clippy::enum_variant_names)] -use crate::http::dep::http::{ +use crate::dep::http::{ header::{self, HeaderName}, HeaderMap, HeaderValue, Method, Request, Response, }; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use bytes::{BufMut, BytesMut}; use std::{array, fmt, mem}; @@ -76,7 +76,7 @@ pub use self::{ /// Layer that applies the [`Cors`] middleware which adds headers for [CORS][mdn]. /// -/// See the [module docs](crate::http::layer::cors) for an example. +/// See the [module docs](crate::layer::cors) for an example. /// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS #[derive(Debug, Clone)] @@ -493,7 +493,7 @@ impl Layer for CorsLayer { /// Middleware which adds headers for [CORS][mdn]. /// -/// See the [module docs](crate::http::layer::cors) for an example. +/// See the [module docs](crate::layer::cors) for an example. /// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS pub struct Cors { diff --git a/rama-http/src/layer/cors/tests.rs b/rama-http/src/layer/cors/tests.rs index 2f8f355f..509032f8 100644 --- a/rama-http/src/layer/cors/tests.rs +++ b/rama-http/src/layer/cors/tests.rs @@ -1,5 +1,5 @@ -use crate::http::layer::cors::{AllowOrigin, CorsLayer}; -use crate::http::{header, Body, HeaderValue, Request, Response}; +use crate::layer::cors::{AllowOrigin, CorsLayer}; +use crate::{header, Body, HeaderValue, Request, Response}; use crate::service::service_fn; use crate::{Context, Layer, Service}; use std::convert::Infallible; diff --git a/rama-http/src/layer/cors/vary.rs b/rama-http/src/layer/cors/vary.rs index 061af5a5..2fadfe60 100644 --- a/rama-http/src/layer/cors/vary.rs +++ b/rama-http/src/layer/cors/vary.rs @@ -1,6 +1,6 @@ use std::array; -use crate::http::{ +use crate::{ header::{self, HeaderName}, HeaderValue, }; diff --git a/rama-http/src/layer/decompression/body.rs b/rama-http/src/layer/decompression/body.rs index d6264972..1f0630aa 100644 --- a/rama-http/src/layer/decompression/body.rs +++ b/rama-http/src/layer/decompression/body.rs @@ -1,11 +1,11 @@ #![allow(unused_imports)] -use crate::error::BoxError; -use crate::http::dep::http_body::{Body, Frame}; -use crate::http::layer::util::compression::{ +use rama_core::error::BoxError; +use crate::dep::http_body::{Body, Frame}; +use crate::layer::util::compression::{ AsyncReadBody, BodyIntoStream, CompressionLevel, DecorateAsyncRead, WrapBody, }; -use crate::http::HeaderMap; +use crate::HeaderMap; use async_compression::tokio::bufread::BrotliDecoder; use async_compression::tokio::bufread::GzipDecoder; diff --git a/rama-http/src/layer/decompression/layer.rs b/rama-http/src/layer/decompression/layer.rs index 59374855..775e3909 100644 --- a/rama-http/src/layer/decompression/layer.rs +++ b/rama-http/src/layer/decompression/layer.rs @@ -1,13 +1,13 @@ use super::Decompression; -use crate::http::layer::util::compression::AcceptEncoding; -use crate::Layer; +use crate::layer::util::compression::AcceptEncoding; +use rama_core::Layer; /// Decompresses response bodies of the underlying service. /// /// This adds the `Accept-Encoding` header to requests and transparently decompresses response /// bodies based on the `Content-Encoding` header. /// -/// See the [module docs](crate::http::layer::decompression) for more details. +/// See the [module docs](crate::layer::decompression) for more details. #[derive(Debug, Default, Clone)] pub struct DecompressionLayer { accept: AcceptEncoding, diff --git a/rama-http/src/layer/decompression/mod.rs b/rama-http/src/layer/decompression/mod.rs index 849dd70d..58ca0fc4 100644 --- a/rama-http/src/layer/decompression/mod.rs +++ b/rama-http/src/layer/decompression/mod.rs @@ -116,9 +116,9 @@ mod tests { use std::convert::Infallible; use std::io::Write; - use crate::http::dep::http_body_util::BodyExt; - use crate::http::layer::compression::Compression; - use crate::http::{Body, HeaderMap, HeaderName, Request, Response}; + use crate::dep::http_body_util::BodyExt; + use crate::layer::compression::Compression; + use crate::{Body, HeaderMap, HeaderName, Request, Response}; use crate::service::service_fn; use crate::{Context, Service}; diff --git a/rama-http/src/layer/decompression/request/layer.rs b/rama-http/src/layer/decompression/request/layer.rs index 6e930e40..985e8e62 100644 --- a/rama-http/src/layer/decompression/request/layer.rs +++ b/rama-http/src/layer/decompression/request/layer.rs @@ -1,6 +1,6 @@ use super::service::RequestDecompression; -use crate::http::layer::util::compression::AcceptEncoding; -use crate::Layer; +use crate::layer::util::compression::AcceptEncoding; +use rama_core::Layer; /// Decompresses request bodies and calls its underlying service. /// @@ -12,7 +12,7 @@ use crate::Layer; /// will call the underlying service with the unmodified request if the encoding is not supported. /// This is disabled by default. /// -/// See the [module docs](crate::http::layer::decompression) for more details. +/// See the [module docs](crate::layer::decompression) for more details. #[derive(Debug, Default, Clone)] pub struct RequestDecompressionLayer { accept: AcceptEncoding, diff --git a/rama-http/src/layer/decompression/request/mod.rs b/rama-http/src/layer/decompression/request/mod.rs index d4d1f569..77cee7f9 100644 --- a/rama-http/src/layer/decompression/request/mod.rs +++ b/rama-http/src/layer/decompression/request/mod.rs @@ -5,9 +5,9 @@ pub(super) mod service; mod tests { use super::service::RequestDecompression; - use crate::http::dep::http_body_util::BodyExt; - use crate::http::layer::decompression::DecompressionBody; - use crate::http::{header, Body, Request, Response, StatusCode}; + use crate::dep::http_body_util::BodyExt; + use crate::layer::decompression::DecompressionBody; + use crate::{header, Body, Request, Response, StatusCode}; use crate::service::service_fn; use crate::{Context, Service}; diff --git a/rama-http/src/layer/decompression/request/service.rs b/rama-http/src/layer/decompression/request/service.rs index dab904e9..dee45995 100644 --- a/rama-http/src/layer/decompression/request/service.rs +++ b/rama-http/src/layer/decompression/request/service.rs @@ -1,17 +1,17 @@ use std::fmt; -use crate::error::BoxError; -use crate::http::dep::http_body::Body; -use crate::http::dep::http_body_util::{combinators::UnsyncBoxBody, BodyExt, Empty}; -use crate::http::layer::{ +use rama_core::error::BoxError; +use crate::dep::http_body::Body; +use crate::dep::http_body_util::{combinators::UnsyncBoxBody, BodyExt, Empty}; +use crate::layer::{ decompression::body::BodyInner, decompression::DecompressionBody, util::compression::{AcceptEncoding, CompressionLevel, WrapBody}, util::content_encoding::SupportedEncodings, }; -use crate::http::{header, HeaderValue, Request, Response, StatusCode}; +use crate::{header, HeaderValue, Request, Response, StatusCode}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Service}; +use rama_core::{Context, Service}; use bytes::Buf; /// Decompresses request bodies and calls its underlying service. @@ -24,7 +24,7 @@ use bytes::Buf; /// will call the underlying service with the unmodified request if the encoding is not supported. /// This is disabled by default. /// -/// See the [module docs](crate::http::layer::decompression) for more details. +/// See the [module docs](crate::layer::decompression) for more details. pub struct RequestDecompression { pub(super) inner: S, pub(super) accept: AcceptEncoding, diff --git a/rama-http/src/layer/decompression/service.rs b/rama-http/src/layer/decompression/service.rs index f3e0ea89..8b72cefc 100644 --- a/rama-http/src/layer/decompression/service.rs +++ b/rama-http/src/layer/decompression/service.rs @@ -1,24 +1,24 @@ use std::fmt; use super::{body::BodyInner, DecompressionBody}; -use crate::http::dep::http_body::Body; -use crate::http::layer::util::{ +use crate::dep::http_body::Body; +use crate::layer::util::{ compression::{AcceptEncoding, CompressionLevel, WrapBody}, content_encoding::SupportedEncodings, }; -use crate::http::{ +use crate::{ header::{self, ACCEPT_ENCODING}, Request, Response, }; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Service}; +use rama_core::{Context, Service}; /// Decompresses response bodies of the underlying service. /// /// This adds the `Accept-Encoding` header to requests and transparently decompresses response /// bodies based on the `Content-Encoding` header. /// -/// See the [module docs](crate::http::layer::decompression) for more details. +/// See the [module docs](crate::layer::decompression) for more details. pub struct Decompression { pub(crate) inner: S, pub(crate) accept: AcceptEncoding, diff --git a/rama-http/src/layer/dns/dns_map/layer.rs b/rama-http/src/layer/dns/dns_map/layer.rs index 608d9352..576aa94f 100644 --- a/rama-http/src/layer/dns/dns_map/layer.rs +++ b/rama-http/src/layer/dns/dns_map/layer.rs @@ -1,9 +1,10 @@ use super::DnsMapService; -use crate::{http::HeaderName, Layer}; +use crate::HeaderName; +use rama_core::Layer; /// Layer which can extend [`Dns`] overwrites with mappings. /// -/// See [the module level documentation](crate::http::layer::dns) for more information. +/// See [the module level documentation](crate::layer::dns) for more information. /// /// [`Dns`]: crate::dns::Dns #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/dns/dns_map/mod.rs b/rama-http/src/layer/dns/dns_map/mod.rs index 07f97169..8796991f 100644 --- a/rama-http/src/layer/dns/dns_map/mod.rs +++ b/rama-http/src/layer/dns/dns_map/mod.rs @@ -1,4 +1,4 @@ -use crate::net::address::Domain; +use rama_net::address::Domain; use serde::Deserialize; use std::{collections::HashMap, net::IpAddr}; diff --git a/rama-http/src/layer/dns/dns_map/service.rs b/rama-http/src/layer/dns/dns_map/service.rs index 542ca669..1634d87a 100644 --- a/rama-http/src/layer/dns/dns_map/service.rs +++ b/rama-http/src/layer/dns/dns_map/service.rs @@ -2,11 +2,9 @@ use std::fmt; use super::DnsMap; use rama_utils::macros::define_inner_service_accessors; -use crate::{ +use crate::{layer::header_config::extract_header_config, utils::HeaderValueErr, HeaderName, Request}; +use rama_core::{ error::OpaqueError, - http::{ - layer::header_config::extract_header_config, utils::HeaderValueErr, HeaderName, Request, - }, Context, Service, }; @@ -18,7 +16,7 @@ use crate::{ /// See [`Dns`] and [`DnsMapLayer`] for more information. /// /// [`Dns`]: crate::dns::Dns -/// [`DnsMapLayer`]: crate::http::layer::dns::DnsMapLayer +/// [`DnsMapLayer`]: crate::layer::dns::DnsMapLayer pub struct DnsMapService { inner: S, header_name: HeaderName, diff --git a/rama-http/src/layer/dns/dns_resolve/layer.rs b/rama-http/src/layer/dns/dns_resolve/layer.rs index b2101ce2..36d49536 100644 --- a/rama-http/src/layer/dns/dns_resolve/layer.rs +++ b/rama-http/src/layer/dns/dns_resolve/layer.rs @@ -1,9 +1,10 @@ use super::DnsResolveModeService; -use crate::{http::HeaderName, Layer}; +use crate::HeaderName; +use rama_core::Layer; /// Layer which can extend [`Dns`] overwrites with mappings. /// -/// See [the module level documentation](crate::http::layer::dns) for more information. +/// See [the module level documentation](crate::layer::dns) for more information. /// /// [`Dns`]: crate::dns::Dns #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/dns/dns_resolve/mod.rs b/rama-http/src/layer/dns/dns_resolve/mod.rs index deaf5eca..381cfd11 100644 --- a/rama-http/src/layer/dns/dns_resolve/mod.rs +++ b/rama-http/src/layer/dns/dns_resolve/mod.rs @@ -5,8 +5,8 @@ //! For example resolving them to make a connection to a target server over a proxy //! by IP address instead of domain name. -use crate::error::{ErrorExt, OpaqueError}; -use crate::http::HeaderValue; +use rama_core::error::{ErrorExt, OpaqueError}; +use crate::HeaderValue; use rama_utils::macros::match_ignore_ascii_case_str; use rama_core::username::{ComposeError, Composer, UsernameLabelWriter}; use std::fmt; diff --git a/rama-http/src/layer/dns/dns_resolve/service.rs b/rama-http/src/layer/dns/dns_resolve/service.rs index b64318dc..fc23dafc 100644 --- a/rama-http/src/layer/dns/dns_resolve/service.rs +++ b/rama-http/src/layer/dns/dns_resolve/service.rs @@ -1,12 +1,11 @@ use std::fmt; - use super::DnsResolveMode; use rama_utils::macros::define_inner_service_accessors; -use crate::{ +use rama_core::{ error::OpaqueError, - http::{HeaderName, Request}, Context, Service, }; +use crate::{HeaderName, Request}; /// Service to support configuring the DNS resolve mode. /// diff --git a/rama-http/src/layer/dns/dns_resolve/username_parser.rs b/rama-http/src/layer/dns/dns_resolve/username_parser.rs index 884b9a2a..df295f15 100644 --- a/rama-http/src/layer/dns/dns_resolve/username_parser.rs +++ b/rama-http/src/layer/dns/dns_resolve/username_parser.rs @@ -1,11 +1,10 @@ -use crate::{ +use rama_core::{ context::Extensions, error::{error, ErrorContext, OpaqueError}, - utils::macros::str::eq_ignore_ascii_case, - utils::username::{UsernameLabelParser, UsernameLabelState}, }; - use super::DnsResolveMode; +use rama_utils::macros::str::eq_ignore_ascii_case; +use rama_core::username::{UsernameLabelParser, UsernameLabelState}; #[derive(Debug, Clone, Default)] #[non_exhaustive] diff --git a/rama-http/src/layer/error_handling.rs b/rama-http/src/layer/error_handling.rs index 1f4af653..b5a7a378 100644 --- a/rama-http/src/layer/error_handling.rs +++ b/rama-http/src/layer/error_handling.rs @@ -45,10 +45,8 @@ //! ``` use rama_utils::macros::define_inner_service_accessors; -use crate::{ - http::{IntoResponse, Request, Response}, - Context, Layer, Service, -}; +use crate::{IntoResponse, Request, Response}; +use rama_core::{Context, Layer, Service}; use std::{convert::Infallible, fmt}; /// A [`Layer`] that wraps a [`Service`] and converts errors into [`Response`]s. diff --git a/rama-http/src/layer/follow_redirect/mod.rs b/rama-http/src/layer/follow_redirect/mod.rs index 0873e4da..dd276ac8 100644 --- a/rama-http/src/layer/follow_redirect/mod.rs +++ b/rama-http/src/layer/follow_redirect/mod.rs @@ -102,10 +102,8 @@ pub mod policy; use rama_utils::macros::define_inner_service_accessors; -use crate::{ - http::{dep::http_body::Body, header::LOCATION, Method, Request, Response, StatusCode, Uri}, - Context, Layer, Service, -}; +use crate::{dep::http_body::Body, header::LOCATION, Method, Request, Response, StatusCode, Uri}; +use rama_core::{Context, Layer, Service}; use iri_string::types::{UriAbsoluteString, UriReferenceStr}; use std::{fmt, future::Future}; @@ -374,7 +372,7 @@ fn resolve_uri(relative: &str, base: &Uri) -> Option { #[cfg(test)] mod tests { use super::{policy::*, *}; - use crate::http::{header::LOCATION, Body}; + use crate::{header::LOCATION, Body}; use crate::service::service_fn; use crate::Layer; use std::convert::Infallible; diff --git a/rama-http/src/layer/follow_redirect/policy/and.rs b/rama-http/src/layer/follow_redirect/policy/and.rs index 01ab46b7..fc5091f3 100644 --- a/rama-http/src/layer/follow_redirect/policy/and.rs +++ b/rama-http/src/layer/follow_redirect/policy/and.rs @@ -1,5 +1,6 @@ use super::{Action, Attempt, Policy}; -use crate::{http::Request, Context}; +use crate::Request; +use rama_core::Context; use std::fmt::Debug; /// A redirection [`Policy`] that combines the results of two `Policy`s. @@ -74,7 +75,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::http::Uri; + use crate::Uri; struct Taint

{ policy: P, diff --git a/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs b/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs index 5a44082c..7d6d5940 100644 --- a/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs +++ b/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs @@ -1,5 +1,4 @@ -use crate::Context; - +use rama_core::Context; use super::{Action, Attempt, Policy}; use std::fmt; diff --git a/rama-http/src/layer/follow_redirect/policy/filter_credentials.rs b/rama-http/src/layer/follow_redirect/policy/filter_credentials.rs index 9a62f8f2..e60f1524 100644 --- a/rama-http/src/layer/follow_redirect/policy/filter_credentials.rs +++ b/rama-http/src/layer/follow_redirect/policy/filter_credentials.rs @@ -1,11 +1,9 @@ use super::{eq_origin, Action, Attempt, Policy}; use crate::{ - http::{ - header::{self, HeaderName}, - Request, - }, - Context, + header::{self, HeaderName}, + Request, }; +use rama_core::Context; /// A redirection [`Policy`] that removes credentials from requests in redirections. #[derive(Debug)] @@ -139,7 +137,7 @@ impl Policy for FilterCredentials { #[cfg(test)] mod tests { use super::*; - use crate::http::Uri; + use crate::Uri; #[test] fn works() { diff --git a/rama-http/src/layer/follow_redirect/policy/limited.rs b/rama-http/src/layer/follow_redirect/policy/limited.rs index 2ab1a378..6c5958c4 100644 --- a/rama-http/src/layer/follow_redirect/policy/limited.rs +++ b/rama-http/src/layer/follow_redirect/policy/limited.rs @@ -1,5 +1,4 @@ -use crate::Context; - +use rama_core::Context; use super::{Action, Attempt, Policy}; /// A redirection [`Policy`] that limits the number of successive redirections. @@ -52,7 +51,7 @@ impl Policy for Limited { #[cfg(test)] mod tests { use super::*; - use crate::http::{Request, Uri}; + use crate::{Request, Uri}; #[test] fn works() { diff --git a/rama-http/src/layer/follow_redirect/policy/mod.rs b/rama-http/src/layer/follow_redirect/policy/mod.rs index d56e7e31..e6fd790d 100644 --- a/rama-http/src/layer/follow_redirect/policy/mod.rs +++ b/rama-http/src/layer/follow_redirect/policy/mod.rs @@ -17,10 +17,8 @@ pub use self::{ redirect_fn::{redirect_fn, RedirectFn}, same_origin::SameOrigin, }; -use crate::{ - http::{Request, Scheme, StatusCode, Uri}, - Context, -}; +use crate::{Request, Scheme, StatusCode, Uri}; +use rama_core::Context; /// Trait for the policy on handling redirection responses. /// diff --git a/rama-http/src/layer/follow_redirect/policy/or.rs b/rama-http/src/layer/follow_redirect/policy/or.rs index 7d3c01eb..65347d02 100644 --- a/rama-http/src/layer/follow_redirect/policy/or.rs +++ b/rama-http/src/layer/follow_redirect/policy/or.rs @@ -1,5 +1,6 @@ use super::{Action, Attempt, Policy}; -use crate::{http::Request, Context}; +use crate::Request; +use rama_core::Context; /// A redirection [`Policy`] that combines the results of two `Policy`s. /// diff --git a/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs b/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs index b3edf5af..9356270f 100644 --- a/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs +++ b/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs @@ -1,5 +1,4 @@ -use crate::Context; - +use rama_core::Context; use super::{Action, Attempt, Policy}; use std::fmt; diff --git a/rama-http/src/layer/follow_redirect/policy/same_origin.rs b/rama-http/src/layer/follow_redirect/policy/same_origin.rs index 2a7091f5..27107c16 100644 --- a/rama-http/src/layer/follow_redirect/policy/same_origin.rs +++ b/rama-http/src/layer/follow_redirect/policy/same_origin.rs @@ -1,5 +1,4 @@ -use crate::Context; - +use rama_core::Context; use super::{eq_origin, Action, Attempt, Policy}; use std::fmt; @@ -35,7 +34,7 @@ impl Policy for SameOrigin { #[cfg(test)] mod tests { use super::*; - use crate::http::{Request, Uri}; + use crate::{Request, Uri}; #[test] fn works() { diff --git a/rama-http/src/layer/forwarded/get_forwarded.rs b/rama-http/src/layer/forwarded/get_forwarded.rs index 8eb7fdcb..b146fb17 100644 --- a/rama-http/src/layer/forwarded/get_forwarded.rs +++ b/rama-http/src/layer/forwarded/get_forwarded.rs @@ -40,11 +40,11 @@ use std::marker::PhantomData; /// but you can use the [`GetForwardedHeadersLayer::new`] constructor and pass the header type as a type parameter, /// alone or in a tuple with other headers. /// -/// [`X-Real-Ip`]: crate::http::headers::XRealIp -/// [`X-Client-Ip`]: crate::http::headers::XClientIp -/// [`Client-Ip`]: crate::http::headers::ClientIp -/// [`CF-Connecting-Ip`]: crate::http::headers::CFConnectingIp -/// [`True-Client-Ip`]: crate::http::headers::TrueClientIp +/// [`X-Real-Ip`]: crate::headers::XRealIp +/// [`X-Client-Ip`]: crate::headers::XClientIp +/// [`Client-Ip`]: crate::headers::ClientIp +/// [`CF-Connecting-Ip`]: crate::headers::CFConnectingIp +/// [`True-Client-Ip`]: crate::headers::TrueClientIp /// /// ## Example /// diff --git a/rama-http/src/layer/forwarded/set_forwarded.rs b/rama-http/src/layer/forwarded/set_forwarded.rs index 3ae6ed25..7ebaa3c8 100644 --- a/rama-http/src/layer/forwarded/set_forwarded.rs +++ b/rama-http/src/layer/forwarded/set_forwarded.rs @@ -41,15 +41,15 @@ use std::marker::PhantomData; /// but you can use the [`SetForwardedHeadersLayer::new`] constructor and pass the header type as a type parameter, /// alone or in a tuple with other headers. /// -/// [`X-Real-Ip`]: crate::http::headers::XRealIp -/// [`X-Client-Ip`]: crate::http::headers::XClientIp -/// [`Client-Ip`]: crate::http::headers::ClientIp -/// [`CF-Connecting-Ip`]: crate::http::headers::CFConnectingIp -/// [`True-Client-Ip`]: crate::http::headers::TrueClientIp +/// [`X-Real-Ip`]: crate::headers::XRealIp +/// [`X-Client-Ip`]: crate::headers::XClientIp +/// [`Client-Ip`]: crate::headers::ClientIp +/// [`CF-Connecting-Ip`]: crate::headers::CFConnectingIp +/// [`True-Client-Ip`]: crate::headers::TrueClientIp /// /// ## Example /// -/// This example shows how you could expose the real Client IP using the [`X-Real-IP`][`crate::http::headers::XRealIp`] header. +/// This example shows how you could expose the real Client IP using the [`X-Real-IP`][`crate::headers::XRealIp`] header. /// /// ```rust /// # use rama::{http::Request, stream::SocketInfo}; diff --git a/rama-http/src/layer/header_config.rs b/rama-http/src/layer/header_config.rs index eb1d034a..74f22eaa 100644 --- a/rama-http/src/layer/header_config.rs +++ b/rama-http/src/layer/header_config.rs @@ -42,19 +42,18 @@ //! } //! ``` -use crate::http::{header::AsHeaderName, HeaderName}; +use crate::{header::AsHeaderName, HeaderName}; use rama_utils::macros::define_inner_service_accessors; use serde::de::DeserializeOwned; use std::{fmt, marker::PhantomData}; - -use crate::{ +use rama_core::{ error::BoxError, - http::{ - utils::{HeaderValueErr, HeaderValueGetter}, - Request, - }, Context, Layer, Service, }; +use crate::{ + utils::{HeaderValueErr, HeaderValueGetter}, + Request, +}; /// Extract a header config from a request or response without consuming it. pub fn extract_header_config(request: &G, header_name: H) -> Result @@ -159,7 +158,7 @@ where Ok(config) => config, Err(err) => { if self.optional - && matches!(err, crate::http::utils::HeaderValueErr::HeaderMissing(_)) + && matches!(err, crate::utils::HeaderValueErr::HeaderMissing(_)) { tracing::debug!(error = %err, "failed to extract header config"); return self.inner.serve(ctx, request).await.map_err(Into::into); @@ -242,7 +241,7 @@ impl Layer for HeaderConfigLayer { mod test { use serde::Deserialize; - use crate::http::Method; + use crate::Method; use super::*; diff --git a/rama-http/src/layer/header_option_value.rs b/rama-http/src/layer/header_option_value.rs index 4a3fe4b5..700dde97 100644 --- a/rama-http/src/layer/header_option_value.rs +++ b/rama-http/src/layer/header_option_value.rs @@ -4,14 +4,13 @@ //! and has a bool-like value. use rama_utils::macros::define_inner_service_accessors; -use crate::{ - error::BoxError, - http::{utils::HeaderValueGetter, Request}, +use rama_core::{ + error::{ErrorExt, OpaqueError, BoxError}, Context, Layer, Service, }; use crate::{ - error::{ErrorExt, OpaqueError}, - http::HeaderName, + HeaderName, + utils::HeaderValueGetter, Request, }; use std::{fmt, marker::PhantomData}; @@ -115,7 +114,7 @@ where } Err(err) => { if self.optional - && matches!(err, crate::http::utils::HeaderValueErr::HeaderMissing(_)) + && matches!(err, crate::utils::HeaderValueErr::HeaderMissing(_)) { tracing::debug!( error = %err, @@ -201,7 +200,7 @@ impl Layer for HeaderOptionValueLayer { #[cfg(test)] mod test { use super::*; - use crate::http::Method; + use crate::Method; #[derive(Debug, Clone, Default)] struct UnitValue; diff --git a/rama-http/src/layer/map_request_body.rs b/rama-http/src/layer/map_request_body.rs index 26c0bc27..15b35c9a 100644 --- a/rama-http/src/layer/map_request_body.rs +++ b/rama-http/src/layer/map_request_body.rs @@ -56,14 +56,14 @@ //! # } //! ``` -use crate::http::{Request, Response}; +use crate::{Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::fmt; /// Apply a transformation to the request body. /// -/// See the [module docs](crate::http::layer::map_request_body) for an example. +/// See the [module docs](crate::layer::map_request_body) for an example. #[derive(Clone)] pub struct MapRequestBodyLayer { f: F, @@ -99,7 +99,7 @@ impl fmt::Debug for MapRequestBodyLayer { /// Apply a transformation to the request body. /// -/// See the [module docs](crate::http::layer::map_request_body) for an example. +/// See the [module docs](crate::layer::map_request_body) for an example. #[derive(Clone)] pub struct MapRequestBody { inner: S, diff --git a/rama-http/src/layer/map_response_body.rs b/rama-http/src/layer/map_response_body.rs index 11149324..972d942b 100644 --- a/rama-http/src/layer/map_response_body.rs +++ b/rama-http/src/layer/map_response_body.rs @@ -80,14 +80,14 @@ //! # } //! ``` -use crate::http::{Request, Response}; +use crate::{Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::fmt; /// Apply a transformation to the response body. /// -/// See the [module docs](crate::http::layer::map_response_body) for an example. +/// See the [module docs](crate::layer::map_response_body) for an example. #[derive(Clone)] pub struct MapResponseBodyLayer { f: F, @@ -123,7 +123,7 @@ impl fmt::Debug for MapResponseBodyLayer { /// Apply a transformation to the response body. /// -/// See the [module docs](crate::http::layer::map_response_body) for an example. +/// See the [module docs](crate::layer::map_response_body) for an example. #[derive(Clone)] pub struct MapResponseBody { inner: S, diff --git a/rama-http/src/layer/normalize_path.rs b/rama-http/src/layer/normalize_path.rs index fcf3d600..8ef30b41 100644 --- a/rama-http/src/layer/normalize_path.rs +++ b/rama-http/src/layer/normalize_path.rs @@ -37,9 +37,9 @@ //! # } //! ``` -use crate::http::{Request, Response, Uri}; +use crate::{Request, Response, Uri}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::borrow::Cow; use std::fmt; use std::future::Future; diff --git a/rama-http/src/layer/propagate_headers.rs b/rama-http/src/layer/propagate_headers.rs index ec678549..86528378 100644 --- a/rama-http/src/layer/propagate_headers.rs +++ b/rama-http/src/layer/propagate_headers.rs @@ -35,16 +35,16 @@ //! # } //! ``` -use crate::http::{header::HeaderName, Request, Response}; +use crate::{header::HeaderName, Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; /// Layer that applies [`PropagateHeader`] which propagates headers from requests to responses. /// /// If the header is present on the request it'll be applied to the response as well. This could /// for example be used to propagate headers such as `X-Request-Id`. /// -/// See the [module docs](crate::http::layer::propagate_headers) for more details. +/// See the [module docs](crate::layer::propagate_headers) for more details. #[derive(Clone, Debug)] pub struct PropagateHeaderLayer { header: HeaderName, @@ -73,7 +73,7 @@ impl Layer for PropagateHeaderLayer { /// If the header is present on the request it'll be applied to the response as well. This could /// for example be used to propagate headers such as `X-Request-Id`. /// -/// See the [module docs](crate::http::layer::propagate_headers) for more details. +/// See the [module docs](crate::layer::propagate_headers) for more details. #[derive(Clone, Debug)] pub struct PropagateHeader { inner: S, diff --git a/rama-http/src/layer/proxy_auth.rs b/rama-http/src/layer/proxy_auth.rs index cdb2d82d..e9b49705 100644 --- a/rama-http/src/layer/proxy_auth.rs +++ b/rama-http/src/layer/proxy_auth.rs @@ -2,12 +2,12 @@ //! //! If the request is not authorized a `407 Proxy Authentication Required` response will be sent. -use crate::http::header::PROXY_AUTHENTICATE; -use crate::http::headers::{authorization::Credentials, HeaderMapExt, ProxyAuthorization}; -use crate::http::{Request, Response, StatusCode}; -use crate::net::user::auth::Authority; +use crate::header::PROXY_AUTHENTICATE; +use crate::headers::{authorization::Credentials, HeaderMapExt, ProxyAuthorization}; +use crate::{Request, Response, StatusCode}; +use rama_net::auth::Authority; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::fmt; use std::marker::PhantomData; diff --git a/rama-http/src/layer/remove_header/mod.rs b/rama-http/src/layer/remove_header/mod.rs index 1194a96d..2020c077 100644 --- a/rama-http/src/layer/remove_header/mod.rs +++ b/rama-http/src/layer/remove_header/mod.rs @@ -2,7 +2,7 @@ //! //! See [request] and [response] for more details. -use crate::http::{header, HeaderMap, HeaderName}; +use crate::{header, HeaderMap, HeaderName}; pub mod request; pub mod response; diff --git a/rama-http/src/layer/remove_header/request.rs b/rama-http/src/layer/remove_header/request.rs index bba538ea..24761f0c 100644 --- a/rama-http/src/layer/remove_header/request.rs +++ b/rama-http/src/layer/remove_header/request.rs @@ -28,9 +28,9 @@ //! # } //! ``` -use crate::http::{HeaderName, Request, Response}; +use crate::{HeaderName, Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::{borrow::Cow, fmt, future::Future}; #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/remove_header/response.rs b/rama-http/src/layer/remove_header/response.rs index 344e049e..05a21f2f 100644 --- a/rama-http/src/layer/remove_header/response.rs +++ b/rama-http/src/layer/remove_header/response.rs @@ -28,9 +28,9 @@ //! # } //! ``` -use crate::http::{HeaderName, Request, Response}; +use crate::{HeaderName, Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::{borrow::Cow, fmt}; #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/request_id.rs b/rama-http/src/layer/request_id.rs index 7abf423c..7c2d065e 100644 --- a/rama-http/src/layer/request_id.rs +++ b/rama-http/src/layer/request_id.rs @@ -59,12 +59,12 @@ use std::fmt; -use crate::http::{ +use crate::{ header::{HeaderName, HeaderValue}, Request, Response, }; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use uuid::Uuid; pub(crate) const X_REQUEST_ID: &str = "x-request-id"; @@ -387,8 +387,8 @@ impl MakeRequestId for MakeRequestUuid { #[cfg(test)] mod tests { - use crate::http::layer::set_header; - use crate::http::{Body, Response}; + use crate::layer::set_header; + use crate::{Body, Response}; use crate::service::service_fn; use crate::Layer; use std::{ diff --git a/rama-http/src/layer/required_header/request.rs b/rama-http/src/layer/required_header/request.rs index ac7ca5fa..a7a011d3 100644 --- a/rama-http/src/layer/required_header/request.rs +++ b/rama-http/src/layer/required_header/request.rs @@ -3,19 +3,14 @@ //! For now this only sets `Host` header on http/1.1, //! as well as always a User-Agent for all versions. -use crate::error::ErrorContext; -use crate::http::RequestContext; -use rama_utils::macros::define_inner_service_accessors; use crate::{ - error::BoxError, - http::{ - header::{self, RAMA_ID_HEADER_VALUE}, - Request, Response, - }, + RequestContext, + header::{self, RAMA_ID_HEADER_VALUE, HOST, USER_AGENT}, + headers::HeaderMapExt, + Request, Response, }; -use crate::{Context, Layer, Service}; -use headers::HeaderMapExt; -use http::header::{HOST, USER_AGENT}; +use rama_utils::macros::define_inner_service_accessors; +use rama_core::{Context, Layer, Service, error::{BoxError, ErrorContext}}; use std::fmt; /// Layer that applies [`AddRequiredRequestHeaders`] which adds a request header. @@ -131,10 +126,10 @@ where .context( "AddRequiredRequestHeaders: get/compute RequestContext to set authority", )?; - let host = crate::http::dep::http::uri::Authority::from_maybe_shared( + let host = crate::dep::http::uri::Authority::from_maybe_shared( request_ctx.authority.to_string(), ) - .map(crate::http::headers::Host::from) + .map(crate::headers::Host::from) .context("AddRequiredRequestHeaders: set authority")?; req.headers_mut().typed_insert(host); } @@ -153,7 +148,7 @@ where #[cfg(test)] mod test { use super::*; - use crate::http::{Body, Request}; + use crate::{Body, Request}; use crate::service::service_fn; use crate::{Context, Layer, Service}; use std::convert::Infallible; diff --git a/rama-http/src/layer/required_header/response.rs b/rama-http/src/layer/required_header/response.rs index 33df5813..323681ab 100644 --- a/rama-http/src/layer/required_header/response.rs +++ b/rama-http/src/layer/required_header/response.rs @@ -2,16 +2,13 @@ //! //! For now this only sets `Server` and `Date` heades. -use crate::http::{ - header::{self, RAMA_ID_HEADER_VALUE}, +use crate::{ + header::{self, RAMA_ID_HEADER_VALUE, DATE, SERVER}, Request, Response, -}; -use crate::http::{ - header::{DATE, SERVER}, headers::{Date, HeaderMapExt}, }; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::{fmt, time::SystemTime}; /// Layer that applies [`AddRequiredResponseHeaders`] which adds a request header. diff --git a/rama-http/src/layer/retry/body.rs b/rama-http/src/layer/retry/body.rs index 8ad75a98..0d1ff2bd 100644 --- a/rama-http/src/layer/retry/body.rs +++ b/rama-http/src/layer/retry/body.rs @@ -22,7 +22,7 @@ impl RetryBody { } } -impl crate::http::dep::http_body::Body for RetryBody { +impl crate::dep::http_body::Body for RetryBody { type Data = Bytes; type Error = crate::error::BoxError; @@ -51,11 +51,11 @@ impl crate::http::dep::http_body::Body for RetryBody { } } -impl From for crate::http::Body { +impl From for crate::Body { fn from(body: RetryBody) -> Self { match body.bytes { Some(bytes) => bytes.into(), - None => crate::http::Body::empty(), + None => crate::Body::empty(), } } } @@ -63,7 +63,7 @@ impl From for crate::http::Body { #[cfg(test)] mod tests { use super::*; - use crate::http::BodyExtractExt; + use crate::BodyExtractExt; #[tokio::test] async fn consume_retry_body() { diff --git a/rama-http/src/layer/retry/managed.rs b/rama-http/src/layer/retry/managed.rs index 466aae0c..f599191e 100644 --- a/rama-http/src/layer/retry/managed.rs +++ b/rama-http/src/layer/retry/managed.rs @@ -5,11 +5,9 @@ //! [`Policy`]: super::Policy use super::{Policy, PolicyResult, RetryBody}; -use crate::{ - http::{Request, Response}, - utils::backoff::Backoff, - Context, -}; +use crate::{Request, Response}; +use rama_utils::backoff::Backoff; +use rama_core::Context; use std::future::Future; #[derive(Debug, Clone, Default)] diff --git a/rama-http/src/layer/retry/mod.rs b/rama-http/src/layer/retry/mod.rs index 0135565c..60cabb6f 100644 --- a/rama-http/src/layer/retry/mod.rs +++ b/rama-http/src/layer/retry/mod.rs @@ -1,11 +1,11 @@ //! Middleware for retrying "failed" requests. -use crate::error::BoxError; -use crate::http::dep::http_body::Body as HttpBody; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::Request; +use rama_core::error::BoxError; +use crate::dep::http_body::Body as HttpBody; +use crate::dep::http_body_util::BodyExt; +use crate::Request; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Service}; +use rama_core::{Context, Service}; mod layer; mod policy; diff --git a/rama-http/src/layer/retry/policy.rs b/rama-http/src/layer/retry/policy.rs index a5efd28a..6398b620 100644 --- a/rama-http/src/layer/retry/policy.rs +++ b/rama-http/src/layer/retry/policy.rs @@ -1,5 +1,6 @@ use super::RetryBody; -use crate::{http::Request, Context}; +use crate::Request; +use rama_core::Context; use std::future::Future; /// A "retry policy" to classify if a request should be retried. diff --git a/rama-http/src/layer/retry/tests.rs b/rama-http/src/layer/retry/tests.rs index 68154143..f6c58a5b 100644 --- a/rama-http/src/layer/retry/tests.rs +++ b/rama-http/src/layer/retry/tests.rs @@ -1,7 +1,7 @@ use super::*; use crate::error::{error, OpaqueError}; -use crate::http::{response::IntoResponse, BodyExtractExt}; -use crate::http::{Request, Response}; +use crate::{response::IntoResponse, BodyExtractExt}; +use crate::{Request, Response}; use crate::{Layer, Service}; use parking_lot::Mutex; use std::sync::{ diff --git a/rama-http/src/layer/sensitive_headers.rs b/rama-http/src/layer/sensitive_headers.rs index e31a492d..21b43a60 100644 --- a/rama-http/src/layer/sensitive_headers.rs +++ b/rama-http/src/layer/sensitive_headers.rs @@ -38,16 +38,16 @@ //! # } //! ``` -use crate::http::{HeaderName, Request, Response}; +use crate::{HeaderName, Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::sync::Arc; /// Mark headers as [sensitive] on both requests and responses. /// /// Produces [`SetSensitiveHeaders`] services. /// -/// See the [module docs](crate::http::layer::sensitive_headers) for more details. +/// See the [module docs](crate::layer::sensitive_headers) for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive #[derive(Clone, Debug)] @@ -84,7 +84,7 @@ impl Layer for SetSensitiveHeadersLayer { /// Mark headers as [sensitive] on both requests and responses. /// -/// See the [module docs](crate::http::layer::sensitive_headers) for more details. +/// See the [module docs](crate::layer::sensitive_headers) for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive pub type SetSensitiveHeaders = SetSensitiveRequestHeaders>; @@ -93,7 +93,7 @@ pub type SetSensitiveHeaders = SetSensitiveRequestHeaders Layer for SetSensitiveRequestHeadersLayer { /// Mark request headers as [sensitive]. /// -/// See the [module docs](crate::http::layer::sensitive_headers) for more details. +/// See the [module docs](crate::layer::sensitive_headers) for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive #[derive(Clone, Debug)] @@ -189,7 +189,7 @@ where /// /// Produces [`SetSensitiveResponseHeaders`] services. /// -/// See the [module docs](crate::http::layer::sensitive_headers) for more details. +/// See the [module docs](crate::layer::sensitive_headers) for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive #[derive(Clone, Debug)] @@ -226,7 +226,7 @@ impl Layer for SetSensitiveResponseHeadersLayer { /// Mark response headers as [sensitive]. /// -/// See the [module docs](crate::http::layer::sensitive_headers) for more details. +/// See the [module docs](crate::layer::sensitive_headers) for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive #[derive(Clone, Debug)] diff --git a/rama-http/src/layer/set_header/mod.rs b/rama-http/src/layer/set_header/mod.rs index 595db03d..3ce1fe6b 100644 --- a/rama-http/src/layer/set_header/mod.rs +++ b/rama-http/src/layer/set_header/mod.rs @@ -2,8 +2,8 @@ //! //! See [request] and [response] for more details. -use crate::http::{HeaderMap, HeaderName, HeaderValue, Request, Response}; -use crate::Context; +use crate::{HeaderMap, HeaderName, HeaderValue, Request, Response}; +use rama_core::Context; use std::{ future::{ready, Future}, marker::PhantomData, diff --git a/rama-http/src/layer/set_header/request.rs b/rama-http/src/layer/set_header/request.rs index 5cc6ce5c..d95385f2 100644 --- a/rama-http/src/layer/set_header/request.rs +++ b/rama-http/src/layer/set_header/request.rs @@ -80,16 +80,14 @@ //! # } //! ``` -use http::HeaderValue; - use super::{BoxMakeHeaderValueFn, InsertHeaderMode, MakeHeaderValue}; -use crate::http::{ +use crate::{ header::HeaderName, headers::{Header, HeaderExt}, - Request, Response, + Request, Response, HeaderValue }; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::fmt; /// Layer that applies [`SetRequestHeader`] which adds a request header. diff --git a/rama-http/src/layer/set_header/response.rs b/rama-http/src/layer/set_header/response.rs index e6ccbb33..f489125a 100644 --- a/rama-http/src/layer/set_header/response.rs +++ b/rama-http/src/layer/set_header/response.rs @@ -92,13 +92,13 @@ //! ``` use super::{BoxMakeHeaderValueFn, InsertHeaderMode, MakeHeaderValue}; -use crate::http::{ +use crate::{ header::HeaderName, headers::{Header, HeaderExt}, HeaderValue, Request, Response, }; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use std::fmt; /// Layer that applies [`SetResponseHeader`] which adds a response header. @@ -366,7 +366,7 @@ where mod tests { use super::*; - use crate::http::{header, Body, HeaderValue, Request, Response}; + use crate::{header, Body, HeaderValue, Request, Response}; use crate::service::service_fn; use std::convert::Infallible; diff --git a/rama-http/src/layer/set_status.rs b/rama-http/src/layer/set_status.rs index 04141073..84e3c3b0 100644 --- a/rama-http/src/layer/set_status.rs +++ b/rama-http/src/layer/set_status.rs @@ -36,9 +36,9 @@ use std::fmt; -use crate::http::{Request, Response, StatusCode}; +use crate::{Request, Response, StatusCode}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; /// Layer that applies [`SetStatus`] which overrides the status codes. #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/timeout.rs b/rama-http/src/layer/timeout.rs index f1663b4f..b0a81292 100644 --- a/rama-http/src/layer/timeout.rs +++ b/rama-http/src/layer/timeout.rs @@ -43,10 +43,9 @@ use std::fmt; use std::time::Duration; - -use crate::http::{Request, Response, StatusCode}; +use crate::{Request, Response, StatusCode}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; /// Layer that applies the [`Timeout`] middleware which apply a timeout to requests. /// diff --git a/rama-http/src/layer/trace/body.rs b/rama-http/src/layer/trace/body.rs index 434d9edf..1a991860 100644 --- a/rama-http/src/layer/trace/body.rs +++ b/rama-http/src/layer/trace/body.rs @@ -1,6 +1,6 @@ use super::{DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, OnBodyChunk, OnEos, OnFailure}; -use crate::http::dep::http_body::{Body, Frame}; -use crate::http::layer::classify::ClassifyEos; +use crate::dep::http_body::{Body, Frame}; +use crate::layer::classify::ClassifyEos; use futures_lite::ready; use pin_project_lite::pin_project; use std::{ diff --git a/rama-http/src/layer/trace/layer.rs b/rama-http/src/layer/trace/layer.rs index 4cd630ca..83d25503 100644 --- a/rama-http/src/layer/trace/layer.rs +++ b/rama-http/src/layer/trace/layer.rs @@ -1,17 +1,16 @@ use std::fmt; - use super::{ DefaultMakeSpan, DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, GrpcMakeClassifier, HttpMakeClassifier, Trace, }; -use crate::http::layer::classify::{ +use crate::layer::classify::{ GrpcErrorsAsFailures, MakeClassifier, ServerErrorsAsFailures, SharedClassifier, }; -use crate::Layer; +use rama_core::Layer; /// [`Layer`] that adds high level [tracing] to a [`Service`]. /// -/// See the [module docs](crate::http::layer::trace) for more details. +/// See the [module docs](crate::layer::trace) for more details. /// /// [`Layer`]: crate::Layer /// [tracing]: https://crates.io/crates/tracing diff --git a/rama-http/src/layer/trace/make_span.rs b/rama-http/src/layer/trace/make_span.rs index 9d929d23..6d3bb083 100644 --- a/rama-http/src/layer/trace/make_span.rs +++ b/rama-http/src/layer/trace/make_span.rs @@ -1,4 +1,4 @@ -use crate::http::Request; +use crate::Request; use tracing::{Level, Span}; use super::DEFAULT_MESSAGE_LEVEL; diff --git a/rama-http/src/layer/trace/mod.rs b/rama-http/src/layer/trace/mod.rs index 663dbd00..bd424ac8 100644 --- a/rama-http/src/layer/trace/mod.rs +++ b/rama-http/src/layer/trace/mod.rs @@ -347,12 +347,12 @@ //! [tracing]: https://crates.io/crates/tracing //! [`Service`]: crate::Service //! [`Service::serve`]: crate::Service::serve -//! [`MakeClassifier`]: crate::http::layer::classify::MakeClassifier -//! [`ClassifyResponse`]: crate::http::layer::classify::ClassifyResponse +//! [`MakeClassifier`]: crate::layer::classify::MakeClassifier +//! [`ClassifyResponse`]: crate::layer::classify::ClassifyResponse //! [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record -//! [`TraceLayer::make_span_with`]: crate::http::layer::trace::TraceLayer::make_span_with +//! [`TraceLayer::make_span_with`]: crate::layer::trace::TraceLayer::make_span_with //! [`Span`]: tracing::Span -//! [`ServerErrorsAsFailures`]: crate::http::layer::classify::ServerErrorsAsFailures +//! [`ServerErrorsAsFailures`]: crate::layer::classify::ServerErrorsAsFailures use std::{fmt, time::Duration}; @@ -371,10 +371,8 @@ pub use self::{ service::Trace, }; -use crate::{ - http::layer::classify::{GrpcErrorsAsFailures, ServerErrorsAsFailures, SharedClassifier}, - utils::latency::LatencyUnit, -}; +use crate::layer::classify::{GrpcErrorsAsFailures, ServerErrorsAsFailures, SharedClassifier}; +use rama_utils::latency::LatencyUnit; /// MakeClassifier for HTTP requests. pub type HttpMakeClassifier = SharedClassifier; @@ -463,9 +461,9 @@ mod tests { use super::*; use crate::error::BoxError; - use crate::http::dep::http_body_util::BodyExt as _; - use crate::http::layer::classify::ServerErrorsFailureClass; - use crate::http::{Body, HeaderMap, Request, Response}; + use crate::dep::http_body_util::BodyExt as _; + use crate::layer::classify::ServerErrorsFailureClass; + use crate::{Body, HeaderMap, Request, Response}; use crate::service::service_fn; use crate::{Context, Layer, Service}; use bytes::Bytes; diff --git a/rama-http/src/layer/trace/on_body_chunk.rs b/rama-http/src/layer/trace/on_body_chunk.rs index eb1809b8..60bddd87 100644 --- a/rama-http/src/layer/trace/on_body_chunk.rs +++ b/rama-http/src/layer/trace/on_body_chunk.rs @@ -18,7 +18,7 @@ pub trait OnBodyChunk: Send + Sync + 'static { /// /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/index.html /// [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record - /// [`TraceLayer::make_span_with`]: crate::http::layer::trace::TraceLayer::make_span_with + /// [`TraceLayer::make_span_with`]: crate::layer::trace::TraceLayer::make_span_with fn on_body_chunk(&mut self, chunk: &B, latency: Duration, span: &Span); } diff --git a/rama-http/src/layer/trace/on_eos.rs b/rama-http/src/layer/trace/on_eos.rs index adceb0d4..6506c8a0 100644 --- a/rama-http/src/layer/trace/on_eos.rs +++ b/rama-http/src/layer/trace/on_eos.rs @@ -1,6 +1,6 @@ use super::{Latency, DEFAULT_MESSAGE_LEVEL}; -use crate::http::header::HeaderMap; -use crate::http::layer::classify::grpc_errors_as_failures::ParsedGrpcStatus; +use crate::header::HeaderMap; +use crate::layer::classify::grpc_errors_as_failures::ParsedGrpcStatus; use rama_utils::latency::LatencyUnit; use std::time::Duration; use tracing::{Level, Span}; @@ -22,7 +22,7 @@ pub trait OnEos: Send + Sync + 'static { /// /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/index.html /// [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record - /// [`TraceLayer::make_span_with`]: crate::http::layer::trace::TraceLayer::make_span_with + /// [`TraceLayer::make_span_with`]: crate::layer::trace::TraceLayer::make_span_with fn on_eos(self, trailers: Option<&HeaderMap>, stream_duration: Duration, span: &Span); } @@ -110,9 +110,9 @@ impl OnEos for DefaultOnEos { duration: stream_duration, }; let status = trailers.and_then(|trailers| { - match crate::http::layer::classify::grpc_errors_as_failures::classify_grpc_metadata( + match crate::layer::classify::grpc_errors_as_failures::classify_grpc_metadata( trailers, - crate::http::layer::classify::GrpcCode::Ok.into_bitmask(), + crate::layer::classify::GrpcCode::Ok.into_bitmask(), ) { ParsedGrpcStatus::Success | ParsedGrpcStatus::HeaderNotString diff --git a/rama-http/src/layer/trace/on_failure.rs b/rama-http/src/layer/trace/on_failure.rs index 76814217..02cdfaf2 100644 --- a/rama-http/src/layer/trace/on_failure.rs +++ b/rama-http/src/layer/trace/on_failure.rs @@ -20,7 +20,7 @@ pub trait OnFailure: Send + Sync + 'static { /// /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/index.html /// [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record - /// [`TraceLayer::make_span_with`]: crate::http::layer::trace::TraceLayer::make_span_with + /// [`TraceLayer::make_span_with`]: crate::layer::trace::TraceLayer::make_span_with fn on_failure(&self, failure_classification: FailureClass, latency: Duration, span: &Span); } diff --git a/rama-http/src/layer/trace/on_request.rs b/rama-http/src/layer/trace/on_request.rs index c273ce1e..4bbafdb4 100644 --- a/rama-http/src/layer/trace/on_request.rs +++ b/rama-http/src/layer/trace/on_request.rs @@ -1,5 +1,5 @@ use super::DEFAULT_MESSAGE_LEVEL; -use crate::http::Request; +use crate::Request; use tracing::Level; use tracing::Span; @@ -18,7 +18,7 @@ pub trait OnRequest: Send + Sync + 'static { /// /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/index.html /// [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record - /// [`TraceLayer::make_span_with`]: crate::http::layer::trace::TraceLayer::make_span_with + /// [`TraceLayer::make_span_with`]: crate::layer::trace::TraceLayer::make_span_with fn on_request(&self, request: &Request, span: &Span); } @@ -68,7 +68,7 @@ impl DefaultOnRequest { /// Defaults to [`Level::DEBUG`]. /// /// [tracing events]: https://docs.rs/tracing/latest/tracing/#events - /// [`DefaultMakeSpan::level`]: crate::http::layer::trace::DefaultMakeSpan::level + /// [`DefaultMakeSpan::level`]: crate::layer::trace::DefaultMakeSpan::level pub fn level(mut self, level: Level) -> Self { self.level = level; self @@ -84,7 +84,7 @@ impl DefaultOnRequest { /// Defaults to [`Level::DEBUG`]. /// /// [tracing events]: https://docs.rs/tracing/latest/tracing/#events - /// [`DefaultMakeSpan::level`]: crate::http::layer::trace::DefaultMakeSpan::level + /// [`DefaultMakeSpan::level`]: crate::layer::trace::DefaultMakeSpan::level pub fn set_level(&mut self, level: Level) -> &mut Self { self.level = level; self diff --git a/rama-http/src/layer/trace/on_response.rs b/rama-http/src/layer/trace/on_response.rs index 20f2d298..602a815a 100644 --- a/rama-http/src/layer/trace/on_response.rs +++ b/rama-http/src/layer/trace/on_response.rs @@ -1,5 +1,5 @@ use super::{Latency, DEFAULT_MESSAGE_LEVEL}; -use crate::http::Response; +use crate::Response; use rama_utils::latency::LatencyUnit; use std::time::Duration; use tracing::Level; @@ -22,7 +22,7 @@ pub trait OnResponse: Send + Sync + 'static { /// /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/index.html /// [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record - /// [`TraceLayer::make_span_with`]: crate::http::layer::trace::TraceLayer::make_span_with + /// [`TraceLayer::make_span_with`]: crate::layer::trace::TraceLayer::make_span_with fn on_response(self, response: &Response, latency: Duration, span: &Span); } @@ -76,7 +76,7 @@ impl DefaultOnResponse { /// Defaults to [`Level::DEBUG`]. /// /// [tracing events]: https://docs.rs/tracing/latest/tracing/#events - /// [`DefaultMakeSpan::level`]: crate::http::layer::trace::DefaultMakeSpan::level + /// [`DefaultMakeSpan::level`]: crate::layer::trace::DefaultMakeSpan::level pub fn level(mut self, level: Level) -> Self { self.level = level; self @@ -92,7 +92,7 @@ impl DefaultOnResponse { /// Defaults to [`Level::DEBUG`]. /// /// [tracing events]: https://docs.rs/tracing/latest/tracing/#events - /// [`DefaultMakeSpan::level`]: crate::http::layer::trace::DefaultMakeSpan::level + /// [`DefaultMakeSpan::level`]: crate::layer::trace::DefaultMakeSpan::level pub fn set_level(&mut self, level: Level) -> &mut Self { self.level = level; self @@ -156,7 +156,7 @@ impl OnResponse for DefaultOnResponse { } fn status(res: &Response) -> Option { - use crate::http::layer::classify::grpc_errors_as_failures::ParsedGrpcStatus; + use crate::layer::classify::grpc_errors_as_failures::ParsedGrpcStatus; // gRPC-over-HTTP2 uses the "application/grpc[+format]" content type, and gRPC-Web uses // "application/grpc-web[+format]" or "application/grpc-web-text[+format]", where "format" is @@ -177,9 +177,9 @@ fn status(res: &Response) -> Option { }); if is_grpc { - match crate::http::layer::classify::grpc_errors_as_failures::classify_grpc_metadata( + match crate::layer::classify::grpc_errors_as_failures::classify_grpc_metadata( res.headers(), - crate::http::layer::classify::GrpcCode::Ok.into_bitmask(), + crate::layer::classify::GrpcCode::Ok.into_bitmask(), ) { ParsedGrpcStatus::Success | ParsedGrpcStatus::HeaderNotString diff --git a/rama-http/src/layer/trace/service.rs b/rama-http/src/layer/trace/service.rs index c3fae916..d88fd8f3 100644 --- a/rama-http/src/layer/trace/service.rs +++ b/rama-http/src/layer/trace/service.rs @@ -3,19 +3,19 @@ use super::{ DefaultOnResponse, GrpcMakeClassifier, HttpMakeClassifier, MakeSpan, OnBodyChunk, OnEos, OnFailure, OnRequest, OnResponse, ResponseBody, }; -use crate::http::dep::http_body::Body as HttpBody; -use crate::http::layer::classify::{ +use crate::dep::http_body::Body as HttpBody; +use crate::layer::classify::{ ClassifiedResponse, ClassifyResponse, GrpcErrorsAsFailures, MakeClassifier, ServerErrorsAsFailures, SharedClassifier, }; -use crate::http::{Request, Response}; +use crate::{Request, Response}; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Service}; +use rama_core::{Context, Service}; use std::{fmt, time::Instant}; /// Middleware that adds high level [tracing] to a [`Service`]. /// -/// See the [module docs](crate::http::layer::trace) for an example. +/// See the [module docs](crate::layer::trace) for an example. /// /// [tracing]: https://crates.io/crates/tracing /// [`Service`]: crate::Service diff --git a/rama-http/src/layer/traffic_writer/mod.rs b/rama-http/src/layer/traffic_writer/mod.rs index 1299b470..17808231 100644 --- a/rama-http/src/layer/traffic_writer/mod.rs +++ b/rama-http/src/layer/traffic_writer/mod.rs @@ -3,12 +3,10 @@ //! Can be useful for cli / debug purposes. use crate::{ - http::{ - io::{write_http_request, write_http_response}, - Request, Response, - }, - rt::Executor, + io::{write_http_request, write_http_response}, + Request, Response, }; +use rama_core::rt::Executor; use tokio::{ io::{AsyncWrite, AsyncWriteExt}, sync::mpsc::{channel, unbounded_channel, Sender, UnboundedSender}, diff --git a/rama-http/src/layer/traffic_writer/request.rs b/rama-http/src/layer/traffic_writer/request.rs index 0c890de3..405adac2 100644 --- a/rama-http/src/layer/traffic_writer/request.rs +++ b/rama-http/src/layer/traffic_writer/request.rs @@ -1,12 +1,12 @@ use super::WriterMode; -use crate::error::{BoxError, ErrorExt, OpaqueError}; -use crate::http::dep::http_body; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::io::write_http_request; -use crate::http::{Body, Request, Response}; -use crate::rt::Executor; +use rama_core::error::{BoxError, ErrorExt, OpaqueError}; +use crate::dep::http_body; +use crate::dep::http_body_util::BodyExt; +use crate::io::write_http_request; +use crate::{Body, Request, Response}; +use rama_core::rt::Executor; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use bytes::Bytes; use std::fmt::Debug; use std::future::Future; diff --git a/rama-http/src/layer/traffic_writer/response.rs b/rama-http/src/layer/traffic_writer/response.rs index fa2a08ac..ea03c5c3 100644 --- a/rama-http/src/layer/traffic_writer/response.rs +++ b/rama-http/src/layer/traffic_writer/response.rs @@ -1,12 +1,12 @@ use super::WriterMode; -use crate::error::{BoxError, ErrorContext, OpaqueError}; -use crate::http::dep::http_body; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::io::write_http_response; -use crate::http::{Body, Request, Response}; -use crate::rt::Executor; +use rama_core::error::{BoxError, ErrorContext, OpaqueError}; +use crate::dep::http_body; +use crate::dep::http_body_util::BodyExt; +use crate::io::write_http_response; +use crate::{Body, Request, Response}; +use rama_core::rt::Executor; use rama_utils::macros::define_inner_service_accessors; -use crate::{Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; use bytes::Bytes; use std::fmt::Debug; use std::future::Future; diff --git a/rama-http/src/layer/ua.rs b/rama-http/src/layer/ua.rs index 782faf64..32103433 100644 --- a/rama-http/src/layer/ua.rs +++ b/rama-http/src/layer/ua.rs @@ -1,18 +1,57 @@ -use super::{HttpAgent, TlsAgent, UserAgent}; +//! User-Agent (see also `rama-ua`) http layer support +//! +//! # Example +//! +//! ``` +//! use rama_http::{ +//! client::HttpClientExt, IntoResponse, Request, Response, StatusCode, +//! layer::ua::{PlatformKind, UserAgent, UserAgentClassifierLayer, UserAgentKind, UserAgentInfo}, +//! }; +//! use rama_core::{Context, Layer, service::service_fn}; +//! use std::convert::Infallible; +//! +//! const UA: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.2478.67"; +//! +//! async fn handle(ctx: Context, _req: Request) -> Result { +//! let ua: &UserAgent = ctx.get().unwrap(); +//! +//! assert_eq!(ua.header_str(), UA); +//! assert_eq!(ua.info(), Some(UserAgentInfo{ kind: UserAgentKind::Chromium, version: Some(124) })); +//! assert_eq!(ua.platform(), Some(PlatformKind::Windows)); +//! +//! Ok(StatusCode::OK.into_response()) +//! } +//! +//! # #[tokio::main] +//! # async fn main() { +//! let service = UserAgentClassifierLayer::new().layer(service_fn(handle)); +//! +//! let _ = service +//! .get("http://www.example.com") +//! .typed_header(headers::UserAgent::from_static(UA)) +//! .send(Context::default()) +//! .await +//! .unwrap(); +//! # } +//! ``` + use rama_utils::macros::define_inner_service_accessors; use crate::{ - http::{ - headers::{self, HeaderMapExt}, - HeaderName, Request, - }, - Layer, Service, + headers::{self, HeaderMapExt}, + HeaderName, Request, }; +use rama_core::{Layer, Service}; use serde::{Deserialize, Serialize}; use std::{ fmt::{self, Debug}, future::Future, }; +pub use rama_ua::{ + DeviceKind, HttpAgent, PlatformKind, TlsAgent, UserAgent, UserAgentInfo, UserAgentKind, + UserAgentOverwrites, +}; + /// A [`Service`] that classifies the [`UserAgent`] of incoming [`Request`]s. /// /// The [`Extensions`] of the [`Context`] is updated with the [`UserAgent`] @@ -163,10 +202,10 @@ impl Layer for UserAgentClassifierLayer { #[cfg(test)] mod tests { use super::*; - use crate::http::client::HttpClientExt; - use crate::http::headers; - use crate::http::layer::required_header::AddRequiredRequestHeadersLayer; - use crate::http::{IntoResponse, StatusCode}; + use crate::client::HttpClientExt; + use crate::headers; + use crate::layer::required_header::AddRequiredRequestHeadersLayer; + use crate::{IntoResponse, StatusCode}; use crate::service::service_fn; use crate::ua::{PlatformKind, UserAgentKind}; use crate::{http::Response, Context}; diff --git a/rama-http/src/layer/upgrade/layer.rs b/rama-http/src/layer/upgrade/layer.rs index 695ec9db..6d99b9a9 100644 --- a/rama-http/src/layer/upgrade/layer.rs +++ b/rama-http/src/layer/upgrade/layer.rs @@ -1,12 +1,13 @@ use super::{service::UpgradeHandler, UpgradeService, Upgraded}; -use crate::{http::Request, matcher::Matcher, Context, Layer, Service}; +use crate::Request; +use rama_core::{matcher::Matcher, Context, Layer, Service}; use std::{convert::Infallible, fmt, sync::Arc}; /// UpgradeLayer is a middleware that can be used to upgrade a request. /// /// See [`UpgradeService`] for more details. /// -/// [`UpgradeService`]: crate::http::layer::upgrade::UpgradeService +/// [`UpgradeService`]: crate::layer::upgrade::UpgradeService pub struct UpgradeLayer { handlers: Vec>>, } diff --git a/rama-http/src/layer/upgrade/service.rs b/rama-http/src/layer/upgrade/service.rs index 5a2bd50c..5311a914 100644 --- a/rama-http/src/layer/upgrade/service.rs +++ b/rama-http/src/layer/upgrade/service.rs @@ -4,9 +4,10 @@ use super::Upgraded; use rama_utils::macros::define_inner_service_accessors; -use crate::{ - context::Extensions, http::Request, matcher::Matcher, service::BoxService, Context, Service, +use rama_core::{ + context::Extensions, matcher::Matcher, service::BoxService, Context, Service, }; +use crate::Request; use std::{convert::Infallible, fmt, sync::Arc}; /// Upgrade service can be used to handle the possibility of upgrading a request, diff --git a/rama-http/src/layer/util/compression.rs b/rama-http/src/layer/util/compression.rs index 8b73f4e7..26b24420 100644 --- a/rama-http/src/layer/util/compression.rs +++ b/rama-http/src/layer/util/compression.rs @@ -11,11 +11,10 @@ use std::{ }; use tokio::io::AsyncRead; use tokio_util::io::StreamReader; - use super::content_encoding::SupportedEncodings; -use crate::error::BoxError; -use crate::http::dep::http_body::{Body, Frame}; -use crate::http::HeaderValue; +use rama_core::error::BoxError; +use crate::dep::http_body::{Body, Frame}; +use crate::HeaderValue; #[derive(Debug, Clone, Copy)] pub(crate) struct AcceptEncoding { diff --git a/rama-http/src/layer/validate_request/accept_header.rs b/rama-http/src/layer/validate_request/accept_header.rs index 46bfb21b..df508c69 100644 --- a/rama-http/src/layer/validate_request/accept_header.rs +++ b/rama-http/src/layer/validate_request/accept_header.rs @@ -1,13 +1,13 @@ use super::ValidateRequest; use crate::{ - http::dep::mime::{Mime, MimeIter}, - http::{header, Request, Response, StatusCode}, - Context, + dep::mime::{Mime, MimeIter}, + header, Request, Response, StatusCode, }; +use rama_core::Context; use std::{fmt, marker::PhantomData, sync::Arc}; /// Type that performs validation of the Accept header. -pub struct AcceptHeader { +pub struct AcceptHeader { header_value: Arc, _ty: PhantomData ResBody>, } diff --git a/rama-http/src/layer/validate_request/validate.rs b/rama-http/src/layer/validate_request/validate.rs index 90f41159..de58a8af 100644 --- a/rama-http/src/layer/validate_request/validate.rs +++ b/rama-http/src/layer/validate_request/validate.rs @@ -1,7 +1,5 @@ -use crate::{ - http::{Request, Response}, - Context, -}; +use crate::{Request, Response}; +use rama_core::Context; use std::future::Future; /// Trait for validating requests. diff --git a/rama-http/src/layer/validate_request/validate_fn.rs b/rama-http/src/layer/validate_request/validate_fn.rs index ff09c74c..3b49cb55 100644 --- a/rama-http/src/layer/validate_request/validate_fn.rs +++ b/rama-http/src/layer/validate_request/validate_fn.rs @@ -1,8 +1,6 @@ use super::ValidateRequest; -use crate::{ - http::{Request, Response}, - Context, -}; +use crate::{Request, Response}; +use rama_core::Context; use std::future::Future; use std::marker::PhantomData; diff --git a/rama-http/src/layer/validate_request/validate_request_header.rs b/rama-http/src/layer/validate_request/validate_request_header.rs index ce11a804..475cc078 100644 --- a/rama-http/src/layer/validate_request/validate_request_header.rs +++ b/rama-http/src/layer/validate_request/validate_request_header.rs @@ -1,14 +1,12 @@ use super::{AcceptHeader, BoxValidateRequestFn, ValidateRequest}; use rama_utils::macros::define_inner_service_accessors; -use crate::{ - http::{Request, Response}, - Context, Layer, Service, -}; +use crate::{Request, Response}; +use rama_core::{Context, Layer, Service}; use std::fmt; /// Layer that applies [`ValidateRequestHeader`] which validates all requests. /// -/// See the [module docs](crate::http::layer::validate_request) for an example. +/// See the [module docs](crate::layer::validate_request) for an example. pub struct ValidateRequestHeaderLayer { validate: T, } @@ -89,7 +87,7 @@ where /// Middleware that validates requests. /// -/// See the [module docs](crate::http::layer::validate_request) for an example. +/// See the [module docs](crate::layer::validate_request) for an example. pub struct ValidateRequestHeader { inner: S, validate: T, @@ -187,7 +185,7 @@ mod tests { #[allow(unused_imports)] use super::*; - use crate::http::{header, Body, StatusCode}; + use crate::{header, Body, StatusCode}; use crate::{error::BoxError, service::service_fn, Layer}; #[tokio::test] diff --git a/rama-http/src/lib.rs b/rama-http/src/lib.rs index 9a95f27e..fc52768f 100644 --- a/rama-http/src/lib.rs +++ b/rama-http/src/lib.rs @@ -57,8 +57,8 @@ pub use ::rama_http_types::{ header, headers, response::{self, IntoResponse, Response}, - utils, Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, - Method, Request, RequestContext, Scheme, StatusCode, Uri, Version, + Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, + Method, Request, Scheme, StatusCode, Uri, Version, }; pub mod matcher; @@ -74,6 +74,9 @@ pub mod io; pub mod executor; +#[doc(hidden)] +mod utils; + pub mod dep { //! Dependencies for rama http modules. //! diff --git a/rama-http/src/matcher/domain.rs b/rama-http/src/matcher/domain.rs index 1e37a9bd..7a02afce 100644 --- a/rama-http/src/matcher/domain.rs +++ b/rama-http/src/matcher/domain.rs @@ -1,9 +1,9 @@ -use crate::{ +use rama_core::{ context::Extensions, - http::{Request, RequestContext}, - net::address::{Domain, Host}, Context, }; +use crate::{Request, RequestContext}; +use rama_net::address::{Domain, Host}; #[derive(Debug, Clone)] /// Matcher based on the (sub)domain of the request's URI. diff --git a/rama-http/src/matcher/header.rs b/rama-http/src/matcher/header.rs index 8e621e58..5ece5ed8 100644 --- a/rama-http/src/matcher/header.rs +++ b/rama-http/src/matcher/header.rs @@ -1,14 +1,14 @@ -use crate::{ +use rama_core::{ context::Extensions, - http::{HeaderName, HeaderValue, Request}, matcher::Matcher, Context, }; +use crate::{HeaderName, HeaderValue, Request}; #[derive(Debug, Clone)] /// Matcher based on the [`Request`]'s headers. /// -/// [`Request`]: crate::http::Request +/// [`Request`]: crate::Request pub struct HeaderMatcher { name: HeaderName, kind: HeaderMatcherKind, diff --git a/rama-http/src/matcher/method.rs b/rama-http/src/matcher/method.rs index 197c0795..48713890 100644 --- a/rama-http/src/matcher/method.rs +++ b/rama-http/src/matcher/method.rs @@ -1,8 +1,8 @@ -use crate::{ +use rama_core::{ context::Extensions, - http::{Method, Request}, Context, }; +use crate::{Method, Request}; use std::{ fmt, fmt::{Debug, Formatter}, diff --git a/rama-http/src/matcher/mod.rs b/rama-http/src/matcher/mod.rs index 1a4fb285..627b3749 100644 --- a/rama-http/src/matcher/mod.rs +++ b/rama-http/src/matcher/mod.rs @@ -3,12 +3,16 @@ //! See [`service::matcher` module] for more information. //! //! [`service::Matcher`]: crate::matcher::Matcher -//! [`http::Request`]: crate::http::Request +//! [`http::Request`]: crate::Request //! [`service::matcher` module]: crate::matcher -use crate::{ - context::Extensions, http::Request, matcher::IteratorMatcherExt, net::address::Domain, - stream::matcher::SocketMatcher, Context, +use rama_core::{ + context::Extensions, matcher::IteratorMatcherExt, Context, }; +use rama_net::{ + address::Domain, + stream::matcher::SocketMatcher, +}; +use crate::Request; use std::fmt; use std::sync::Arc; diff --git a/rama-http/src/matcher/path/mod.rs b/rama-http/src/matcher/path/mod.rs index 5be738f9..2c21b062 100644 --- a/rama-http/src/matcher/path/mod.rs +++ b/rama-http/src/matcher/path/mod.rs @@ -1,8 +1,8 @@ -use crate::{ +use rama_core::{ context::Extensions, - http::{IntoResponse, Request, StatusCode}, Context, }; +use crate::{IntoResponse, Request, StatusCode}; use std::collections::HashMap; mod de; @@ -75,7 +75,7 @@ pub struct UriParamsDeserializeError(de::PathDeserializationError); impl UriParamsDeserializeError { /// Get the response body text used for this rejection. pub fn body_text(&self) -> String { - use crate::http::matcher::path::de::ErrorKind; + use crate::matcher::path::de::ErrorKind; match self.0.kind { ErrorKind::Message(_) | ErrorKind::NoParams @@ -90,7 +90,7 @@ impl UriParamsDeserializeError { /// Get the status code used for this rejection. pub fn status(&self) -> StatusCode { - use crate::http::matcher::path::de::ErrorKind; + use crate::matcher::path::de::ErrorKind; match self.0.kind { ErrorKind::Message(_) | ErrorKind::NoParams @@ -113,7 +113,7 @@ impl std::fmt::Display for UriParamsDeserializeError { impl std::error::Error for UriParamsDeserializeError {} impl IntoResponse for UriParamsDeserializeError { - fn into_response(self) -> crate::http::Response { + fn into_response(self) -> crate::Response { rama_utils::macros::log_http_rejection!( rejection_type = UriParamsDeserializeError, body_text = self.body_text(), diff --git a/rama-http/src/matcher/uri.rs b/rama-http/src/matcher/uri.rs index 98787988..c4ff671f 100644 --- a/rama-http/src/matcher/uri.rs +++ b/rama-http/src/matcher/uri.rs @@ -1,10 +1,10 @@ //! provides a [`UriMatcher`] matcher for matching requests based on their URI. -use crate::{ +use rama_core::{ context::Extensions, - http::{Request, Uri}, Context, }; +use crate::{Request, Uri}; pub mod dep { //! dependencies for the `uri` matcher module diff --git a/rama-http/src/matcher/version.rs b/rama-http/src/matcher/version.rs index 8bd2f35d..98ec4bdf 100644 --- a/rama-http/src/matcher/version.rs +++ b/rama-http/src/matcher/version.rs @@ -1,8 +1,8 @@ -use crate::{ +use rama_core::{ context::Extensions, - http::{Request, Version}, Context, }; +use crate::{Request, Version}; use std::fmt::{self, Debug, Formatter}; /// A matcher that matches one or more HTTP methods. diff --git a/rama-http/src/request_context.rs b/rama-http/src/request_context.rs index adf57ea2..e2db2b27 100644 --- a/rama-http/src/request_context.rs +++ b/rama-http/src/request_context.rs @@ -17,7 +17,7 @@ use crate::tls::SecureTransport; #[derive(Debug, Clone, PartialEq, Eq)] /// The context of the [`Request`] being served by the [`HttpServer`] /// -/// [`HttpServer`]: crate::http::server::HttpServer +/// [`HttpServer`]: crate::server::HttpServer pub struct RequestContext { /// The HTTP Version. pub http_version: Version, @@ -60,7 +60,7 @@ impl TryFrom<(&Context, &Request)> for RequestContext }) .or_else(|| { req.headers() - .get(crate::http::header::HOST) + .get(crate::header::HOST) .and_then(|host| { host.try_into() // try to consume as Authority, otherwise as Host .or_else(|_| Host::try_from(host).map(|h| (h, default_port).into())) @@ -126,7 +126,7 @@ impl TryFrom<(&Context, &Parts)> for RequestContext { .or_else(|| { parts .headers - .get(crate::http::header::HOST) + .get(crate::header::HOST) .and_then(|host| { host.try_into() // try to consume as Authority, otherwise as Host .or_else(|_| Host::try_from(host).map(|h| (h, default_port).into())) @@ -233,11 +233,11 @@ impl From<&RequestContext> for TransportContext { } } -impl TryFrom<(&Context, &crate::http::Request)> for TransportContext { +impl TryFrom<(&Context, &crate::Request)> for TransportContext { type Error = OpaqueError; fn try_from( - (ctx, req): (&Context, &crate::http::Request), + (ctx, req): (&Context, &crate::Request), ) -> Result { Ok(match ctx.get::() { Some(req_ctx) => req_ctx.into(), @@ -249,13 +249,13 @@ impl TryFrom<(&Context, &crate::http::Request)> for Tr } } -impl TryFrom<(&Context, &crate::http::dep::http::request::Parts)> +impl TryFrom<(&Context, &crate::dep::http::request::Parts)> for TransportContext { type Error = OpaqueError; fn try_from( - (ctx, parts): (&Context, &crate::http::dep::http::request::Parts), + (ctx, parts): (&Context, &crate::dep::http::request::Parts), ) -> Result { Ok(match ctx.get::() { Some(req_ctx) => req_ctx.into(), @@ -267,7 +267,7 @@ impl TryFrom<(&Context, &crate::http::dep::http::request::Parts)> } } -impl TryRefIntoTransportContext for crate::http::Request { +impl TryRefIntoTransportContext for crate::Request { type Error = OpaqueError; fn try_ref_into_transport_ctx( @@ -278,7 +278,7 @@ impl TryRefIntoTransportContext for crate::http::Request TryRefIntoTransportContext for crate::http::dep::http::request::Parts { +impl TryRefIntoTransportContext for crate::dep::http::request::Parts { type Error = OpaqueError; fn try_ref_into_transport_ctx( @@ -292,8 +292,8 @@ impl TryRefIntoTransportContext for crate::http::dep::http::reques #[cfg(test)] mod tests { use super::*; - use crate::http::header::FORWARDED; - use crate::http::layer::forwarded::GetForwardedHeadersLayer; + use crate::header::FORWARDED; + use crate::layer::forwarded::GetForwardedHeadersLayer; use crate::net::forwarded::{Forwarded, ForwardedElement, NodeId}; use crate::service::{service_fn, Service}; use crate::Layer; diff --git a/rama-http/src/server/hyper_conn.rs b/rama-http/src/server/hyper_conn.rs index 7ba67b9b..a2be3a40 100644 --- a/rama-http/src/server/hyper_conn.rs +++ b/rama-http/src/server/hyper_conn.rs @@ -1,6 +1,6 @@ use super::{svc_hyper::HyperService, HttpServeResult}; -use crate::http::executor::HyperExecutor; -use crate::http::{IntoResponse, Request}; +use crate::executor::HyperExecutor; +use crate::{IntoResponse, Request}; use crate::stream::Stream; use crate::tcp::utils::is_connection_error; use rama_utils::future::Fuse; @@ -205,7 +205,7 @@ fn map_hyper_err_to_result(err: hyper::Error) -> HttpServeResult { } mod private { - use crate::http::executor::HyperExecutor; + use crate::executor::HyperExecutor; pub trait Sealed {} diff --git a/rama-http/src/server/service.rs b/rama-http/src/server/service.rs index b361bd14..da8be39a 100644 --- a/rama-http/src/server/service.rs +++ b/rama-http/src/server/service.rs @@ -2,10 +2,10 @@ use super::hyper_conn::HyperConnServer; use super::HttpServeResult; -use crate::graceful::ShutdownGuard; -use crate::http::executor::HyperExecutor; -use crate::http::{IntoResponse, Request}; -use crate::rt::Executor; +use rama_core::graceful::ShutdownGuard; +use crate::executor::HyperExecutor; +use crate::{IntoResponse, Request}; +use rama_core::rt::Executor; use crate::stream::Stream; use crate::tcp::server::TcpListener; use crate::{Context, Service}; diff --git a/rama-http/src/server/svc_hyper.rs b/rama-http/src/server/svc_hyper.rs index fa012cea..2a66c910 100644 --- a/rama-http/src/server/svc_hyper.rs +++ b/rama-http/src/server/svc_hyper.rs @@ -1,4 +1,4 @@ -use crate::http::{BodyLimit, IntoResponse, Request}; +use crate::{BodyLimit, IntoResponse, Request}; use crate::{Context, Service}; use std::{convert::Infallible, fmt, future::Future, pin::Pin, sync::Arc}; @@ -30,7 +30,7 @@ where T: Service, Response: IntoResponse + Send + 'static, { - type Response = crate::http::Response; + type Response = crate::Response; type Error = std::convert::Infallible; type Future = Pin> + Send + 'static>>; @@ -42,14 +42,14 @@ where let body_limit = ctx.get::().cloned(); let req = match body_limit.and_then(|limit| limit.request()) { - Some(limit) => req.map(|body| crate::http::Body::with_limit(body, limit)), - None => req.map(crate::http::Body::new), + Some(limit) => req.map(|body| crate::Body::with_limit(body, limit)), + None => req.map(crate::Body::new), }; Box::pin(async move { let resp = inner.serve(ctx, req).await.into_response(); Ok(match body_limit.and_then(|limit| limit.response()) { - Some(limit) => resp.map(|body| crate::http::Body::with_limit(body, limit)), + Some(limit) => resp.map(|body| crate::Body::with_limit(body, limit)), // If there is no limit, we can just return the response as is. None => resp, }) diff --git a/rama-http/src/service/fs/serve_dir/future.rs b/rama-http/src/service/fs/serve_dir/future.rs index 521f66b1..9744c5a3 100644 --- a/rama-http/src/service/fs/serve_dir/future.rs +++ b/rama-http/src/service/fs/serve_dir/future.rs @@ -1,12 +1,13 @@ use super::open_file::{FileOpened, FileRequestExtent, OpenFileOutput}; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::{ +use crate::{ header::{self, ALLOW}, Body, HeaderValue, Request, Response, StatusCode, + layer::util::content_encoding::Encoding, + service::fs::AsyncReadBody, + dep::http_body_util::BodyExt, }; -use crate::{ - error::BoxError, http::layer::util::content_encoding::Encoding, - http::service::fs::AsyncReadBody, Context, Service, +use rama_core::{ + error::BoxError, Service, }; use bytes::Bytes; use std::{convert::Infallible, io}; diff --git a/rama-http/src/service/fs/serve_dir/headers.rs b/rama-http/src/service/fs/serve_dir/headers.rs index 24a1cb6c..f8de3cc5 100644 --- a/rama-http/src/service/fs/serve_dir/headers.rs +++ b/rama-http/src/service/fs/serve_dir/headers.rs @@ -1,4 +1,4 @@ -use crate::http::header::HeaderValue; +use crate::header::HeaderValue; use httpdate::HttpDate; use std::time::SystemTime; diff --git a/rama-http/src/service/fs/serve_dir/mod.rs b/rama-http/src/service/fs/serve_dir/mod.rs index ac2e0469..7d280906 100644 --- a/rama-http/src/service/fs/serve_dir/mod.rs +++ b/rama-http/src/service/fs/serve_dir/mod.rs @@ -1,11 +1,11 @@ -use crate::error::BoxError; -use crate::http::dep::http_body::Body as HttpBody; -use crate::http::layer::{ +use rama_core::error::BoxError; +use crate::dep::http_body::Body as HttpBody; +use crate::layer::{ set_status::SetStatus, util::content_encoding::{encodings, SupportedEncodings}, }; -use crate::http::{header, Body, HeaderValue, Method, Request, Response, StatusCode}; -use crate::{Context, Service}; +use crate::{header, Body, HeaderValue, Method, Request, Response, StatusCode}; +use rama_core::{Context, Service}; use bytes::Bytes; use percent_encoding::percent_decode; use std::{ diff --git a/rama-http/src/service/fs/serve_dir/open_file.rs b/rama-http/src/service/fs/serve_dir/open_file.rs index 99f2b6c5..4d28ae87 100644 --- a/rama-http/src/service/fs/serve_dir/open_file.rs +++ b/rama-http/src/service/fs/serve_dir/open_file.rs @@ -2,8 +2,8 @@ use super::{ headers::{IfModifiedSince, IfUnmodifiedSince, LastModified}, ServeVariant, }; -use crate::http::layer::util::content_encoding::{Encoding, QValue}; -use crate::http::{header, HeaderValue, Method, Request, Uri}; +use crate::layer::util::content_encoding::{Encoding, QValue}; +use crate::{header, HeaderValue, Method, Request, Uri}; use http_range_header::RangeUnsatisfiableError; use std::{ ffi::OsStr, diff --git a/rama-http/src/service/fs/serve_dir/tests.rs b/rama-http/src/service/fs/serve_dir/tests.rs index fcb0300f..e6493bea 100644 --- a/rama-http/src/service/fs/serve_dir/tests.rs +++ b/rama-http/src/service/fs/serve_dir/tests.rs @@ -1,10 +1,10 @@ -use crate::http::dep::http_body::Body as HttpBody; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::header::ALLOW; -use crate::http::service::fs::{ServeDir, ServeFile}; -use crate::http::Body; -use crate::http::{header, Method, Response}; -use crate::http::{Request, StatusCode}; +use crate::dep::http_body::Body as HttpBody; +use crate::dep::http_body_util::BodyExt; +use crate::header::ALLOW; +use crate::service::fs::{ServeDir, ServeFile}; +use crate::Body; +use crate::{header, Method, Response}; +use crate::{Request, StatusCode}; use crate::service::service_fn; use crate::{Context, Service}; use brotli::BrotliDecompress; diff --git a/rama-http/src/service/fs/serve_file.rs b/rama-http/src/service/fs/serve_file.rs index 8bef883f..f1540f4c 100644 --- a/rama-http/src/service/fs/serve_file.rs +++ b/rama-http/src/service/fs/serve_file.rs @@ -1,9 +1,9 @@ //! Service that serves a file. use super::ServeDir; -use crate::http::dep::{mime::Mime, mime_guess}; -use crate::http::{HeaderValue, Request, Response}; -use crate::{Context, Service}; +use crate::dep::{mime::Mime, mime_guess}; +use crate::{HeaderValue, Request, Response}; +use rama_core::{Context, Service}; use std::path::Path; /// Service that serves a file. @@ -142,7 +142,7 @@ where #[cfg(feature = "compression")] mod compression_tests { use super::*; - use crate::http::Body; + use crate::Body; #[tokio::test] #[cfg(feature = "compression")] @@ -171,13 +171,13 @@ mod compression_tests { #[cfg(test)] mod tests { - use crate::http::dep::http_body_util::BodyExt; - use crate::http::dep::mime::Mime; - use crate::http::header; - use crate::http::service::fs::ServeFile; - use crate::http::Body; - use crate::http::Method; - use crate::http::{Request, StatusCode}; + use crate::dep::http_body_util::BodyExt; + use crate::dep::mime::Mime; + use crate::header; + use crate::service::fs::ServeFile; + use crate::Body; + use crate::Method; + use crate::{Request, StatusCode}; use crate::{Context, Service}; use brotli::BrotliDecompress; use flate2::bufread::DeflateDecoder; diff --git a/rama-http/src/service/redirect.rs b/rama-http/src/service/redirect.rs index f909a741..67f7bb78 100644 --- a/rama-http/src/service/redirect.rs +++ b/rama-http/src/service/redirect.rs @@ -1,8 +1,8 @@ //! Service that redirects all requests. -use crate::http::Request; -use crate::http::{header, HeaderValue, Response, StatusCode, Uri}; -use crate::{Context, Service}; +use crate::Request; +use crate::{header, HeaderValue, Response, StatusCode, Uri}; +use rama_core::{Context, Service}; use std::{ convert::{Infallible, TryFrom}, fmt, diff --git a/rama-http/src/service/web/endpoint/extract/authority.rs b/rama-http/src/service/web/endpoint/extract/authority.rs index 03248b60..2e4e39b7 100644 --- a/rama-http/src/service/web/endpoint/extract/authority.rs +++ b/rama-http/src/service/web/endpoint/extract/authority.rs @@ -1,9 +1,10 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use crate::http::RequestContext; -use crate::net::address; -use rama_utils::macros::{define_http_rejection, impl_deref}; -use crate::Context; +use crate::dep::http::request::Parts; +use crate::RequestContext; +use rama_net::address; +use rama_utils::macros::impl_deref; +use crate::utils::macros::define_http_rejection; +use rama_core::Context; /// Extractor that resolves the authority of the request. /// @@ -51,12 +52,12 @@ where mod tests { use super::*; - use crate::http::dep::http_body_util::BodyExt as _; - use crate::http::header::X_FORWARDED_HOST; - use crate::http::layer::forwarded::GetForwardedHeadersService; - use crate::http::service::web::WebService; - use crate::http::StatusCode; - use crate::http::{Body, HeaderName, Request}; + use crate::dep::http_body_util::BodyExt as _; + use crate::header::X_FORWARDED_HOST; + use crate::layer::forwarded::GetForwardedHeadersService; + use crate::service::web::WebService; + use crate::StatusCode; + use crate::{Body, HeaderName, Request}; use crate::Service; async fn test_authority_from_request(authority: &str, headers: Vec<(&HeaderName, &str)>) { diff --git a/rama-http/src/service/web/endpoint/extract/body/bytes.rs b/rama-http/src/service/web/endpoint/extract/body/bytes.rs index c7e78349..336a575e 100644 --- a/rama-http/src/service/web/endpoint/extract/body/bytes.rs +++ b/rama-http/src/service/web/endpoint/extract/body/bytes.rs @@ -1,8 +1,9 @@ -use crate::http::dep::http_body_util::BodyExt; -use crate::http::service::web::extract::FromRequest; -use crate::http::Request; -use rama_utils::macros::{define_http_rejection, impl_deref}; -use crate::Context; +use crate::dep::http_body_util::BodyExt; +use crate::service::web::extract::FromRequest; +use crate::Request; +use rama_utils::macros::impl_deref; +use crate::utils::macros::define_http_rejection; +use rama_core::Context; /// Extractor to get the response body, collected as [`Bytes`]. /// @@ -37,7 +38,7 @@ where #[cfg(test)] mod test { use super::*; - use crate::http::{self, StatusCode}; + use crate::{self, StatusCode}; use crate::{http::service::web::WebService, service::Service}; #[tokio::test] diff --git a/rama-http/src/service/web/endpoint/extract/body/form.rs b/rama-http/src/service/web/endpoint/extract/body/form.rs index 120b90d3..eeb1b0c3 100644 --- a/rama-http/src/service/web/endpoint/extract/body/form.rs +++ b/rama-http/src/service/web/endpoint/extract/body/form.rs @@ -1,11 +1,11 @@ use super::BytesRejection; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::service::web::extract::FromRequest; -use crate::http::{Method, Request}; -use rama_utils::macros::{composite_http_rejection, define_http_rejection}; -use crate::Context; +use crate::dep::http_body_util::BodyExt; +use crate::service::web::extract::FromRequest; +use crate::{Method, Request}; +use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use rama_core::Context; -pub use crate::http::response::Form; +pub use crate::response::Form; define_http_rejection! { #[status = UNSUPPORTED_MEDIA_TYPE] @@ -52,7 +52,7 @@ where }; Ok(Form(value)) } else { - if !crate::http::service::web::extract::has_any_content_type( + if !crate::service::web::extract::has_any_content_type( req.headers(), &[&mime::APPLICATION_WWW_FORM_URLENCODED], ) { @@ -77,8 +77,8 @@ where #[cfg(test)] mod test { use super::*; - use crate::http; - use crate::http::StatusCode; + use crate; + use crate::StatusCode; use crate::{http::service::web::WebService, service::Service}; #[tokio::test] diff --git a/rama-http/src/service/web/endpoint/extract/body/json.rs b/rama-http/src/service/web/endpoint/extract/body/json.rs index 74258635..33225174 100644 --- a/rama-http/src/service/web/endpoint/extract/body/json.rs +++ b/rama-http/src/service/web/endpoint/extract/body/json.rs @@ -1,11 +1,11 @@ use super::BytesRejection; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::service::web::extract::FromRequest; -use crate::http::Request; -use rama_utils::macros::{composite_http_rejection, define_http_rejection}; -use crate::Context; +use crate::dep::http_body_util::BodyExt; +use crate::service::web::extract::FromRequest; +use crate::Request; +use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use rama_core::Context; -pub use crate::http::response::Json; +pub use crate::response::Json; define_http_rejection! { #[status = UNSUPPORTED_MEDIA_TYPE] @@ -44,7 +44,7 @@ where type Rejection = JsonRejection; async fn from_request(_ctx: Context, req: Request) -> Result { - if !crate::http::service::web::extract::has_any_content_type( + if !crate::service::web::extract::has_any_content_type( req.headers(), &[&mime::APPLICATION_JSON], ) { @@ -68,7 +68,7 @@ where #[cfg(test)] mod test { use super::*; - use crate::http::StatusCode; + use crate::StatusCode; use crate::{http::service::web::WebService, service::Service}; #[tokio::test] diff --git a/rama-http/src/service/web/endpoint/extract/body/mod.rs b/rama-http/src/service/web/endpoint/extract/body/mod.rs index 61af8db0..b029a987 100644 --- a/rama-http/src/service/web/endpoint/extract/body/mod.rs +++ b/rama-http/src/service/web/endpoint/extract/body/mod.rs @@ -1,7 +1,6 @@ use super::FromRequest; -use crate::http; use rama_utils::macros::impl_deref; -use crate::Context; +use rama_core::Context; use std::convert::Infallible; mod bytes; @@ -40,8 +39,8 @@ where #[cfg(test)] mod test { use super::*; - use crate::http::dep::http_body_util::BodyExt; - use crate::http::{self, StatusCode}; + use crate::dep::http_body_util::BodyExt; + use crate::{self, StatusCode}; use crate::{http::service::web::WebService, service::Service}; #[tokio::test] diff --git a/rama-http/src/service/web/endpoint/extract/body/text.rs b/rama-http/src/service/web/endpoint/extract/body/text.rs index 5cb52980..b64a4323 100644 --- a/rama-http/src/service/web/endpoint/extract/body/text.rs +++ b/rama-http/src/service/web/endpoint/extract/body/text.rs @@ -1,9 +1,9 @@ use super::BytesRejection; -use crate::http::dep::http_body_util::BodyExt; -use crate::http::service::web::extract::FromRequest; -use crate::http::Request; +use crate::dep::http_body_util::BodyExt; +use crate::service::web::extract::FromRequest; +use crate::Request; use rama_utils::macros::{composite_http_rejection, define_http_rejection, impl_deref}; -use crate::Context; +use rama_core::Context; /// Extractor to get the response body, collected as [`String`]. #[derive(Debug, Clone)] @@ -47,7 +47,7 @@ where type Rejection = TextRejection; async fn from_request(_ctx: Context, req: Request) -> Result { - if !crate::http::service::web::extract::has_any_content_type( + if !crate::service::web::extract::has_any_content_type( req.headers(), &[&mime::TEXT_PLAIN], ) { @@ -68,7 +68,7 @@ where #[cfg(test)] mod test { use super::*; - use crate::http::{self, StatusCode}; + use crate::{self, StatusCode}; use crate::{http::service::web::WebService, service::Service}; #[tokio::test] diff --git a/rama-http/src/service/web/endpoint/extract/context.rs b/rama-http/src/service/web/endpoint/extract/context.rs index bc697db6..43662345 100644 --- a/rama-http/src/service/web/endpoint/extract/context.rs +++ b/rama-http/src/service/web/endpoint/extract/context.rs @@ -1,6 +1,6 @@ use super::FromRequest; -use crate::http::Request; -use crate::Context; +use crate::Request; +use rama_core::Context; use std::convert::Infallible; impl FromRequest for Context diff --git a/rama-http/src/service/web/endpoint/extract/dns.rs b/rama-http/src/service/web/endpoint/extract/dns.rs index 693426a9..d180f090 100644 --- a/rama-http/src/service/web/endpoint/extract/dns.rs +++ b/rama-http/src/service/web/endpoint/extract/dns.rs @@ -1,6 +1,6 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use crate::Context; +use crate::dep::http::request::Parts; +use rama_core::Context; use std::convert::Infallible; use std::ops::Deref; diff --git a/rama-http/src/service/web/endpoint/extract/extension.rs b/rama-http/src/service/web/endpoint/extract/extension.rs index bc1279f7..c670dea1 100644 --- a/rama-http/src/service/web/endpoint/extract/extension.rs +++ b/rama-http/src/service/web/endpoint/extract/extension.rs @@ -1,7 +1,7 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use rama_utils::macros::define_http_rejection; -use crate::Context; +use crate::dep::http::request::Parts; +use crate::utils::macros::define_http_rejection; +use rama_core::Context; use std::ops::{Deref, DerefMut}; /// Extractor to get an Extension from the context (e.g. a shared Database). diff --git a/rama-http/src/service/web/endpoint/extract/host.rs b/rama-http/src/service/web/endpoint/extract/host.rs index 14cf0cd8..e1f7e991 100644 --- a/rama-http/src/service/web/endpoint/extract/host.rs +++ b/rama-http/src/service/web/endpoint/extract/host.rs @@ -1,9 +1,10 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use crate::http::RequestContext; -use crate::net::address; -use rama_utils::macros::{define_http_rejection, impl_deref}; -use crate::Context; +use crate::dep::http::request::Parts; +use crate::RequestContext; +use rama_net::address; +use rama_utils::macros::impl_deref; +use crate::utils::macros::define_http_rejection; +use rama_core::Context; /// Extractor that resolves the hostname of the request. /// @@ -52,12 +53,12 @@ where mod tests { use super::*; - use crate::http::dep::http_body_util::BodyExt as _; - use crate::http::header::X_FORWARDED_HOST; - use crate::http::layer::forwarded::GetForwardedHeadersService; - use crate::http::service::web::WebService; - use crate::http::StatusCode; - use crate::http::{Body, HeaderName, Request}; + use crate::dep::http_body_util::BodyExt as _; + use crate::header::X_FORWARDED_HOST; + use crate::layer::forwarded::GetForwardedHeadersService; + use crate::service::web::WebService; + use crate::StatusCode; + use crate::{Body, HeaderName, Request}; use crate::Service; async fn test_host_from_request(host: &str, headers: Vec<(&HeaderName, &str)>) { diff --git a/rama-http/src/service/web/endpoint/extract/method.rs b/rama-http/src/service/web/endpoint/extract/method.rs index 15c727cc..cf8073e5 100644 --- a/rama-http/src/service/web/endpoint/extract/method.rs +++ b/rama-http/src/service/web/endpoint/extract/method.rs @@ -1,6 +1,6 @@ use super::FromRequest; -use crate::http::{Method, Request}; -use crate::Context; +use crate::{Method, Request}; +use rama_core::Context; use std::convert::Infallible; impl FromRequest for Method diff --git a/rama-http/src/service/web/endpoint/extract/mod.rs b/rama-http/src/service/web/endpoint/extract/mod.rs index f8ecea15..d2254257 100644 --- a/rama-http/src/service/web/endpoint/extract/mod.rs +++ b/rama-http/src/service/web/endpoint/extract/mod.rs @@ -1,7 +1,7 @@ //! Extract utilities to develop endpoint services efortless. -use crate::http::{self, dep::http::request::Parts, dep::mime, header, HeaderMap, IntoResponse}; -use crate::Context; +use crate::{self, dep::http::request::Parts, dep::mime, header, HeaderMap, IntoResponse}; +use rama_core::Context; use std::future::Future; mod extension; diff --git a/rama-http/src/service/web/endpoint/extract/path.rs b/rama-http/src/service/web/endpoint/extract/path.rs index 1b0f84db..b1b3a338 100644 --- a/rama-http/src/service/web/endpoint/extract/path.rs +++ b/rama-http/src/service/web/endpoint/extract/path.rs @@ -1,8 +1,8 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use crate::http::matcher::{UriParams, UriParamsDeserializeError}; -use rama_utils::macros::{composite_http_rejection, define_http_rejection}; -use crate::Context; +use crate::dep::http::request::Parts; +use crate::matcher::{UriParams, UriParamsDeserializeError}; +use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use rama_core::Context; use serde::de::DeserializeOwned; use std::ops::{Deref, DerefMut}; @@ -75,8 +75,8 @@ impl DerefMut for Path { mod tests { use super::*; - use crate::http::service::web::WebService; - use crate::http::{Body, Request, StatusCode}; + use crate::service::web::WebService; + use crate::{Body, Request, StatusCode}; use crate::Service; #[tokio::test] diff --git a/rama-http/src/service/web/endpoint/extract/query.rs b/rama-http/src/service/web/endpoint/extract/query.rs index c8d696d0..e66962a7 100644 --- a/rama-http/src/service/web/endpoint/extract/query.rs +++ b/rama-http/src/service/web/endpoint/extract/query.rs @@ -1,7 +1,7 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use rama_utils::macros::define_http_rejection; -use crate::Context; +use crate::dep::http::request::Parts; +use crate::utils::macros::define_http_rejection; +use rama_core::Context; use serde::de::DeserializeOwned; /// Extractor that deserializes query strings into some type. diff --git a/rama-http/src/service/web/endpoint/extract/request.rs b/rama-http/src/service/web/endpoint/extract/request.rs index cb7fdf22..fd885bfe 100644 --- a/rama-http/src/service/web/endpoint/extract/request.rs +++ b/rama-http/src/service/web/endpoint/extract/request.rs @@ -1,6 +1,6 @@ use super::FromRequest; -use crate::http::Request; -use crate::Context; +use crate::Request; +use rama_core::Context; use std::convert::Infallible; impl FromRequest for Request diff --git a/rama-http/src/service/web/endpoint/extract/state.rs b/rama-http/src/service/web/endpoint/extract/state.rs index 6d3d931b..5e983f6a 100644 --- a/rama-http/src/service/web/endpoint/extract/state.rs +++ b/rama-http/src/service/web/endpoint/extract/state.rs @@ -1,6 +1,6 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use crate::Context; +use crate::dep::http::request::Parts; +use rama_core::Context; use std::convert::Infallible; use std::ops::Deref; use std::sync::Arc; diff --git a/rama-http/src/service/web/endpoint/extract/typed_header.rs b/rama-http/src/service/web/endpoint/extract/typed_header.rs index aaa88c2b..e1980595 100644 --- a/rama-http/src/service/web/endpoint/extract/typed_header.rs +++ b/rama-http/src/service/web/endpoint/extract/typed_header.rs @@ -1,8 +1,8 @@ use super::FromRequestParts; -use crate::http::dep::http::request::Parts; -use crate::http::headers::{self, Header}; -use crate::http::{HeaderName, IntoResponse, Response}; -use crate::Context; +use crate::dep::http::request::Parts; +use crate::headers::{self, Header}; +use crate::{HeaderName, IntoResponse, Response}; +use rama_core::Context; use std::ops::Deref; /// Extractor to get a TypedHeader from the request. diff --git a/rama-http/src/service/web/endpoint/mod.rs b/rama-http/src/service/web/endpoint/mod.rs index 8b25bfbc..7a79aa7f 100644 --- a/rama-http/src/service/web/endpoint/mod.rs +++ b/rama-http/src/service/web/endpoint/mod.rs @@ -1,8 +1,8 @@ -use crate::{ - http::{matcher::HttpMatcher, Body, IntoResponse, Request, Response}, - layer::MapResponseLayer, - service::BoxService, +use crate::{matcher::HttpMatcher, Body, IntoResponse, Request, Response}; +use rama_core::{ Context, Layer, Service, + service::BoxService, + layer::MapResponseLayer, }; use std::future::Future; use std::{convert::Infallible, fmt}; @@ -270,7 +270,7 @@ mod private { #[cfg(test)] mod tests { use super::*; - use crate::http::{self, dep::http_body_util::BodyExt, Body, Method, Request, StatusCode}; + use crate::{self, dep::http_body_util::BodyExt, Body, Method, Request, StatusCode}; use extract::*; fn assert_into_endpoint_service(_: I) @@ -394,7 +394,7 @@ mod tests { foo: String, } - let svc = crate::http::service::web::WebService::default().get( + let svc = crate::service::web::WebService::default().get( "/:foo/bar", |Host(host): Host, Path(params): Path| async move { format!("{} => {}", host, params.foo) diff --git a/rama-http/src/service/web/endpoint/service.rs b/rama-http/src/service/web/endpoint/service.rs index 204b394c..e3b0d71d 100644 --- a/rama-http/src/service/web/endpoint/service.rs +++ b/rama-http/src/service/web/endpoint/service.rs @@ -1,11 +1,8 @@ use std::future::Future; - use super::extract::{FromRequest, FromRequestParts}; use rama_utils::macros::all_the_tuples_no_last_special_case; -use crate::{ - http::{IntoResponse, Request, Response}, - Context, -}; +use crate::{IntoResponse, Request, Response}; +use rama_core::Context; /// [`crate::Service`] implemented for functions taking extractors. pub trait EndpointServiceFn: private::Sealed + Clone + Send + Sync + 'static { diff --git a/rama-http/src/service/web/k8s.rs b/rama-http/src/service/web/k8s.rs index 6ccb9026..636a8159 100644 --- a/rama-http/src/service/web/k8s.rs +++ b/rama-http/src/service/web/k8s.rs @@ -1,10 +1,11 @@ //! k8s web service -use http::StatusCode; -use std::{convert::Infallible, fmt, marker::PhantomData, sync::Arc}; - use crate::{ - http::{matcher::HttpMatcher, IntoResponse, Request, Response}, + StatusCode, + matcher::HttpMatcher, IntoResponse, Request, Response, +}; +use std::{convert::Infallible, fmt, marker::PhantomData, sync::Arc}; +use rama_core::{ service::{service_fn, BoxService}, Context, Service, }; diff --git a/rama-http/src/service/web/service.rs b/rama-http/src/service/web/service.rs index 60b53553..f2599aaa 100644 --- a/rama-http/src/service/web/service.rs +++ b/rama-http/src/service/web/service.rs @@ -1,13 +1,13 @@ use super::{endpoint::Endpoint, IntoEndpointService}; use crate::{ - context::Extensions, - http::{ - matcher::{HttpMatcher, UriParams}, - service::fs::ServeDir, - Body, IntoResponse, Request, Response, StatusCode, Uri, - }, - matcher::Matcher, + matcher::{HttpMatcher, UriParams}, + service::fs::ServeDir, + Body, IntoResponse, Request, Response, StatusCode, Uri, +}; +use rama_core::{ service::{service_fn, BoxService, Service}, + matcher::Matcher, + context::Extensions, Context, }; use std::{convert::Infallible, fmt, future::Future, marker::PhantomData, sync::Arc}; @@ -321,7 +321,7 @@ where /// that each service is an actual Endpoint service. macro_rules! __match_service { ($($M:expr => $S:expr),+, _ => $F:expr $(,)?) => {{ - use $crate::http::service::web::IntoEndpointService; + use $crate::service::web::IntoEndpointService; ($(($M, $S.into_endpoint_service())),+, $F.into_endpoint_service()) }}; } @@ -331,9 +331,9 @@ pub use __match_service as match_service; #[cfg(test)] mod test { - use crate::http::dep::http_body_util::BodyExt; - use crate::http::matcher::MethodMatcher; - use crate::http::Body; + use crate::dep::http_body_util::BodyExt; + use crate::matcher::MethodMatcher; + use crate::Body; use super::*; diff --git a/rama-http/src/utils/utils/macros/http_error.rs b/rama-http/src/utils/macros/http_error.rs similarity index 87% rename from rama-http/src/utils/utils/macros/http_error.rs rename to rama-http/src/utils/macros/http_error.rs index 3778c8bd..71821605 100644 --- a/rama-http/src/utils/utils/macros/http_error.rs +++ b/rama-http/src/utils/macros/http_error.rs @@ -32,12 +32,12 @@ macro_rules! __define_http_rejection { #[non_exhaustive] pub struct $name; - impl $crate::http::IntoResponse for $name { - fn into_response(self) -> $crate::http::Response { + impl $crate::IntoResponse for $name { + fn into_response(self) -> $crate::Response { $crate::__log_http_rejection!( rejection_type = $name, body_text = $body, - status = $crate::http::StatusCode::$status, + status = $crate::StatusCode::$status, ); (self.status(), $body).into_response() } @@ -50,8 +50,8 @@ macro_rules! __define_http_rejection { } /// Get the status code used for this rejection. - pub fn status(&self) -> $crate::http::StatusCode { - $crate::http::StatusCode::$status + pub fn status(&self) -> $crate::StatusCode { + $crate::StatusCode::$status } } @@ -98,12 +98,12 @@ macro_rules! __define_http_rejection { } } - impl $crate::http::IntoResponse for $name { - fn into_response(self) -> $crate::http::Response { + impl $crate::IntoResponse for $name { + fn into_response(self) -> $crate::Response { $crate::__log_http_rejection!( rejection_type = $name, body_text = self.body_text(), - status = $crate::http::StatusCode::$status, + status = $crate::StatusCode::$status, ); (self.status(), self.body_text()).into_response() } @@ -116,8 +116,8 @@ macro_rules! __define_http_rejection { } /// Get the status code used for this rejection. - pub fn status(&self) -> $crate::http::StatusCode { - $crate::http::StatusCode::$status + pub fn status(&self) -> $crate::StatusCode { + $crate::StatusCode::$status } } @@ -156,8 +156,8 @@ macro_rules! __composite_http_rejection { ),+ } - impl $crate::http::IntoResponse for $name { - fn into_response(self) -> $crate::http::Response { + impl $crate::IntoResponse for $name { + fn into_response(self) -> $crate::Response { match self { $( Self::$variant(inner) => inner.into_response(), @@ -177,7 +177,7 @@ macro_rules! __composite_http_rejection { } /// Get the status code used for this rejection. - pub fn status(&self) -> $crate::http::StatusCode { + pub fn status(&self) -> $crate::StatusCode { match self { $( Self::$variant(inner) => inner.status(), diff --git a/rama-http/src/utils/utils/macros/mod.rs b/rama-http/src/utils/macros/mod.rs similarity index 58% rename from rama-http/src/utils/utils/macros/mod.rs rename to rama-http/src/utils/macros/mod.rs index 3f78e047..7f416081 100644 --- a/rama-http/src/utils/utils/macros/mod.rs +++ b/rama-http/src/utils/macros/mod.rs @@ -2,5 +2,3 @@ mod http_error; pub(crate) use http_error::*; - -pub(crate) use ::rama_core::utils::macros::*; diff --git a/rama-http/src/utils/mod.rs b/rama-http/src/utils/mod.rs index 9da84ca5..f88bceca 100644 --- a/rama-http/src/utils/mod.rs +++ b/rama-http/src/utils/mod.rs @@ -3,3 +3,6 @@ mod header_value; #[doc(inline)] pub use header_value::{HeaderValueErr, HeaderValueGetter}; + +#[use_macro] +pub(crate) mod macros; diff --git a/rama-http/src/utils/utils/mod.rs b/rama-http/src/utils/utils/mod.rs deleted file mode 100644 index 4af7702f..00000000 --- a/rama-http/src/utils/utils/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Utilities in service of the `rama-core` project. - -#[macro_use] -pub(crate) mod macros; - -pub use ::rama_core::utils::{backoff, future, info, latency, rng, str, username}; - -#[allow(unused_imports)] -pub(crate) use ::rama_core::utils::test_helpers; diff --git a/rama-net/src/stream/matcher/ip.rs b/rama-net/src/stream/matcher/ip.rs index 16c90ebb..dc340015 100644 --- a/rama-net/src/stream/matcher/ip.rs +++ b/rama-net/src/stream/matcher/ip.rs @@ -1,9 +1,11 @@ use crate::stream::dep::ipnet::{IpNet, Ipv4Net, Ipv6Net}; -use crate::stream::SocketInfo; use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; +#[cfg(feature = "http")] +use crate::stream::SocketInfo; + #[derive(Debug, Clone)] /// Matcher based on whether or not the [`IpNet`] contains the [`SocketAddr`] of the peer. diff --git a/rama-net/src/stream/matcher/loopback.rs b/rama-net/src/stream/matcher/loopback.rs index 97e3239a..b9ea71ca 100644 --- a/rama-net/src/stream/matcher/loopback.rs +++ b/rama-net/src/stream/matcher/loopback.rs @@ -1,8 +1,10 @@ -use crate::stream::SocketInfo; use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; +#[cfg(feature = "http")] +use crate::stream::SocketInfo; + #[derive(Debug, Clone)] /// Matcher based on the ip part of the [`SocketAddr`] of the peer, diff --git a/rama-net/src/stream/matcher/port.rs b/rama-net/src/stream/matcher/port.rs index 818f5109..15570ba8 100644 --- a/rama-net/src/stream/matcher/port.rs +++ b/rama-net/src/stream/matcher/port.rs @@ -1,8 +1,9 @@ -use crate::stream::SocketInfo; use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; +#[cfg(feature = "http")] +use crate::stream::SocketInfo; #[derive(Debug, Clone)] /// Matcher based on the port part of the [`SocketAddr`] of the peer. diff --git a/rama-net/src/stream/matcher/private_ip.rs b/rama-net/src/stream/matcher/private_ip.rs index 3b01c74a..25fe9680 100644 --- a/rama-net/src/stream/matcher/private_ip.rs +++ b/rama-net/src/stream/matcher/private_ip.rs @@ -1,9 +1,10 @@ use crate::stream::dep::ipnet::IpNet; -use crate::stream::SocketInfo; use rama_core::{context::Extensions, Context}; #[cfg(feature = "http")] use rama_http_types::Request; +#[cfg(feature = "http")] +use crate::stream::SocketInfo; #[derive(Debug, Clone)] /// Matcher based on the ip part of the [`SocketAddr`] of the peer, diff --git a/rama-net/src/stream/matcher/socket.rs b/rama-net/src/stream/matcher/socket.rs index 7b988d9e..b36cd181 100644 --- a/rama-net/src/stream/matcher/socket.rs +++ b/rama-net/src/stream/matcher/socket.rs @@ -1,9 +1,11 @@ -use crate::stream::SocketInfo; use rama_core::{context::Extensions, Context}; use std::net::SocketAddr; #[cfg(feature = "http")] use rama_http_types::Request; +#[cfg(feature = "http")] +use crate::stream::SocketInfo; + #[derive(Debug, Clone)] /// Matcher based on the [`SocketAddr`] of the peer. @@ -38,6 +40,7 @@ impl SocketAddressMatcher { } } +#[cfg(feature = "http")] impl rama_core::matcher::Matcher> for SocketAddressMatcher { fn matches( &self, diff --git a/rama-net/src/user/credentials/basic.rs b/rama-net/src/user/credentials/basic.rs index 3a72875f..fd7552e6 100644 --- a/rama-net/src/user/credentials/basic.rs +++ b/rama-net/src/user/credentials/basic.rs @@ -1,11 +1,13 @@ use base64::engine::general_purpose::STANDARD as ENGINE; use base64::Engine; -use headers::authorization; use rama_core::error::{ErrorContext, OpaqueError}; use std::borrow::Cow; #[cfg(feature = "http")] -use rama_http_types::HeaderValue; +use rama_http_types::{ + HeaderValue, + headers::authorization, +}; #[derive(Debug, Clone)] /// Basic credentials. @@ -108,6 +110,7 @@ impl Basic { encoded } + #[cfg(feature = "http")] /// View this [`Basic`] as a [`HeaderValue`] pub fn as_header_value(&self) -> HeaderValue { let encoded = self.as_header_string(); @@ -163,6 +166,7 @@ impl Eq for Basic {} const BASIC_SCHEME: &str = "Basic"; +#[cfg(feature = "http")] impl authorization::Credentials for Basic { const SCHEME: &'static str = BASIC_SCHEME; @@ -179,7 +183,6 @@ impl authorization::Credentials for Basic { #[cfg(test)] mod tests { use super::*; - use authorization::Credentials; #[test] fn basic_parse_empty() { @@ -216,74 +219,81 @@ mod tests { } #[test] - fn basic_decode() { - let auth = Basic::decode(&HeaderValue::from_static( - "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", - )) - .unwrap(); + fn basic_header() { + let auth = Basic::try_from_header_str("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==").unwrap(); assert_eq!(auth.username(), "Aladdin"); assert_eq!(auth.password(), "open sesame"); + assert_eq!( + "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + auth.as_header_string() + ); } #[test] - fn basic_decode_case_insensitive() { - let auth = Basic::decode(&HeaderValue::from_static( - "basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", - )) - .unwrap(); + fn basic_header_no_password() { + let auth = Basic::try_from_header_str("Basic QWxhZGRpbjo=").unwrap(); assert_eq!(auth.username(), "Aladdin"); - assert_eq!(auth.password(), "open sesame"); + assert_eq!(auth.password(), ""); + assert_eq!("Basic QWxhZGRpbjo=", auth.as_header_string()); } #[test] - fn basic_decode_extra_whitespaces() { - let auth = Basic::decode(&HeaderValue::from_static( - "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", - )) - .unwrap(); + fn basic_clear() { + let auth = Basic::try_from_clear_str("Aladdin:open sesame".to_owned()).unwrap(); assert_eq!(auth.username(), "Aladdin"); assert_eq!(auth.password(), "open sesame"); + assert_eq!("Aladdin:open sesame", auth.as_clear_string()); } #[test] - fn basic_decode_no_password() { - let auth = Basic::decode(&HeaderValue::from_static("Basic QWxhZGRpbjo=")).unwrap(); + fn basic_clear_no_password() { + let auth = Basic::try_from_clear_str("Aladdin:".to_owned()).unwrap(); assert_eq!(auth.username(), "Aladdin"); assert_eq!(auth.password(), ""); + assert_eq!("Aladdin:", auth.as_clear_string()); } +} + +#[cfg(feature = "http")] +#[cfg(test)] +mod tests_http { + use super::*; + use authorization::Credentials; #[test] - fn basic_header() { - let auth = Basic::try_from_header_str("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==").unwrap(); + fn basic_decode() { + let auth = Basic::decode(&HeaderValue::from_static( + "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + )) + .unwrap(); assert_eq!(auth.username(), "Aladdin"); assert_eq!(auth.password(), "open sesame"); - assert_eq!( - "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", - auth.as_header_string() - ); } #[test] - fn basic_header_no_password() { - let auth = Basic::try_from_header_str("Basic QWxhZGRpbjo=").unwrap(); + fn basic_decode_case_insensitive() { + let auth = Basic::decode(&HeaderValue::from_static( + "basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + )) + .unwrap(); assert_eq!(auth.username(), "Aladdin"); - assert_eq!(auth.password(), ""); - assert_eq!("Basic QWxhZGRpbjo=", auth.as_header_string()); + assert_eq!(auth.password(), "open sesame"); } #[test] - fn basic_clear() { - let auth = Basic::try_from_clear_str("Aladdin:open sesame".to_owned()).unwrap(); + fn basic_decode_extra_whitespaces() { + let auth = Basic::decode(&HeaderValue::from_static( + "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + )) + .unwrap(); assert_eq!(auth.username(), "Aladdin"); assert_eq!(auth.password(), "open sesame"); - assert_eq!("Aladdin:open sesame", auth.as_clear_string()); } #[test] - fn basic_clear_no_password() { - let auth = Basic::try_from_clear_str("Aladdin:".to_owned()).unwrap(); + fn basic_decode_no_password() { + let auth = Basic::decode(&HeaderValue::from_static("Basic QWxhZGRpbjo=")).unwrap(); assert_eq!(auth.username(), "Aladdin"); assert_eq!(auth.password(), ""); - assert_eq!("Aladdin:", auth.as_clear_string()); } } diff --git a/rama-net/src/user/credentials/bearer.rs b/rama-net/src/user/credentials/bearer.rs index 020d5257..3d0184d5 100644 --- a/rama-net/src/user/credentials/bearer.rs +++ b/rama-net/src/user/credentials/bearer.rs @@ -1,9 +1,11 @@ -use headers::authorization; use rama_core::error::{ErrorContext, OpaqueError}; use std::borrow::Cow; #[cfg(feature = "http")] -use rama_http_types::HeaderValue; +use rama_http_types::{ + HeaderValue, + headers::authorization, +}; #[derive(Debug, Clone, PartialEq, Eq)] /// Bearer credentials. @@ -56,6 +58,7 @@ impl Bearer { format!("{BEARER_SCHEME} {}", self.0) } + #[cfg(feature = "http")] /// View this [`Bearer`] as a [`HeaderValue`]. pub fn as_header_value(&self) -> HeaderValue { let encoded = self.as_header_string(); @@ -76,6 +79,7 @@ impl Bearer { const BEARER_SCHEME: &str = "Bearer"; +#[cfg(feature = "http")] impl authorization::Credentials for Bearer { const SCHEME: &'static str = BEARER_SCHEME; diff --git a/rama-ua/Cargo.toml b/rama-ua/Cargo.toml index 79350c63..30ff0c88 100644 --- a/rama-ua/Cargo.toml +++ b/rama-ua/Cargo.toml @@ -12,9 +12,12 @@ rust-version = { workspace = true } [dependencies] rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } serde = { workspace = true, features = ["derive"] } [dev-dependencies] +serde_json = { workspace = true } +tokio = { workspace = true, features = ["macros"] } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-ua/src/info.rs b/rama-ua/src/info.rs index bfbb1fa5..f5013bdc 100644 --- a/rama-ua/src/info.rs +++ b/rama-ua/src/info.rs @@ -1,6 +1,6 @@ use super::parse_http_user_agent_header; -use rama_core::match_ignore_ascii_case_str; -use rama_core::{error, OpaqueError}; +use rama_utils::macros::match_ignore_ascii_case_str; +use rama_core::error::OpaqueError; use serde::{Deserialize, Deserializer, Serialize}; use std::{convert::Infallible, fmt, str::FromStr}; @@ -295,7 +295,7 @@ impl FromStr for HttpAgent { "Firefox" => Ok(HttpAgent::Firefox), "Safari" => Ok(HttpAgent::Safari), "preserve" => Ok(HttpAgent::Preserve), - _ => Err(error!("invalid http agent: {}", s)), + _ => Err(OpaqueError::from_display(format!("invalid http agent: {}", s))), } } } @@ -383,7 +383,7 @@ impl FromStr for TlsAgent { "boring" | "boringssl" => Ok(TlsAgent::Boringssl), "nss" => Ok(TlsAgent::Nss), "preserve" => Ok(TlsAgent::Preserve), - _ => Err(error!("invalid tls agent: {}", s)), + _ => Err(OpaqueError::from_display(format!("invalid tls agent: {}", s))), } } } diff --git a/rama-ua/src/lib.rs b/rama-ua/src/lib.rs index 691638dc..450152e5 100644 --- a/rama-ua/src/lib.rs +++ b/rama-ua/src/lib.rs @@ -46,42 +46,6 @@ //! Please open an [issue](https://github.com/plabayo/rama/issues) in case you need support for more User Agents, //! and have a good case to make for it. For example we might also support the default user agents used by mobile //! application SDKs. This makes however only sense if we can provide Http and Tls emulation for it. -//! -//! # Example -//! -//! ``` -//! use rama::{ -//! http::{client::HttpClientExt, IntoResponse, Request, Response, StatusCode}, -//! service::service_fn, -//! ua::{PlatformKind, UserAgent, UserAgentClassifierLayer, UserAgentKind, UserAgentInfo}, -//! Context, Layer, -//! }; -//! use std::convert::Infallible; -//! -//! const UA: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.2478.67"; -//! -//! async fn handle(ctx: Context, _req: Request) -> Result { -//! let ua: &UserAgent = ctx.get().unwrap(); -//! -//! assert_eq!(ua.header_str(), UA); -//! assert_eq!(ua.info(), Some(UserAgentInfo{ kind: UserAgentKind::Chromium, version: Some(124) })); -//! assert_eq!(ua.platform(), Some(PlatformKind::Windows)); -//! -//! Ok(StatusCode::OK.into_response()) -//! } -//! -//! # #[tokio::main] -//! # async fn main() { -//! let service = UserAgentClassifierLayer::new().layer(service_fn(handle)); -//! -//! let _ = service -//! .get("http://www.example.com") -//! .typed_header(headers::UserAgent::from_static(UA)) -//! .send(Context::default()) -//! .await -//! .unwrap(); -//! # } -//! ``` #![doc( html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" @@ -128,6 +92,8 @@ #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] +use serde::{Serialize, Deserialize}; + mod info; pub use info::{ DeviceKind, HttpAgent, PlatformKind, TlsAgent, UserAgent, UserAgentInfo, UserAgentKind, diff --git a/rama-ua/src/parse_tests.rs b/rama-ua/src/parse_tests.rs index efb25703..944634e3 100644 --- a/rama-ua/src/parse_tests.rs +++ b/rama-ua/src/parse_tests.rs @@ -1,4 +1,4 @@ -use crate::ua::{ +use crate::{ DeviceKind, HttpAgent, PlatformKind, TlsAgent, UserAgent, UserAgentInfo, UserAgentKind, }; From 12723d56ca2a99052bb0352a7193f38708ecdd7e Mon Sep 17 00:00:00 2001 From: glendc Date: Tue, 3 Sep 2024 21:32:35 +0200 Subject: [PATCH 06/24] fix polar links closes #303 --- README.md | 4 ++-- docs/book/src/preface.md | 2 +- docs/book/src/sponsor.md | 4 ++-- src/lib.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 23a5a972..20c5a2f2 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ It goes also without saying that we do not nilly-willy change designs or break o there is still plenty to be improve and work out. Production use and feedback from you and other users helps a lot with that. As such, if you use Rama do let us know feedback over [Discord][discord-url], [email](mailto:glen@plabayo.tech) or a [GitHub issue](https://github.com/plabayo/rama/issues). -πŸ‘‰ If you are a company or enterprise that makes use of Rama, or even an individual user that makes use of Rama for commcercial purposes. Please consider becoming [a business/enterprise subscriber](https://polar.sh/plabayo/subscriptions). It helps make the development cycle to remain sustainable, and is beneficial to you as well. As part of your benefits we are also available to assist you with migrations between breaking releases. For enterprise users we can even make time to develop those PR's in your integration codebases ourselves on your behalf. A win for everybody. πŸ’ͺ +πŸ‘‰ If you are a company or enterprise that makes use of Rama, or even an individual user that makes use of Rama for commcercial purposes. Please consider becoming [a business/enterprise subscriber](https://polar.sh/plabayo). It helps make the development cycle to remain sustainable, and is beneficial to you as well. As part of your benefits we are also available to assist you with migrations between breaking releases. For enterprise users we can even make time to develop those PR's in your integration codebases ourselves on your behalf. A win for everybody. πŸ’ͺ ## πŸ“£ | Rama Ecosystem @@ -388,7 +388,7 @@ An extra big shoutout goes also to the online communities surrounding and part o Rama is **completely free, open-source software** which needs lots of effort and time to develop and maintain. -You can become a regular financial contributor to Rama by paying for a monthly subscription at [polar.sh/plabayo](https://polar.sh/plabayo/subscriptions). In case you want a specific github issue to be resolved or like you can also fund issues via that platform. One time contributions are possible as well and greatly appreciated. +You can become a regular financial contributor to Rama by paying for a monthly subscription at [polar.sh/plabayo](https://polar.sh/plabayo). In case you want a specific github issue to be resolved or like you can also fund issues via that platform. One time contributions are possible as well and greatly appreciated. Alternatively you can also become a (monthly subscriber) sponsor or pay a one-time donation via [Github Sponsors][ghs-url]. For one-time donations you are also free to use ["Buy me a Coffee"][bmac-url] or ["Paypal Donations"][paypal-url] in case you are more at ease with any of these. diff --git a/docs/book/src/preface.md b/docs/book/src/preface.md index 323cce46..bf332a33 100644 --- a/docs/book/src/preface.md +++ b/docs/book/src/preface.md @@ -143,4 +143,4 @@ It goes also without saying that we do not nilly-willy change designs or break o there is still plenty to be improve and work out. Production use and feedback from you and other users helps a lot with that. As such, if you use Rama do let us know feedback over [Discord][discord-url], [email](mailto:glen@plabayo.tech) or a [GitHub issue](https://github.com/plabayo/rama/issues). -πŸ‘‰ If you are a company or enterprise that makes use of Rama, or even an individual user that makes use of Rama for commcercial purposes. Please consider becoming [a business/enterprise subscriber](https://polar.sh/plabayo/subscriptions). It helps make the development cycle to remain sustainable, and is beneficial to you as well. As part of your benefits we are also available to assist you with migrations between breaking releases. For enterprise users we can even make time to develop those PR's in your integration codebases ourselves on your behalf. A win for everybody. πŸ’ͺ +πŸ‘‰ If you are a company or enterprise that makes use of Rama, or even an individual user that makes use of Rama for commcercial purposes. Please consider becoming [a business/enterprise subscriber](https://polar.sh/plabayo). It helps make the development cycle to remain sustainable, and is beneficial to you as well. As part of your benefits we are also available to assist you with migrations between breaking releases. For enterprise users we can even make time to develop those PR's in your integration codebases ourselves on your behalf. A win for everybody. πŸ’ͺ diff --git a/docs/book/src/sponsor.md b/docs/book/src/sponsor.md index ad215381..e50b3849 100644 --- a/docs/book/src/sponsor.md +++ b/docs/book/src/sponsor.md @@ -27,9 +27,9 @@ Financial contributors help in compensate for the many unpaid developer hours we ## πŸ’Ž | Financial Contributions -You can become a regular financial contributor to Rama by paying for a monthly subscription at [polar.sh/plabayo](https://polar.sh/plabayo/subscriptions). In case you want a specific github issue to be resolved or like you can also fund issues via that platform. One time contributions are possible as well and greatly appreciated. +You can become a regular financial contributor to Rama by paying for a monthly subscription at [polar.sh/plabayo](https://polar.sh/plabayo). In case you want a specific github issue to be resolved or like you can also fund issues via that platform. One time contributions are possible as well and greatly appreciated. -> πŸ’‘ Business subscriptions are available at [polar.sh/plabayo](https://polar.sh/plabayo/subscriptions) for businesses, enterprises and individuals who can afford it πŸ™. These subscriptions keep the development of Rama and other projects sustainable and unlocks support for you and your team in the integration and usage of Rama. +> πŸ’‘ Business subscriptions are available at [polar.sh/plabayo](https://polar.sh/plabayo) for businesses, enterprises and individuals who can afford it πŸ™. These subscriptions keep the development of Rama and other projects sustainable and unlocks support for you and your team in the integration and usage of Rama. > > πŸ‘‰ For even more custom integrations or features you can always get in touch by sending an email to [glen@plabayo.tech](mailto:glen@plabayo.tech). diff --git a/src/lib.rs b/src/lib.rs index cc74ffa1..1422fc43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,7 @@ //! if you use Rama do let us know feedback over [Discord][discord-url], [email](mailto:glen@plabayo.tech) or a [GitHub issue](https://github.com/plabayo/rama/issues). //! //! πŸ‘‰ If you are a company or enterprise that makes use of Rama, or even an individual user that makes use of Rama for commcercial purposes. -//! Please consider becoming [a business/enterprise subscriber](https://polar.sh/plabayo/subscriptions). +//! Please consider becoming [a business/enterprise subscriber](https://polar.sh/plabayo). //! It helps make the development cycle to remain sustainable, and is beneficial to you as well. //! As part of your benefits we are also available to assist you with migrations between breaking releases. //! For enterprise users we can even make time to develop those PR's in your integration codebases ourselves on your behalf. From 521cf2171b4b060288a5dcaaa85eb4ca697028fd Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 10:56:00 +0200 Subject: [PATCH 07/24] make tls / net rama crates pass more tests --- Cargo.lock | 35 +++++- Cargo.toml | 8 +- rama-core/src/context/mod.rs | 6 +- rama-core/src/dns/mod.rs | 18 +-- rama-http-backend/Cargo.toml | 1 + .../src/client/conn.rs | 2 +- .../src/client/error.rs | 2 +- .../src/client/ext.rs | 44 ++------ .../src/client/mod.rs | 0 .../src/client/svc.rs | 0 .../src/executor.rs | 0 rama-http-backend/src/lib.rs | 6 + .../src/server/hyper_conn.rs | 4 +- rama-http-backend/src/server/layer/mod.rs | 3 + .../src/server}/layer/upgrade/layer.rs | 0 .../src/server}/layer/upgrade/mod.rs | 0 .../src/server}/layer/upgrade/service.rs | 6 +- .../src/server}/layer/upgrade/upgraded.rs | 0 .../src/server/mod.rs | 4 +- .../src/server/service.rs | 12 +- .../src/server/svc_hyper.rs | 2 +- rama-http-types/src/body_limit.rs | 6 - rama-http/Cargo.toml | 10 +- .../headers/forwarded/exotic_forward_ip.rs | 2 +- rama-http/src/headers/forwarded/mod.rs | 4 +- rama-http/src/headers/forwarded/via.rs | 2 +- .../src/headers/forwarded/x_forwarded_for.rs | 2 +- .../src/headers/forwarded/x_forwarded_host.rs | 4 +- .../headers/forwarded/x_forwarded_proto.rs | 2 +- rama-http/src/headers/mod.rs | 2 +- rama-http/src/io/request.rs | 8 +- rama-http/src/io/response.rs | 8 +- rama-http/src/layer/auth/add_authorization.rs | 10 +- .../layer/auth/async_require_authorization.rs | 8 +- .../src/layer/auth/require_authorization.rs | 6 +- rama-http/src/layer/body_limit.rs | 2 +- rama-http/src/layer/catch_panic.rs | 4 +- rama-http/src/layer/compression/body.rs | 2 +- rama-http/src/layer/compression/layer.rs | 6 +- rama-http/src/layer/compression/mod.rs | 4 +- rama-http/src/layer/compression/service.rs | 2 +- .../src/layer/cors/allow_private_network.rs | 6 +- rama-http/src/layer/cors/mod.rs | 4 +- rama-http/src/layer/cors/tests.rs | 4 +- rama-http/src/layer/decompression/body.rs | 2 +- rama-http/src/layer/decompression/mod.rs | 4 +- .../src/layer/decompression/request/mod.rs | 4 +- .../layer/decompression/request/service.rs | 6 +- rama-http/src/layer/decompression/service.rs | 2 +- rama-http/src/layer/dns/dns_map/service.rs | 13 +-- rama-http/src/layer/dns/dns_resolve/mod.rs | 8 +- .../src/layer/dns/dns_resolve/service.rs | 15 +-- .../layer/dns/dns_resolve/username_parser.rs | 8 +- rama-http/src/layer/error_handling.rs | 2 +- rama-http/src/layer/follow_redirect/mod.rs | 8 +- .../follow_redirect/policy/clone_body_fn.rs | 2 +- .../layer/follow_redirect/policy/limited.rs | 2 +- .../follow_redirect/policy/redirect_fn.rs | 2 +- .../follow_redirect/policy/same_origin.rs | 2 +- .../src/layer/forwarded/get_forwarded.rs | 7 +- .../src/layer/forwarded/set_forwarded.rs | 10 +- rama-http/src/layer/header_config.rs | 23 ++-- rama-http/src/layer/header_option_value.rs | 13 +-- rama-http/src/layer/map_request_body.rs | 2 +- rama-http/src/layer/map_response_body.rs | 2 +- rama-http/src/layer/mod.rs | 8 +- rama-http/src/layer/normalize_path.rs | 4 +- rama-http/src/layer/opentelemetry.rs | 27 ++--- rama-http/src/layer/propagate_headers.rs | 2 +- rama-http/src/layer/proxy_auth.rs | 4 +- rama-http/src/layer/remove_header/request.rs | 2 +- rama-http/src/layer/remove_header/response.rs | 2 +- rama-http/src/layer/request_id.rs | 6 +- .../src/layer/required_header/request.rs | 14 ++- .../src/layer/required_header/response.rs | 6 +- rama-http/src/layer/retry/body.rs | 2 +- rama-http/src/layer/retry/layer.rs | 2 +- rama-http/src/layer/retry/managed.rs | 4 +- rama-http/src/layer/retry/mod.rs | 6 +- rama-http/src/layer/retry/policy.rs | 12 +- rama-http/src/layer/retry/tests.rs | 6 +- rama-http/src/layer/sensitive_headers.rs | 2 +- rama-http/src/layer/set_header/request.rs | 4 +- rama-http/src/layer/set_header/response.rs | 4 +- rama-http/src/layer/set_status.rs | 2 +- rama-http/src/layer/timeout.rs | 8 +- rama-http/src/layer/trace/layer.rs | 6 +- rama-http/src/layer/trace/mod.rs | 6 +- rama-http/src/layer/trace/service.rs | 2 +- rama-http/src/layer/traffic_writer/request.rs | 6 +- .../src/layer/traffic_writer/response.rs | 6 +- rama-http/src/layer/ua.rs | 19 ++-- rama-http/src/layer/util/compression.rs | 8 +- .../validate_request_header.rs | 4 +- rama-http/src/lib.rs | 17 +-- rama-http/src/matcher/domain.rs | 7 +- rama-http/src/matcher/header.rs | 6 +- rama-http/src/matcher/method.rs | 7 +- rama-http/src/matcher/mod.rs | 35 +++--- rama-http/src/matcher/path/mod.rs | 13 +-- rama-http/src/matcher/uri.rs | 7 +- rama-http/src/matcher/version.rs | 9 +- rama-http/src/service/fs/serve_dir/future.rs | 8 +- rama-http/src/service/fs/serve_dir/mod.rs | 4 +- rama-http/src/service/fs/serve_dir/tests.rs | 4 +- rama-http/src/service/fs/serve_file.rs | 2 +- .../service/web/endpoint/extract/authority.rs | 6 +- .../web/endpoint/extract/body/bytes.rs | 4 +- .../service/web/endpoint/extract/body/form.rs | 2 +- .../service/web/endpoint/extract/body/json.rs | 2 +- .../service/web/endpoint/extract/body/mod.rs | 3 +- .../service/web/endpoint/extract/body/text.rs | 9 +- .../src/service/web/endpoint/extract/dns.rs | 6 +- .../src/service/web/endpoint/extract/host.rs | 6 +- .../src/service/web/endpoint/extract/mod.rs | 6 +- .../src/service/web/endpoint/extract/path.rs | 2 +- rama-http/src/service/web/endpoint/mod.rs | 6 +- rama-http/src/service/web/endpoint/service.rs | 4 +- rama-http/src/service/web/k8s.rs | 7 +- rama-http/src/service/web/service.rs | 6 +- rama-http/src/utils/macros/http_error.rs | 6 +- rama-http/src/utils/mod.rs | 2 +- rama-net/Cargo.toml | 10 +- rama-net/src/address/domain.rs | 7 ++ rama-net/src/forwarded/mod.rs | 2 +- rama-net/src/http/mod.rs | 9 ++ .../src/http}/request_context.rs | 105 ++++++------------ rama-net/src/lib.rs | 6 + rama-net/src/mod.rs | 11 -- rama-net/src/stream/layer/http/body_limit.rs | 2 +- rama-net/src/stream/layer/opentelemetry.rs | 2 +- rama-net/src/stream/layer/tracker/incoming.rs | 6 +- rama-net/src/stream/layer/tracker/outgoing.rs | 6 +- rama-net/src/stream/matcher/ip.rs | 5 +- rama-net/src/stream/matcher/loopback.rs | 5 +- rama-net/src/stream/matcher/port.rs | 4 +- rama-net/src/stream/matcher/private_ip.rs | 4 +- rama-net/src/stream/matcher/socket.rs | 5 +- .../src/tls}/client/hello/boring.rs | 3 +- .../src/tls}/client/hello/mod.rs | 10 +- .../src/tls}/client/hello/rustls.rs | 0 .../src => rama-net/src/tls}/client/mod.rs | 0 .../src => rama-net/src/tls}/client/parser.rs | 16 +-- .../src => rama-net/src/tls}/enums/mod.rs | 2 +- .../src => rama-net/src/tls}/enums/rustls.rs | 0 rama-net/src/tls/mod.rs | 45 ++++++++ rama-net/src/transport.rs | 37 +++++- rama-net/src/user/auth.rs | 6 - rama-net/src/user/credentials/basic.rs | 37 +++--- rama-net/src/user/credentials/bearer.rs | 5 +- .../client/layer/proxy_connector/layer.rs | 2 +- rama-proxy/src/proxydb/layer.rs | 2 +- rama-proxy/src/proxydb/mod.rs | 4 +- rama-proxy/src/username.rs | 4 +- rama-tcp/Cargo.toml | 32 ++++++ rama-tcp/README.md | 49 ++++++++ {src/tcp => rama-tcp/src}/client/connect.rs | 4 +- {src/tcp => rama-tcp/src}/client/mod.rs | 2 + {src/tcp => rama-tcp/src}/client/request.rs | 11 +- .../src}/client/service/connector.rs | 15 ++- .../src}/client/service/forward.rs | 24 ++-- .../src}/client/service/mod.rs | 0 rama-tcp/src/lib.rs | 59 ++++++++++ {src/tcp => rama-tcp/src}/server/listener.rs | 20 ++-- {src/tcp => rama-tcp/src}/server/mod.rs | 2 +- {src/tcp => rama-tcp/src}/utils.rs | 0 rama-tls/Cargo.toml | 19 +++- rama-tls/README.md | 2 +- rama-tls/src/backend/mod.rs | 13 --- .../src/{backend => }/boring/client/http.rs | 15 ++- .../src/{backend => }/boring/client/mod.rs | 0 rama-tls/src/{backend => }/boring/mod.rs | 0 .../src/{backend => }/boring/server/config.rs | 4 +- .../src/{backend => }/boring/server/layer.rs | 2 +- .../src/{backend => }/boring/server/mod.rs | 0 .../{backend => }/boring/server/service.rs | 22 ++-- rama-tls/src/lib.rs | 58 +++------- .../src/{backend => }/rustls/client/http.rs | 26 ++--- .../src/{backend => }/rustls/client/mod.rs | 0 rama-tls/src/{backend => }/rustls/mod.rs | 2 +- .../rustls/server/client_config.rs | 6 +- .../src/{backend => }/rustls/server/layer.rs | 3 +- .../src/{backend => }/rustls/server/mod.rs | 0 .../{backend => }/rustls/server/service.rs | 18 ++- rama-tls/src/{backend => }/rustls/verify.rs | 2 +- src/http.rs | 26 +++++ src/lib.rs | 10 +- src/tcp/mod.rs | 5 - 188 files changed, 861 insertions(+), 730 deletions(-) rename {rama-http => rama-http-backend}/src/client/conn.rs (100%) rename {rama-http => rama-http-backend}/src/client/error.rs (98%) rename {rama-http => rama-http-backend}/src/client/ext.rs (94%) rename {rama-http => rama-http-backend}/src/client/mod.rs (100%) rename {rama-http => rama-http-backend}/src/client/svc.rs (100%) rename {rama-http => rama-http-backend}/src/executor.rs (100%) rename {rama-http => rama-http-backend}/src/server/hyper_conn.rs (100%) create mode 100644 rama-http-backend/src/server/layer/mod.rs rename {rama-http/src => rama-http-backend/src/server}/layer/upgrade/layer.rs (100%) rename {rama-http/src => rama-http-backend/src/server}/layer/upgrade/mod.rs (100%) rename {rama-http/src => rama-http-backend/src/server}/layer/upgrade/service.rs (97%) rename {rama-http/src => rama-http-backend/src/server}/layer/upgrade/upgraded.rs (100%) rename {rama-http => rama-http-backend}/src/server/mod.rs (72%) rename {rama-http => rama-http-backend}/src/server/service.rs (99%) rename {rama-http => rama-http-backend}/src/server/svc_hyper.rs (98%) create mode 100644 rama-net/src/http/mod.rs rename {rama-http/src => rama-net/src/http}/request_context.rs (80%) delete mode 100644 rama-net/src/mod.rs rename {rama-tls/src => rama-net/src/tls}/client/hello/boring.rs (78%) rename {rama-tls/src => rama-net/src/tls}/client/hello/mod.rs (97%) rename {rama-tls/src => rama-net/src/tls}/client/hello/rustls.rs (100%) rename {rama-tls/src => rama-net/src/tls}/client/mod.rs (100%) rename {rama-tls/src => rama-net/src/tls}/client/parser.rs (98%) rename {rama-tls/src => rama-net/src/tls}/enums/mod.rs (99%) rename {rama-tls/src => rama-net/src/tls}/enums/rustls.rs (100%) create mode 100644 rama-net/src/tls/mod.rs create mode 100644 rama-tcp/Cargo.toml create mode 100644 rama-tcp/README.md rename {src/tcp => rama-tcp/src}/client/connect.rs (99%) rename {src/tcp => rama-tcp/src}/client/mod.rs (78%) rename {src/tcp => rama-tcp/src}/client/request.rs (96%) rename {src/tcp => rama-tcp/src}/client/service/connector.rs (87%) rename {src/tcp => rama-tcp/src}/client/service/forward.rs (95%) rename {src/tcp => rama-tcp/src}/client/service/mod.rs (100%) create mode 100644 rama-tcp/src/lib.rs rename {src/tcp => rama-tcp/src}/server/listener.rs (95%) rename {src/tcp => rama-tcp/src}/server/mod.rs (96%) rename {src/tcp => rama-tcp/src}/utils.rs (100%) delete mode 100644 rama-tls/src/backend/mod.rs rename rama-tls/src/{backend => }/boring/client/http.rs (97%) rename rama-tls/src/{backend => }/boring/client/mod.rs (100%) rename rama-tls/src/{backend => }/boring/mod.rs (100%) rename rama-tls/src/{backend => }/boring/server/config.rs (90%) rename rama-tls/src/{backend => }/boring/server/layer.rs (98%) rename rama-tls/src/{backend => }/boring/server/mod.rs (100%) rename rama-tls/src/{backend => }/boring/server/service.rs (97%) rename rama-tls/src/{backend => }/rustls/client/http.rs (96%) rename rama-tls/src/{backend => }/rustls/client/mod.rs (100%) rename rama-tls/src/{backend => }/rustls/mod.rs (96%) rename rama-tls/src/{backend => }/rustls/server/client_config.rs (95%) rename rama-tls/src/{backend => }/rustls/server/layer.rs (96%) rename rama-tls/src/{backend => }/rustls/server/mod.rs (100%) rename rama-tls/src/{backend => }/rustls/server/service.rs (95%) rename rama-tls/src/{backend => }/rustls/verify.rs (98%) create mode 100644 src/http.rs delete mode 100644 src/tcp/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 50ee9d09..7110e5af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1769,8 +1769,11 @@ dependencies = [ "pin-project-lite", "rama-core", "rama-http", + "rama-http-backend", "rama-macros", + "rama-net", "rama-proxy", + "rama-tcp", "rama-tls", "rama-ua", "rama-utils", @@ -1852,6 +1855,7 @@ version = "0.2.0-alpha.2" dependencies = [ "async-compression", "base64 0.22.1", + "bitflags", "bytes", "const_format", "futures-core", @@ -1862,13 +1866,16 @@ dependencies = [ "http-body-util", "http-range-header", "httpdate", + "iri-string", "mime", "mime_guess", "paste", + "percent-encoding", "pin-project-lite", "rama-core", "rama-http-types", "rama-net", + "rama-tls", "rama-ua", "rama-utils", "regex", @@ -1878,7 +1885,9 @@ dependencies = [ "sync_wrapper 1.0.1", "tokio", "tokio-test", + "tokio-util", "tracing", + "uuid", ] [[package]] @@ -1886,6 +1895,7 @@ name = "rama-http-backend" version = "0.2.0-alpha.2" dependencies = [ "rama-core", + "rama-tcp", ] [[package]] @@ -1931,12 +1941,15 @@ name = "rama-net" version = "0.2.0-alpha.2" dependencies = [ "base64 0.22.1", + "boring", "bytes", "futures-lite", "headers", + "hex", "hickory-resolver", "ipnet", "itertools 0.13.0", + "nom", "opentelemetry", "opentelemetry-semantic-conventions", "opentelemetry_sdk", @@ -1947,6 +1960,7 @@ dependencies = [ "rama-core", "rama-http-types", "rama-utils", + "rustls", "serde", "tokio", "tokio-graceful", @@ -1964,20 +1978,39 @@ dependencies = [ "venndb", ] +[[package]] +name = "rama-tcp" +version = "0.2.0-alpha.2" +dependencies = [ + "rama-core", + "rama-http-types", + "rama-net", + "rama-utils", + "tokio", + "tracing", +] + [[package]] name = "rama-tls" version = "0.2.0-alpha.2" dependencies = [ "boring", - "nom", + "hex", + "parking_lot", + "pin-project-lite", "rama-core", + "rama-http-types", + "rama-net", + "rama-utils", "rcgen", "rustls", "rustls-native-certs", "rustls-pemfile", "rustls-pki-types", + "tokio", "tokio-boring", "tokio-rustls", + "tracing", "webpki-roots", ] diff --git a/Cargo.toml b/Cargo.toml index 80526ffa..6013ba2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "rama-cli", "rama-core", "rama-error", + "rama-tcp", "rama-http", "rama-http-backend", "rama-http-types", @@ -140,7 +141,9 @@ rustls = ["tls", "rama-tls/rustls"] rustls-ring = ["tls", "rama-tls/rustls-ring"] boring = ["tls", "rama-tls/boring"] cli = [] -http = ["dep:rama-http"] +net = [] +tcp = ["net"] +http = ["dep:rama-http", "dep:rama-http-backend", "net", "ua"] proxy = ["dep:rama-proxy"] ua = ["dep:rama-ua"] @@ -176,12 +179,15 @@ paste = { workspace = true } percent-encoding = { workspace = true } pin-project-lite = { workspace = true } rama-core = { version = "0.2.0-alpha.2", path = "rama-core" } +rama-net = { version = "0.2.0-alpha.2", path = "rama-net", optional = true } rama-http = { version = "0.2.0-alpha.2", path = "rama-http", optional = true } +rama-http-backend = { version = "0.2.0-alpha.2", path = "rama-http-backend", optional = true } rama-macros = { version = "0.2.0-alpha.2", path = "rama-macros" } rama-proxy = { version = "0.2.0-alpha.2", path = "rama-proxy", optional = true } rama-tls = { version = "0.2.0-alpha.2", path = "rama-tls", optional = true } rama-ua = { version = "0.2.0-alpha.2", path = "rama-ua", optional = true } rama-utils = { version = "0.2.0-alpha.2", path = "rama-utils" } +rama-tcp = { version = "0.2.0-alpha.2", path = "rama-tcp", optional = true } regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } diff --git a/rama-core/src/context/mod.rs b/rama-core/src/context/mod.rs index a37e55a9..88b4bd18 100644 --- a/rama-core/src/context/mod.rs +++ b/rama-core/src/context/mod.rs @@ -35,8 +35,8 @@ //! [`rama`] was built from the ground up to operate on and between different layers of the network stack. //! This has also an impact on state. Because sure, typed state is nice, but state leakage is not. What do I mean with that? //! -//! When creating a [`TcpListener`] with state you are essentially creating and injecting state, which will remain -//! as "read-only" for the enire life cycle of that [`TcpListener`] and to be made available for every incoming _tcp_ connection, +//! When creating a `TcpListener` with state you are essentially creating and injecting state, which will remain +//! as "read-only" for the enire life cycle of that `TcpListener` and to be made available for every incoming _tcp_ connection, //! as well as the application requests (Http requests). This is great for stuff that is okay to share, but it is not desired //! for state that you wish to have a narrower scope. Examples are state that are tied to a single _tcp_ connection and thus //! you do not wish to keep a global cache for this, as it would either be shared or get overly complicated to ensure @@ -57,8 +57,6 @@ //! it is of no use to have that middleware compile without knowing for sure that data source is made available //! to that middleware. //! -//! [`TcpListener`]: crate::tcp::server::TcpListener -//! //! # Example //! //! ``` diff --git a/rama-core/src/dns/mod.rs b/rama-core/src/dns/mod.rs index 29b81e77..1d5a9f90 100644 --- a/rama-core/src/dns/mod.rs +++ b/rama-core/src/dns/mod.rs @@ -123,11 +123,11 @@ impl Dns { /// /// Note that this impacts both [`Self::ipv4_lookup`] and [`Self::ipv6_lookup`], /// meaning that no Ipv6 addresses will be returned for the domain. - pub fn insert_overwrite(&mut self, name: Name, addresses: Vec) -> &mut Self { + pub fn insert_overwrite(&mut self, name: impl TryIntoName, addresses: Vec) -> Result<&mut Self, OpaqueError> { self.overwrites .get_or_insert_with(HashMap::new) - .insert(name, addresses); - self + .insert(name.try_into_name()?, addresses); + Ok(self) } /// Extend the overwrites with a new mapping. @@ -135,11 +135,13 @@ impl Dns { /// Existing mappings will be overwritten. /// /// See [`Self::insert_overwrite`] for more information. - pub fn extend_overwrites(&mut self, overwrites: HashMap>) -> &mut Self { - self.overwrites - .get_or_insert_with(HashMap::new) - .extend(overwrites); - self + pub fn extend_overwrites(&mut self, overwrites: HashMap>) -> Result<&mut Self, OpaqueError> { + let map = self.overwrites + .get_or_insert_with(HashMap::new); + for (name, addresses) in overwrites.into_iter() { + map.insert(name.try_into_name()?, addresses); + } + Ok(self) } /// Performs a 'A' DNS record lookup. diff --git a/rama-http-backend/Cargo.toml b/rama-http-backend/Cargo.toml index 123ade10..d9d596a4 100644 --- a/rama-http-backend/Cargo.toml +++ b/rama-http-backend/Cargo.toml @@ -12,6 +12,7 @@ rust-version = { workspace = true } [dependencies] rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp", features = ["http"] } [dev-dependencies] diff --git a/rama-http/src/client/conn.rs b/rama-http-backend/src/client/conn.rs similarity index 100% rename from rama-http/src/client/conn.rs rename to rama-http-backend/src/client/conn.rs index e436b2ad..63a73499 100644 --- a/rama-http/src/client/conn.rs +++ b/rama-http-backend/src/client/conn.rs @@ -1,6 +1,5 @@ use super::{svc::SendRequest, HttpClientService}; use crate::executor::HyperExecutor; -use rama_utils::macros::define_inner_service_accessors; use crate::{ error::{BoxError, OpaqueError}, http::{dep::http_body, Request, Version}, @@ -9,6 +8,7 @@ use crate::{ Context, Layer, Service, }; use hyper_util::rt::TokioIo; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; use tokio::sync::Mutex; diff --git a/rama-http/src/client/error.rs b/rama-http-backend/src/client/error.rs similarity index 98% rename from rama-http/src/client/error.rs rename to rama-http-backend/src/client/error.rs index f9778807..09b44e5d 100644 --- a/rama-http/src/client/error.rs +++ b/rama-http-backend/src/client/error.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use crate::error::{BoxError, OpaqueError}; +use rama_core::error::{BoxError, OpaqueError}; use crate::Uri; // TODO: support perhaps also more context, such as tracing id, ... diff --git a/rama-http/src/client/ext.rs b/rama-http-backend/src/client/ext.rs similarity index 94% rename from rama-http/src/client/ext.rs rename to rama-http-backend/src/client/ext.rs index 1a0ee8e3..5f2728bd 100644 --- a/rama-http/src/client/ext.rs +++ b/rama-http-backend/src/client/ext.rs @@ -300,8 +300,7 @@ mod private { impl IntoHeaderNameSealed for &[u8] { fn into_header_name(self) -> Result { - let name = - crate::HeaderName::from_bytes(self).map_err(HttpClientError::from_std)?; + let name = crate::HeaderName::from_bytes(self).map_err(HttpClientError::from_std)?; Ok(name) } } @@ -339,8 +338,7 @@ mod private { impl IntoHeaderValueSealed for &[u8] { fn into_header_value(self) -> Result { - let value = - crate::HeaderValue::from_bytes(self).map_err(HttpClientError::from_std)?; + let value = crate::HeaderValue::from_bytes(self).map_err(HttpClientError::from_std)?; Ok(value) } } @@ -462,8 +460,7 @@ where U: AsRef, P: AsRef, { - let header = - crate::headers::Authorization::basic(username.as_ref(), password.as_ref()); + let header = crate::headers::Authorization::basic(username.as_ref(), password.as_ref()); self.typed_header(header) } @@ -536,9 +533,7 @@ where } None => builder.header( crate::header::CONTENT_TYPE, - crate::HeaderValue::from_static( - "application/x-www-form-urlencoded", - ), + crate::HeaderValue::from_static("application/x-www-form-urlencoded"), ), }; match builder.body(body.into()) { @@ -550,15 +545,10 @@ where }, RequestBuilderState::PostBody(mut req) => match serde_html_form::to_string(form) { Ok(body) => { - if !req - .headers() - .contains_key(crate::header::CONTENT_TYPE) - { + if !req.headers().contains_key(crate::header::CONTENT_TYPE) { req.headers_mut().insert( crate::header::CONTENT_TYPE, - crate::HeaderValue::from_static( - "application/x-www-form-urlencoded", - ), + crate::HeaderValue::from_static("application/x-www-form-urlencoded"), ); } *req.body_mut() = body.into(); @@ -602,10 +592,7 @@ where }, RequestBuilderState::PostBody(mut req) => match serde_json::to_vec(json) { Ok(body) => { - if !req - .headers() - .contains_key(crate::header::CONTENT_TYPE) - { + if !req.headers().contains_key(crate::header::CONTENT_TYPE) { req.headers_mut().insert( crate::header::CONTENT_TYPE, crate::HeaderValue::from_static("application/json"), @@ -694,17 +681,10 @@ mod test { + Send + 'static, { - let ua = request - .headers() - .get(crate::header::USER_AGENT) - .unwrap(); + let ua = request.headers().get(crate::header::USER_AGENT).unwrap(); assert_eq!( ua.to_str().unwrap(), - format!( - "{}/{}", - rama_utils::info::NAME, - rama_utils::info::VERSION - ) + format!("{}/{}", rama_utils::info::NAME, rama_utils::info::VERSION) ); Ok(StatusCode::OK.into_response()) @@ -712,9 +692,9 @@ mod test { fn map_internal_client_error( result: Result, E>, - ) -> Result + ) -> Result where - E: Into, + E: Into, Body: crate::dep::http_body::Body> + Send + Sync @@ -726,7 +706,7 @@ mod test { } } - type HttpClientError = crate::error::BoxError; + type HttpClientError = rama_core::error::BoxError; type HttpClient = BoxService; fn client() -> HttpClient { diff --git a/rama-http/src/client/mod.rs b/rama-http-backend/src/client/mod.rs similarity index 100% rename from rama-http/src/client/mod.rs rename to rama-http-backend/src/client/mod.rs diff --git a/rama-http/src/client/svc.rs b/rama-http-backend/src/client/svc.rs similarity index 100% rename from rama-http/src/client/svc.rs rename to rama-http-backend/src/client/svc.rs diff --git a/rama-http/src/executor.rs b/rama-http-backend/src/executor.rs similarity index 100% rename from rama-http/src/executor.rs rename to rama-http-backend/src/executor.rs diff --git a/rama-http-backend/src/lib.rs b/rama-http-backend/src/lib.rs index ac6b11f5..f9e47558 100644 --- a/rama-http-backend/src/lib.rs +++ b/rama-http-backend/src/lib.rs @@ -51,3 +51,9 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +pub mod server; +pub mod client; +pub mod layer; + +mod executor; diff --git a/rama-http/src/server/hyper_conn.rs b/rama-http-backend/src/server/hyper_conn.rs similarity index 100% rename from rama-http/src/server/hyper_conn.rs rename to rama-http-backend/src/server/hyper_conn.rs index a2be3a40..604d6fbc 100644 --- a/rama-http/src/server/hyper_conn.rs +++ b/rama-http-backend/src/server/hyper_conn.rs @@ -1,14 +1,14 @@ use super::{svc_hyper::HyperService, HttpServeResult}; use crate::executor::HyperExecutor; -use crate::{IntoResponse, Request}; use crate::stream::Stream; use crate::tcp::utils::is_connection_error; -use rama_utils::future::Fuse; use crate::Context; use crate::Service; +use crate::{IntoResponse, Request}; use hyper::server::conn::http1::Builder as Http1Builder; use hyper::server::conn::http2::Builder as Http2Builder; use hyper_util::{rt::TokioIo, server::conn::auto::Builder as AutoBuilder}; +use rama_utils::future::Fuse; use std::convert::Infallible; use std::error::Error; use std::pin::pin; diff --git a/rama-http-backend/src/server/layer/mod.rs b/rama-http-backend/src/server/layer/mod.rs new file mode 100644 index 00000000..0cb8f5b1 --- /dev/null +++ b/rama-http-backend/src/server/layer/mod.rs @@ -0,0 +1,3 @@ +//! rama http backend server layers + +pub mod upgrade; diff --git a/rama-http/src/layer/upgrade/layer.rs b/rama-http-backend/src/server/layer/upgrade/layer.rs similarity index 100% rename from rama-http/src/layer/upgrade/layer.rs rename to rama-http-backend/src/server/layer/upgrade/layer.rs diff --git a/rama-http/src/layer/upgrade/mod.rs b/rama-http-backend/src/server/layer/upgrade/mod.rs similarity index 100% rename from rama-http/src/layer/upgrade/mod.rs rename to rama-http-backend/src/server/layer/upgrade/mod.rs diff --git a/rama-http/src/layer/upgrade/service.rs b/rama-http-backend/src/server/layer/upgrade/service.rs similarity index 97% rename from rama-http/src/layer/upgrade/service.rs rename to rama-http-backend/src/server/layer/upgrade/service.rs index 5311a914..89f83578 100644 --- a/rama-http/src/layer/upgrade/service.rs +++ b/rama-http-backend/src/server/layer/upgrade/service.rs @@ -3,11 +3,9 @@ //! See [`UpgradeService`] for more details. use super::Upgraded; -use rama_utils::macros::define_inner_service_accessors; -use rama_core::{ - context::Extensions, matcher::Matcher, service::BoxService, Context, Service, -}; use crate::Request; +use rama_core::{context::Extensions, matcher::Matcher, service::BoxService, Context, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{convert::Infallible, fmt, sync::Arc}; /// Upgrade service can be used to handle the possibility of upgrading a request, diff --git a/rama-http/src/layer/upgrade/upgraded.rs b/rama-http-backend/src/server/layer/upgrade/upgraded.rs similarity index 100% rename from rama-http/src/layer/upgrade/upgraded.rs rename to rama-http-backend/src/server/layer/upgrade/upgraded.rs diff --git a/rama-http/src/server/mod.rs b/rama-http-backend/src/server/mod.rs similarity index 72% rename from rama-http/src/server/mod.rs rename to rama-http-backend/src/server/mod.rs index 255dd8ba..3fcecd91 100644 --- a/rama-http/src/server/mod.rs +++ b/rama-http-backend/src/server/mod.rs @@ -2,10 +2,12 @@ //! which provides the [`HttpServer`] type to serve HTTP requests. /// Result type of [`HttpServer::serve`]. -pub type HttpServeResult = Result<(), crate::error::BoxError>; +pub type HttpServeResult = Result<(), rama_core::error::BoxError>; pub mod service; pub use service::HttpServer; mod hyper_conn; mod svc_hyper; + +pub mod layer; diff --git a/rama-http/src/server/service.rs b/rama-http-backend/src/server/service.rs similarity index 99% rename from rama-http/src/server/service.rs rename to rama-http-backend/src/server/service.rs index da8be39a..62945ff2 100644 --- a/rama-http/src/server/service.rs +++ b/rama-http-backend/src/server/service.rs @@ -2,18 +2,18 @@ use super::hyper_conn::HyperConnServer; use super::HttpServeResult; -use rama_core::graceful::ShutdownGuard; use crate::executor::HyperExecutor; +use rama_net::stream::Stream; +use rama_tcp::server::TcpListener; +use rama_core::{Context, Service}; use crate::{IntoResponse, Request}; -use rama_core::rt::Executor; -use crate::stream::Stream; -use crate::tcp::server::TcpListener; -use crate::{Context, Service}; use hyper::server::conn::http2::Builder as H2ConnBuilder; use hyper::{rt::Timer, server::conn::http1::Builder as Http1ConnBuilder}; use hyper_util::server::conn::auto::Builder as AutoConnBuilder; use hyper_util::server::conn::auto::Http1Builder as InnerAutoHttp1Builder; use hyper_util::server::conn::auto::Http2Builder as InnerAutoHttp2Builder; +use rama_core::graceful::ShutdownGuard; +use rama_core::rt::Executor; use std::convert::Infallible; use std::fmt; use std::future::Future; @@ -775,7 +775,7 @@ where IO: Stream, { type Response = (); - type Error = crate::error::BoxError; + type Error = rama_core::error::BoxError; fn serve( &self, diff --git a/rama-http/src/server/svc_hyper.rs b/rama-http-backend/src/server/svc_hyper.rs similarity index 98% rename from rama-http/src/server/svc_hyper.rs rename to rama-http-backend/src/server/svc_hyper.rs index 2a66c910..046a79f7 100644 --- a/rama-http/src/server/svc_hyper.rs +++ b/rama-http-backend/src/server/svc_hyper.rs @@ -1,5 +1,5 @@ use crate::{BodyLimit, IntoResponse, Request}; -use crate::{Context, Service}; +use rama_core::{Context, Service}; use std::{convert::Infallible, fmt, future::Future, pin::Pin, sync::Arc}; /// Wrapper service that implements [`hyper::service::Service`]. diff --git a/rama-http-types/src/body_limit.rs b/rama-http-types/src/body_limit.rs index 2bddfd34..293ff1ca 100644 --- a/rama-http-types/src/body_limit.rs +++ b/rama-http-types/src/body_limit.rs @@ -1,10 +1,4 @@ /// Can be used to communicate the desire to limit the size of request/response bodies. -/// -/// It is for example used by the [`BodyLimitLayer`] to add this to the request [`Context`], -/// such that http services used can apply the limit when found in that [`Context`]. -/// -/// [`Context`]: crate::Context` -/// [`BodyLimitLayer`]: crate::layer::body_limit::BodyLimitLayer #[derive(Debug, Clone, Copy)] pub struct BodyLimit { kind: Option, diff --git a/rama-http/Cargo.toml b/rama-http/Cargo.toml index 0af17436..c6fe8722 100644 --- a/rama-http/Cargo.toml +++ b/rama-http/Cargo.toml @@ -13,6 +13,8 @@ rust-version = { workspace = true } [features] default = [] compression = ["dep:async-compression"] +telemetry = ["rama-core/telemetry"] +tls = ["dep:rama-tls"] [dependencies] async-compression = { workspace = true, features = [ @@ -38,7 +40,8 @@ rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } rama-ua = { version = "0.2.0-alpha.2", path = "../rama-ua" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } -rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } +rama-tls = { version = "0.2.0-alpha.2", path = "../rama-tls", optional = true } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } serde_json = { workspace = true } @@ -49,6 +52,11 @@ base64 = { workspace = true } httpdate = { workspace = true } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } http-range-header = { workspace = true } +iri-string = { workspace = true } +tokio-util = { workspace = true, features = ["io"] } +uuid = { workspace = true, features = ["v4"] } +percent-encoding = { workspace = true } +bitflags = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["full"] } diff --git a/rama-http/src/headers/forwarded/exotic_forward_ip.rs b/rama-http/src/headers/forwarded/exotic_forward_ip.rs index 265ac321..e715801f 100644 --- a/rama-http/src/headers/forwarded/exotic_forward_ip.rs +++ b/rama-http/src/headers/forwarded/exotic_forward_ip.rs @@ -3,7 +3,7 @@ use crate::headers::Header; use crate::{HeaderName, HeaderValue}; use paste::paste; use rama_core::error::{ErrorContext, OpaqueError}; -use rama_core::net::forwarded::{ForwardedElement, NodeId}; +use rama_net::forwarded::{ForwardedElement, NodeId}; use std::fmt; use std::net::{IpAddr, Ipv6Addr}; diff --git a/rama-http/src/headers/forwarded/mod.rs b/rama-http/src/headers/forwarded/mod.rs index 32e3ece5..0d7e0624 100644 --- a/rama-http/src/headers/forwarded/mod.rs +++ b/rama-http/src/headers/forwarded/mod.rs @@ -1,5 +1,5 @@ -pub use rama_core::net::forwarded::Forwarded; -use rama_core::net::forwarded::ForwardedElement; +pub use rama_net::forwarded::Forwarded; +use rama_net::forwarded::ForwardedElement; mod via; #[doc(inline)] diff --git a/rama-http/src/headers/forwarded/via.rs b/rama-http/src/headers/forwarded/via.rs index e7a92b62..ef9ed8b2 100644 --- a/rama-http/src/headers/forwarded/via.rs +++ b/rama-http/src/headers/forwarded/via.rs @@ -1,7 +1,7 @@ use crate::headers::{self, Header}; use crate::{HeaderName, HeaderValue}; use rama_core::error::{ErrorContext, OpaqueError}; -use rama_core::net::forwarded::{ForwardedElement, ForwardedProtocol, ForwardedVersion, NodeId}; +use rama_net::forwarded::{ForwardedElement, ForwardedProtocol, ForwardedVersion, NodeId}; /// The Via general header is added by proxies, both forward and reverse. /// diff --git a/rama-http/src/headers/forwarded/x_forwarded_for.rs b/rama-http/src/headers/forwarded/x_forwarded_for.rs index 89fe00fe..7046f254 100644 --- a/rama-http/src/headers/forwarded/x_forwarded_for.rs +++ b/rama-http/src/headers/forwarded/x_forwarded_for.rs @@ -1,6 +1,6 @@ use crate::headers::{self, Header}; use crate::{HeaderName, HeaderValue}; -use rama_core::net::forwarded::ForwardedElement; +use rama_net::forwarded::ForwardedElement; use std::iter::FromIterator; use std::net::IpAddr; diff --git a/rama-http/src/headers/forwarded/x_forwarded_host.rs b/rama-http/src/headers/forwarded/x_forwarded_host.rs index 6f6793cc..9579a685 100644 --- a/rama-http/src/headers/forwarded/x_forwarded_host.rs +++ b/rama-http/src/headers/forwarded/x_forwarded_host.rs @@ -1,7 +1,7 @@ use crate::headers::{self, Header}; use crate::{HeaderName, HeaderValue}; -use rama_core::net::address::Host; -use rama_core::net::forwarded::{ForwardedAuthority, ForwardedElement}; +use rama_net::address::Host; +use rama_net::forwarded::{ForwardedAuthority, ForwardedElement}; /// The X-Forwarded-Host (XFH) header is a de-facto standard header for identifying the /// original host requested by the client in the Host HTTP request header. diff --git a/rama-http/src/headers/forwarded/x_forwarded_proto.rs b/rama-http/src/headers/forwarded/x_forwarded_proto.rs index 0a9a8686..b0aa8132 100644 --- a/rama-http/src/headers/forwarded/x_forwarded_proto.rs +++ b/rama-http/src/headers/forwarded/x_forwarded_proto.rs @@ -1,6 +1,6 @@ use crate::headers::{self, Header}; use crate::{HeaderName, HeaderValue}; -use rama_core::net::forwarded::{ForwardedElement, ForwardedProtocol}; +use rama_net::forwarded::{ForwardedElement, ForwardedProtocol}; /// The X-Forwarded-Proto (XFP) header is a de-facto standard header for /// identifying the protocol (HTTP or HTTPS) that a client used to connect to your proxy or load balancer. diff --git a/rama-http/src/headers/mod.rs b/rama-http/src/headers/mod.rs index f5dcbc5d..eebb7827 100644 --- a/rama-http/src/headers/mod.rs +++ b/rama-http/src/headers/mod.rs @@ -94,7 +94,7 @@ pub mod authorization { pub use headers::authorization::{Authorization, Basic, Bearer}; } -pub use rama_http_types::HeaderExt; +pub use rama_http_types::headers::HeaderExt; pub(crate) mod util; pub use util::quality_value::{Quality, QualityValue}; diff --git a/rama-http/src/io/request.rs b/rama-http/src/io/request.rs index be225220..b9ea1026 100644 --- a/rama-http/src/io/request.rs +++ b/rama-http/src/io/request.rs @@ -1,11 +1,9 @@ use crate::{ - error::BoxError, - http::{ - dep::{http_body, http_body_util::BodyExt}, - Body, Request, - }, + dep::{http_body, http_body_util::BodyExt}, + Body, Request, }; use bytes::Bytes; +use rama_core::error::BoxError; use tokio::io::{AsyncWrite, AsyncWriteExt}; /// Write an HTTP request to a writer in std http format. diff --git a/rama-http/src/io/response.rs b/rama-http/src/io/response.rs index 21e1b41d..25d2d8c5 100644 --- a/rama-http/src/io/response.rs +++ b/rama-http/src/io/response.rs @@ -1,11 +1,9 @@ use crate::{ - error::BoxError, - http::{ - dep::{http_body, http_body_util::BodyExt}, - Body, Response, - }, + dep::{http_body, http_body_util::BodyExt}, + Body, Response, }; use bytes::Bytes; +use rama_core::error::BoxError; use tokio::io::{AsyncWrite, AsyncWriteExt}; /// Write an HTTP response to a writer in std http format. diff --git a/rama-http/src/layer/auth/add_authorization.rs b/rama-http/src/layer/auth/add_authorization.rs index 31a6e382..2222a95c 100644 --- a/rama-http/src/layer/auth/add_authorization.rs +++ b/rama-http/src/layer/auth/add_authorization.rs @@ -41,9 +41,9 @@ //! ``` use crate::{HeaderValue, Request, Response}; -use rama_utils::macros::define_inner_service_accessors; -use rama_core::{Context, Layer, Service}; use base64::Engine as _; +use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::convert::TryFrom; use std::fmt; @@ -301,11 +301,11 @@ mod tests { #[allow(unused_imports)] use super::*; - use crate::error::BoxError; use crate::layer::validate_request::ValidateRequestHeaderLayer; use crate::{Body, Request, Response, StatusCode}; - use crate::service::service_fn; - use crate::{Context, Service}; + use rama_core::error::BoxError; + use rama_core::service::service_fn; + use rama_core::{Context, Service}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/auth/async_require_authorization.rs b/rama-http/src/layer/auth/async_require_authorization.rs index 0a29ee28..d5c84395 100644 --- a/rama-http/src/layer/auth/async_require_authorization.rs +++ b/rama-http/src/layer/auth/async_require_authorization.rs @@ -116,10 +116,10 @@ //! # } //! ``` -use std::future::Future; use crate::{Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; +use std::future::Future; /// Layer that applies [`AsyncRequireAuthorization`] which authorizes all requests using the /// [`Authorization`] header. @@ -247,9 +247,9 @@ mod tests { #[allow(unused_imports)] use super::*; - use crate::error::BoxError; - use crate::{header, Body, StatusCode}; use crate::service::service_fn; + use crate::{header, Body, StatusCode}; + use rama_core::error::BoxError; #[derive(Clone, Copy)] struct MyAuth; diff --git a/rama-http/src/layer/auth/require_authorization.rs b/rama-http/src/layer/auth/require_authorization.rs index 7b92244d..fa64cd67 100644 --- a/rama-http/src/layer/auth/require_authorization.rs +++ b/rama-http/src/layer/auth/require_authorization.rs @@ -263,11 +263,11 @@ mod tests { #[allow(unused_imports)] use super::*; - use crate::error::BoxError; use crate::layer::validate_request::ValidateRequestHeaderLayer; use crate::{header, Body}; - use crate::service::service_fn; - use crate::{Context, Layer, Service}; + use rama_core::error::BoxError; + use rama_core::service::service_fn; + use rama_core::{Context, Layer, Service}; #[tokio::test] async fn valid_basic_token() { diff --git a/rama-http/src/layer/body_limit.rs b/rama-http/src/layer/body_limit.rs index 8b21e9a3..ff8e0853 100644 --- a/rama-http/src/layer/body_limit.rs +++ b/rama-http/src/layer/body_limit.rs @@ -31,8 +31,8 @@ use crate::dep::http_body_util::Limited; use crate::Request; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Apply a limit to the request body's size. diff --git a/rama-http/src/layer/catch_panic.rs b/rama-http/src/layer/catch_panic.rs index 0279ddb1..4f1e0a0f 100644 --- a/rama-http/src/layer/catch_panic.rs +++ b/rama-http/src/layer/catch_panic.rs @@ -87,9 +87,9 @@ //! ``` use crate::{Body, HeaderValue, Request, Response, StatusCode}; -use rama_utils::macros::define_inner_service_accessors; -use rama_core::{Context, Layer, Service}; use futures_lite::future::FutureExt; +use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; use std::{any::Any, panic::AssertUnwindSafe}; diff --git a/rama-http/src/layer/compression/body.rs b/rama-http/src/layer/compression/body.rs index 8a85826f..8f1b185a 100644 --- a/rama-http/src/layer/compression/body.rs +++ b/rama-http/src/layer/compression/body.rs @@ -1,11 +1,11 @@ #![allow(unused_imports)] -use rama_core::error::BoxError; use crate::dep::http_body::{Body, Frame}; use crate::layer::util::compression::{ AsyncReadBody, BodyIntoStream, CompressionLevel, DecorateAsyncRead, WrapBody, }; use crate::HeaderMap; +use rama_core::error::BoxError; use async_compression::tokio::bufread::{BrotliEncoder, GzipEncoder, ZlibEncoder, ZstdEncoder}; diff --git a/rama-http/src/layer/compression/layer.rs b/rama-http/src/layer/compression/layer.rs index 204ed7cb..adba95e2 100644 --- a/rama-http/src/layer/compression/layer.rs +++ b/rama-http/src/layer/compression/layer.rs @@ -119,8 +119,8 @@ mod tests { use crate::dep::http_body_util::BodyExt; use crate::{header::ACCEPT_ENCODING, Body, Request, Response}; - use crate::service::service_fn; - use crate::{Context, Service}; + use rama_core::service::service_fn; + use rama_core::{Context, Service}; use std::convert::Infallible; use tokio::fs::File; use tokio_util::io::ReaderStream; @@ -137,7 +137,7 @@ mod tests { } #[tokio::test] - async fn accept_encoding_configuration_works() -> Result<(), crate::error::BoxError> { + async fn accept_encoding_configuration_works() -> Result<(), rama_core::error::BoxError> { let deflate_only_layer = CompressionLayer::new() .quality(CompressionLevel::Best) .br(false) diff --git a/rama-http/src/layer/compression/mod.rs b/rama-http/src/layer/compression/mod.rs index c2f471c7..43e48051 100644 --- a/rama-http/src/layer/compression/mod.rs +++ b/rama-http/src/layer/compression/mod.rs @@ -101,10 +101,10 @@ mod tests { ACCEPT_ENCODING, ACCEPT_RANGES, CONTENT_ENCODING, CONTENT_RANGE, CONTENT_TYPE, RANGE, }; use crate::{Body, HeaderValue, Request, Response}; - use crate::service::service_fn; - use crate::{Context, Service}; use async_compression::tokio::write::{BrotliDecoder, BrotliEncoder}; use flate2::read::GzDecoder; + use rama_core::service::service_fn; + use rama_core::{Context, Service}; use std::convert::Infallible; use std::io::Read; use std::sync::{Arc, RwLock}; diff --git a/rama-http/src/layer/compression/service.rs b/rama-http/src/layer/compression/service.rs index d281e959..5bd2d518 100644 --- a/rama-http/src/layer/compression/service.rs +++ b/rama-http/src/layer/compression/service.rs @@ -6,8 +6,8 @@ use crate::dep::http_body::Body; use crate::layer::util::compression::WrapBody; use crate::layer::util::{compression::AcceptEncoding, content_encoding::Encoding}; use crate::{header, Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Service}; +use rama_utils::macros::define_inner_service_accessors; /// Compress response bodies of the underlying service. /// diff --git a/rama-http/src/layer/cors/allow_private_network.rs b/rama-http/src/layer/cors/allow_private_network.rs index ed8c8a54..e6dab26d 100644 --- a/rama-http/src/layer/cors/allow_private_network.rs +++ b/rama-http/src/layer/cors/allow_private_network.rs @@ -113,14 +113,14 @@ impl Default for AllowPrivateNetworkInner { mod tests { use super::AllowPrivateNetwork; - use crate::error::BoxError; use crate::dep::http::{ header::ORIGIN, request::Parts, HeaderName, HeaderValue, Request, Response, }; use crate::layer::cors::CorsLayer; use crate::Body; - use crate::service::service_fn; - use crate::{Context, Layer, Service}; + use rama_core::error::BoxError; + use rama_core::service::service_fn; + use rama_core::{Context, Layer, Service}; static REQUEST_PRIVATE_NETWORK: HeaderName = HeaderName::from_static("access-control-request-private-network"); diff --git a/rama-http/src/layer/cors/mod.rs b/rama-http/src/layer/cors/mod.rs index 9fd37dde..1ae057ac 100644 --- a/rama-http/src/layer/cors/mod.rs +++ b/rama-http/src/layer/cors/mod.rs @@ -50,9 +50,9 @@ use crate::dep::http::{ header::{self, HeaderName}, HeaderMap, HeaderValue, Method, Request, Response, }; -use rama_utils::macros::define_inner_service_accessors; -use rama_core::{Context, Layer, Service}; use bytes::{BufMut, BytesMut}; +use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{array, fmt, mem}; mod allow_credentials; diff --git a/rama-http/src/layer/cors/tests.rs b/rama-http/src/layer/cors/tests.rs index 509032f8..f8c1a9f7 100644 --- a/rama-http/src/layer/cors/tests.rs +++ b/rama-http/src/layer/cors/tests.rs @@ -1,7 +1,7 @@ use crate::layer::cors::{AllowOrigin, CorsLayer}; use crate::{header, Body, HeaderValue, Request, Response}; -use crate::service::service_fn; -use crate::{Context, Layer, Service}; +use rama_core::service::service_fn; +use rama_core::{Context, Layer, Service}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/decompression/body.rs b/rama-http/src/layer/decompression/body.rs index 1f0630aa..0b31cec2 100644 --- a/rama-http/src/layer/decompression/body.rs +++ b/rama-http/src/layer/decompression/body.rs @@ -1,11 +1,11 @@ #![allow(unused_imports)] -use rama_core::error::BoxError; use crate::dep::http_body::{Body, Frame}; use crate::layer::util::compression::{ AsyncReadBody, BodyIntoStream, CompressionLevel, DecorateAsyncRead, WrapBody, }; use crate::HeaderMap; +use rama_core::error::BoxError; use async_compression::tokio::bufread::BrotliDecoder; use async_compression::tokio::bufread::GzipDecoder; diff --git a/rama-http/src/layer/decompression/mod.rs b/rama-http/src/layer/decompression/mod.rs index 58ca0fc4..6ff6f865 100644 --- a/rama-http/src/layer/decompression/mod.rs +++ b/rama-http/src/layer/decompression/mod.rs @@ -119,8 +119,8 @@ mod tests { use crate::dep::http_body_util::BodyExt; use crate::layer::compression::Compression; use crate::{Body, HeaderMap, HeaderName, Request, Response}; - use crate::service::service_fn; - use crate::{Context, Service}; + use rama_core::service::service_fn; + use rama_core::{Context, Service}; use flate2::write::GzEncoder; diff --git a/rama-http/src/layer/decompression/request/mod.rs b/rama-http/src/layer/decompression/request/mod.rs index 77cee7f9..cd90a502 100644 --- a/rama-http/src/layer/decompression/request/mod.rs +++ b/rama-http/src/layer/decompression/request/mod.rs @@ -8,8 +8,8 @@ mod tests { use crate::dep::http_body_util::BodyExt; use crate::layer::decompression::DecompressionBody; use crate::{header, Body, Request, Response, StatusCode}; - use crate::service::service_fn; - use crate::{Context, Service}; + use rama_core::service::service_fn; + use rama_core::{Context, Service}; use flate2::{write::GzEncoder, Compression}; use std::{convert::Infallible, io::Write}; diff --git a/rama-http/src/layer/decompression/request/service.rs b/rama-http/src/layer/decompression/request/service.rs index dee45995..532e2d20 100644 --- a/rama-http/src/layer/decompression/request/service.rs +++ b/rama-http/src/layer/decompression/request/service.rs @@ -1,6 +1,5 @@ use std::fmt; -use rama_core::error::BoxError; use crate::dep::http_body::Body; use crate::dep::http_body_util::{combinators::UnsyncBoxBody, BodyExt, Empty}; use crate::layer::{ @@ -10,9 +9,10 @@ use crate::layer::{ util::content_encoding::SupportedEncodings, }; use crate::{header, HeaderValue, Request, Response, StatusCode}; -use rama_utils::macros::define_inner_service_accessors; -use rama_core::{Context, Service}; use bytes::Buf; +use rama_core::error::BoxError; +use rama_core::{Context, Service}; +use rama_utils::macros::define_inner_service_accessors; /// Decompresses request bodies and calls its underlying service. /// diff --git a/rama-http/src/layer/decompression/service.rs b/rama-http/src/layer/decompression/service.rs index 8b72cefc..8270587a 100644 --- a/rama-http/src/layer/decompression/service.rs +++ b/rama-http/src/layer/decompression/service.rs @@ -10,8 +10,8 @@ use crate::{ header::{self, ACCEPT_ENCODING}, Request, Response, }; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Service}; +use rama_utils::macros::define_inner_service_accessors; /// Decompresses response bodies of the underlying service. /// diff --git a/rama-http/src/layer/dns/dns_map/service.rs b/rama-http/src/layer/dns/dns_map/service.rs index 1634d87a..9dc09875 100644 --- a/rama-http/src/layer/dns/dns_map/service.rs +++ b/rama-http/src/layer/dns/dns_map/service.rs @@ -1,12 +1,11 @@ use std::fmt; use super::DnsMap; -use rama_utils::macros::define_inner_service_accessors; -use crate::{layer::header_config::extract_header_config, utils::HeaderValueErr, HeaderName, Request}; -use rama_core::{ - error::OpaqueError, - Context, Service, +use crate::{ + layer::header_config::extract_header_config, utils::HeaderValueErr, HeaderName, Request, }; +use rama_core::{error::OpaqueError, Context, Service}; +use rama_utils::macros::define_inner_service_accessors; /// Service to support DNS lookup overwrites. /// @@ -52,7 +51,7 @@ impl Service> for DnsMapService where State: Send + Sync + 'static, Body: Send + Sync + 'static, - E: Into + Send + Sync + 'static, + E: Into + Send + Sync + 'static, S: Service, Error = E>, { type Response = S::Response; @@ -72,7 +71,7 @@ where } Err(HeaderValueErr::HeaderMissing(_)) => (), // ignore if missing, it's opt-in Ok(dns_map) => { - ctx.dns_mut().extend_overwrites(dns_map.0); + ctx.dns_mut().extend_overwrites(dns_map.0)?; } } diff --git a/rama-http/src/layer/dns/dns_resolve/mod.rs b/rama-http/src/layer/dns/dns_resolve/mod.rs index 381cfd11..f714710a 100644 --- a/rama-http/src/layer/dns/dns_resolve/mod.rs +++ b/rama-http/src/layer/dns/dns_resolve/mod.rs @@ -5,10 +5,10 @@ //! For example resolving them to make a connection to a target server over a proxy //! by IP address instead of domain name. -use rama_core::error::{ErrorExt, OpaqueError}; use crate::HeaderValue; -use rama_utils::macros::match_ignore_ascii_case_str; +use rama_core::error::{ErrorExt, OpaqueError}; use rama_core::username::{ComposeError, Composer, UsernameLabelWriter}; +use rama_utils::macros::match_ignore_ascii_case_str; use std::fmt; mod service; @@ -26,7 +26,7 @@ pub use username_parser::DnsResolveModeUsernameParser; #[derive(Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] /// A vanity [`Extensions`] type for others to easily check if eager DNS resolution is enabled. /// -/// [`Extensions`]: crate::context::Extensions +/// [`Extensions`]: rama_core::context::Extensions pub struct DnsResolveMode(ResolveMode); impl fmt::Display for DnsResolveMode { @@ -119,7 +119,7 @@ impl UsernameLabelWriter for DnsResolveMode { #[cfg(test)] mod tests { use super::*; - use crate::context::Extensions; + use rama_core::context::Extensions; use rama_core::username::{compose_username, parse_username}; #[test] diff --git a/rama-http/src/layer/dns/dns_resolve/service.rs b/rama-http/src/layer/dns/dns_resolve/service.rs index fc23dafc..b4d39089 100644 --- a/rama-http/src/layer/dns/dns_resolve/service.rs +++ b/rama-http/src/layer/dns/dns_resolve/service.rs @@ -1,11 +1,8 @@ -use std::fmt; use super::DnsResolveMode; -use rama_utils::macros::define_inner_service_accessors; -use rama_core::{ - error::OpaqueError, - Context, Service, -}; use crate::{HeaderName, Request}; +use rama_core::{error::OpaqueError, Context, Service}; +use rama_utils::macros::define_inner_service_accessors; +use std::fmt; /// Service to support configuring the DNS resolve mode. /// @@ -53,7 +50,11 @@ impl Service> for DnsResolveModeService where State: Send + Sync + 'static, Body: Send + Sync + 'static, - S: Service, Error: Into + Send + Sync + 'static>, + S: Service< + State, + Request, + Error: Into + Send + Sync + 'static, + >, { type Response = S::Response; type Error = OpaqueError; diff --git a/rama-http/src/layer/dns/dns_resolve/username_parser.rs b/rama-http/src/layer/dns/dns_resolve/username_parser.rs index df295f15..fb5b6dc1 100644 --- a/rama-http/src/layer/dns/dns_resolve/username_parser.rs +++ b/rama-http/src/layer/dns/dns_resolve/username_parser.rs @@ -1,18 +1,18 @@ +use super::DnsResolveMode; +use rama_core::username::{UsernameLabelParser, UsernameLabelState}; use rama_core::{ context::Extensions, error::{error, ErrorContext, OpaqueError}, }; -use super::DnsResolveMode; use rama_utils::macros::str::eq_ignore_ascii_case; -use rama_core::username::{UsernameLabelParser, UsernameLabelState}; #[derive(Debug, Clone, Default)] #[non_exhaustive] /// A parser which parses [`DnsResolveMode`]s from username labels /// and adds it to the [`Context`]'s [`Extensions`]. /// -/// [`Context`]: crate::Context -/// [`Extensions`]: crate::context::Extensions +/// [`Context`]: rama_core::Context +/// [`Extensions`]: rama_core::context::Extensions pub struct DnsResolveModeUsernameParser { key_found: bool, mode: DnsResolveMode, diff --git a/rama-http/src/layer/error_handling.rs b/rama-http/src/layer/error_handling.rs index b5a7a378..6222cc24 100644 --- a/rama-http/src/layer/error_handling.rs +++ b/rama-http/src/layer/error_handling.rs @@ -44,9 +44,9 @@ //! # } //! ``` -use rama_utils::macros::define_inner_service_accessors; use crate::{IntoResponse, Request, Response}; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{convert::Infallible, fmt}; /// A [`Layer`] that wraps a [`Service`] and converts errors into [`Response`]s. diff --git a/rama-http/src/layer/follow_redirect/mod.rs b/rama-http/src/layer/follow_redirect/mod.rs index dd276ac8..1fe9878a 100644 --- a/rama-http/src/layer/follow_redirect/mod.rs +++ b/rama-http/src/layer/follow_redirect/mod.rs @@ -101,10 +101,10 @@ pub mod policy; -use rama_utils::macros::define_inner_service_accessors; use crate::{dep::http_body::Body, header::LOCATION, Method, Request, Response, StatusCode, Uri}; -use rama_core::{Context, Layer, Service}; use iri_string::types::{UriAbsoluteString, UriReferenceStr}; +use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, future::Future}; use self::policy::{Action, Attempt, Policy, Standard}; @@ -372,9 +372,9 @@ fn resolve_uri(relative: &str, base: &Uri) -> Option { #[cfg(test)] mod tests { use super::{policy::*, *}; - use crate::{header::LOCATION, Body}; use crate::service::service_fn; - use crate::Layer; + use crate::{header::LOCATION, Body}; + use rama_core::Layer; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs b/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs index 7d6d5940..fd27d5b9 100644 --- a/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs +++ b/rama-http/src/layer/follow_redirect/policy/clone_body_fn.rs @@ -1,5 +1,5 @@ -use rama_core::Context; use super::{Action, Attempt, Policy}; +use rama_core::Context; use std::fmt; /// A redirection [`Policy`] created from a closure. diff --git a/rama-http/src/layer/follow_redirect/policy/limited.rs b/rama-http/src/layer/follow_redirect/policy/limited.rs index 6c5958c4..3b21ae84 100644 --- a/rama-http/src/layer/follow_redirect/policy/limited.rs +++ b/rama-http/src/layer/follow_redirect/policy/limited.rs @@ -1,5 +1,5 @@ -use rama_core::Context; use super::{Action, Attempt, Policy}; +use rama_core::Context; /// A redirection [`Policy`] that limits the number of successive redirections. #[derive(Debug)] diff --git a/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs b/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs index 9356270f..274cfd88 100644 --- a/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs +++ b/rama-http/src/layer/follow_redirect/policy/redirect_fn.rs @@ -1,5 +1,5 @@ -use rama_core::Context; use super::{Action, Attempt, Policy}; +use rama_core::Context; use std::fmt; /// A redirection [`Policy`] created from a closure. diff --git a/rama-http/src/layer/follow_redirect/policy/same_origin.rs b/rama-http/src/layer/follow_redirect/policy/same_origin.rs index 27107c16..6d1aa3b7 100644 --- a/rama-http/src/layer/follow_redirect/policy/same_origin.rs +++ b/rama-http/src/layer/follow_redirect/policy/same_origin.rs @@ -1,5 +1,5 @@ -use rama_core::Context; use super::{eq_origin, Action, Attempt, Policy}; +use rama_core::Context; use std::fmt; /// A redirection [`Policy`] that stops cross-origin redirections. diff --git a/rama-http/src/layer/forwarded/get_forwarded.rs b/rama-http/src/layer/forwarded/get_forwarded.rs index b146fb17..207c8948 100644 --- a/rama-http/src/layer/forwarded/get_forwarded.rs +++ b/rama-http/src/layer/forwarded/get_forwarded.rs @@ -2,9 +2,10 @@ use crate::headers::{ ForwardHeader, HeaderMapExt, Via, XForwardedFor, XForwardedHost, XForwardedProto, }; use crate::Request; -use rama_core::net::forwarded::ForwardedElement; -use rama_core::utils::macros::all_the_tuples_no_last_special_case; -use rama_core::{net::forwarded::Forwarded, Context, Layer, Service}; +use rama_core::{Context, Layer, Service}; +use rama_net::forwarded::Forwarded; +use rama_net::forwarded::ForwardedElement; +use rama_utils::macros::all_the_tuples_no_last_special_case; use std::fmt; use std::future::Future; use std::marker::PhantomData; diff --git a/rama-http/src/layer/forwarded/set_forwarded.rs b/rama-http/src/layer/forwarded/set_forwarded.rs index 7ebaa3c8..d4a635f6 100644 --- a/rama-http/src/layer/forwarded/set_forwarded.rs +++ b/rama-http/src/layer/forwarded/set_forwarded.rs @@ -1,13 +1,13 @@ use crate::headers::{ ForwardHeader, HeaderMapExt, Via, XForwardedFor, XForwardedHost, XForwardedProto, }; -use crate::net::address::Domain; -use crate::net::forwarded::{Forwarded, ForwardedElement, NodeId}; -use crate::stream::SocketInfo; -use rama_utils::macros::all_the_tuples_no_last_special_case; -use crate::{Context, Layer, Service}; use crate::{Request, RequestContext}; use rama_core::error::BoxError; +use rama_core::{Context, Layer, Service}; +use rama_net::address::Domain; +use rama_net::forwarded::{Forwarded, ForwardedElement, NodeId}; +use rama_net::stream::SocketInfo; +use rama_utils::macros::all_the_tuples_no_last_special_case; use std::fmt; use std::marker::PhantomData; diff --git a/rama-http/src/layer/header_config.rs b/rama-http/src/layer/header_config.rs index 74f22eaa..06278fab 100644 --- a/rama-http/src/layer/header_config.rs +++ b/rama-http/src/layer/header_config.rs @@ -1,7 +1,7 @@ //! Extract a header config from a request or response and insert it into the [`Extensions`] of its [`Context`]. //! -//! [`Extensions`]: crate::context::Extensions -//! [`Context`]: crate::Context +//! [`Extensions`]: rama_core::context::Extensions +//! [`Context`]: rama_core::Context //! //! # Example //! @@ -43,17 +43,14 @@ //! ``` use crate::{header::AsHeaderName, HeaderName}; -use rama_utils::macros::define_inner_service_accessors; -use serde::de::DeserializeOwned; -use std::{fmt, marker::PhantomData}; -use rama_core::{ - error::BoxError, - Context, Layer, Service, -}; use crate::{ utils::{HeaderValueErr, HeaderValueGetter}, Request, }; +use rama_core::{error::BoxError, Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; +use serde::de::DeserializeOwned; +use std::{fmt, marker::PhantomData}; /// Extract a header config from a request or response without consuming it. pub fn extract_header_config(request: &G, header_name: H) -> Result @@ -71,7 +68,7 @@ where /// A [`Service`] which extracts a header config from a request or response /// and inserts it into the [`Extensions`] of that object. /// -/// [`Extensions`]: crate::context::Extensions +/// [`Extensions`]: rama_core::context::Extensions pub struct HeaderConfigService { inner: S, header_name: HeaderName, @@ -157,9 +154,7 @@ where let config = match extract_header_config::<_, T, _>(&request, &self.header_name) { Ok(config) => config, Err(err) => { - if self.optional - && matches!(err, crate::utils::HeaderValueErr::HeaderMissing(_)) - { + if self.optional && matches!(err, crate::utils::HeaderValueErr::HeaderMissing(_)) { tracing::debug!(error = %err, "failed to extract header config"); return self.inner.serve(ctx, request).await.map_err(Into::into); } else { @@ -175,7 +170,7 @@ where /// Layer which extracts a header config for the given HeaderName /// from a request or response and inserts it into the [`Extensions`] of that object. /// -/// [`Extensions`]: crate::context::Extensions +/// [`Extensions`]: rama_core::context::Extensions pub struct HeaderConfigLayer { header_name: HeaderName, optional: bool, diff --git a/rama-http/src/layer/header_option_value.rs b/rama-http/src/layer/header_option_value.rs index 700dde97..e5673835 100644 --- a/rama-http/src/layer/header_option_value.rs +++ b/rama-http/src/layer/header_option_value.rs @@ -3,15 +3,12 @@ //! the header with the given [`HeaderName`] is present //! and has a bool-like value. -use rama_utils::macros::define_inner_service_accessors; +use crate::{utils::HeaderValueGetter, HeaderName, Request}; use rama_core::{ - error::{ErrorExt, OpaqueError, BoxError}, + error::{BoxError, ErrorExt, OpaqueError}, Context, Layer, Service, }; -use crate::{ - HeaderName, - utils::HeaderValueGetter, Request, -}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, marker::PhantomData}; /// A [`Service`] which stores the [`Default`] value of type `T` in case @@ -113,9 +110,7 @@ where } } Err(err) => { - if self.optional - && matches!(err, crate::utils::HeaderValueErr::HeaderMissing(_)) - { + if self.optional && matches!(err, crate::utils::HeaderValueErr::HeaderMissing(_)) { tracing::debug!( error = %err, header_name = %self.header_name, diff --git a/rama-http/src/layer/map_request_body.rs b/rama-http/src/layer/map_request_body.rs index 15b35c9a..ba69fa6b 100644 --- a/rama-http/src/layer/map_request_body.rs +++ b/rama-http/src/layer/map_request_body.rs @@ -57,8 +57,8 @@ //! ``` use crate::{Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Apply a transformation to the request body. diff --git a/rama-http/src/layer/map_response_body.rs b/rama-http/src/layer/map_response_body.rs index 972d942b..f1ca5166 100644 --- a/rama-http/src/layer/map_response_body.rs +++ b/rama-http/src/layer/map_response_body.rs @@ -81,8 +81,8 @@ //! ``` use crate::{Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Apply a transformation to the response body. diff --git a/rama-http/src/layer/mod.rs b/rama-http/src/layer/mod.rs index 6c1da0b1..754d2be3 100644 --- a/rama-http/src/layer/mod.rs +++ b/rama-http/src/layer/mod.rs @@ -13,8 +13,8 @@ //! This is done to allow the layer to be used as a service, and to allow it to be //! composed with other layers. //! -//! [`Layer`]: crate::Layer -//! [`Service`]: crate::Service +//! [`Layer`]: rama_core::Layer +//! [`Service`]: rama_core::Service pub mod auth; pub mod body_limit; @@ -24,6 +24,7 @@ pub mod cors; pub mod dns; pub mod error_handling; pub mod follow_redirect; +pub mod forwarded; pub mod header_config; pub mod header_option_value; pub mod map_request_body; @@ -42,11 +43,8 @@ pub mod timeout; pub mod trace; pub mod traffic_writer; pub mod ua; -pub mod upgrade; pub mod validate_request; -pub use ::rama_http_types::layer::forwarded; - #[cfg(feature = "telemetry")] pub mod opentelemetry; diff --git a/rama-http/src/layer/normalize_path.rs b/rama-http/src/layer/normalize_path.rs index 8ef30b41..81e1ff3b 100644 --- a/rama-http/src/layer/normalize_path.rs +++ b/rama-http/src/layer/normalize_path.rs @@ -38,8 +38,8 @@ //! ``` use crate::{Request, Response, Uri}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::borrow::Cow; use std::fmt; use std::future::Future; @@ -171,7 +171,7 @@ fn normalize_trailing_slash(uri: &mut Uri) { mod tests { use super::*; use crate::service::service_fn; - use crate::Layer; + use rama_core::Layer; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/opentelemetry.rs b/rama-http/src/layer/opentelemetry.rs index bb34523d..7740c71c 100644 --- a/rama-http/src/layer/opentelemetry.rs +++ b/rama-http/src/layer/opentelemetry.rs @@ -1,26 +1,19 @@ //! Http OpenTelemetry [`Layer`] Support for Rama. //! -//! [`Layer`]: crate::Layer +//! [`Layer`]: rama_core::Layer -use rama_utils::macros::define_inner_service_accessors; use crate::{ - http::RequestContext, - telemetry::opentelemetry::{ - global, - metrics::{Histogram, Meter, UpDownCounter}, - semantic_conventions, KeyValue, - }, + headers::{ContentLength, HeaderMapExt, UserAgent}, + IntoResponse, Request, RequestContext, Response, }; -use crate::{ - http::{ - self, - headers::{HeaderMapExt, UserAgent}, - IntoResponse, Request, Response, - }, - stream::SocketInfo, - Context, Layer, Service, +use rama_core::telemetry::opentelemetry::{ + global, + metrics::{Histogram, Meter, UpDownCounter}, + semantic_conventions, KeyValue, }; -use headers::ContentLength; +use rama_core::{Context, Layer, Service}; +use rama_net::stream::SocketInfo; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, sync::Arc, time::SystemTime}; // Follows the experimental semantic conventions for HTTP metrics: diff --git a/rama-http/src/layer/propagate_headers.rs b/rama-http/src/layer/propagate_headers.rs index 86528378..138ba58b 100644 --- a/rama-http/src/layer/propagate_headers.rs +++ b/rama-http/src/layer/propagate_headers.rs @@ -36,8 +36,8 @@ //! ``` use crate::{header::HeaderName, Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; /// Layer that applies [`PropagateHeader`] which propagates headers from requests to responses. /// diff --git a/rama-http/src/layer/proxy_auth.rs b/rama-http/src/layer/proxy_auth.rs index e9b49705..afac23dc 100644 --- a/rama-http/src/layer/proxy_auth.rs +++ b/rama-http/src/layer/proxy_auth.rs @@ -5,9 +5,9 @@ use crate::header::PROXY_AUTHENTICATE; use crate::headers::{authorization::Credentials, HeaderMapExt, ProxyAuthorization}; use crate::{Request, Response, StatusCode}; -use rama_net::auth::Authority; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_net::user::auth::Authority; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; use std::marker::PhantomData; diff --git a/rama-http/src/layer/remove_header/request.rs b/rama-http/src/layer/remove_header/request.rs index 24761f0c..915c7080 100644 --- a/rama-http/src/layer/remove_header/request.rs +++ b/rama-http/src/layer/remove_header/request.rs @@ -29,8 +29,8 @@ //! ``` use crate::{HeaderName, Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{borrow::Cow, fmt, future::Future}; #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/remove_header/response.rs b/rama-http/src/layer/remove_header/response.rs index 05a21f2f..1c16563e 100644 --- a/rama-http/src/layer/remove_header/response.rs +++ b/rama-http/src/layer/remove_header/response.rs @@ -29,8 +29,8 @@ //! ``` use crate::{HeaderName, Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{borrow::Cow, fmt}; #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/request_id.rs b/rama-http/src/layer/request_id.rs index 7c2d065e..f35b4692 100644 --- a/rama-http/src/layer/request_id.rs +++ b/rama-http/src/layer/request_id.rs @@ -63,8 +63,8 @@ use crate::{ header::{HeaderName, HeaderValue}, Request, Response, }; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use uuid::Uuid; pub(crate) const X_REQUEST_ID: &str = "x-request-id"; @@ -388,9 +388,9 @@ impl MakeRequestId for MakeRequestUuid { #[cfg(test)] mod tests { use crate::layer::set_header; - use crate::{Body, Response}; use crate::service::service_fn; - use crate::Layer; + use crate::{Body, Response}; + use rama_core::Layer; use std::{ convert::Infallible, sync::{ diff --git a/rama-http/src/layer/required_header/request.rs b/rama-http/src/layer/required_header/request.rs index a7a011d3..f3d9e7bf 100644 --- a/rama-http/src/layer/required_header/request.rs +++ b/rama-http/src/layer/required_header/request.rs @@ -4,13 +4,15 @@ //! as well as always a User-Agent for all versions. use crate::{ - RequestContext, - header::{self, RAMA_ID_HEADER_VALUE, HOST, USER_AGENT}, + header::{self, HOST, RAMA_ID_HEADER_VALUE, USER_AGENT}, headers::HeaderMapExt, - Request, Response, + Request, RequestContext, Response, +}; +use rama_core::{ + error::{BoxError, ErrorContext}, + Context, Layer, Service, }; use rama_utils::macros::define_inner_service_accessors; -use rama_core::{Context, Layer, Service, error::{BoxError, ErrorContext}}; use std::fmt; /// Layer that applies [`AddRequiredRequestHeaders`] which adds a request header. @@ -149,8 +151,8 @@ where mod test { use super::*; use crate::{Body, Request}; - use crate::service::service_fn; - use crate::{Context, Layer, Service}; + use rama_core::service::service_fn; + use rama_core::{Context, Layer, Service}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/required_header/response.rs b/rama-http/src/layer/required_header/response.rs index 323681ab..e60f2cae 100644 --- a/rama-http/src/layer/required_header/response.rs +++ b/rama-http/src/layer/required_header/response.rs @@ -3,12 +3,12 @@ //! For now this only sets `Server` and `Date` heades. use crate::{ - header::{self, RAMA_ID_HEADER_VALUE, DATE, SERVER}, - Request, Response, + header::{self, DATE, RAMA_ID_HEADER_VALUE, SERVER}, headers::{Date, HeaderMapExt}, + Request, Response, }; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, time::SystemTime}; /// Layer that applies [`AddRequiredResponseHeaders`] which adds a request header. diff --git a/rama-http/src/layer/retry/body.rs b/rama-http/src/layer/retry/body.rs index 0d1ff2bd..5eefa01e 100644 --- a/rama-http/src/layer/retry/body.rs +++ b/rama-http/src/layer/retry/body.rs @@ -24,7 +24,7 @@ impl RetryBody { impl crate::dep::http_body::Body for RetryBody { type Data = Bytes; - type Error = crate::error::BoxError; + type Error = rama_core::error::BoxError; fn poll_frame( mut self: std::pin::Pin<&mut Self>, diff --git a/rama-http/src/layer/retry/layer.rs b/rama-http/src/layer/retry/layer.rs index 43aa917d..7d124045 100644 --- a/rama-http/src/layer/retry/layer.rs +++ b/rama-http/src/layer/retry/layer.rs @@ -1,5 +1,5 @@ use super::Retry; -use crate::Layer; +use rama_core::Layer; use std::fmt; /// Retry requests based on a policy diff --git a/rama-http/src/layer/retry/managed.rs b/rama-http/src/layer/retry/managed.rs index f599191e..c6dc8104 100644 --- a/rama-http/src/layer/retry/managed.rs +++ b/rama-http/src/layer/retry/managed.rs @@ -6,8 +6,8 @@ use super::{Policy, PolicyResult, RetryBody}; use crate::{Request, Response}; -use rama_utils::backoff::Backoff; use rama_core::Context; +use rama_utils::backoff::Backoff; use std::future::Future; #[derive(Debug, Clone, Default)] @@ -16,7 +16,7 @@ use std::future::Future; /// /// This requires the [`ManagedPolicy`] to be used. /// -/// [`Extensions`]: crate::context::Extensions +/// [`Extensions`]: rama_core::context::Extensions #[non_exhaustive] pub struct DoNotRetry; diff --git a/rama-http/src/layer/retry/mod.rs b/rama-http/src/layer/retry/mod.rs index 60cabb6f..f694ae4c 100644 --- a/rama-http/src/layer/retry/mod.rs +++ b/rama-http/src/layer/retry/mod.rs @@ -1,11 +1,11 @@ //! Middleware for retrying "failed" requests. -use rama_core::error::BoxError; use crate::dep::http_body::Body as HttpBody; use crate::dep::http_body_util::BodyExt; use crate::Request; -use rama_utils::macros::define_inner_service_accessors; +use rama_core::error::BoxError; use rama_core::{Context, Service}; +use rama_utils::macros::define_inner_service_accessors; mod layer; mod policy; @@ -233,7 +233,7 @@ mod test { let txt = req.try_into_string().await.unwrap(); match txt.as_str() { "internal" => Ok(StatusCode::INTERNAL_SERVER_ERROR.into_response()), - "error" => Err(crate::error::BoxError::from("custom error")), + "error" => Err(rama_core::error::BoxError::from("custom error")), _ => Ok(txt.into_response()), } }, diff --git a/rama-http/src/layer/retry/policy.rs b/rama-http/src/layer/retry/policy.rs index 6398b620..6117b9ba 100644 --- a/rama-http/src/layer/retry/policy.rs +++ b/rama-http/src/layer/retry/policy.rs @@ -82,8 +82,8 @@ pub trait Policy: Send + Sync + 'static { /// information about the number of retries required or to record that a /// failure failed after exhausting all retries. /// - /// [`Service::Response`]: crate::Service::Response - /// [`Service::Error`]: crate::Service::Error + /// [`Service::Response`]: rama_core::Service::Response + /// [`Service::Error`]: rama_core::Service::Error fn retry( &self, ctx: Context, @@ -159,7 +159,7 @@ where macro_rules! impl_retry_policy_either { ($id:ident, $($param:ident),+ $(,)?) => { - impl<$($param),+, State, Response, Error> Policy for crate::combinators::$id<$($param),+> + impl<$($param),+, State, Response, Error> Policy for rama_core::combinators::$id<$($param),+> where $($param: Policy),+, State: Send + Sync + 'static, @@ -174,7 +174,7 @@ macro_rules! impl_retry_policy_either { ) -> PolicyResult { match self { $( - crate::combinators::$id::$param(policy) => policy.retry(ctx, req, result).await, + rama_core::combinators::$id::$param(policy) => policy.retry(ctx, req, result).await, )+ } } @@ -186,7 +186,7 @@ macro_rules! impl_retry_policy_either { ) -> Option<(Context, http::Request)> { match self { $( - crate::combinators::$id::$param(policy) => policy.clone_input(ctx, req), + rama_core::combinators::$id::$param(policy) => policy.clone_input(ctx, req), )+ } } @@ -194,4 +194,4 @@ macro_rules! impl_retry_policy_either { }; } -crate::combinators::impl_either!(impl_retry_policy_either); +rama_core::combinators::impl_either!(impl_retry_policy_either); diff --git a/rama-http/src/layer/retry/tests.rs b/rama-http/src/layer/retry/tests.rs index f6c58a5b..eb3503ed 100644 --- a/rama-http/src/layer/retry/tests.rs +++ b/rama-http/src/layer/retry/tests.rs @@ -1,9 +1,9 @@ use super::*; -use crate::error::{error, OpaqueError}; use crate::{response::IntoResponse, BodyExtractExt}; -use crate::{Request, Response}; use crate::{Layer, Service}; +use crate::{Request, Response}; use parking_lot::Mutex; +use rama_core::error::{error, OpaqueError}; use std::sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, @@ -225,7 +225,7 @@ async fn retry_mutating_policy() { type State = (); type InnerError = &'static str; -type Error = crate::error::OpaqueError; +type Error = rama_core::error::OpaqueError; fn request(s: &'static str) -> Request { Request::builder() diff --git a/rama-http/src/layer/sensitive_headers.rs b/rama-http/src/layer/sensitive_headers.rs index 21b43a60..813f78f2 100644 --- a/rama-http/src/layer/sensitive_headers.rs +++ b/rama-http/src/layer/sensitive_headers.rs @@ -39,8 +39,8 @@ //! ``` use crate::{HeaderName, Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::sync::Arc; /// Mark headers as [sensitive] on both requests and responses. diff --git a/rama-http/src/layer/set_header/request.rs b/rama-http/src/layer/set_header/request.rs index d95385f2..01ac926e 100644 --- a/rama-http/src/layer/set_header/request.rs +++ b/rama-http/src/layer/set_header/request.rs @@ -84,10 +84,10 @@ use super::{BoxMakeHeaderValueFn, InsertHeaderMode, MakeHeaderValue}; use crate::{ header::HeaderName, headers::{Header, HeaderExt}, - Request, Response, HeaderValue + HeaderValue, Request, Response, }; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Layer that applies [`SetRequestHeader`] which adds a request header. diff --git a/rama-http/src/layer/set_header/response.rs b/rama-http/src/layer/set_header/response.rs index f489125a..842f824e 100644 --- a/rama-http/src/layer/set_header/response.rs +++ b/rama-http/src/layer/set_header/response.rs @@ -97,8 +97,8 @@ use crate::{ headers::{Header, HeaderExt}, HeaderValue, Request, Response, }; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Layer that applies [`SetResponseHeader`] which adds a response header. @@ -366,8 +366,8 @@ where mod tests { use super::*; - use crate::{header, Body, HeaderValue, Request, Response}; use crate::service::service_fn; + use crate::{header, Body, HeaderValue, Request, Response}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/set_status.rs b/rama-http/src/layer/set_status.rs index 84e3c3b0..0a2b877a 100644 --- a/rama-http/src/layer/set_status.rs +++ b/rama-http/src/layer/set_status.rs @@ -37,8 +37,8 @@ use std::fmt; use crate::{Request, Response, StatusCode}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; /// Layer that applies [`SetStatus`] which overrides the status codes. #[derive(Debug, Clone)] diff --git a/rama-http/src/layer/timeout.rs b/rama-http/src/layer/timeout.rs index b0a81292..bf38b015 100644 --- a/rama-http/src/layer/timeout.rs +++ b/rama-http/src/layer/timeout.rs @@ -6,7 +6,7 @@ //! # Differences from `rama::service::layer::Timeout` //! //! The generic [`Timeout`](crate::layer::timeout::Timeout) middleware uses an error to signal timeout, i.e. -//! it changes the error type to [`BoxError`](crate::error::BoxError). For HTTP services that is rarely +//! it changes the error type to [`BoxError`](rama_core::error::BoxError). For HTTP services that is rarely //! what you want as returning errors will terminate the connection without sending a response. //! //! This middleware won't change the error type and instead return a `408 Request Timeout` @@ -41,11 +41,11 @@ //! //! [`Infallible`]: std::convert::Infallible -use std::fmt; -use std::time::Duration; use crate::{Request, Response, StatusCode}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; +use std::fmt; +use std::time::Duration; /// Layer that applies the [`Timeout`] middleware which apply a timeout to requests. /// diff --git a/rama-http/src/layer/trace/layer.rs b/rama-http/src/layer/trace/layer.rs index 83d25503..36f82672 100644 --- a/rama-http/src/layer/trace/layer.rs +++ b/rama-http/src/layer/trace/layer.rs @@ -1,4 +1,3 @@ -use std::fmt; use super::{ DefaultMakeSpan, DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, GrpcMakeClassifier, HttpMakeClassifier, Trace, @@ -7,14 +6,15 @@ use crate::layer::classify::{ GrpcErrorsAsFailures, MakeClassifier, ServerErrorsAsFailures, SharedClassifier, }; use rama_core::Layer; +use std::fmt; /// [`Layer`] that adds high level [tracing] to a [`Service`]. /// /// See the [module docs](crate::layer::trace) for more details. /// -/// [`Layer`]: crate::Layer +/// [`Layer`]: rama_core::Layer /// [tracing]: https://crates.io/crates/tracing -/// [`Service`]: crate::Service +/// [`Service`]: rama_core::Service pub struct TraceLayer< M, MakeSpan = DefaultMakeSpan, diff --git a/rama-http/src/layer/trace/mod.rs b/rama-http/src/layer/trace/mod.rs index bd424ac8..5d7f7a50 100644 --- a/rama-http/src/layer/trace/mod.rs +++ b/rama-http/src/layer/trace/mod.rs @@ -460,13 +460,13 @@ impl fmt::Display for Latency { mod tests { use super::*; - use crate::error::BoxError; use crate::dep::http_body_util::BodyExt as _; use crate::layer::classify::ServerErrorsFailureClass; use crate::{Body, HeaderMap, Request, Response}; - use crate::service::service_fn; - use crate::{Context, Layer, Service}; use bytes::Bytes; + use rama_core::error::BoxError; + use rama_core::service::service_fn; + use rama_core::{Context, Layer, Service}; use std::sync::OnceLock; use std::{ sync::atomic::{AtomicU32, Ordering}, diff --git a/rama-http/src/layer/trace/service.rs b/rama-http/src/layer/trace/service.rs index d88fd8f3..755f3f48 100644 --- a/rama-http/src/layer/trace/service.rs +++ b/rama-http/src/layer/trace/service.rs @@ -9,8 +9,8 @@ use crate::layer::classify::{ ServerErrorsAsFailures, SharedClassifier, }; use crate::{Request, Response}; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, time::Instant}; /// Middleware that adds high level [tracing] to a [`Service`]. diff --git a/rama-http/src/layer/traffic_writer/request.rs b/rama-http/src/layer/traffic_writer/request.rs index 405adac2..7842a0ac 100644 --- a/rama-http/src/layer/traffic_writer/request.rs +++ b/rama-http/src/layer/traffic_writer/request.rs @@ -1,13 +1,13 @@ use super::WriterMode; -use rama_core::error::{BoxError, ErrorExt, OpaqueError}; use crate::dep::http_body; use crate::dep::http_body_util::BodyExt; use crate::io::write_http_request; use crate::{Body, Request, Response}; +use bytes::Bytes; +use rama_core::error::{BoxError, ErrorExt, OpaqueError}; use rama_core::rt::Executor; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; -use bytes::Bytes; +use rama_utils::macros::define_inner_service_accessors; use std::fmt::Debug; use std::future::Future; use tokio::io::{stderr, stdout, AsyncWrite, AsyncWriteExt}; diff --git a/rama-http/src/layer/traffic_writer/response.rs b/rama-http/src/layer/traffic_writer/response.rs index ea03c5c3..fff4bcba 100644 --- a/rama-http/src/layer/traffic_writer/response.rs +++ b/rama-http/src/layer/traffic_writer/response.rs @@ -1,13 +1,13 @@ use super::WriterMode; -use rama_core::error::{BoxError, ErrorContext, OpaqueError}; use crate::dep::http_body; use crate::dep::http_body_util::BodyExt; use crate::io::write_http_response; use crate::{Body, Request, Response}; +use bytes::Bytes; +use rama_core::error::{BoxError, ErrorContext, OpaqueError}; use rama_core::rt::Executor; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{Context, Layer, Service}; -use bytes::Bytes; +use rama_utils::macros::define_inner_service_accessors; use std::fmt::Debug; use std::future::Future; use tokio::io::{stderr, stdout, AsyncWrite}; diff --git a/rama-http/src/layer/ua.rs b/rama-http/src/layer/ua.rs index 32103433..f3218c3e 100644 --- a/rama-http/src/layer/ua.rs +++ b/rama-http/src/layer/ua.rs @@ -35,12 +35,12 @@ //! # } //! ``` -use rama_utils::macros::define_inner_service_accessors; use crate::{ headers::{self, HeaderMapExt}, HeaderName, Request, }; -use rama_core::{Layer, Service}; +use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use serde::{Deserialize, Serialize}; use std::{ fmt::{self, Debug}, @@ -57,8 +57,8 @@ pub use rama_ua::{ /// The [`Extensions`] of the [`Context`] is updated with the [`UserAgent`] /// if the [`Request`] contains a valid [`UserAgent`] header. /// -/// [`Extensions`]: crate::context::Extensions -/// [`Context`]: crate::Context +/// [`Extensions`]: rama_core::context::Extensions +/// [`Context`]: rama_core::Context pub struct UserAgentClassifier { inner: S, overwrite_header: Option, @@ -121,7 +121,7 @@ where fn serve( &self, - mut ctx: crate::Context, + mut ctx: Context, req: Request, ) -> impl Future> + Send + '_ { let mut user_agent = req @@ -205,10 +205,10 @@ mod tests { use crate::client::HttpClientExt; use crate::headers; use crate::layer::required_header::AddRequiredRequestHeadersLayer; - use crate::{IntoResponse, StatusCode}; use crate::service::service_fn; use crate::ua::{PlatformKind, UserAgentKind}; use crate::{http::Response, Context}; + use crate::{IntoResponse, StatusCode}; use std::convert::Infallible; #[tokio::test] @@ -218,12 +218,7 @@ mod tests { assert_eq!( ua.header_str(), - format!( - "{}/{}", - rama_utils::info::NAME, - rama_utils::info::VERSION - ) - .as_str(), + format!("{}/{}", rama_utils::info::NAME, rama_utils::info::VERSION).as_str(), ); assert!(ua.info().is_none()); assert!(ua.platform().is_none()); diff --git a/rama-http/src/layer/util/compression.rs b/rama-http/src/layer/util/compression.rs index 26b24420..289fb945 100644 --- a/rama-http/src/layer/util/compression.rs +++ b/rama-http/src/layer/util/compression.rs @@ -1,9 +1,13 @@ //! Types used by compression and decompression middleware. +use super::content_encoding::SupportedEncodings; +use crate::dep::http_body::{Body, Frame}; +use crate::HeaderValue; use bytes::{Buf, Bytes, BytesMut}; use futures_lite::ready; use futures_lite::Stream; use pin_project_lite::pin_project; +use rama_core::error::BoxError; use std::{ io, pin::Pin, @@ -11,10 +15,6 @@ use std::{ }; use tokio::io::AsyncRead; use tokio_util::io::StreamReader; -use super::content_encoding::SupportedEncodings; -use rama_core::error::BoxError; -use crate::dep::http_body::{Body, Frame}; -use crate::HeaderValue; #[derive(Debug, Clone, Copy)] pub(crate) struct AcceptEncoding { diff --git a/rama-http/src/layer/validate_request/validate_request_header.rs b/rama-http/src/layer/validate_request/validate_request_header.rs index 475cc078..e40911b5 100644 --- a/rama-http/src/layer/validate_request/validate_request_header.rs +++ b/rama-http/src/layer/validate_request/validate_request_header.rs @@ -1,7 +1,7 @@ use super::{AcceptHeader, BoxValidateRequestFn, ValidateRequest}; -use rama_utils::macros::define_inner_service_accessors; use crate::{Request, Response}; use rama_core::{Context, Layer, Service}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// Layer that applies [`ValidateRequestHeader`] which validates all requests. @@ -185,8 +185,8 @@ mod tests { #[allow(unused_imports)] use super::*; - use crate::{header, Body, StatusCode}; use crate::{error::BoxError, service::service_fn, Layer}; + use crate::{header, Body, StatusCode}; #[tokio::test] async fn valid_accept_header() { diff --git a/rama-http/src/lib.rs b/rama-http/src/lib.rs index fc52768f..07b59e14 100644 --- a/rama-http/src/lib.rs +++ b/rama-http/src/lib.rs @@ -55,25 +55,20 @@ #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] pub use ::rama_http_types::{ - header, headers, + header, response::{self, IntoResponse, Response}, - Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, - Method, Request, Scheme, StatusCode, Uri, Version, + Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, Method, + Request, Scheme, StatusCode, Uri, Version, }; +pub mod headers; pub mod matcher; pub mod layer; pub mod service; -pub mod server; - -pub mod client; - pub mod io; -pub mod executor; - #[doc(hidden)] mod utils; @@ -84,7 +79,3 @@ pub mod dep { pub use ::rama_http_types::dep::{http, http_body, http_body_util, mime, mime_guess}; } - -mod request_context; -#[doc(inline)] -pub use request_context::RequestContext; diff --git a/rama-http/src/matcher/domain.rs b/rama-http/src/matcher/domain.rs index 7a02afce..b0b349d5 100644 --- a/rama-http/src/matcher/domain.rs +++ b/rama-http/src/matcher/domain.rs @@ -1,8 +1,5 @@ -use rama_core::{ - context::Extensions, - Context, -}; use crate::{Request, RequestContext}; +use rama_core::{context::Extensions, Context}; use rama_net::address::{Domain, Host}; #[derive(Debug, Clone)] @@ -28,7 +25,7 @@ impl DomainMatcher { } } -impl crate::matcher::Matcher> for DomainMatcher { +impl rama_core::matcher::Matcher> for DomainMatcher { fn matches( &self, ext: Option<&mut Extensions>, diff --git a/rama-http/src/matcher/header.rs b/rama-http/src/matcher/header.rs index 5ece5ed8..7695e691 100644 --- a/rama-http/src/matcher/header.rs +++ b/rama-http/src/matcher/header.rs @@ -1,9 +1,5 @@ -use rama_core::{ - context::Extensions, - matcher::Matcher, - Context, -}; use crate::{HeaderName, HeaderValue, Request}; +use rama_core::{context::Extensions, matcher::Matcher, Context}; #[derive(Debug, Clone)] /// Matcher based on the [`Request`]'s headers. diff --git a/rama-http/src/matcher/method.rs b/rama-http/src/matcher/method.rs index 48713890..27324474 100644 --- a/rama-http/src/matcher/method.rs +++ b/rama-http/src/matcher/method.rs @@ -1,8 +1,5 @@ -use rama_core::{ - context::Extensions, - Context, -}; use crate::{Method, Request}; +use rama_core::{context::Extensions, Context}; use std::{ fmt, fmt::{Debug, Formatter}, @@ -51,7 +48,7 @@ impl MethodMatcher { } } -impl crate::matcher::Matcher> for MethodMatcher { +impl rama_core::matcher::Matcher> for MethodMatcher { /// returns true on a match, false otherwise fn matches( &self, diff --git a/rama-http/src/matcher/mod.rs b/rama-http/src/matcher/mod.rs index 627b3749..a1316501 100644 --- a/rama-http/src/matcher/mod.rs +++ b/rama-http/src/matcher/mod.rs @@ -2,17 +2,12 @@ //! //! See [`service::matcher` module] for more information. //! -//! [`service::Matcher`]: crate::matcher::Matcher +//! [`service::Matcher`]: rama_core::matcher::Matcher //! [`http::Request`]: crate::Request -//! [`service::matcher` module]: crate::matcher -use rama_core::{ - context::Extensions, matcher::IteratorMatcherExt, Context, -}; -use rama_net::{ - address::Domain, - stream::matcher::SocketMatcher, -}; +//! [`service::matcher` module]: rama_core use crate::Request; +use rama_core::{context::Extensions, matcher::IteratorMatcherExt, Context}; +use rama_net::{address::Domain, stream::matcher::SocketMatcher}; use std::fmt; use std::sync::Arc; @@ -85,8 +80,8 @@ pub enum HttpMatcherKind { /// /// [`SocketAddr`]: std::net::SocketAddr Socket(SocketMatcher>), - /// A custom matcher that implements [`crate::matcher::Matcher`]. - Custom(Arc>>), + /// A custom matcher that implements [`rama_core::matcher::Matcher`]. + Custom(Arc>>), } impl Clone for HttpMatcherKind { @@ -578,10 +573,10 @@ impl HttpMatcher { /// Create a matcher that matches according to a custom predicate. /// - /// See [`crate::matcher::Matcher`] for more information. + /// See [`rama_core::matcher::Matcher`] for more information. pub fn custom(matcher: M) -> Self where - M: crate::matcher::Matcher>, + M: rama_core::matcher::Matcher>, { Self { kind: HttpMatcherKind::Custom(Arc::new(matcher)), @@ -591,20 +586,20 @@ impl HttpMatcher { /// Add a custom matcher to match on top of the existing set of [`HttpMatcher`] matchers. /// - /// See [`crate::matcher::Matcher`] for more information. + /// See [`rama_core::matcher::Matcher`] for more information. pub fn and_custom(self, matcher: M) -> Self where - M: crate::matcher::Matcher>, + M: rama_core::matcher::Matcher>, { self.and(Self::custom(matcher)) } /// Create a custom matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers. /// - /// See [`crate::matcher::Matcher`] for more information. + /// See [`rama_core::matcher::Matcher`] for more information. pub fn or_custom(self, matcher: M) -> Self where - M: crate::matcher::Matcher>, + M: rama_core::matcher::Matcher>, { self.or(Self::custom(matcher)) } @@ -681,7 +676,7 @@ impl HttpMatcher { } } -impl crate::matcher::Matcher> for HttpMatcher +impl rama_core::matcher::Matcher> for HttpMatcher where State: Send + Sync + 'static, Body: Send + 'static, @@ -701,7 +696,7 @@ where } } -impl crate::matcher::Matcher> for HttpMatcherKind +impl rama_core::matcher::Matcher> for HttpMatcherKind where State: Send + Sync + 'static, Body: Send + 'static, @@ -731,7 +726,7 @@ where mod test { use itertools::Itertools; - use crate::matcher::Matcher; + use rama_core::matcher::Matcher; use super::*; diff --git a/rama-http/src/matcher/path/mod.rs b/rama-http/src/matcher/path/mod.rs index 2c21b062..678b1a4d 100644 --- a/rama-http/src/matcher/path/mod.rs +++ b/rama-http/src/matcher/path/mod.rs @@ -1,8 +1,5 @@ -use rama_core::{ - context::Extensions, - Context, -}; use crate::{IntoResponse, Request, StatusCode}; +use rama_core::{context::Extensions, Context}; use std::collections::HashMap; mod de; @@ -75,7 +72,7 @@ pub struct UriParamsDeserializeError(de::PathDeserializationError); impl UriParamsDeserializeError { /// Get the response body text used for this rejection. pub fn body_text(&self) -> String { - use crate::matcher::path::de::ErrorKind; + use de::ErrorKind; match self.0.kind { ErrorKind::Message(_) | ErrorKind::NoParams @@ -90,7 +87,7 @@ impl UriParamsDeserializeError { /// Get the status code used for this rejection. pub fn status(&self) -> StatusCode { - use crate::matcher::path::de::ErrorKind; + use de::ErrorKind; match self.0.kind { ErrorKind::Message(_) | ErrorKind::NoParams @@ -114,7 +111,7 @@ impl std::error::Error for UriParamsDeserializeError {} impl IntoResponse for UriParamsDeserializeError { fn into_response(self) -> crate::Response { - rama_utils::macros::log_http_rejection!( + crate::utils::macros::log_http_rejection!( rejection_type = UriParamsDeserializeError, body_text = self.body_text(), status = self.status(), @@ -245,7 +242,7 @@ impl PathMatcher { } } -impl crate::matcher::Matcher> for PathMatcher { +impl rama_core::matcher::Matcher> for PathMatcher { fn matches( &self, ext: Option<&mut Extensions>, diff --git a/rama-http/src/matcher/uri.rs b/rama-http/src/matcher/uri.rs index c4ff671f..aebea13e 100644 --- a/rama-http/src/matcher/uri.rs +++ b/rama-http/src/matcher/uri.rs @@ -1,10 +1,7 @@ //! provides a [`UriMatcher`] matcher for matching requests based on their URI. -use rama_core::{ - context::Extensions, - Context, -}; use crate::{Request, Uri}; +use rama_core::{context::Extensions, Context}; pub mod dep { //! dependencies for the `uri` matcher module @@ -45,7 +42,7 @@ impl From for UriMatcher { } } -impl crate::matcher::Matcher> for UriMatcher { +impl rama_core::matcher::Matcher> for UriMatcher { fn matches( &self, _ext: Option<&mut Extensions>, diff --git a/rama-http/src/matcher/version.rs b/rama-http/src/matcher/version.rs index 98ec4bdf..71edef4c 100644 --- a/rama-http/src/matcher/version.rs +++ b/rama-http/src/matcher/version.rs @@ -1,8 +1,5 @@ -use rama_core::{ - context::Extensions, - Context, -}; use crate::{Request, Version}; +use rama_core::{context::Extensions, Context}; use std::fmt::{self, Debug, Formatter}; /// A matcher that matches one or more HTTP methods. @@ -44,7 +41,7 @@ impl VersionMatcher { } } -impl crate::matcher::Matcher> for VersionMatcher { +impl rama_core::matcher::Matcher> for VersionMatcher { /// returns true on a match, false otherwise fn matches( &self, @@ -98,7 +95,7 @@ impl TryFrom for VersionMatcher { #[cfg(test)] mod test { use super::*; - use crate::matcher::Matcher; + use rama_core::matcher::Matcher; #[test] fn test_version_matcher() { diff --git a/rama-http/src/service/fs/serve_dir/future.rs b/rama-http/src/service/fs/serve_dir/future.rs index 9744c5a3..83754434 100644 --- a/rama-http/src/service/fs/serve_dir/future.rs +++ b/rama-http/src/service/fs/serve_dir/future.rs @@ -1,15 +1,13 @@ use super::open_file::{FileOpened, FileRequestExtent, OpenFileOutput}; use crate::{ + dep::http_body_util::BodyExt, header::{self, ALLOW}, - Body, HeaderValue, Request, Response, StatusCode, layer::util::content_encoding::Encoding, service::fs::AsyncReadBody, - dep::http_body_util::BodyExt, -}; -use rama_core::{ - error::BoxError, Service, + Body, HeaderValue, Request, Response, StatusCode, }; use bytes::Bytes; +use rama_core::{error::BoxError, Context, Service}; use std::{convert::Infallible, io}; pub(super) async fn consume_open_file_result( diff --git a/rama-http/src/service/fs/serve_dir/mod.rs b/rama-http/src/service/fs/serve_dir/mod.rs index 7d280906..c9e912dd 100644 --- a/rama-http/src/service/fs/serve_dir/mod.rs +++ b/rama-http/src/service/fs/serve_dir/mod.rs @@ -1,13 +1,13 @@ -use rama_core::error::BoxError; use crate::dep::http_body::Body as HttpBody; use crate::layer::{ set_status::SetStatus, util::content_encoding::{encodings, SupportedEncodings}, }; use crate::{header, Body, HeaderValue, Method, Request, Response, StatusCode}; -use rama_core::{Context, Service}; use bytes::Bytes; use percent_encoding::percent_decode; +use rama_core::error::BoxError; +use rama_core::{Context, Service}; use std::{ convert::Infallible, path::{Component, Path, PathBuf}, diff --git a/rama-http/src/service/fs/serve_dir/tests.rs b/rama-http/src/service/fs/serve_dir/tests.rs index e6493bea..954859c1 100644 --- a/rama-http/src/service/fs/serve_dir/tests.rs +++ b/rama-http/src/service/fs/serve_dir/tests.rs @@ -5,11 +5,11 @@ use crate::service::fs::{ServeDir, ServeFile}; use crate::Body; use crate::{header, Method, Response}; use crate::{Request, StatusCode}; -use crate::service::service_fn; -use crate::{Context, Service}; use brotli::BrotliDecompress; use bytes::Bytes; use flate2::bufread::{DeflateDecoder, GzDecoder}; +use rama_core::service::service_fn; +use rama_core::{Context, Service}; use std::convert::Infallible; use std::io::Read; diff --git a/rama-http/src/service/fs/serve_file.rs b/rama-http/src/service/fs/serve_file.rs index f1540f4c..e78e462e 100644 --- a/rama-http/src/service/fs/serve_file.rs +++ b/rama-http/src/service/fs/serve_file.rs @@ -178,10 +178,10 @@ mod tests { use crate::Body; use crate::Method; use crate::{Request, StatusCode}; - use crate::{Context, Service}; use brotli::BrotliDecompress; use flate2::bufread::DeflateDecoder; use flate2::bufread::GzDecoder; + use rama_core::{Context, Service}; use std::io::Read; use std::str::FromStr; diff --git a/rama-http/src/service/web/endpoint/extract/authority.rs b/rama-http/src/service/web/endpoint/extract/authority.rs index 2e4e39b7..9b9642e4 100644 --- a/rama-http/src/service/web/endpoint/extract/authority.rs +++ b/rama-http/src/service/web/endpoint/extract/authority.rs @@ -1,10 +1,10 @@ use super::FromRequestParts; use crate::dep::http::request::Parts; +use crate::utils::macros::define_http_rejection; use crate::RequestContext; +use rama_core::Context; use rama_net::address; use rama_utils::macros::impl_deref; -use crate::utils::macros::define_http_rejection; -use rama_core::Context; /// Extractor that resolves the authority of the request. /// @@ -56,9 +56,9 @@ mod tests { use crate::header::X_FORWARDED_HOST; use crate::layer::forwarded::GetForwardedHeadersService; use crate::service::web::WebService; + use crate::Service; use crate::StatusCode; use crate::{Body, HeaderName, Request}; - use crate::Service; async fn test_authority_from_request(authority: &str, headers: Vec<(&HeaderName, &str)>) { let svc = GetForwardedHeadersService::x_forwarded_host( diff --git a/rama-http/src/service/web/endpoint/extract/body/bytes.rs b/rama-http/src/service/web/endpoint/extract/body/bytes.rs index 336a575e..41eb2ea7 100644 --- a/rama-http/src/service/web/endpoint/extract/body/bytes.rs +++ b/rama-http/src/service/web/endpoint/extract/body/bytes.rs @@ -1,9 +1,9 @@ use crate::dep::http_body_util::BodyExt; use crate::service::web::extract::FromRequest; -use crate::Request; -use rama_utils::macros::impl_deref; use crate::utils::macros::define_http_rejection; +use crate::Request; use rama_core::Context; +use rama_utils::macros::impl_deref; /// Extractor to get the response body, collected as [`Bytes`]. /// diff --git a/rama-http/src/service/web/endpoint/extract/body/form.rs b/rama-http/src/service/web/endpoint/extract/body/form.rs index eeb1b0c3..8a6eadf8 100644 --- a/rama-http/src/service/web/endpoint/extract/body/form.rs +++ b/rama-http/src/service/web/endpoint/extract/body/form.rs @@ -1,8 +1,8 @@ use super::BytesRejection; use crate::dep::http_body_util::BodyExt; use crate::service::web::extract::FromRequest; -use crate::{Method, Request}; use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use crate::{Method, Request}; use rama_core::Context; pub use crate::response::Form; diff --git a/rama-http/src/service/web/endpoint/extract/body/json.rs b/rama-http/src/service/web/endpoint/extract/body/json.rs index 33225174..b2f31098 100644 --- a/rama-http/src/service/web/endpoint/extract/body/json.rs +++ b/rama-http/src/service/web/endpoint/extract/body/json.rs @@ -1,8 +1,8 @@ use super::BytesRejection; use crate::dep::http_body_util::BodyExt; use crate::service::web::extract::FromRequest; -use crate::Request; use crate::utils::macros::{composite_http_rejection, define_http_rejection}; +use crate::Request; use rama_core::Context; pub use crate::response::Json; diff --git a/rama-http/src/service/web/endpoint/extract/body/mod.rs b/rama-http/src/service/web/endpoint/extract/body/mod.rs index b029a987..048a4dae 100644 --- a/rama-http/src/service/web/endpoint/extract/body/mod.rs +++ b/rama-http/src/service/web/endpoint/extract/body/mod.rs @@ -1,6 +1,7 @@ use super::FromRequest; -use rama_utils::macros::impl_deref; use rama_core::Context; +use rama_http_types as http; +use rama_utils::macros::impl_deref; use std::convert::Infallible; mod bytes; diff --git a/rama-http/src/service/web/endpoint/extract/body/text.rs b/rama-http/src/service/web/endpoint/extract/body/text.rs index b64a4323..a3fdb50e 100644 --- a/rama-http/src/service/web/endpoint/extract/body/text.rs +++ b/rama-http/src/service/web/endpoint/extract/body/text.rs @@ -1,9 +1,10 @@ use super::BytesRejection; use crate::dep::http_body_util::BodyExt; use crate::service::web::extract::FromRequest; +use crate::utils::macros::{composite_http_rejection, define_http_rejection}; use crate::Request; -use rama_utils::macros::{composite_http_rejection, define_http_rejection, impl_deref}; use rama_core::Context; +use rama_utils::macros::impl_deref; /// Extractor to get the response body, collected as [`String`]. #[derive(Debug, Clone)] @@ -47,10 +48,8 @@ where type Rejection = TextRejection; async fn from_request(_ctx: Context, req: Request) -> Result { - if !crate::service::web::extract::has_any_content_type( - req.headers(), - &[&mime::TEXT_PLAIN], - ) { + if !crate::service::web::extract::has_any_content_type(req.headers(), &[&mime::TEXT_PLAIN]) + { return Err(InvalidTextContentType.into()); } diff --git a/rama-http/src/service/web/endpoint/extract/dns.rs b/rama-http/src/service/web/endpoint/extract/dns.rs index d180f090..e1d9ff8d 100644 --- a/rama-http/src/service/web/endpoint/extract/dns.rs +++ b/rama-http/src/service/web/endpoint/extract/dns.rs @@ -8,8 +8,8 @@ use std::ops::Deref; /// Extractor to get a clone of the [`Dns`] from the [`Context`]. /// /// [`Dns`]: crate::dns::Dns -/// [`Context`]: crate::Context -pub struct Dns(pub crate::dns::Dns); +/// [`Context`]: rama_core::Context +pub struct Dns(pub rama_core::dns::Dns); impl FromRequestParts for Dns where @@ -23,7 +23,7 @@ where } impl Deref for Dns { - type Target = crate::dns::Dns; + type Target = rama_core::dns::Dns; fn deref(&self) -> &Self::Target { &self.0 diff --git a/rama-http/src/service/web/endpoint/extract/host.rs b/rama-http/src/service/web/endpoint/extract/host.rs index e1f7e991..509c0edb 100644 --- a/rama-http/src/service/web/endpoint/extract/host.rs +++ b/rama-http/src/service/web/endpoint/extract/host.rs @@ -1,10 +1,10 @@ use super::FromRequestParts; use crate::dep::http::request::Parts; +use crate::utils::macros::define_http_rejection; use crate::RequestContext; +use rama_core::Context; use rama_net::address; use rama_utils::macros::impl_deref; -use crate::utils::macros::define_http_rejection; -use rama_core::Context; /// Extractor that resolves the hostname of the request. /// @@ -57,9 +57,9 @@ mod tests { use crate::header::X_FORWARDED_HOST; use crate::layer::forwarded::GetForwardedHeadersService; use crate::service::web::WebService; + use crate::Service; use crate::StatusCode; use crate::{Body, HeaderName, Request}; - use crate::Service; async fn test_host_from_request(host: &str, headers: Vec<(&HeaderName, &str)>) { let svc = GetForwardedHeadersService::x_forwarded_host( diff --git a/rama-http/src/service/web/endpoint/extract/mod.rs b/rama-http/src/service/web/endpoint/extract/mod.rs index d2254257..2eb929e4 100644 --- a/rama-http/src/service/web/endpoint/extract/mod.rs +++ b/rama-http/src/service/web/endpoint/extract/mod.rs @@ -1,6 +1,6 @@ //! Extract utilities to develop endpoint services efortless. -use crate::{self, dep::http::request::Parts, dep::mime, header, HeaderMap, IntoResponse}; +use crate::{dep::http::request::Parts, dep::mime, header, HeaderMap, IntoResponse}; use rama_core::Context; use std::future::Future; @@ -86,7 +86,7 @@ pub trait FromRequest: Sized + Send + Sync + 'static /// Perform the extraction. fn from_request( ctx: Context, - req: http::Request, + req: crate::Request, ) -> impl Future> + Send; } @@ -97,7 +97,7 @@ where { type Rejection = >::Rejection; - async fn from_request(ctx: Context, req: http::Request) -> Result { + async fn from_request(ctx: Context, req: crate::Request) -> Result { let (parts, _) = req.into_parts(); Self::from_request_parts(&ctx, &parts).await } diff --git a/rama-http/src/service/web/endpoint/extract/path.rs b/rama-http/src/service/web/endpoint/extract/path.rs index b1b3a338..4c1d8d4a 100644 --- a/rama-http/src/service/web/endpoint/extract/path.rs +++ b/rama-http/src/service/web/endpoint/extract/path.rs @@ -77,7 +77,7 @@ mod tests { use crate::service::web::WebService; use crate::{Body, Request, StatusCode}; - use crate::Service; + use rama_core::Service; #[tokio::test] async fn test_host_from_request() { diff --git a/rama-http/src/service/web/endpoint/mod.rs b/rama-http/src/service/web/endpoint/mod.rs index 7a79aa7f..689c2763 100644 --- a/rama-http/src/service/web/endpoint/mod.rs +++ b/rama-http/src/service/web/endpoint/mod.rs @@ -1,9 +1,5 @@ use crate::{matcher::HttpMatcher, Body, IntoResponse, Request, Response}; -use rama_core::{ - Context, Layer, Service, - service::BoxService, - layer::MapResponseLayer, -}; +use rama_core::{layer::MapResponseLayer, service::BoxService, Context, Layer, Service}; use std::future::Future; use std::{convert::Infallible, fmt}; diff --git a/rama-http/src/service/web/endpoint/service.rs b/rama-http/src/service/web/endpoint/service.rs index e3b0d71d..b9555153 100644 --- a/rama-http/src/service/web/endpoint/service.rs +++ b/rama-http/src/service/web/endpoint/service.rs @@ -1,8 +1,8 @@ -use std::future::Future; use super::extract::{FromRequest, FromRequestParts}; -use rama_utils::macros::all_the_tuples_no_last_special_case; use crate::{IntoResponse, Request, Response}; use rama_core::Context; +use rama_utils::macros::all_the_tuples_no_last_special_case; +use std::future::Future; /// [`crate::Service`] implemented for functions taking extractors. pub trait EndpointServiceFn: private::Sealed + Clone + Send + Sync + 'static { diff --git a/rama-http/src/service/web/k8s.rs b/rama-http/src/service/web/k8s.rs index 636a8159..f037caf0 100644 --- a/rama-http/src/service/web/k8s.rs +++ b/rama-http/src/service/web/k8s.rs @@ -1,14 +1,11 @@ //! k8s web service -use crate::{ - StatusCode, - matcher::HttpMatcher, IntoResponse, Request, Response, -}; -use std::{convert::Infallible, fmt, marker::PhantomData, sync::Arc}; +use crate::{matcher::HttpMatcher, IntoResponse, Request, Response, StatusCode}; use rama_core::{ service::{service_fn, BoxService}, Context, Service, }; +use std::{convert::Infallible, fmt, marker::PhantomData, sync::Arc}; use super::match_service; diff --git a/rama-http/src/service/web/service.rs b/rama-http/src/service/web/service.rs index f2599aaa..8fce9abc 100644 --- a/rama-http/src/service/web/service.rs +++ b/rama-http/src/service/web/service.rs @@ -5,9 +5,9 @@ use crate::{ Body, IntoResponse, Request, Response, StatusCode, Uri, }; use rama_core::{ - service::{service_fn, BoxService, Service}, - matcher::Matcher, context::Extensions, + matcher::Matcher, + service::{service_fn, BoxService, Service}, Context, }; use std::{convert::Infallible, fmt, future::Future, marker::PhantomData, sync::Arc}; @@ -332,8 +332,8 @@ pub use __match_service as match_service; #[cfg(test)] mod test { use crate::dep::http_body_util::BodyExt; - use crate::matcher::MethodMatcher; use crate::Body; + use rama_core::MethodMatcher; use super::*; diff --git a/rama-http/src/utils/macros/http_error.rs b/rama-http/src/utils/macros/http_error.rs index 71821605..19115415 100644 --- a/rama-http/src/utils/macros/http_error.rs +++ b/rama-http/src/utils/macros/http_error.rs @@ -78,7 +78,7 @@ macro_rules! __define_http_rejection { ) => { $(#[$m])* #[derive(Debug)] - pub struct $name(pub(crate) $crate::error::OpaqueError); + pub struct $name(pub(crate) rama_core::error::OpaqueError); impl $name { #[allow(dead_code)] @@ -86,7 +86,7 @@ macro_rules! __define_http_rejection { where E: std::error::Error + Send + Sync + 'static, { - Self($crate::error::OpaqueError::from_std(err)) + Self(::rama_core::error::OpaqueError::from_std(err)) } #[allow(dead_code)] @@ -94,7 +94,7 @@ macro_rules! __define_http_rejection { where C: std::fmt::Display + std::fmt::Debug + Send + Sync + 'static, { - Self($crate::error::OpaqueError::from_display(msg)) + Self(::rama_core::error::OpaqueError::from_display(msg)) } } diff --git a/rama-http/src/utils/mod.rs b/rama-http/src/utils/mod.rs index f88bceca..715755cf 100644 --- a/rama-http/src/utils/mod.rs +++ b/rama-http/src/utils/mod.rs @@ -4,5 +4,5 @@ mod header_value; #[doc(inline)] pub use header_value::{HeaderValueErr, HeaderValueGetter}; -#[use_macro] +#[macro_use] pub(crate) mod macros; diff --git a/rama-net/Cargo.toml b/rama-net/Cargo.toml index bdf826e6..c2fcc932 100644 --- a/rama-net/Cargo.toml +++ b/rama-net/Cargo.toml @@ -12,8 +12,12 @@ rust-version = { workspace = true } [features] default = [] -full = ["http"] +full = ["http", "rustls", "boring", "telemetry"] http = ["dep:rama-http-types", "rama-core/http"] +tls = ["dep:hex"] +rustls = ["tls", "dep:rustls"] +boring = ["tls", "dep:boring", "dep:nom"] +rustls-ring = ["rustls", "rustls/ring"] telemetry = ["rama-core/telemetry"] [dependencies] @@ -37,6 +41,10 @@ tokio = { workspace = true, features = ["macros", "fs", "io-std"] } tokio-graceful = { workspace = true } tracing = { workspace = true } venndb = { workspace = true, optional = true } +boring = { workspace = true, optional = true } +rustls = { workspace = true, optional = true } +nom = { workspace = true, optional = true } +hex = { workspace = true, optional = true } [dev-dependencies] itertools = { workspace = true } diff --git a/rama-net/src/address/domain.rs b/rama-net/src/address/domain.rs index ce058499..16400a3d 100644 --- a/rama-net/src/address/domain.rs +++ b/rama-net/src/address/domain.rs @@ -1,4 +1,5 @@ use super::Host; +use rama_core::dns::TryIntoName; use rama_core::error::{ErrorContext, OpaqueError}; use std::{borrow::Cow, cmp::Ordering, fmt, iter::repeat}; @@ -166,6 +167,12 @@ impl TryFrom> for Domain { } } +impl TryIntoName for Domain { + fn try_into_name(self) -> Result { + self.to_string().try_into_name() + } +} + fn cmp_domain(a: impl AsRef, b: impl AsRef) -> Ordering { let a = a.as_ref(); let a = a.strip_prefix('.').unwrap_or(a); diff --git a/rama-net/src/forwarded/mod.rs b/rama-net/src/forwarded/mod.rs index 8b80e378..e807789f 100644 --- a/rama-net/src/forwarded/mod.rs +++ b/rama-net/src/forwarded/mod.rs @@ -43,7 +43,7 @@ pub use version::ForwardedVersion; /// /// RFC: /// -/// [`Context`]: crate::Context +/// [`Context`]: rama_core::Context pub struct Forwarded { first: ForwardedElement, others: Vec, diff --git a/rama-net/src/http/mod.rs b/rama-net/src/http/mod.rs new file mode 100644 index 00000000..53e69f41 --- /dev/null +++ b/rama-net/src/http/mod.rs @@ -0,0 +1,9 @@ +//! http net support added as part of rama's net support +//! +//! See `rama-http` and `rama-http-backend` for most +//! http support. In this module lives only the stuff +//! directly connected to `rama-net` types. + +mod request_context; +#[doc(inline)] +pub use request_context::RequestContext; diff --git a/rama-http/src/request_context.rs b/rama-net/src/http/request_context.rs similarity index 80% rename from rama-http/src/request_context.rs rename to rama-net/src/http/request_context.rs index e2db2b27..3f5e3445 100644 --- a/rama-http/src/request_context.rs +++ b/rama-net/src/http/request_context.rs @@ -1,15 +1,12 @@ -use super::{dep::http::request::Parts, Request, Version}; -use crate::Uri; -use rama_core::error::OpaqueError; -use rama_core::net::forwarded::Forwarded; -use rama_core::net::{ +use crate::forwarded::Forwarded; +use crate::transport::{TransportContext, TransportProtocol, TryRefIntoTransportContext}; +use crate::{ address::{Authority, Host}, Protocol, }; -use rama_core::stream::transport::{ - TransportContext, TransportProtocol, TryRefIntoTransportContext, -}; +use rama_core::error::OpaqueError; use rama_core::Context; +use rama_http_types::{dep::http::request::Parts, Request, Uri, Version}; #[cfg(feature = "tls")] use crate::tls::SecureTransport; @@ -60,7 +57,7 @@ impl TryFrom<(&Context, &Request)> for RequestContext }) .or_else(|| { req.headers() - .get(crate::header::HOST) + .get(rama_http_types::header::HOST) .and_then(|host| { host.try_into() // try to consume as Authority, otherwise as Host .or_else(|_| Host::try_from(host).map(|h| (h, default_port).into())) @@ -81,11 +78,11 @@ impl TryFrom<(&Context, &Request)> for RequestContext .get::() .and_then(|f| { f.client_version().map(|v| match v { - crate::net::forwarded::ForwardedVersion::HTTP_09 => Version::HTTP_09, - crate::net::forwarded::ForwardedVersion::HTTP_10 => Version::HTTP_10, - crate::net::forwarded::ForwardedVersion::HTTP_11 => Version::HTTP_11, - crate::net::forwarded::ForwardedVersion::HTTP_2 => Version::HTTP_2, - crate::net::forwarded::ForwardedVersion::HTTP_3 => Version::HTTP_3, + crate::forwarded::ForwardedVersion::HTTP_09 => Version::HTTP_09, + crate::forwarded::ForwardedVersion::HTTP_10 => Version::HTTP_10, + crate::forwarded::ForwardedVersion::HTTP_11 => Version::HTTP_11, + crate::forwarded::ForwardedVersion::HTTP_2 => Version::HTTP_2, + crate::forwarded::ForwardedVersion::HTTP_3 => Version::HTTP_3, }) }) .unwrap_or_else(|| req.version()); @@ -126,7 +123,7 @@ impl TryFrom<(&Context, &Parts)> for RequestContext { .or_else(|| { parts .headers - .get(crate::header::HOST) + .get(rama_http_types::header::HOST) .and_then(|host| { host.try_into() // try to consume as Authority, otherwise as Host .or_else(|_| Host::try_from(host).map(|h| (h, default_port).into())) @@ -149,11 +146,11 @@ impl TryFrom<(&Context, &Parts)> for RequestContext { .get::() .and_then(|f| { f.client_version().map(|v| match v { - crate::net::forwarded::ForwardedVersion::HTTP_09 => Version::HTTP_09, - crate::net::forwarded::ForwardedVersion::HTTP_10 => Version::HTTP_10, - crate::net::forwarded::ForwardedVersion::HTTP_11 => Version::HTTP_11, - crate::net::forwarded::ForwardedVersion::HTTP_2 => Version::HTTP_2, - crate::net::forwarded::ForwardedVersion::HTTP_3 => Version::HTTP_3, + crate::forwarded::ForwardedVersion::HTTP_09 => Version::HTTP_09, + crate::forwarded::ForwardedVersion::HTTP_10 => Version::HTTP_10, + crate::forwarded::ForwardedVersion::HTTP_11 => Version::HTTP_11, + crate::forwarded::ForwardedVersion::HTTP_2 => Version::HTTP_2, + crate::forwarded::ForwardedVersion::HTTP_3 => Version::HTTP_3, }) }) .unwrap_or(parts.version); @@ -233,41 +230,7 @@ impl From<&RequestContext> for TransportContext { } } -impl TryFrom<(&Context, &crate::Request)> for TransportContext { - type Error = OpaqueError; - - fn try_from( - (ctx, req): (&Context, &crate::Request), - ) -> Result { - Ok(match ctx.get::() { - Some(req_ctx) => req_ctx.into(), - None => { - let req_ctx = RequestContext::try_from((ctx, req))?; - req_ctx.into() - } - }) - } -} - -impl TryFrom<(&Context, &crate::dep::http::request::Parts)> - for TransportContext -{ - type Error = OpaqueError; - - fn try_from( - (ctx, parts): (&Context, &crate::dep::http::request::Parts), - ) -> Result { - Ok(match ctx.get::() { - Some(req_ctx) => req_ctx.into(), - None => { - let req_ctx = RequestContext::try_from((ctx, parts))?; - req_ctx.into() - } - }) - } -} - -impl TryRefIntoTransportContext for crate::Request { +impl TryRefIntoTransportContext for rama_http_types::Request { type Error = OpaqueError; fn try_ref_into_transport_ctx( @@ -278,7 +241,7 @@ impl TryRefIntoTransportContext for crate::Request { } } -impl TryRefIntoTransportContext for crate::dep::http::request::Parts { +impl TryRefIntoTransportContext for rama_http_types::dep::http::request::Parts { type Error = OpaqueError; fn try_ref_into_transport_ctx( @@ -292,11 +255,9 @@ impl TryRefIntoTransportContext for crate::dep::http::request::Par #[cfg(test)] mod tests { use super::*; - use crate::header::FORWARDED; - use crate::layer::forwarded::GetForwardedHeadersLayer; - use crate::net::forwarded::{Forwarded, ForwardedElement, NodeId}; - use crate::service::{service_fn, Service}; - use crate::Layer; + use crate::forwarded::{Forwarded, ForwardedElement, NodeId}; + use rama_http_types::header::FORWARDED; + use rama_http_types::headers::HeaderMapExt; #[test] fn test_request_context_from_request() { @@ -347,8 +308,8 @@ mod tests { assert_eq!(ctx.authority.to_string(), "example.com:8080"); } - #[tokio::test] - async fn forwarded_parsing() { + #[test] + fn forwarded_parsing() { for (forwarded_str_vec, expected) in [ // base ( @@ -387,23 +348,21 @@ mod tests { }, ), ] { - let svc = GetForwardedHeadersLayer::forwarded().layer(service_fn( - |mut ctx: Context<()>, req: Request<()>| async move { - ctx.get_or_try_insert_with_ctx::(|ctx| { - (ctx, &req).try_into() - }) - .cloned() - }, - )); - let mut req_builder = Request::builder(); for header in forwarded_str_vec.clone() { req_builder = req_builder.header(FORWARDED, header); } let req = req_builder.body(()).unwrap(); + let mut ctx = Context::default(); + + let forwarded = req.headers().typed_get::().unwrap(); + ctx.insert(forwarded); - let req_ctx = svc.serve(Context::default(), req).await.unwrap(); + let req_ctx = ctx + .get_or_try_insert_with_ctx::(|ctx| (ctx, &req).try_into()) + .unwrap() + .clone(); assert_eq!(req_ctx, expected, "Failed for {:?}", forwarded_str_vec); } diff --git a/rama-net/src/lib.rs b/rama-net/src/lib.rs index 26787c2a..68b3611b 100644 --- a/rama-net/src/lib.rs +++ b/rama-net/src/lib.rs @@ -66,3 +66,9 @@ pub use proto::Protocol; #[cfg(feature = "http")] pub mod transport; + +#[cfg(feature = "http")] +pub mod http; + +#[cfg(feature = "tls")] +pub mod tls; diff --git a/rama-net/src/mod.rs b/rama-net/src/mod.rs deleted file mode 100644 index e8a31e70..00000000 --- a/rama-net/src/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! protocol agnostic network modules - -pub mod address; -pub mod asn; -pub mod client; -pub mod forwarded; -pub mod user; - -pub(crate) mod proto; -#[doc(inline)] -pub use proto::Protocol; diff --git a/rama-net/src/stream/layer/http/body_limit.rs b/rama-net/src/stream/layer/http/body_limit.rs index d6bb5559..c749bdf8 100644 --- a/rama-net/src/stream/layer/http/body_limit.rs +++ b/rama-net/src/stream/layer/http/body_limit.rs @@ -11,7 +11,7 @@ use std::fmt; /// such that the L7 http service can apply the limit when found in that [`Context`]. /// /// [`Stream`]: crate::stream::Stream -/// [`Context`]: crate::Context` +/// [`Context`]: rama_core::Context` #[derive(Debug, Clone)] pub struct BodyLimitLayer { limit: BodyLimit, diff --git a/rama-net/src/stream/layer/opentelemetry.rs b/rama-net/src/stream/layer/opentelemetry.rs index 975cc09f..c846045e 100644 --- a/rama-net/src/stream/layer/opentelemetry.rs +++ b/rama-net/src/stream/layer/opentelemetry.rs @@ -1,6 +1,6 @@ //! Http OpenTelemetry [`Layer`] Support for Rama. //! -//! [`Layer`]: crate::Layer +//! [`Layer`]: rama_core::Layer use crate::stream::SocketInfo; use rama_core::telemetry::opentelemetry::semantic_conventions::trace::{ diff --git a/rama-net/src/stream/layer/tracker/incoming.rs b/rama-net/src/stream/layer/tracker/incoming.rs index d624c59c..ca48a38d 100644 --- a/rama-net/src/stream/layer/tracker/incoming.rs +++ b/rama-net/src/stream/layer/tracker/incoming.rs @@ -6,7 +6,7 @@ use std::{fmt, future::Future}; /// A [`Service`] that wraps a [`Service`]'s input IO [`Stream`] with an atomic R/W tracker. /// -/// [`Service`]: crate::Service +/// [`Service`]: rama_core::Service /// [`Stream`]: crate::stream::Stream pub struct IncomingBytesTrackerService { inner: S, @@ -65,8 +65,8 @@ where /// A [`Layer`] that wraps a [`Service`]'s input IO [`Stream`] with an atomic R/W tracker. /// -/// [`Layer`]: crate::Layer -/// [`Service`]: crate::Service +/// [`Layer`]: rama_core::Layer +/// [`Service`]: rama_core::Service /// [`Stream`]: crate::stream::Stream #[derive(Debug, Clone)] #[non_exhaustive] diff --git a/rama-net/src/stream/layer/tracker/outgoing.rs b/rama-net/src/stream/layer/tracker/outgoing.rs index 5c160a53..2c091f36 100644 --- a/rama-net/src/stream/layer/tracker/outgoing.rs +++ b/rama-net/src/stream/layer/tracker/outgoing.rs @@ -9,7 +9,7 @@ use std::fmt; /// A [`Service`] that wraps a [`Service`]'s output IO [`Stream`] with an atomic R/W tracker. /// -/// [`Service`]: crate::Service +/// [`Service`]: rama_core::Service /// [`Stream`]: crate::stream::Stream pub struct OutgoingBytesTrackerService { inner: S, @@ -79,8 +79,8 @@ where /// A [`Layer`] that wraps a [`Service`]'s output IO [`Stream`] with an atomic R/W tracker. /// -/// [`Layer`]: crate::Layer -/// [`Service`]: crate::Service +/// [`Layer`]: rama_core::Layer +/// [`Service`]: rama_core::Service /// [`Stream`]: crate::stream::Stream #[derive(Debug, Clone)] #[non_exhaustive] diff --git a/rama-net/src/stream/matcher/ip.rs b/rama-net/src/stream/matcher/ip.rs index dc340015..d4fc00b1 100644 --- a/rama-net/src/stream/matcher/ip.rs +++ b/rama-net/src/stream/matcher/ip.rs @@ -1,11 +1,10 @@ use crate::stream::dep::ipnet::{IpNet, Ipv4Net, Ipv6Net}; use rama_core::{context::Extensions, Context}; -#[cfg(feature = "http")] -use rama_http_types::Request; #[cfg(feature = "http")] use crate::stream::SocketInfo; - +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on whether or not the [`IpNet`] contains the [`SocketAddr`] of the peer. diff --git a/rama-net/src/stream/matcher/loopback.rs b/rama-net/src/stream/matcher/loopback.rs index b9ea71ca..9dd7177a 100644 --- a/rama-net/src/stream/matcher/loopback.rs +++ b/rama-net/src/stream/matcher/loopback.rs @@ -1,10 +1,9 @@ use rama_core::{context::Extensions, Context}; -#[cfg(feature = "http")] -use rama_http_types::Request; #[cfg(feature = "http")] use crate::stream::SocketInfo; - +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on the ip part of the [`SocketAddr`] of the peer, diff --git a/rama-net/src/stream/matcher/port.rs b/rama-net/src/stream/matcher/port.rs index 15570ba8..87192c90 100644 --- a/rama-net/src/stream/matcher/port.rs +++ b/rama-net/src/stream/matcher/port.rs @@ -1,9 +1,9 @@ use rama_core::{context::Extensions, Context}; -#[cfg(feature = "http")] -use rama_http_types::Request; #[cfg(feature = "http")] use crate::stream::SocketInfo; +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on the port part of the [`SocketAddr`] of the peer. diff --git a/rama-net/src/stream/matcher/private_ip.rs b/rama-net/src/stream/matcher/private_ip.rs index 25fe9680..da5e7def 100644 --- a/rama-net/src/stream/matcher/private_ip.rs +++ b/rama-net/src/stream/matcher/private_ip.rs @@ -1,10 +1,10 @@ use crate::stream::dep::ipnet::IpNet; use rama_core::{context::Extensions, Context}; -#[cfg(feature = "http")] -use rama_http_types::Request; #[cfg(feature = "http")] use crate::stream::SocketInfo; +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on the ip part of the [`SocketAddr`] of the peer, diff --git a/rama-net/src/stream/matcher/socket.rs b/rama-net/src/stream/matcher/socket.rs index b36cd181..ee7f7477 100644 --- a/rama-net/src/stream/matcher/socket.rs +++ b/rama-net/src/stream/matcher/socket.rs @@ -1,11 +1,10 @@ use rama_core::{context::Extensions, Context}; use std::net::SocketAddr; -#[cfg(feature = "http")] -use rama_http_types::Request; #[cfg(feature = "http")] use crate::stream::SocketInfo; - +#[cfg(feature = "http")] +use rama_http_types::Request; #[derive(Debug, Clone)] /// Matcher based on the [`SocketAddr`] of the peer. diff --git a/rama-tls/src/client/hello/boring.rs b/rama-net/src/tls/client/hello/boring.rs similarity index 78% rename from rama-tls/src/client/hello/boring.rs rename to rama-net/src/tls/client/hello/boring.rs index 0d53c986..fe99fe1d 100644 --- a/rama-tls/src/client/hello/boring.rs +++ b/rama-net/src/tls/client/hello/boring.rs @@ -1,6 +1,5 @@ -use crate::error::{ErrorContext, OpaqueError}; -use crate::tls::backend::boring::dep::boring; use crate::tls::client::parser::parse_client_hello; +use rama_core::error::{ErrorContext, OpaqueError}; impl<'ssl> TryFrom> for super::ClientHello { type Error = OpaqueError; diff --git a/rama-tls/src/client/hello/mod.rs b/rama-net/src/tls/client/hello/mod.rs similarity index 97% rename from rama-tls/src/client/hello/mod.rs rename to rama-net/src/tls/client/hello/mod.rs index 732e5b89..b644d8f8 100644 --- a/rama-tls/src/client/hello/mod.rs +++ b/rama-net/src/tls/client/hello/mod.rs @@ -1,9 +1,7 @@ -use crate::{ - net::address::Domain, - tls::{ - enums::CompressionAlgorithm, ApplicationProtocol, CipherSuite, ECPointFormat, ExtensionId, - ProtocolVersion, SignatureScheme, SupportedGroup, - }, +use crate::address::Domain; +use crate::tls::{ + enums::CompressionAlgorithm, ApplicationProtocol, CipherSuite, ECPointFormat, ExtensionId, + ProtocolVersion, SignatureScheme, SupportedGroup, }; #[cfg(feature = "rustls")] diff --git a/rama-tls/src/client/hello/rustls.rs b/rama-net/src/tls/client/hello/rustls.rs similarity index 100% rename from rama-tls/src/client/hello/rustls.rs rename to rama-net/src/tls/client/hello/rustls.rs diff --git a/rama-tls/src/client/mod.rs b/rama-net/src/tls/client/mod.rs similarity index 100% rename from rama-tls/src/client/mod.rs rename to rama-net/src/tls/client/mod.rs diff --git a/rama-tls/src/client/parser.rs b/rama-net/src/tls/client/parser.rs similarity index 98% rename from rama-tls/src/client/parser.rs rename to rama-net/src/tls/client/parser.rs index 9e94408b..aa8affbb 100644 --- a/rama-tls/src/client/parser.rs +++ b/rama-net/src/tls/client/parser.rs @@ -4,12 +4,9 @@ //! src and attribution: use super::{ClientHello, ClientHelloExtension}; -use crate::{ - error::OpaqueError, - net::address::Domain, - tls::{ - enums::CompressionAlgorithm, ApplicationProtocol, CipherSuite, ExtensionId, ProtocolVersion, - }, +use crate::address::Domain; +use crate::tls::{ + enums::CompressionAlgorithm, ApplicationProtocol, CipherSuite, ExtensionId, ProtocolVersion, }; use nom::{ bytes::streaming::take, @@ -19,6 +16,7 @@ use nom::{ number::streaming::{be_u16, be_u8}, IResult, }; +use rama_core::error::OpaqueError; #[inline] pub(crate) fn parse_client_hello(i: &[u8]) -> Result { @@ -276,10 +274,8 @@ fn parse_u16_type>(i: &[u8]) -> IResult<&[u8], Vec> { #[cfg(test)] mod tests { use super::*; - use crate::{ - net::address::Domain, - tls::{ECPointFormat, ExtensionId, SignatureScheme, SupportedGroup}, - }; + use crate::address::Domain; + use crate::tls::{ECPointFormat, ExtensionId, SignatureScheme, SupportedGroup}; #[test] fn test_parse_client_hello_zero_bytes_failure() { diff --git a/rama-tls/src/enums/mod.rs b/rama-net/src/tls/enums/mod.rs similarity index 99% rename from rama-tls/src/enums/mod.rs rename to rama-net/src/tls/enums/mod.rs index 62291cb9..9399a535 100644 --- a/rama-tls/src/enums/mod.rs +++ b/rama-net/src/tls/enums/mod.rs @@ -1,7 +1,7 @@ #![allow(missing_docs)] #![allow(non_camel_case_types)] -use crate::error::OpaqueError; +use rama_core::error::OpaqueError; #[cfg(feature = "rustls")] mod rustls; diff --git a/rama-tls/src/enums/rustls.rs b/rama-net/src/tls/enums/rustls.rs similarity index 100% rename from rama-tls/src/enums/rustls.rs rename to rama-net/src/tls/enums/rustls.rs diff --git a/rama-net/src/tls/mod.rs b/rama-net/src/tls/mod.rs new file mode 100644 index 00000000..a1c68de7 --- /dev/null +++ b/rama-net/src/tls/mod.rs @@ -0,0 +1,45 @@ +//! rama common tls types +//! +mod enums; +use client::ClientHello; +pub use enums::{ + ApplicationProtocol, CipherSuite, CompressionAlgorithm, ECPointFormat, ExtensionId, + ProtocolVersion, SignatureScheme, SupportedGroup, +}; + +pub mod client; + +#[derive(Debug, Clone)] +/// Context information that can be provided `https` connectors`, +/// to configure the connection in function on an https tunnel. +pub struct HttpsTunnel { + /// The server name to use for the connection. + pub server_name: String, +} + +#[derive(Debug, Clone, Default)] +/// An [`Extensions`] value that can be added to the [`Context`] +/// of a transport layer to signal that the transport is secure. +/// +/// [`Extensions`]: rama_core::context::Extensions +/// [`Context`]: rama_core::Context +pub struct SecureTransport { + client_hello: Option, +} + +impl SecureTransport { + /// Create a [`SecureTransport`] with a [`ClientHello`] + /// attached to it, containing the client hello info + /// used to establish this secure transport. + pub fn with_client_hello(hello: ClientHello) -> Self { + Self { + client_hello: Some(hello), + } + } + + /// Return the [`ClientHello`] used to establish this secure transport, + /// only available if the tls service stored it. + pub fn client_hello(&self) -> Option<&ClientHello> { + self.client_hello.as_ref() + } +} diff --git a/rama-net/src/transport.rs b/rama-net/src/transport.rs index 1368ee7e..530d36b6 100644 --- a/rama-net/src/transport.rs +++ b/rama-net/src/transport.rs @@ -2,9 +2,10 @@ //! //! See [`TransportContext`] for the centerpiece of this module. +use crate::http::RequestContext; use crate::{address::Authority, Protocol}; -use rama_core::Context; -use rama_http_types::Version; +use rama_core::{error::OpaqueError, Context}; +use rama_http_types::{dep::http::request::Parts as HttpParts, Request, Version}; #[derive(Debug, Clone, PartialEq, Eq)] /// The context as relevant to the transport layer, @@ -49,3 +50,35 @@ pub trait TryRefIntoTransportContext { ctx: &Context, ) -> Result; } + +impl TryFrom<(&Context, &Request)> for TransportContext { + type Error = OpaqueError; + + fn try_from( + (ctx, req): (&Context, &Request), + ) -> Result { + Ok(match ctx.get::() { + Some(req_ctx) => req_ctx.into(), + None => { + let req_ctx = RequestContext::try_from((ctx, req))?; + req_ctx.into() + } + }) + } +} + +impl TryFrom<(&Context, &HttpParts)> for TransportContext { + type Error = OpaqueError; + + fn try_from( + (ctx, parts): (&Context, &HttpParts), + ) -> Result { + Ok(match ctx.get::() { + Some(req_ctx) => req_ctx.into(), + None => { + let req_ctx = RequestContext::try_from((ctx, parts))?; + req_ctx.into() + } + }) + } +} diff --git a/rama-net/src/user/auth.rs b/rama-net/src/user/auth.rs index f6c99f6e..14447a9b 100644 --- a/rama-net/src/user/auth.rs +++ b/rama-net/src/user/auth.rs @@ -13,12 +13,6 @@ use rama_http_types::headers::authorization::Credentials; /// [`Credential`]: headers::authorization::Credentials pub trait Authority: Send + Sync + 'static { /// Returns `true` if the credentials are authorized, otherwise `false`. - /// - /// If the `filter_char` is defined it is expected that the authority, - /// takes into account that the username contains [`ProxyFilter`] data, - /// and that it is extracted out prior to validation. - /// - /// [`ProxyFilter`]: crate::proxy::ProxyFilter fn authorized(&self, credentials: C) -> impl Future> + Send + '_; } diff --git a/rama-net/src/user/credentials/basic.rs b/rama-net/src/user/credentials/basic.rs index fd7552e6..7360220a 100644 --- a/rama-net/src/user/credentials/basic.rs +++ b/rama-net/src/user/credentials/basic.rs @@ -4,10 +4,7 @@ use rama_core::error::{ErrorContext, OpaqueError}; use std::borrow::Cow; #[cfg(feature = "http")] -use rama_http_types::{ - HeaderValue, - headers::authorization, -}; +use rama_http_types::{headers::authorization, HeaderValue}; #[derive(Debug, Clone)] /// Basic credentials. @@ -202,22 +199,6 @@ mod tests { assert!(value.is_err()); } - #[test] - fn basic_encode() { - let auth = Basic::new("Aladdin", "open sesame"); - let value = auth.encode(); - - assert_eq!(value, "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",); - } - - #[test] - fn basic_encode_no_password() { - let auth = Basic::unprotected("Aladdin"); - let value = auth.encode(); - - assert_eq!(value, "Basic QWxhZGRpbjo=",); - } - #[test] fn basic_header() { let auth = Basic::try_from_header_str("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==").unwrap(); @@ -260,6 +241,22 @@ mod tests_http { use super::*; use authorization::Credentials; + #[test] + fn basic_encode() { + let auth = Basic::new("Aladdin", "open sesame"); + let value = auth.encode(); + + assert_eq!(value, "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",); + } + + #[test] + fn basic_encode_no_password() { + let auth = Basic::unprotected("Aladdin"); + let value = auth.encode(); + + assert_eq!(value, "Basic QWxhZGRpbjo=",); + } + #[test] fn basic_decode() { let auth = Basic::decode(&HeaderValue::from_static( diff --git a/rama-net/src/user/credentials/bearer.rs b/rama-net/src/user/credentials/bearer.rs index 3d0184d5..be036b86 100644 --- a/rama-net/src/user/credentials/bearer.rs +++ b/rama-net/src/user/credentials/bearer.rs @@ -2,10 +2,7 @@ use rama_core::error::{ErrorContext, OpaqueError}; use std::borrow::Cow; #[cfg(feature = "http")] -use rama_http_types::{ - HeaderValue, - headers::authorization, -}; +use rama_http_types::{headers::authorization, HeaderValue}; #[derive(Debug, Clone, PartialEq, Eq)] /// Bearer credentials. diff --git a/rama-proxy/src/http/client/layer/proxy_connector/layer.rs b/rama-proxy/src/http/client/layer/proxy_connector/layer.rs index 26be8750..cdf85e22 100644 --- a/rama-proxy/src/http/client/layer/proxy_connector/layer.rs +++ b/rama-proxy/src/http/client/layer/proxy_connector/layer.rs @@ -1,5 +1,5 @@ use super::HttpProxyConnector; -use crate::Layer; +use rama_core::Layer; #[derive(Debug, Clone, Default)] /// A [`Layer`] which wraps the given service with a [`HttpProxyConnector`]. diff --git a/rama-proxy/src/proxydb/layer.rs b/rama-proxy/src/proxydb/layer.rs index bfd11eec..38c5e1a9 100644 --- a/rama-proxy/src/proxydb/layer.rs +++ b/rama-proxy/src/proxydb/layer.rs @@ -14,7 +14,7 @@ //! //! [`ProxyAddress`]: crate::net::address::ProxyAddress //! [`ProxyDB`]: crate::proxy::ProxyDB -//! [`Context`]: crate::Context +//! [`Context`]: rama_core::Context //! [`HeaderConfigLayer`]: crate::http::layer::header_config::HeaderConfigLayer //! //! # Example diff --git a/rama-proxy/src/proxydb/mod.rs b/rama-proxy/src/proxydb/mod.rs index 8f0232f9..00310be2 100644 --- a/rama-proxy/src/proxydb/mod.rs +++ b/rama-proxy/src/proxydb/mod.rs @@ -79,8 +79,8 @@ impl From for ProxyID { /// [`HeaderConfigLayer`]: crate::http::layer::header_config::HeaderConfigLayer /// [`Request`]: crate::http::Request /// [`ProxyAuthLayer`]: crate::http::layer::proxy_auth::ProxyAuthLayer -/// [`Context`]: crate::Context -/// [`Extensions`]: crate::context::Extensions +/// [`Context`]: rama_core::Context +/// [`Extensions`]: rama_core::context::Extensions pub struct ProxyFilter { /// The ID of the proxy to select. pub id: Option, diff --git a/rama-proxy/src/username.rs b/rama-proxy/src/username.rs index 7b1931e0..0e5792de 100644 --- a/rama-proxy/src/username.rs +++ b/rama-proxy/src/username.rs @@ -11,8 +11,8 @@ use crate::{ /// A parser which parses [`ProxyFilter`]s from username labels /// and adds it to the [`Context`]'s [`Extensions`]. /// -/// [`Context`]: crate::Context -/// [`Extensions`]: crate::context::Extensions +/// [`Context`]: rama_core::Context +/// [`Extensions`]: rama_core::context::Extensions pub struct ProxyFilterUsernameParser { key: Option, proxy_filter: ProxyFilter, diff --git a/rama-tcp/Cargo.toml b/rama-tcp/Cargo.toml new file mode 100644 index 00000000..6b94095d --- /dev/null +++ b/rama-tcp/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "rama-tcp" +description = "TCP support for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = [] +http = ["dep:rama-http-types", "rama-net/http"] + +[dependencies] +tokio = { workspace = true, features = ["macros", "net"] } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } +tracing = { workspace = true } + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-tcp/README.md b/rama-tcp/README.md new file mode 100644 index 00000000..9ccd0796 --- /dev/null +++ b/rama-tcp/README.md @@ -0,0 +1,49 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-tcp.svg +[crates-url]: https://crates.io/crates/rama-tcp +[docs-badge]: https://img.shields.io/docsrs/rama-tcp/latest +[docs-url]: https://docs.rs/rama-tcp/latest/rama_tcp/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-tcp + +TCP support for rama. + +Crate used by the end-user `rama` crate. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/src/tcp/client/connect.rs b/rama-tcp/src/client/connect.rs similarity index 99% rename from src/tcp/client/connect.rs rename to rama-tcp/src/client/connect.rs index 3839a002..3ce1f348 100644 --- a/src/tcp/client/connect.rs +++ b/rama-tcp/src/client/connect.rs @@ -1,10 +1,10 @@ -use crate::{ +use rama_core::{ combinators::Either4, dns::Dns, error::{ErrorContext, OpaqueError}, - net::address::{Authority, Domain, Host}, Context, }; +use rama_net::address::{Authority, Domain, Host}; use std::{ net::{IpAddr, SocketAddr}, sync::{ diff --git a/src/tcp/client/mod.rs b/rama-tcp/src/client/mod.rs similarity index 78% rename from src/tcp/client/mod.rs rename to rama-tcp/src/client/mod.rs index 1bbed2c3..7f1aeb27 100644 --- a/src/tcp/client/mod.rs +++ b/rama-tcp/src/client/mod.rs @@ -6,6 +6,8 @@ mod connect; #[doc(inline)] pub use connect::{connect, connect_trusted}; +#[cfg(feature = "http")] mod request; +#[cfg(feature = "http")] #[doc(inline)] pub use request::{Parts, Request}; diff --git a/src/tcp/client/request.rs b/rama-tcp/src/client/request.rs similarity index 96% rename from src/tcp/client/request.rs rename to rama-tcp/src/client/request.rs index b2042aef..79197cec 100644 --- a/src/tcp/client/request.rs +++ b/rama-tcp/src/client/request.rs @@ -1,8 +1,9 @@ -use crate::{ - http::Version, - net::{address::Authority, Protocol}, - stream::transport::{TransportContext, TransportProtocol, TryRefIntoTransportContext}, - Context, +use rama_core::Context; +use rama_http_types::Version; +use rama_net::{ + address::Authority, + transport::{TransportContext, TransportProtocol, TryRefIntoTransportContext}, + Protocol, }; use std::convert::Infallible; diff --git a/src/tcp/client/service/connector.rs b/rama-tcp/src/client/service/connector.rs similarity index 87% rename from src/tcp/client/service/connector.rs rename to rama-tcp/src/client/service/connector.rs index 8ec06f1a..0cbbd79a 100644 --- a/src/tcp/client/service/connector.rs +++ b/rama-tcp/src/client/service/connector.rs @@ -1,8 +1,11 @@ -use crate::{ +use rama_core::{ error::{BoxError, ErrorContext, ErrorExt, OpaqueError}, - net::{address::ProxyAddress, client::EstablishedClientConnection}, - stream::transport::{TransportProtocol, TryRefIntoTransportContext}, - tcp, Context, Service, + Context, Service, +}; +use rama_net::{ + address::ProxyAddress, + client::EstablishedClientConnection, + transport::{TransportProtocol, TryRefIntoTransportContext}, }; use tokio::net::TcpStream; @@ -42,7 +45,7 @@ where req: Request, ) -> Result { if let Some(proxy) = ctx.get::() { - let (conn, addr) = tcp::client::connect_trusted(&ctx, proxy.authority.clone()) + let (conn, addr) = crate::client::connect_trusted(&ctx, proxy.authority.clone()) .await .context("tcp connector: conncept to proxy")?; return Ok(EstablishedClientConnection { @@ -72,7 +75,7 @@ where } let authority = transport_ctx.authority.clone(); - let (conn, addr) = tcp::client::connect(&ctx, authority) + let (conn, addr) = crate::client::connect(&ctx, authority) .await .context("tcp connector: connect to server")?; diff --git a/src/tcp/client/service/forward.rs b/rama-tcp/src/client/service/forward.rs similarity index 95% rename from src/tcp/client/service/forward.rs rename to rama-tcp/src/client/service/forward.rs index e9855053..d028d81c 100644 --- a/src/tcp/client/service/forward.rs +++ b/rama-tcp/src/client/service/forward.rs @@ -1,19 +1,17 @@ -use std::{fmt, ops::DerefMut}; - -use tokio::sync::Mutex; - use super::TcpConnector; -use rama_utils::macros::impl_deref; -use crate::{ +use crate::{client::Request as TcpRequest, utils::is_connection_error}; +use rama_core::{ error::{BoxError, ErrorExt, OpaqueError}, - net::{ - address::Authority, - client::{ConnectorService, EstablishedClientConnection}, - }, - stream::Stream, - tcp::{client::Request as TcpRequest, utils::is_connection_error}, Context, Layer, Service, }; +use rama_net::{ + address::Authority, + client::{ConnectorService, EstablishedClientConnection}, + stream::Stream, +}; +use rama_utils::macros::impl_deref; +use std::{fmt, ops::DerefMut}; +use tokio::sync::Mutex; /// [`Forwarder`] using [`Forwarder::ctx`] requires this struct /// to be present in the [`Context`]. @@ -140,7 +138,7 @@ where T: Stream + Unpin, C: ConnectorService< S, - crate::tcp::client::Request, + crate::client::Request, Connection: Stream + Unpin, Error: Into, >, diff --git a/src/tcp/client/service/mod.rs b/rama-tcp/src/client/service/mod.rs similarity index 100% rename from src/tcp/client/service/mod.rs rename to rama-tcp/src/client/service/mod.rs diff --git a/rama-tcp/src/lib.rs b/rama-tcp/src/lib.rs new file mode 100644 index 00000000..19ebf68a --- /dev/null +++ b/rama-tcp/src/lib.rs @@ -0,0 +1,59 @@ +//! TCP module for Rama. +//! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +pub mod client; +pub mod server; +pub mod utils; diff --git a/src/tcp/server/listener.rs b/rama-tcp/src/server/listener.rs similarity index 95% rename from src/tcp/server/listener.rs rename to rama-tcp/src/server/listener.rs index ee322a6f..2998606c 100644 --- a/src/tcp/server/listener.rs +++ b/rama-tcp/src/server/listener.rs @@ -1,9 +1,9 @@ -use crate::graceful::ShutdownGuard; -use crate::rt::Executor; -use crate::service::handler::{Factory, FromContextRequest}; -use crate::stream::SocketInfo; -use crate::Context; -use crate::Service; +use rama_core::graceful::ShutdownGuard; +use rama_core::rt::Executor; +use rama_core::service::handler::{Factory, FromContextRequest}; +use rama_core::Context; +use rama_core::Service; +use rama_net::stream::SocketInfo; use std::fmt; use std::future::Future; use std::pin::pin; @@ -216,14 +216,14 @@ where E: Send + Sync + 'static, T: FromContextRequest, { - let service = crate::service::service_fn(f); + let service = rama_core::service::service_fn(f); self.serve(service).await } /// Serve gracefully connections from this listener with the given service. /// /// This method does the same as [`Self::serve`] but it - /// will respect the given [`crate::graceful::ShutdownGuard`], and also pass + /// will respect the given [`rama_core::graceful::ShutdownGuard`], and also pass /// it to the service. pub async fn serve_graceful(self, guard: ShutdownGuard, service: S) where @@ -272,13 +272,13 @@ where E: Send + Sync + 'static, T: FromContextRequest, { - let service = crate::service::service_fn(service); + let service = rama_core::service::service_fn(service); self.serve_graceful(guard, service).await } } async fn handle_accept_err(err: io::Error) { - if crate::tcp::utils::is_connection_error(&err) { + if crate::utils::is_connection_error(&err) { tracing::trace!( error = &err as &dyn std::error::Error, "TCP accept error: connect error" diff --git a/src/tcp/server/mod.rs b/rama-tcp/src/server/mod.rs similarity index 96% rename from src/tcp/server/mod.rs rename to rama-tcp/src/server/mod.rs index 73aef1c6..45954328 100644 --- a/src/tcp/server/mod.rs +++ b/rama-tcp/src/server/mod.rs @@ -5,7 +5,7 @@ //! # Example //! //! ```no_run -//! use rama::tcp::server::TcpListener; +//! use rama_tcp::server::TcpListener; //! use tokio::{io::AsyncWriteExt, net::TcpStream}; //! //! const SRC: &str = include_str!("../../../examples/tcp_listener_hello.rs"); diff --git a/src/tcp/utils.rs b/rama-tcp/src/utils.rs similarity index 100% rename from src/tcp/utils.rs rename to rama-tcp/src/utils.rs diff --git a/rama-tls/Cargo.toml b/rama-tls/Cargo.toml index 007bd9c0..28bfe627 100644 --- a/rama-tls/Cargo.toml +++ b/rama-tls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rama-tls" -description = "tls support for rama" +description = "tls implementations for rama" version = { workspace = true } license = { workspace = true } edition = { workspace = true } @@ -12,14 +12,16 @@ rust-version = { workspace = true } [features] default = [] -rustls = ["dep:rustls", "dep:rustls-native-certs", "dep:rustls-pemfile", "dep:rustls-pki-types", "dep:webpki-roots", "dep:tokio-rustls"] -boring = ["dep:boring", "dep:tokio-boring", "nom"] -rustls-ring = ["rustls", "tokio-rustls/ring", "rustls/ring"] +rustls = ["dep:rustls", "dep:rustls-native-certs", "dep:rustls-pemfile", "dep:rustls-pki-types", "dep:webpki-roots", "dep:tokio-rustls", "rama-net/rustls"] +boring = ["dep:boring", "dep:tokio-boring", "rama-net/boring"] +rustls-ring = ["rustls", "tokio-rustls/ring", "rustls/ring", "rama-net/rustls-ring"] [dependencies] boring = { workspace = true, optional = true } -nom = { workspace = true, optional = true } -rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http", "tls"] } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rcgen = { workspace = true } rustls = { workspace = true, optional = true } rustls-native-certs = { workspace = true, optional = true } @@ -28,6 +30,11 @@ rustls-pki-types = { workspace = true, optional = true } tokio-boring = { workspace = true, optional = true } tokio-rustls = { workspace = true, optional = true } webpki-roots = { workspace = true, optional = true } +parking_lot = { workspace = true } +tokio = { workspace = true, features = ["macros", "io-std"] } +tracing = { workspace = true } +pin-project-lite = { workspace = true } +hex = { workspace = true } [dev-dependencies] diff --git a/rama-tls/README.md b/rama-tls/README.md index 5ab2b2bf..f5dd63a2 100644 --- a/rama-tls/README.md +++ b/rama-tls/README.md @@ -39,7 +39,7 @@ The reasons behind the creation of rama can be read in [the "Why Rama" chapter]( ## rama-tls -Tls support for `rama`. +Tls implementations for `rama`. Learn more about `rama`: diff --git a/rama-tls/src/backend/mod.rs b/rama-tls/src/backend/mod.rs deleted file mode 100644 index 96e8755a..00000000 --- a/rama-tls/src/backend/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! tls implementations shipped with rama - -#[cfg(feature = "rustls")] -pub mod rustls; - -#[cfg(feature = "boring")] -pub mod boring; - -#[cfg(all(feature = "rustls", not(feature = "boring")))] -pub use rustls as std; - -#[cfg(feature = "boring")] -pub use boring as std; diff --git a/rama-tls/src/backend/boring/client/http.rs b/rama-tls/src/boring/client/http.rs similarity index 97% rename from rama-tls/src/backend/boring/client/http.rs rename to rama-tls/src/boring/client/http.rs index e8b64e95..282d3622 100644 --- a/rama-tls/src/backend/boring/client/http.rs +++ b/rama-tls/src/boring/client/http.rs @@ -1,13 +1,12 @@ -use crate::error::{BoxError, ErrorContext, ErrorExt, OpaqueError}; -use crate::net::client::{ConnectorService, EstablishedClientConnection}; -use crate::stream::transport::TryRefIntoTransportContext; -use crate::stream::Stream; -use crate::tls::HttpsTunnel; -use crate::Layer; -use crate::{Context, Service}; +use crate::types::HttpsTunnel; use boring::ssl::SslVerifyMode; use pin_project_lite::pin_project; use private::{ConnectorKindAuto, ConnectorKindSecure, ConnectorKindTunnel}; +use rama_core::error::{BoxError, ErrorContext, ErrorExt, OpaqueError}; +use rama_core::{Context, Layer, Service}; +use rama_net::client::{ConnectorService, EstablishedClientConnection}; +use rama_net::stream::Stream; +use rama_net::transport::TryRefIntoTransportContext; use std::fmt; use tokio::io::{AsyncRead, AsyncWrite}; use tokio_boring::SslStream; @@ -448,7 +447,7 @@ mod private { /// The connections will only be done if the [`HttpsTunnel`] /// is present in the context. /// - /// [`HttpsTunnel`]: crate::tls::HttpsTunnel + /// [`HttpsTunnel`]: crate::HttpsTunnel pub struct ConnectorKindTunnel; } diff --git a/rama-tls/src/backend/boring/client/mod.rs b/rama-tls/src/boring/client/mod.rs similarity index 100% rename from rama-tls/src/backend/boring/client/mod.rs rename to rama-tls/src/boring/client/mod.rs diff --git a/rama-tls/src/backend/boring/mod.rs b/rama-tls/src/boring/mod.rs similarity index 100% rename from rama-tls/src/backend/boring/mod.rs rename to rama-tls/src/boring/mod.rs diff --git a/rama-tls/src/backend/boring/server/config.rs b/rama-tls/src/boring/server/config.rs similarity index 90% rename from rama-tls/src/backend/boring/server/config.rs rename to rama-tls/src/boring/server/config.rs index eb390b61..415e9c0c 100644 --- a/rama-tls/src/backend/boring/server/config.rs +++ b/rama-tls/src/boring/server/config.rs @@ -1,8 +1,8 @@ -use crate::tls::backend::boring::dep::boring::{ +use crate::boring::dep::boring::{ pkey::{PKey, Private}, x509::X509, }; -use crate::tls::ApplicationProtocol; +use crate::types::ApplicationProtocol; #[derive(Clone, Debug)] /// Common configuration for a set of server sessions. diff --git a/rama-tls/src/backend/boring/server/layer.rs b/rama-tls/src/boring/server/layer.rs similarity index 98% rename from rama-tls/src/backend/boring/server/layer.rs rename to rama-tls/src/boring/server/layer.rs index 61a1bb6e..f9a7a153 100644 --- a/rama-tls/src/backend/boring/server/layer.rs +++ b/rama-tls/src/boring/server/layer.rs @@ -1,5 +1,5 @@ use super::{ServerConfig, TlsAcceptorService}; -use crate::Layer; +use rama_core::Layer; use std::sync::Arc; /// A [`Layer`] which wraps the given service with a [`TlsAcceptorService`]. diff --git a/rama-tls/src/backend/boring/server/mod.rs b/rama-tls/src/boring/server/mod.rs similarity index 100% rename from rama-tls/src/backend/boring/server/mod.rs rename to rama-tls/src/boring/server/mod.rs diff --git a/rama-tls/src/backend/boring/server/service.rs b/rama-tls/src/boring/server/service.rs similarity index 97% rename from rama-tls/src/backend/boring/server/service.rs rename to rama-tls/src/boring/server/service.rs index c17c35bc..b2c09627 100644 --- a/rama-tls/src/backend/boring/server/service.rs +++ b/rama-tls/src/boring/server/service.rs @@ -1,19 +1,19 @@ use super::ServerConfig; -use rama_utils::macros::define_inner_service_accessors; use crate::{ - error::{ErrorContext, ErrorExt, OpaqueError}, - stream::Stream, - tls::{ - backend::boring::dep::{ - boring::ssl::{SslAcceptor, SslMethod}, - tokio_boring::SslStream, - }, - client::ClientHello, - SecureTransport, + boring::dep::{ + boring::ssl::{SslAcceptor, SslMethod}, + tokio_boring::SslStream, }, - Context, Service, + types::client::ClientHello, + types::SecureTransport, }; use parking_lot::Mutex; +use rama_core::{ + error::{ErrorContext, ErrorExt, OpaqueError}, + Context, Service, +}; +use rama_net::stream::Stream; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, sync::Arc}; /// A [`Service`] which accepts TLS connections and delegates the underlying transport diff --git a/rama-tls/src/lib.rs b/rama-tls/src/lib.rs index df1afdc4..47b32e67 100644 --- a/rama-tls/src/lib.rs +++ b/rama-tls/src/lib.rs @@ -1,4 +1,4 @@ -//! TLS module for Rama. +//! TLS implementations for Rama. //! //! # Rama //! @@ -54,23 +54,24 @@ #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] -mod enums; -use client::ClientHello; -pub use enums::{ - ApplicationProtocol, CipherSuite, CompressionAlgorithm, ECPointFormat, ExtensionId, - ProtocolVersion, SignatureScheme, SupportedGroup, -}; +#[cfg(feature = "rustls")] +pub mod rustls; -pub mod backend; +#[cfg(feature = "boring")] +pub mod boring; -pub mod client; +#[cfg(all(feature = "rustls", not(feature = "boring")))] +pub use rustls as std; -#[derive(Debug, Clone)] -/// Context information that can be provided `https` connectors`, -/// to configure the connection in function on an https tunnel. -pub struct HttpsTunnel { - /// The server name to use for the connection. - pub server_name: String, +#[cfg(feature = "boring")] +pub use boring as std; + +pub mod types { + //! common tls types + pub use ::rama_net::tls::{ + client, ApplicationProtocol, CipherSuite, CompressionAlgorithm, ECPointFormat, ExtensionId, + HttpsTunnel, ProtocolVersion, SecureTransport, SignatureScheme, SupportedGroup, + }; } pub mod dep { @@ -86,30 +87,3 @@ pub mod dep { pub use rcgen::*; } } - -#[derive(Debug, Clone, Default)] -/// An [`Extensions`] value that can be added to the [`Context`] -/// of a transport layer to signal that the transport is secure. -/// -/// [`Extensions`]: crate::context::Extensions -/// [`Context`]: crate::Context -pub struct SecureTransport { - client_hello: Option, -} - -impl SecureTransport { - /// Create a [`SecureTransport`] with a [`ClientHello`] - /// attached to it, containing the client hello info - /// used to establish this secure transport. - pub fn with_client_hello(hello: ClientHello) -> Self { - Self { - client_hello: Some(hello), - } - } - - /// Return the [`ClientHello`] used to establish this secure transport, - /// only available if the tls service stored it. - pub fn client_hello(&self) -> Option<&ClientHello> { - self.client_hello.as_ref() - } -} diff --git a/rama-tls/src/backend/rustls/client/http.rs b/rama-tls/src/rustls/client/http.rs similarity index 96% rename from rama-tls/src/backend/rustls/client/http.rs rename to rama-tls/src/rustls/client/http.rs index 311e6fdf..73675df2 100644 --- a/rama-tls/src/backend/rustls/client/http.rs +++ b/rama-tls/src/rustls/client/http.rs @@ -1,17 +1,17 @@ -use crate::error::{BoxError, ErrorExt, OpaqueError}; -use crate::http::Version; -use crate::net::client::{ConnectorService, EstablishedClientConnection}; -use crate::stream::transport::TryRefIntoTransportContext; -use crate::stream::Stream; -use crate::tls::backend::rustls::dep::pki_types::ServerName; -use crate::tls::backend::rustls::dep::rustls::RootCertStore; -use crate::tls::backend::rustls::dep::tokio_rustls::{client::TlsStream, TlsConnector}; -use crate::tls::backend::rustls::verify::NoServerCertVerifier; -use crate::tls::HttpsTunnel; -use crate::{tls::backend::rustls::dep::rustls::ClientConfig, Layer}; -use crate::{Context, Service}; +use crate::rustls::dep::pki_types::ServerName; +use crate::rustls::dep::rustls::ClientConfig; +use crate::rustls::dep::rustls::RootCertStore; +use crate::rustls::dep::tokio_rustls::{client::TlsStream, TlsConnector}; +use crate::rustls::verify::NoServerCertVerifier; +use crate::types::HttpsTunnel; use pin_project_lite::pin_project; use private::{ConnectorKindAuto, ConnectorKindSecure, ConnectorKindTunnel}; +use rama_core::error::{BoxError, ErrorExt, OpaqueError}; +use rama_core::{Context, Layer, Service}; +use rama_http_types::Version; +use rama_net::client::{ConnectorService, EstablishedClientConnection}; +use rama_net::stream::Stream; +use rama_net::transport::TryRefIntoTransportContext; use std::sync::OnceLock; use std::{fmt, sync::Arc}; use tokio::io::{AsyncRead, AsyncWrite}; @@ -546,7 +546,7 @@ mod private { /// The connections will only be done if the [`HttpsTunnel`] /// is present in the context. /// - /// [`HttpsTunnel`]: crate::tls::HttpsTunnel + /// [`HttpsTunnel`]: crate::HttpsTunnel pub struct ConnectorKindTunnel; } diff --git a/rama-tls/src/backend/rustls/client/mod.rs b/rama-tls/src/rustls/client/mod.rs similarity index 100% rename from rama-tls/src/backend/rustls/client/mod.rs rename to rama-tls/src/rustls/client/mod.rs diff --git a/rama-tls/src/backend/rustls/mod.rs b/rama-tls/src/rustls/mod.rs similarity index 96% rename from rama-tls/src/backend/rustls/mod.rs rename to rama-tls/src/rustls/mod.rs index cdd90b3a..ddaa3f5b 100644 --- a/rama-tls/src/backend/rustls/mod.rs +++ b/rama-tls/src/rustls/mod.rs @@ -43,7 +43,7 @@ pub mod dep { //! //! [`rustls`]: https://docs.rs/rustls //! [`tokio-rustls`]: https://docs.rs/tokio-rustls - //! [`TlsAcceptorLayer`]: crate::tls::backend::rustls::server::TlsAcceptorLayer + //! [`TlsAcceptorLayer`]: crate::rustls::server::TlsAcceptorLayer pub use rustls::*; diff --git a/rama-tls/src/backend/rustls/server/client_config.rs b/rama-tls/src/rustls/server/client_config.rs similarity index 95% rename from rama-tls/src/backend/rustls/server/client_config.rs rename to rama-tls/src/rustls/server/client_config.rs index d2855847..f18e86f4 100644 --- a/rama-tls/src/backend/rustls/server/client_config.rs +++ b/rama-tls/src/rustls/server/client_config.rs @@ -1,4 +1,4 @@ -use crate::tls::{backend::rustls::dep::rustls::ServerConfig, client::ClientHello}; +use crate::{rustls::dep::rustls::ServerConfig, types::client::ClientHello}; use std::{fmt, future::Future, sync::Arc}; /// A handler that allows you to define what to do with the client config, @@ -84,8 +84,8 @@ impl TlsClientConfigHandler { /// Consumes the handler and returns a new [`TlsClientConfigHandler`] which stores /// the client (TLS) config in the [`Context`]'s [`Extensions`]. /// - /// [`Context`]: crate::Context - /// [`Extensions`]: crate::context::Extensions + /// [`Context`]: rama_core::Context + /// [`Extensions`]: rama_core::context::Extensions pub fn store_client_hello(self) -> Self { Self { store_client_hello: true, diff --git a/rama-tls/src/backend/rustls/server/layer.rs b/rama-tls/src/rustls/server/layer.rs similarity index 96% rename from rama-tls/src/backend/rustls/server/layer.rs rename to rama-tls/src/rustls/server/layer.rs index d4a95b53..9546ab87 100644 --- a/rama-tls/src/backend/rustls/server/layer.rs +++ b/rama-tls/src/rustls/server/layer.rs @@ -1,5 +1,6 @@ use super::{TlsAcceptorService, TlsClientConfigHandler}; -use crate::{tls::backend::rustls::dep::rustls::ServerConfig, Layer}; +use crate::rustls::dep::rustls::ServerConfig; +use rama_core::Layer; use std::sync::Arc; /// A [`Layer`] which wraps the given service with a [`TlsAcceptorService`]. diff --git a/rama-tls/src/backend/rustls/server/mod.rs b/rama-tls/src/rustls/server/mod.rs similarity index 100% rename from rama-tls/src/backend/rustls/server/mod.rs rename to rama-tls/src/rustls/server/mod.rs diff --git a/rama-tls/src/backend/rustls/server/service.rs b/rama-tls/src/rustls/server/service.rs similarity index 95% rename from rama-tls/src/backend/rustls/server/service.rs rename to rama-tls/src/rustls/server/service.rs index f05e1855..44feeac7 100644 --- a/rama-tls/src/backend/rustls/server/service.rs +++ b/rama-tls/src/rustls/server/service.rs @@ -1,16 +1,14 @@ -use rama_utils::macros::define_inner_service_accessors; use crate::{ - stream::Stream, - tls::{ - backend::rustls::dep::{ - rustls::{server::Acceptor, ServerConfig}, - tokio_rustls::{server::TlsStream, LazyConfigAcceptor, TlsAcceptor}, - }, - client::ClientHello, - SecureTransport, + rustls::dep::{ + rustls::{server::Acceptor, ServerConfig}, + tokio_rustls::{server::TlsStream, LazyConfigAcceptor, TlsAcceptor}, }, - Context, Service, + types::client::ClientHello, + types::SecureTransport, }; +use rama_core::{Context, Service}; +use rama_net::stream::Stream; +use rama_utils::macros::define_inner_service_accessors; use std::{fmt, sync::Arc}; use super::{ServerConfigProvider, TlsClientConfigHandler}; diff --git a/rama-tls/src/backend/rustls/verify.rs b/rama-tls/src/rustls/verify.rs similarity index 98% rename from rama-tls/src/backend/rustls/verify.rs rename to rama-tls/src/rustls/verify.rs index 7fb94ee6..5506d3ec 100644 --- a/rama-tls/src/backend/rustls/verify.rs +++ b/rama-tls/src/rustls/verify.rs @@ -2,7 +2,7 @@ //! //! ... or rather the lack of verification where it is not needed. -use crate::tls::backend::rustls::dep::{ +use crate::rustls::dep::{ pki_types::{CertificateDer, ServerName, UnixTime}, rustls::{ client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, diff --git a/src/http.rs b/src/http.rs new file mode 100644 index 00000000..fc7ebb35 --- /dev/null +++ b/src/http.rs @@ -0,0 +1,26 @@ +//! rama http support +//! +//! mostly contains re-exports from +//! `rama-http` and `rama-http-backend`. + +pub use ::rama_http::{ + header, + response::{self, IntoResponse, Response}, + Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, Method, + Request, Scheme, StatusCode, Uri, Version, + headers, matcher, service, io, dep, RequestContext, +}; + +pub mod layer { + //! Http [`Layer`]s provided by Rama. + //! + //! mostly contains re-exports from + //! `rama-http` and `rama-http-backend`. + + pub use ::rama_http::layer::*; + pub use ::rama_http_backend::layer::*; +} + +pub use ::rama_http_backend::{ + server, client, +}; diff --git a/src/lib.rs b/src/lib.rs index 1422fc43..93f889fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -281,7 +281,8 @@ pub use ::rama_core::{ Layer, Service, }; -pub mod tcp; +#[cfg(feature = "tcp")] +pub use ::rama_tcp as tcp; #[cfg(feature = "telemetry")] pub use ::rama_core::telemetry; @@ -289,10 +290,11 @@ pub use ::rama_core::telemetry; #[cfg(feature = "tls")] pub use ::rama_tls as tls; -#[cfg(feature = "http")] -pub use ::rama_http as http; +#[cfg(feature = "net")] +pub use ::rama_net as net; -// TODO: integrate http-backend in here somehow... +#[cfg(feature = "http")] +pub mod http; #[cfg(feature = "proxy")] pub use ::rama_proxy as proxy; diff --git a/src/tcp/mod.rs b/src/tcp/mod.rs deleted file mode 100644 index 4a09c64b..00000000 --- a/src/tcp/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! TCP module for Rama. - -pub mod client; -pub mod server; -pub mod utils; From bad0be1800fa60b00bb57ba8152e601d7f765995 Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 16:05:41 +0200 Subject: [PATCH 08/24] create rama-haproxy and fix rama-http + rama-http-backend --- Cargo.lock | 34 +- Cargo.toml | 5 +- rama-core/src/dns/mod.rs | 4 +- rama-haproxy/Cargo.toml | 30 + rama-haproxy/README.md | 47 + rama-haproxy/src/client/layer.rs | 840 ++++++++++++++++++ rama-haproxy/src/client/mod.rs | 7 + rama-haproxy/src/lib.rs | 14 + rama-haproxy/src/protocol/ip.rs | 62 ++ rama-haproxy/src/protocol/mod.rs | 126 +++ rama-haproxy/src/protocol/v1/error.rs | 116 +++ rama-haproxy/src/protocol/v1/mod.rs | 701 +++++++++++++++ rama-haproxy/src/protocol/v1/model.rs | 307 +++++++ rama-haproxy/src/protocol/v2/builder.rs | 638 +++++++++++++ rama-haproxy/src/protocol/v2/error.rs | 47 + rama-haproxy/src/protocol/v2/mod.rs | 749 ++++++++++++++++ rama-haproxy/src/protocol/v2/model.rs | 475 ++++++++++ rama-haproxy/src/server/layer.rs | 177 ++++ rama-haproxy/src/server/mod.rs | 7 + rama-http-backend/Cargo.toml | 19 +- rama-http-backend/src/client/conn.rs | 10 +- rama-http-backend/src/client/error.rs | 89 -- rama-http-backend/src/client/mod.rs | 32 +- .../src/client/proxy}/layer/mod.rs | 0 .../src/client/proxy}/layer/proxy_address.rs | 4 +- .../client/proxy}/layer/proxy_auth_header.rs | 13 +- .../proxy}/layer/proxy_connector/connector.rs | 12 +- .../proxy}/layer/proxy_connector/layer.rs | 0 .../proxy}/layer/proxy_connector/mod.rs | 0 .../proxy}/layer/proxy_connector/service.rs | 17 +- .../src/client/proxy}/mod.rs | 0 rama-http-backend/src/client/svc.rs | 22 +- rama-http-backend/src/executor.rs | 2 +- rama-http-backend/src/lib.rs | 1 - rama-http-backend/src/server/hyper_conn.rs | 9 +- .../src/server/layer/upgrade/layer.rs | 2 +- .../src/server/layer/upgrade/service.rs | 2 +- rama-http-backend/src/server/service.rs | 2 +- rama-http-backend/src/server/svc_hyper.rs | 10 +- rama-http-types/src/response/mod.rs | 6 +- rama-http/Cargo.toml | 12 +- rama-http/src/headers/common/accept.rs | 18 +- rama-http/src/layer/auth/add_authorization.rs | 12 +- .../layer/auth/async_require_authorization.rs | 22 +- .../src/layer/auth/require_authorization.rs | 10 +- rama-http/src/layer/body_limit.rs | 8 +- rama-http/src/layer/catch_panic.rs | 26 +- .../layer/classify/grpc_errors_as_failures.rs | 2 +- rama-http/src/layer/classify/mod.rs | 6 +- rama-http/src/layer/compression/mod.rs | 16 +- rama-http/src/layer/compression/predicate.rs | 2 +- rama-http/src/layer/compression/service.rs | 6 +- rama-http/src/layer/cors/mod.rs | 52 +- rama-http/src/layer/decompression/mod.rs | 24 +- rama-http/src/layer/dns/dns_map/layer.rs | 13 +- rama-http/src/layer/dns/dns_map/service.rs | 5 +- rama-http/src/layer/dns/dns_resolve/layer.rs | 9 +- .../src/layer/dns/dns_resolve/service.rs | 4 +- rama-http/src/layer/dns/mod.rs | 11 +- rama-http/src/layer/error_handling.rs | 14 +- rama-http/src/layer/follow_redirect/mod.rs | 22 +- .../src/layer/follow_redirect/policy/mod.rs | 12 +- .../src/layer/follow_redirect/policy/or.rs | 3 +- .../src/layer/forwarded/get_forwarded.rs | 12 +- .../src/layer/forwarded/set_forwarded.rs | 24 +- rama-http/src/layer/header_config.rs | 20 +- rama-http/src/layer/header_option_value.rs | 22 +- rama-http/src/layer/map_request_body.rs | 12 +- rama-http/src/layer/map_response_body.rs | 12 +- rama-http/src/layer/mod.rs | 2 +- rama-http/src/layer/normalize_path.rs | 12 +- rama-http/src/layer/opentelemetry.rs | 5 +- rama-http/src/layer/propagate_headers.rs | 10 +- rama-http/src/layer/proxy_auth.rs | 3 +- rama-http/src/layer/remove_header/request.rs | 17 +- rama-http/src/layer/remove_header/response.rs | 15 +- rama-http/src/layer/request_id.rs | 12 +- .../src/layer/required_header/request.rs | 3 +- .../src/layer/required_header/response.rs | 3 +- rama-http/src/layer/retry/managed.rs | 6 +- rama-http/src/layer/retry/mod.rs | 9 +- rama-http/src/layer/retry/policy.rs | 6 +- rama-http/src/layer/retry/tests.rs | 2 +- rama-http/src/layer/sensitive_headers.rs | 53 +- rama-http/src/layer/set_header/request.rs | 20 +- rama-http/src/layer/set_header/response.rs | 24 +- rama-http/src/layer/set_status.rs | 10 +- rama-http/src/layer/timeout.rs | 14 +- rama-http/src/layer/trace/mod.rs | 58 +- rama-http/src/layer/trace/service.rs | 2 +- rama-http/src/layer/ua.rs | 13 +- rama-http/src/layer/validate_request/mod.rs | 30 +- .../validate_request_header.rs | 4 +- rama-http/src/lib.rs | 3 +- rama-http/src/matcher/domain.rs | 3 +- .../src/service}/client/ext.rs | 114 ++- rama-http/src/service/client/mod.rs | 5 + rama-http/src/service/fs/serve_dir/mod.rs | 35 +- rama-http/src/service/fs/serve_dir/tests.rs | 92 +- rama-http/src/service/fs/serve_file.rs | 42 +- rama-http/src/service/mod.rs | 1 + .../service/web/endpoint/extract/authority.rs | 4 +- .../web/endpoint/extract/body/bytes.rs | 9 +- .../service/web/endpoint/extract/body/form.rs | 30 +- .../service/web/endpoint/extract/body/json.rs | 3 +- .../service/web/endpoint/extract/body/mod.rs | 9 +- .../service/web/endpoint/extract/body/text.rs | 27 +- .../src/service/web/endpoint/extract/dns.rs | 2 +- .../src/service/web/endpoint/extract/host.rs | 4 +- .../web/endpoint/extract/typed_header.rs | 10 +- rama-http/src/service/web/endpoint/mod.rs | 18 +- rama-http/src/service/web/endpoint/service.rs | 2 +- rama-http/src/service/web/service.rs | 22 +- rama-http/src/utils/macros/http_error.rs | 2 +- rama-http/src/utils/mod.rs | 1 + rama-net/src/http/request_context.rs | 4 +- rama-proxy/src/http/mod.rs | 14 - rama-proxy/src/lib.rs | 8 +- rama-ua/src/info.rs | 14 +- rama-ua/src/lib.rs | 18 +- src/lib.rs | 12 +- 121 files changed, 5084 insertions(+), 806 deletions(-) create mode 100644 rama-haproxy/Cargo.toml create mode 100644 rama-haproxy/README.md create mode 100644 rama-haproxy/src/client/layer.rs create mode 100644 rama-haproxy/src/client/mod.rs create mode 100644 rama-haproxy/src/lib.rs create mode 100644 rama-haproxy/src/protocol/ip.rs create mode 100644 rama-haproxy/src/protocol/mod.rs create mode 100644 rama-haproxy/src/protocol/v1/error.rs create mode 100644 rama-haproxy/src/protocol/v1/mod.rs create mode 100644 rama-haproxy/src/protocol/v1/model.rs create mode 100644 rama-haproxy/src/protocol/v2/builder.rs create mode 100644 rama-haproxy/src/protocol/v2/error.rs create mode 100644 rama-haproxy/src/protocol/v2/mod.rs create mode 100644 rama-haproxy/src/protocol/v2/model.rs create mode 100644 rama-haproxy/src/server/layer.rs create mode 100644 rama-haproxy/src/server/mod.rs delete mode 100644 rama-http-backend/src/client/error.rs rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/layer/mod.rs (100%) rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/layer/proxy_address.rs (99%) rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/layer/proxy_auth_header.rs (93%) rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/layer/proxy_connector/connector.rs (96%) rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/layer/proxy_connector/layer.rs (100%) rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/layer/proxy_connector/mod.rs (100%) rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/layer/proxy_connector/service.rs (96%) rename {rama-proxy/src/http/client => rama-http-backend/src/client/proxy}/mod.rs (100%) rename {rama-http-backend/src => rama-http/src/service}/client/ext.rs (87%) create mode 100644 rama-http/src/service/client/mod.rs delete mode 100644 rama-proxy/src/http/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 7110e5af..6e46b062 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1752,8 +1752,6 @@ dependencies = [ "http-body-util", "http-range-header", "httpdate", - "hyper", - "hyper-util", "ipnet", "iri-string", "itertools 0.13.0", @@ -1768,6 +1766,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rama-core", + "rama-haproxy", "rama-http", "rama-http-backend", "rama-macros", @@ -1849,6 +1848,17 @@ dependencies = [ "rama", ] +[[package]] +name = "rama-haproxy" +version = "0.2.0-alpha.2" +dependencies = [ + "rama-core", + "rama-net", + "tokio", + "tokio-test", + "tracing", +] + [[package]] name = "rama-http" version = "0.2.0-alpha.2" @@ -1856,8 +1866,10 @@ dependencies = [ "async-compression", "base64 0.22.1", "bitflags", + "brotli", "bytes", "const_format", + "flate2", "futures-core", "futures-lite", "headers", @@ -1867,15 +1879,18 @@ dependencies = [ "http-range-header", "httpdate", "iri-string", + "itertools 0.13.0", "mime", "mime_guess", + "parking_lot", "paste", "percent-encoding", "pin-project-lite", "rama-core", + "rama-http-backend", "rama-http-types", "rama-net", - "rama-tls", + "rama-tcp", "rama-ua", "rama-utils", "regex", @@ -1883,19 +1898,32 @@ dependencies = [ "serde_html_form", "serde_json", "sync_wrapper 1.0.1", + "tempfile", "tokio", "tokio-test", "tokio-util", "tracing", + "tracing-subscriber", "uuid", + "zstd", ] [[package]] name = "rama-http-backend" version = "0.2.0-alpha.2" dependencies = [ + "h2", + "hyper", + "hyper-util", + "pin-project-lite", "rama-core", + "rama-http-types", + "rama-net", "rama-tcp", + "rama-tls", + "rama-utils", + "tokio", + "tracing", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6013ba2c..f7a68019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "rama-macros", "rama-net", "rama-proxy", + "rama-haproxy", "rama-tls", "rama-ua", "rama-utils", @@ -145,6 +146,7 @@ net = [] tcp = ["net"] http = ["dep:rama-http", "dep:rama-http-backend", "net", "ua"] proxy = ["dep:rama-proxy"] +haproxy = ["dep:rama-haproxy"] ua = ["dep:rama-ua"] [build-dependencies] @@ -165,8 +167,6 @@ http-body = { workspace = true } http-body-util = { workspace = true } http-range-header = { workspace = true } httpdate = { workspace = true } -hyper = { workspace = true, features = ["http1", "http2", "server", "client"] } -hyper-util = { workspace = true, features = ["tokio", "server-auto"] } ipnet = { workspace = true } iri-string = { workspace = true } mime = { workspace = true } @@ -184,6 +184,7 @@ rama-http = { version = "0.2.0-alpha.2", path = "rama-http", optional = true } rama-http-backend = { version = "0.2.0-alpha.2", path = "rama-http-backend", optional = true } rama-macros = { version = "0.2.0-alpha.2", path = "rama-macros" } rama-proxy = { version = "0.2.0-alpha.2", path = "rama-proxy", optional = true } +rama-haproxy = { version = "0.2.0-alpha.2", path = "rama-haproxy", optional = true } rama-tls = { version = "0.2.0-alpha.2", path = "rama-tls", optional = true } rama-ua = { version = "0.2.0-alpha.2", path = "rama-ua", optional = true } rama-utils = { version = "0.2.0-alpha.2", path = "rama-utils" } diff --git a/rama-core/src/dns/mod.rs b/rama-core/src/dns/mod.rs index 1d5a9f90..1895629a 100644 --- a/rama-core/src/dns/mod.rs +++ b/rama-core/src/dns/mod.rs @@ -126,7 +126,7 @@ impl Dns { pub fn insert_overwrite(&mut self, name: impl TryIntoName, addresses: Vec) -> Result<&mut Self, OpaqueError> { self.overwrites .get_or_insert_with(HashMap::new) - .insert(name.try_into_name()?, addresses); + .insert(Name::fqdn_from_domain(name)?, addresses); Ok(self) } @@ -139,7 +139,7 @@ impl Dns { let map = self.overwrites .get_or_insert_with(HashMap::new); for (name, addresses) in overwrites.into_iter() { - map.insert(name.try_into_name()?, addresses); + map.insert(Name::fqdn_from_domain(name)?, addresses); } Ok(self) } diff --git a/rama-haproxy/Cargo.toml b/rama-haproxy/Cargo.toml new file mode 100644 index 00000000..987e6f05 --- /dev/null +++ b/rama-haproxy/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "rama-haproxy" +description = "rama HaProxy support" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = [] + +[dependencies] +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } +tokio = { workspace = true, features = ["macros", "io-std"] } +tracing = { workspace = true } + +[dev-dependencies] +tokio-test = { workspace = true } + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-haproxy/README.md b/rama-haproxy/README.md new file mode 100644 index 00000000..dc5d4cf2 --- /dev/null +++ b/rama-haproxy/README.md @@ -0,0 +1,47 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramahaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-haproxy.svg +[crates-url]: https://crates.io/crates/rama-haproxy +[docs-badge]: https://img.shields.io/docsrs/rama-haproxy/latest +[docs-url]: https://docs.rs/rama-haproxy/latest/rama_haproxy/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramahaproxy.org/book/why_rama). + +## rama-haproxy + +Rama HaProxy support. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-haproxy/src/client/layer.rs b/rama-haproxy/src/client/layer.rs new file mode 100644 index 00000000..04fcf653 --- /dev/null +++ b/rama-haproxy/src/client/layer.rs @@ -0,0 +1,840 @@ +use std::{fmt, marker::PhantomData, net::IpAddr}; + +use crate::protocol::{v1, v2}; +use rama_core::{ + error::{BoxError, ErrorContext, OpaqueError}, + Context, Layer, Service, +}; +use rama_net::{ + client::{ConnectorService, EstablishedClientConnection}, + forwarded::Forwarded, + stream::{SocketInfo, Stream}, +}; +use tokio::io::AsyncWriteExt; + +/// Layer to encode and write the HaProxy Protocol, +/// as a client on the connected stream. +/// +/// This connector should in most cases +/// happen as the first thing after establishing the connection. +#[derive(Debug, Clone)] +pub struct HaProxyLayer

{ + version: V, + _phantom: PhantomData, +} + +impl HaProxyLayer { + /// Create a new [`HaProxyLayer`] for the TCP protocol (default). + /// + /// This is in the PROXY spec referred to as: + /// + /// - TCP4 (for IPv4, v1) + /// - TCP6 (for IPv6, v1) + /// - Stream (v2) + pub fn tcp() -> Self { + HaProxyLayer { + version: Default::default(), + _phantom: PhantomData, + } + } + + /// Use version one of PROXY protocol, instead of the + /// default version two. + /// + /// Version one makes use of a less advanced text protocol, + /// instead the more advanced binary v2 protocol. + /// + /// Use this only if you have no control over a v1-only server. + pub fn v1(self) -> HaProxyLayer { + HaProxyLayer { + version: Default::default(), + _phantom: PhantomData, + } + } +} + +impl HaProxyLayer { + /// Create a new [`HaProxyLayer`] for the UDP protocol, + /// instead of the default TCP protocol. + /// + /// This is in the PROXY spec referred to as: + /// + /// - Datagram (v2) + pub fn udp() -> Self { + HaProxyLayer { + version: Default::default(), + _phantom: PhantomData, + } + } +} + +impl

HaProxyLayer

{ + /// Attach a custom bytes payload to the PROXY header. + /// + /// NOTE this is only possible in Version two of the PROXY Protocol. + /// In case you downgrade this [`HaProxyLayer`] to version one later + /// using [`Self::v1`] this payload will be dropped. + pub fn payload(mut self, payload: Vec) -> Self { + self.version.payload = Some(payload); + self + } + + /// Attach a custom bytes payload to the PROXY header. + /// + /// NOTE this is only possible in Version two of the PROXY Protocol. + /// In case you downgrade this [`HaProxyLayer`] to version one later + /// using [`Self::v1`] this payload will be dropped. + pub fn set_payload(&mut self, payload: Vec) -> &mut Self { + self.version.payload = Some(payload); + self + } +} + +impl Layer for HaProxyLayer { + type Service = HaProxyService; + + fn layer(&self, inner: S) -> Self::Service { + HaProxyService { + inner, + version: self.version.clone(), + _phantom: PhantomData, + } + } +} + +/// Service to encode and write the HaProxy Protocol +/// as a client on the connected stream. +/// +/// This connector should in most cases +/// happen as the first thing after establishing the connection. +pub struct HaProxyService { + inner: S, + version: V, + _phantom: PhantomData, +} + +impl HaProxyService { + /// Create a new [`HaProxyService`] for the TCP protocol (default). + /// + /// This is in the PROXY spec referred to as: + /// + /// - TCP4 (for IPv4, v1) + /// - TCP6 (for IPv6, v1) + /// - Stream (v2) + pub fn tcp(inner: S) -> Self { + HaProxyService { + inner, + version: Default::default(), + _phantom: PhantomData, + } + } + + /// Use version one of PROXY protocol, instead of the + /// default version two. + /// + /// Version one makes use of a less advanced text protocol, + /// instead the more advanced binary v2 protocol. + /// + /// Use this only if you have no control over a v1-only server. + pub fn v1(self) -> HaProxyService { + HaProxyService { + inner: self.inner, + version: Default::default(), + _phantom: PhantomData, + } + } +} + +impl HaProxyService { + /// Create a new [`HaProxyService`] for the UDP protocol, + /// instead of the default TCP protocol. + /// + /// This is in the PROXY spec referred to as: + /// + /// - Datagram (v2) + pub fn udp(inner: S) -> Self { + HaProxyService { + inner, + version: Default::default(), + _phantom: PhantomData, + } + } +} + +impl HaProxyService { + /// Attach a custom bytes payload to the PROXY header. + /// + /// NOTE this is only possible in Version two of the PROXY Protocol. + /// In case you downgrade this [`HaProxyLayer`] to version one later + /// using [`Self::v1`] this payload will be dropped. + pub fn payload(mut self, payload: Vec) -> Self { + self.version.payload = Some(payload); + self + } + + /// Attach a custom bytes payload to the PROXY header. + /// + /// NOTE this is only possible in Version two of the PROXY Protocol. + /// In case you downgrade this [`HaProxyLayer`] to version one later + /// using [`Self::v1`] this payload will be dropped. + pub fn set_payload(&mut self, payload: Vec) -> &mut Self { + self.version.payload = Some(payload); + self + } +} + +impl fmt::Debug for HaProxyService { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("HaProxyService") + .field("inner", &self.inner) + .field("version", &self.version) + .field( + "_phantom", + &format_args!("{}", std::any::type_name::()), + ) + .finish() + } +} + +impl Clone for HaProxyService { + fn clone(&self) -> Self { + HaProxyService { + inner: self.inner.clone(), + version: self.version.clone(), + _phantom: PhantomData, + } + } +} + +impl Service for HaProxyService +where + S: ConnectorService>, + P: Send + 'static, + State: Send + Sync + 'static, + Request: Send + 'static, +{ + type Response = EstablishedClientConnection; + type Error = BoxError; + + async fn serve( + &self, + ctx: Context, + req: Request, + ) -> Result { + let EstablishedClientConnection { + ctx, + req, + mut conn, + addr, + } = self.inner.connect(ctx, req).await.map_err(Into::into)?; + + let src = ctx + .get::() + .and_then(|f| f.client_socket_addr()) + .or_else(|| ctx.get::().map(|info| *info.peer_addr())) + .ok_or_else(|| { + OpaqueError::from_display("PROXY client (v1): missing src socket address") + })?; + + let addresses = match (src.ip(), addr.ip()) { + (IpAddr::V4(src_ip), IpAddr::V4(dst_ip)) => { + v1::Addresses::new_tcp4(src_ip, dst_ip, src.port(), addr.port()) + } + (IpAddr::V6(src_ip), IpAddr::V6(dst_ip)) => { + v1::Addresses::new_tcp6(src_ip, dst_ip, src.port(), addr.port()) + } + (_, _) => { + return Err(OpaqueError::from_display( + "PROXY client (v1): IP version mismatch between src and dest", + ) + .into()) + } + }; + + conn.write_all(addresses.to_string().as_bytes()) + .await + .context("PROXY client (v1): write addresses")?; + + Ok(EstablishedClientConnection { + ctx, + req, + conn, + addr, + }) + } +} + +impl Service for HaProxyService +where + S: Service< + State, + Request, + Response = EstablishedClientConnection, + Error: Into, + >, + P: protocol::Protocol + Send + 'static, + State: Send + Sync + 'static, + Request: Send + 'static, + T: Stream + Unpin, +{ + type Response = EstablishedClientConnection; + type Error = BoxError; + + async fn serve( + &self, + ctx: Context, + req: Request, + ) -> Result { + let EstablishedClientConnection { + ctx, + req, + mut conn, + addr, + } = self.inner.serve(ctx, req).await.map_err(Into::into)?; + + let src = ctx + .get::() + .and_then(|f| f.client_socket_addr()) + .or_else(|| ctx.get::().map(|info| *info.peer_addr())) + .ok_or_else(|| { + OpaqueError::from_display("PROXY client (v2): missing src socket address") + })?; + + let builder = match (src.ip(), addr.ip()) { + (IpAddr::V4(src_ip), IpAddr::V4(dst_ip)) => v2::Builder::with_addresses( + v2::Version::Two | v2::Command::Proxy, + P::v2_protocol(), + v2::IPv4::new(src_ip, dst_ip, src.port(), addr.port()), + ), + (IpAddr::V6(src_ip), IpAddr::V6(dst_ip)) => v2::Builder::with_addresses( + v2::Version::Two | v2::Command::Proxy, + P::v2_protocol(), + v2::IPv6::new(src_ip, dst_ip, src.port(), addr.port()), + ), + (_, _) => { + return Err(OpaqueError::from_display( + "PROXY client (v2): IP version mismatch between src and dest", + ) + .into()) + } + }; + + let builder = if let Some(payload) = self.version.payload.as_deref() { + builder + .write_payload(payload) + .context("PROXY client (v2): write custom binary payload to to header")? + } else { + builder + }; + + let header = builder + .build() + .context("PROXY client (v2): encode header")?; + conn.write_all(&header[..]) + .await + .context("PROXY client (v2): write header")?; + + Ok(EstablishedClientConnection { + ctx, + req, + conn, + addr, + }) + } +} + +pub mod version { + //! Marker traits for the HaProxy (PROXY) version to be used by client layer (service). + + #[derive(Debug, Clone, Default)] + /// Use version 1 of the PROXY protocol. + /// + /// See [`crate::protocol`] for more information. + #[non_exhaustive] + pub struct One; + + #[derive(Debug, Clone, Default)] + /// Use version 2 of the PROXY protocol. + /// + /// See [`crate::protocol`] for more information. + pub struct Two { + pub(crate) payload: Option>, + } +} + +pub mod protocol { + //! Marker traits for the HaProxy (PROXY) protocol to be used by client layer (service). + + use crate::protocol::v2; + + #[derive(Debug, Clone)] + /// Encode the data for the TCP protocol (possible in [`super::version::One`] and [`super::version::Two`]). + /// + /// See [`crate::protocol`] for more information. + pub struct Tcp; + + #[derive(Debug, Clone)] + /// Encode the data for the UDP protocol (possible only in [`super::version::Two`]). + /// + /// See [`crate::protocol`] for more information. + pub struct Udp; + + pub(super) trait Protocol { + /// Return the v2 PROXY protocol linked to the protocol implementation. + fn v2_protocol() -> v2::Protocol; + } + + impl Protocol for Tcp { + fn v2_protocol() -> v2::Protocol { + v2::Protocol::Stream + } + } + + impl Protocol for Udp { + fn v2_protocol() -> v2::Protocol { + v2::Protocol::Datagram + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rama_core::{service::service_fn, Layer}; + use rama_net::forwarded::{ForwardedElement, NodeId}; + use std::convert::Infallible; + use tokio_test::io::Builder; + + #[tokio::test] + async fn test_v1_tcp() { + for (expected_line, input_ctx, target_addr) in [ + ( + "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n", + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); + ctx + }, + "192.168.1.101:443", + ), + ( + "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n", + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443".parse().unwrap())); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for(NodeId::try_from("127.0.1.2:80").unwrap()))); + ctx + }, + "192.168.1.101:443", + ), + ( + "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n", + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443".parse().unwrap())); + ctx + }, + "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", + ), + ( + "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n", + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for(NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443").unwrap()))); + ctx + }, + "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", + ), + ] { + let svc = HaProxyLayer::tcp().v1() + .layer(service_fn(move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new().write(expected_line.as_bytes()).build(), + addr: target_addr.parse().unwrap(), + }) + })); + svc.serve(input_ctx, ()).await.unwrap(); + } + } + + #[tokio::test] + async fn test_v1_tcp_ip_version_mismatch() { + for (input_ctx, target_addr) in [ + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" + .parse() + .unwrap(), + )); + ctx + }, + "192.168.1.101:443", + ), + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), + ))); + ctx + }, + "192.168.1.101:443", + ), + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); + ctx + }, + "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", + ), + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" + .parse() + .unwrap(), + )); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("127.0.1.2:80").unwrap(), + ))); + ctx + }, + "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", + ), + ] { + let svc = HaProxyLayer::tcp() + .v1() + .layer(service_fn(move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new().build(), + addr: target_addr.parse().unwrap(), + }) + })); + assert!(svc.serve(input_ctx, ()).await.is_err()); + } + } + + #[tokio::test] + async fn test_v1_tcp_missing_src() { + for (input_ctx, target_addr) in [ + (Context::default(), "192.168.1.101:443"), + ( + Context::default(), + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443", + ), + ] { + let svc = HaProxyLayer::tcp() + .v1() + .layer(service_fn(move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new().build(), + addr: target_addr.parse().unwrap(), + }) + })); + assert!(svc.serve(input_ctx, ()).await.is_err()); + } + } + + #[tokio::test] + async fn test_v2_tcp4() { + for input_ctx in [ + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); + ctx + }, + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443" + .parse() + .unwrap(), + )); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("127.0.0.1:80").unwrap(), + ))); + ctx + }, + ] { + let svc = HaProxyLayer::tcp().payload(vec![42]).layer(service_fn( + move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new() + .write(&[ + b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', + b'T', b'\n', 0x21, 0x11, 0, 13, 127, 0, 0, 1, 192, 168, 1, 1, 0, + 80, 1, 187, 42, + ]) + .build(), + addr: "192.168.1.1:443".parse().unwrap(), + }) + }, + )); + svc.serve(input_ctx, ()).await.unwrap(); + } + } + + #[tokio::test] + async fn test_v2_udp4() { + for input_ctx in [ + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); + ctx + }, + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443" + .parse() + .unwrap(), + )); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("127.0.0.1:80").unwrap(), + ))); + ctx + }, + ] { + let svc = HaProxyLayer::udp().payload(vec![42]).layer(service_fn( + move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new() + .write(&[ + b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', + b'T', b'\n', 0x21, 0x12, 0, 13, 127, 0, 0, 1, 192, 168, 1, 1, 0, + 80, 1, 187, 42, + ]) + .build(), + addr: "192.168.1.1:443".parse().unwrap(), + }) + }, + )); + svc.serve(input_ctx, ()).await.unwrap(); + } + } + + #[tokio::test] + async fn test_v2_tcp6() { + for input_ctx in [ + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" + .parse() + .unwrap(), + )); + ctx + }, + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), + ))); + ctx + }, + ] { + let svc = HaProxyLayer::tcp().payload(vec![42]).layer(service_fn( + move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new() + .write(&[ + b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', + b'T', b'\n', 0x21, 0x21, 0, 37, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, + 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0x43, + 0x21, 0x87, 0x65, 0xba, 0x09, 0xfe, 0xdc, 0xcd, 0xef, 0x90, 0xab, + 0x56, 0x78, 0x12, 0x34, 0, 80, 1, 187, 42, + ]) + .build(), + addr: "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:443" + .parse() + .unwrap(), + }) + }, + )); + svc.serve(input_ctx, ()).await.unwrap(); + } + } + + #[tokio::test] + async fn test_v2_udp6() { + for input_ctx in [ + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" + .parse() + .unwrap(), + )); + ctx + }, + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), + ))); + ctx + }, + ] { + let svc = HaProxyLayer::udp().payload(vec![42]).layer(service_fn( + move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new() + .write(&[ + b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', + b'T', b'\n', 0x21, 0x22, 0, 37, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, + 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0x43, + 0x21, 0x87, 0x65, 0xba, 0x09, 0xfe, 0xdc, 0xcd, 0xef, 0x90, 0xab, + 0x56, 0x78, 0x12, 0x34, 0, 80, 1, 187, 42, + ]) + .build(), + addr: "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:443" + .parse() + .unwrap(), + }) + }, + )); + svc.serve(input_ctx, ()).await.unwrap(); + } + } + + #[tokio::test] + async fn test_v2_ip_version_mismatch() { + for (input_ctx, target_addr) in [ + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" + .parse() + .unwrap(), + )); + ctx + }, + "192.168.1.101:443", + ), + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), + ))); + ctx + }, + "192.168.1.101:443", + ), + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); + ctx + }, + "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", + ), + ( + { + let mut ctx = Context::default(); + ctx.insert(SocketInfo::new( + None, + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" + .parse() + .unwrap(), + )); + ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( + NodeId::try_from("127.0.1.2:80").unwrap(), + ))); + ctx + }, + "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", + ), + ] { + // TCP + + let svc = HaProxyLayer::tcp().layer(service_fn(move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new().build(), + addr: target_addr.parse().unwrap(), + }) + })); + assert!(svc.serve(input_ctx.clone(), ()).await.is_err()); + + // UDP + + let svc = HaProxyLayer::udp().layer(service_fn(move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new().build(), + addr: target_addr.parse().unwrap(), + }) + })); + assert!(svc.serve(input_ctx, ()).await.is_err()); + } + } + + #[tokio::test] + async fn test_v2_missing_src() { + for (input_ctx, target_addr) in [ + (Context::default(), "192.168.1.101:443"), + ( + Context::default(), + "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443", + ), + ] { + // TCP + + let svc = HaProxyLayer::tcp().layer(service_fn(move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new().build(), + addr: target_addr.parse().unwrap(), + }) + })); + assert!(svc.serve(input_ctx.clone(), ()).await.is_err()); + + // UDP + + let svc = HaProxyLayer::udp().layer(service_fn(move |ctx, req| async move { + Ok::<_, Infallible>(EstablishedClientConnection { + ctx, + req, + conn: Builder::new().build(), + addr: target_addr.parse().unwrap(), + }) + })); + assert!(svc.serve(input_ctx.clone(), ()).await.is_err()); + } + } +} diff --git a/rama-haproxy/src/client/mod.rs b/rama-haproxy/src/client/mod.rs new file mode 100644 index 00000000..4a1d196e --- /dev/null +++ b/rama-haproxy/src/client/mod.rs @@ -0,0 +1,7 @@ +//! HaProxy Protocol Client support +//! +//! + +mod layer; +#[doc(inline)] +pub use layer::{protocol, version, HaProxyLayer, HaProxyService}; diff --git a/rama-haproxy/src/lib.rs b/rama-haproxy/src/lib.rs new file mode 100644 index 00000000..81737884 --- /dev/null +++ b/rama-haproxy/src/lib.rs @@ -0,0 +1,14 @@ +//! rama HaProxy support +//! +//! +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +pub mod client; +pub mod protocol; +pub mod server; diff --git a/rama-haproxy/src/protocol/ip.rs b/rama-haproxy/src/protocol/ip.rs new file mode 100644 index 00000000..d4cfcc5c --- /dev/null +++ b/rama-haproxy/src/protocol/ip.rs @@ -0,0 +1,62 @@ +//! Models for storing IP v4 and v6 addresses and ports. + +use std::net::{Ipv4Addr, Ipv6Addr}; + +/// The source and destination IPv4 addresses and TCP ports of a header. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct IPv4 { + /// The source IPv4 address. + pub source_address: Ipv4Addr, + /// The source TCP/UDP port. + pub source_port: u16, + /// The destination IPv4 address. + pub destination_address: Ipv4Addr, + /// The destination TCP/UDP port. + pub destination_port: u16, +} + +impl IPv4 { + /// Create a new IPv4 addresses. + pub fn new>( + source_address: T, + destination_address: T, + source_port: u16, + destination_port: u16, + ) -> Self { + IPv4 { + source_address: source_address.into(), + source_port, + destination_address: destination_address.into(), + destination_port, + } + } +} +/// The source and destination IPv6 addresses and TCP ports of a header. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct IPv6 { + /// The source IPv6 address. + pub source_address: Ipv6Addr, + /// The source TCP/UDP port. + pub source_port: u16, + /// The destination IPv6 address. + pub destination_address: Ipv6Addr, + /// The destination TCP/UDP port. + pub destination_port: u16, +} + +impl IPv6 { + /// Create a new IPv6 addresses. + pub fn new>( + source_address: T, + destination_address: T, + source_port: u16, + destination_port: u16, + ) -> Self { + IPv6 { + source_address: source_address.into(), + source_port, + destination_address: destination_address.into(), + destination_port, + } + } +} diff --git a/rama-haproxy/src/protocol/mod.rs b/rama-haproxy/src/protocol/mod.rs new file mode 100644 index 00000000..8177e8e2 --- /dev/null +++ b/rama-haproxy/src/protocol/mod.rs @@ -0,0 +1,126 @@ +//! A Proxy Protocol Parser written in Rust. +//! Supports both text and binary versions of the header protocol. +//! +//! Forked from (Apache-2.0 license), +//! a crate originally developed by Miguel D. Salcedo. The fork happened +//! on commit `28c5db92fda7337fc1ef36e6f19db96d511cd319`. + +mod ip; + +pub mod v1; +pub mod v2; + +/// The canonical way to determine when a streamed header should be retried in a streaming context. +/// The protocol states that servers may choose to support partial headers or to close the connection if the header is not present all at once. +pub trait PartialResult { + /// Tests whether this `Result` is successful or whether the error is terminal. + /// A terminal error will not result in a success even with more bytes. + /// Retrying with the same -- or more -- input will not change the result. + fn is_complete(&self) -> bool { + !self.is_incomplete() + } + + /// Tests whether this `Result` is incomplete. + /// An action that leads to an incomplete result may have a different result with more bytes. + /// Retrying with the same input will not change the result. + fn is_incomplete(&self) -> bool; +} + +impl PartialResult for Result { + fn is_incomplete(&self) -> bool { + match self { + Ok(_) => false, + Err(error) => error.is_incomplete(), + } + } +} + +impl PartialResult for v1::ParseError { + fn is_incomplete(&self) -> bool { + matches!( + self, + v1::ParseError::Partial + | v1::ParseError::MissingPrefix + | v1::ParseError::MissingProtocol + | v1::ParseError::MissingSourceAddress + | v1::ParseError::MissingDestinationAddress + | v1::ParseError::MissingSourcePort + | v1::ParseError::MissingDestinationPort + | v1::ParseError::MissingNewLine + ) + } +} + +impl PartialResult for v1::BinaryParseError { + fn is_incomplete(&self) -> bool { + match self { + v1::BinaryParseError::Parse(error) => error.is_incomplete(), + v1::BinaryParseError::InvalidUtf8(_) => false, + } + } +} + +impl PartialResult for v2::ParseError { + fn is_incomplete(&self) -> bool { + matches!( + self, + v2::ParseError::Incomplete(..) | v2::ParseError::Partial(..) + ) + } +} + +/// An enumeration of the supported header version's parse results. +/// Useful for parsing either version 1 or version 2 of the PROXY protocol. +/// +/// ## Examples +/// ```rust +/// use rama_haproxy::protocol::{HeaderResult, PartialResult, v1, v2}; +/// +/// let input = "PROXY UNKNOWN\r\n"; +/// let header = HeaderResult::parse(input.as_bytes()); +/// +/// assert_eq!(header, Ok(v1::Header::new(input, v1::Addresses::Unknown)).into()); +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +#[must_use = "this `HeaderResult` may contain a V1 or V2 `Err` variant, which should be handled"] +pub enum HeaderResult<'a> { + /// Version 1 of the PROXY protocol header. + V1(Result, v1::BinaryParseError>), + /// Version 2 of the PROXY protocol header. + V2(Result, v2::ParseError>), +} + +impl<'a> From, v1::BinaryParseError>> for HeaderResult<'a> { + fn from(result: Result, v1::BinaryParseError>) -> Self { + HeaderResult::V1(result) + } +} + +impl<'a> From, v2::ParseError>> for HeaderResult<'a> { + fn from(result: Result, v2::ParseError>) -> Self { + HeaderResult::V2(result) + } +} + +impl<'a> PartialResult for HeaderResult<'a> { + fn is_incomplete(&self) -> bool { + match self { + Self::V1(result) => result.is_incomplete(), + Self::V2(result) => result.is_incomplete(), + } + } +} + +impl<'a> HeaderResult<'a> { + /// Parses a PROXY protocol version 2 `Header`. + /// If the input is not a valid version 2 `Header`, attempts to parse a version 1 `Header`. + pub fn parse(input: &'a [u8]) -> HeaderResult<'a> { + let header = v2::Header::try_from(input); + + if header.is_complete() && header.is_err() { + v1::Header::try_from(input).into() + } else { + header.into() + } + } +} diff --git a/rama-haproxy/src/protocol/v1/error.rs b/rama-haproxy/src/protocol/v1/error.rs new file mode 100644 index 00000000..dbe88bf1 --- /dev/null +++ b/rama-haproxy/src/protocol/v1/error.rs @@ -0,0 +1,116 @@ +//! Errors for the text proxy protocol. + +use std::fmt; + +/// An error in parsing a text PROXY protocol header. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ParseError { + /// Header must start with 'PROXY'. + InvalidPrefix, + /// Header is only partially present. + Partial, + /// Header is empty. + MissingPrefix, + /// Header does not end with the string '\r\n'. + MissingNewLine, + /// Header missing protocol. + MissingProtocol, + /// Header missing source address. + MissingSourceAddress, + /// Header missing destination address. + MissingDestinationAddress, + /// Header missing source port. + MissingSourcePort, + /// Header missing destination port. + MissingDestinationPort, + /// Header does not fit within the expected buffer size of 107 bytes (plus 1 byte for null-terminated strings). + HeaderTooLong, + /// Header has an invalid protocol. + InvalidProtocol, + /// Header must end in '\r\n'. + InvalidSuffix, + /// Header contains invalid IP address for the source. + InvalidSourceAddress(std::net::AddrParseError), + /// Header contains invalid IP address for the destination. + InvalidDestinationAddress(std::net::AddrParseError), + /// Header contains invalid TCP port for the source. + InvalidSourcePort(Option), + /// Header contains invalid TCP port for the destination.] + InvalidDestinationPort(Option), +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidPrefix => write!(f, "Header must start with 'PROXY'."), + Self::Partial => write!(f, "Header is only partially present."), + Self::MissingPrefix => write!(f, "Header is empty."), + Self::MissingNewLine => write!(f, "Header does not end with the string '\\r\\n'."), + Self::MissingProtocol => write!(f, "Header missing protocol."), + Self::MissingSourceAddress => write!(f, "Header missing source address."), + Self::MissingDestinationAddress => write!(f, "Header missing destination address."), + Self::MissingSourcePort => write!(f, "Header missing source port."), + Self::MissingDestinationPort => write!(f, "Header missing destination port."), + Self::HeaderTooLong => write!(f, "Header does not fit within the expected buffer size of 107 bytes (plus 1 byte for null-terminated strings)."), + Self::InvalidProtocol => write!(f, "Header has an invalid protocol."), + Self::InvalidSuffix => write!(f, "Header must end in '\r\n'."), + Self::InvalidSourceAddress(source) => write!(f, "Header contains invalid IP address for the source: {}", source), + Self::InvalidDestinationAddress(destination) => write!(f, "Header contains invalid IP address for the destination: {}", destination), + Self::InvalidSourcePort(port) => write!(f, "Header contains invalid TCP port for the source: {}", port.as_ref().map(|e| e.to_string()).unwrap_or_default()), + Self::InvalidDestinationPort(port) => write!(f, "Header contains invalid TCP port for the destination: {}", port.as_ref().map(|e| e.to_string()).unwrap_or_default()), + } + } +} + +impl std::error::Error for ParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::InvalidSourceAddress(source) => Some(source), + Self::InvalidDestinationAddress(destination) => Some(destination), + Self::InvalidSourcePort(port) => port.as_ref().map(|e| e as &dyn std::error::Error), + Self::InvalidDestinationPort(port) => { + port.as_ref().map(|e| e as &dyn std::error::Error) + } + _ => None, + } + } +} + +/// An error in parsing a text PROXY protocol header that is represented as a byte slice. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BinaryParseError { + /// An error in parsing a binary PROXY protocol header. + Parse(ParseError), + /// Header is not valid UTF-8. + InvalidUtf8(std::str::Utf8Error), +} + +impl From for BinaryParseError { + fn from(error: ParseError) -> Self { + Self::Parse(error) + } +} + +impl From for BinaryParseError { + fn from(error: std::str::Utf8Error) -> Self { + Self::InvalidUtf8(error) + } +} + +impl fmt::Display for BinaryParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Parse(error) => write!(f, "{}", error), + Self::InvalidUtf8(error) => write!(f, "Header is not valid UTF-8: {}", error), + } + } +} + +impl std::error::Error for BinaryParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Parse(error) => Some(error), + Self::InvalidUtf8(error) => Some(error), + } + } +} diff --git a/rama-haproxy/src/protocol/v1/mod.rs b/rama-haproxy/src/protocol/v1/mod.rs new file mode 100644 index 00000000..18c7bdcf --- /dev/null +++ b/rama-haproxy/src/protocol/v1/mod.rs @@ -0,0 +1,701 @@ +//! Version 1 of the HAProxy protocol (text version). +//! +//! See + +mod error; +mod model; + +pub use crate::protocol::ip::{IPv4, IPv6}; +pub use error::{BinaryParseError, ParseError}; +pub use model::{Addresses, Header, SEPARATOR, TCP4, TCP6, UNKNOWN}; +pub use model::{PROTOCOL_PREFIX, PROTOCOL_SUFFIX}; +use std::borrow::Cow; +use std::net::{AddrParseError, Ipv4Addr, Ipv6Addr}; +use std::str::{from_utf8, FromStr}; + +const ZERO: &str = "0"; +const NEWLINE: &str = "\n"; +const CARRIAGE_RETURN: char = '\r'; + +/// The maximum length of a header in bytes. +const MAX_LENGTH: usize = 107; +/// The total number of parts in the header. +const PARTS: usize = 7; + +/// Parses a text PROXY protocol header. +/// The given string is expected to only include the header and to end in \r\n. +fn parse_header(header: &str) -> Result { + if header.is_empty() { + return Err(ParseError::MissingPrefix); + } else if header.len() > MAX_LENGTH { + return Err(ParseError::HeaderTooLong); + } + + let mut iterator = header + .splitn(PARTS, |c| c == SEPARATOR || c == CARRIAGE_RETURN) + .peekable(); + + let prefix = iterator.next().ok_or(ParseError::MissingPrefix)?; + + if !prefix.is_empty() && PROTOCOL_PREFIX.starts_with(prefix) && header.ends_with(prefix) { + return Err(ParseError::Partial); + } else if prefix != PROTOCOL_PREFIX { + return Err(ParseError::InvalidPrefix); + } + + let addresses = match iterator.next() { + Some(TCP4) => { + let (source_address, destination_address, source_port, destination_port) = + parse_addresses::(&mut iterator)?; + + Addresses::Tcp4(IPv4 { + source_address, + source_port, + destination_address, + destination_port, + }) + } + Some(TCP6) => { + let (source_address, destination_address, source_port, destination_port) = + parse_addresses::(&mut iterator)?; + + Addresses::Tcp6(IPv6 { + source_address, + source_port, + destination_address, + destination_port, + }) + } + Some(UNKNOWN) => { + while iterator.next_if(|&s| s != NEWLINE).is_some() {} + + Addresses::Unknown + } + Some(protocol) if protocol.is_empty() && iterator.peek().is_none() => { + return Err(ParseError::MissingProtocol) + } + Some(protocol) + if !protocol.is_empty() + && header.ends_with(protocol) + && (TCP4.starts_with(protocol) || UNKNOWN.starts_with(protocol)) => + { + return Err(ParseError::Partial) + } + Some(_) => return Err(ParseError::InvalidProtocol), + None => return Err(ParseError::MissingProtocol), + }; + + let newline = iterator + .next() + .filter(|s| !s.is_empty()) + .ok_or(ParseError::MissingNewLine)?; + + if newline != NEWLINE { + return Err(ParseError::InvalidSuffix); + } + + Ok(Header { + header: Cow::Borrowed(header), + addresses, + }) +} + +/// Parses the addresses and ports from a PROXY protocol header for IPv4 and IPv6. +fn parse_addresses<'a, T: FromStr, I: Iterator>( + iterator: &mut I, +) -> Result<(T, T, u16, u16), ParseError> { + let source_address = iterator.next().ok_or(ParseError::MissingSourceAddress)?; + let destination_address = iterator + .next() + .ok_or(ParseError::MissingDestinationAddress)?; + let source_port = iterator.next().ok_or(ParseError::MissingSourcePort)?; + let destination_port = iterator.next().ok_or(ParseError::MissingDestinationPort)?; + + let source_address = source_address + .parse::() + .map_err(ParseError::InvalidSourceAddress)?; + let destination_address = destination_address + .parse::() + .map_err(ParseError::InvalidDestinationAddress)?; + + if source_port.starts_with(ZERO) && source_port != ZERO { + return Err(ParseError::InvalidSourcePort(None)); + } + + let source_port = source_port + .parse::() + .map_err(|e| ParseError::InvalidSourcePort(Some(e)))?; + + if destination_port.starts_with(ZERO) && destination_port != ZERO { + return Err(ParseError::InvalidDestinationPort(None)); + } + + let destination_port = destination_port + .parse::() + .map_err(|e| ParseError::InvalidDestinationPort(Some(e)))?; + + Ok(( + source_address, + destination_address, + source_port, + destination_port, + )) +} + +impl<'a> TryFrom<&'a str> for Header<'a> { + type Error = ParseError; + + fn try_from(input: &'a str) -> Result { + let length = match input.find(CARRIAGE_RETURN) { + Some(suffix) => suffix + PROTOCOL_SUFFIX.len(), + None if input.len() >= MAX_LENGTH => return Err(ParseError::HeaderTooLong), + None => input.len(), + }; + + parse_header(&input[..length]) + } +} + +impl<'a> TryFrom<&'a [u8]> for Header<'a> { + type Error = BinaryParseError; + + fn try_from(input: &'a [u8]) -> Result { + let length = match input.iter().position(|&c| CARRIAGE_RETURN == (c as char)) { + Some(suffix) => suffix + PROTOCOL_SUFFIX.len(), + None if input.len() >= MAX_LENGTH => return Err(ParseError::HeaderTooLong.into()), + None => input.len(), + }; + let header = from_utf8(&input[..length])?; + + parse_header(header).map_err(BinaryParseError::Parse) + } +} + +impl FromStr for Addresses { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + Ok(Header::try_from(s)?.addresses) + } +} + +impl FromStr for Header<'static> { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + Ok(Header::try_from(s)?.to_owned()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[allow(invalid_from_utf8)] + fn bytes_invalid_utf8() { + let text = b"Hello \xF0\x90\x80World\r\n"; + + assert_eq!( + Header::try_from(&text[..]).unwrap_err(), + BinaryParseError::InvalidUtf8(from_utf8(text).unwrap_err()) + ); + } + + #[test] + fn exact_tcp4() { + let ip: Ipv4Addr = "255.255.255.255".parse().unwrap(); + let port = 65535; + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; + let expected = Header::new(text, Addresses::new_tcp4(ip, ip, port, port)); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn valid_tcp4() { + let ip: Ipv4Addr = "255.255.255.255".parse().unwrap(); + let port = 65535; + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\nFoobar"; + let expected = Header::new( + "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n", + Addresses::new_tcp4(ip, ip, port, port), + ); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn parse_partial() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535"; + + assert_eq!( + Header::try_from(text).unwrap_err(), + ParseError::MissingNewLine + ); + assert_eq!( + Header::try_from(text.as_bytes()).unwrap_err(), + ParseError::MissingNewLine.into() + ); + } + + #[test] + fn parse_tcp4_invalid() { + let text = "PROXY TCP4 255.255.255.255 256.255.255.255 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidDestinationAddress( + "".parse::().unwrap_err() + )) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidDestinationAddress("".parse::().unwrap_err()).into()) + ); + } + + #[test] + fn parse_tcp4_leading_zeroes() { + let text = "PROXY TCP4 255.0255.255.255 255.255.255.255 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidSourceAddress( + "".parse::().unwrap_err() + )) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) + ); + } + + #[test] + fn parse_unknown_connection() { + let text = "PROXY UNKNOWN\r\nTwo"; + + assert_eq!( + Header::try_from(text), + Ok(Header::new("PROXY UNKNOWN\r\n", Addresses::default())) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Ok(Header::new("PROXY UNKNOWN\r\n", Addresses::default())) + ); + } + + #[test] + fn valid_tcp6() { + let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); + let port = 65535; + let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\nHi!"; + let expected = Header::new("PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n", Addresses::new_tcp6(ip, ip, port, port)); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn valid_tcp6_short() { + let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); + let port = 65535; + let short_ip = "::1".parse().unwrap(); + let text = "PROXY TCP6 ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\nHi!"; + let expected = Header::new( + "PROXY TCP6 ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n", + Addresses::new_tcp6(short_ip, ip, port, port), + ); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn parse_tcp6_invalid() { + let text = "PROXY TCP6 ffff:gggg:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidSourceAddress( + "".parse::().unwrap_err() + )) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) + ); + } + + #[test] + fn parse_tcp6_leading_zeroes() { + let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:0ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidDestinationAddress( + "".parse::().unwrap_err() + )) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidDestinationAddress("".parse::().unwrap_err()).into()) + ); + } + + #[test] + fn parse_tcp6_shortened_connection() { + let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); + let short_ip = "ffff::ffff".parse().unwrap(); + let port = 65535; + let text = "PROXY TCP6 ffff::ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn parse_tcp6_single_zero() { + let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); + let short_ip = "ffff:ffff:ffff:ffff::ffff:ffff:ffff".parse().unwrap(); + let port = 65535; + let text = "PROXY TCP6 ffff:ffff:ffff:ffff::ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn parse_tcp6_wildcard() { + let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); + let short_ip = "::".parse().unwrap(); + let port = 65535; + let text = "PROXY TCP6 :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn parse_tcp6_implied() { + let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); + let short_ip = "ffff::".parse().unwrap(); + let port = 65535; + let text = "PROXY TCP6 ffff:: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn parse_tcp6_over_shortened() { + let text = "PROXY TCP6 ffff::ffff:ffff:ffff:ffff::ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidSourceAddress( + "".parse::().unwrap_err() + )) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) + ); + } + + #[test] + fn parse_worst_case() { + let text = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; + let expected = Header::new(text, Addresses::Unknown); + + assert_eq!(Header::try_from(text), Ok(expected.to_owned())); + assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); + } + + #[test] + fn parse_leading_zeroes_in_source_port() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 05535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidSourcePort(None)) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSourcePort(None).into()) + ); + } + + #[test] + fn parse_leading_zeroes_in_destination_port() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 05535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidDestinationPort(None)) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidDestinationPort(None).into()) + ); + } + + #[test] + fn parse_source_port_too_large() { + let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65536 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidSourcePort(Some( + "65536".parse::().unwrap_err() + ))) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSourcePort(Some("65536".parse::().unwrap_err())).into()) + ); + } + + #[test] + fn parse_destination_port_too_large() { + let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65536\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidDestinationPort(Some( + "65536".parse::().unwrap_err() + ))) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err( + ParseError::InvalidDestinationPort(Some("65536".parse::().unwrap_err())) + .into() + ) + ); + } + + #[test] + fn parse_lowercase_proxy() { + let text = "proxy UNKNOWN\r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidPrefix.into()) + ); + } + + #[test] + fn parse_lowercase_protocol_family() { + let text = "PROXY tcp4\r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidProtocol.into()) + ); + } + + #[test] + fn parse_too_long() { + let text = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535 \r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::HeaderTooLong)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::HeaderTooLong.into()) + ); + } + + #[test] + fn parse_more_than_one_space() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidProtocol.into()) + ); + } + + #[test] + fn parse_more_than_one_space_source_address() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidSourceAddress( + "".parse::().unwrap_err() + )) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) + ); + } + + #[test] + fn parse_more_than_one_space_destination_address() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidDestinationAddress( + "".parse::().unwrap_err() + )) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidDestinationAddress("".parse::().unwrap_err()).into()) + ); + } + + #[test] + fn parse_more_than_one_space_source_port() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidSourcePort(Some( + "".parse::().unwrap_err() + ))) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSourcePort(Some("".parse::().unwrap_err())).into()) + ); + } + + #[test] + fn parse_more_than_one_space_destination_port() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; + + assert_eq!( + Header::try_from(text), + Err(ParseError::InvalidDestinationPort(Some( + "".parse::().unwrap_err() + ))) + ); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidDestinationPort(Some("".parse::().unwrap_err())).into()) + ); + } + + #[test] + fn parse_more_than_one_space_end() { + let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535 \r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidSuffix)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSuffix.into()) + ); + } + + #[test] + fn parse_partial_prefix() { + let text = "PROX\r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidPrefix.into()) + ); + } + + #[test] + fn parse_empty_newline() { + let text = "\r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidPrefix.into()) + ); + } + + #[test] + fn parse_partial_prefix_missing_newline() { + let text = "PROX"; + + assert_eq!(Header::try_from(text), Err(ParseError::Partial)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::Partial.into()) + ); + } + + #[test] + fn parse_partial_protocol_missing_newline() { + let text = "PROXY UNKN"; + + assert_eq!(Header::try_from(text), Err(ParseError::Partial)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::Partial.into()) + ); + } + + #[test] + fn parse_partial_protocol_with_newline() { + let text = "PROXY UNKN\r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidProtocol.into()) + ); + } + + #[test] + fn parse_empty_protocol_with_newline() { + let text = "PROXY \r\n"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidProtocol.into()) + ); + } + + #[test] + fn parse_empty() { + let text = ""; + + assert_eq!(Header::try_from(text), Err(ParseError::MissingPrefix)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::MissingPrefix.into()) + ); + } + + #[test] + fn parse_no_new_line() { + let text = "PROXY TCP4 127.0.0.1 192.168.1.1 80 443\r\t"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidSuffix)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidSuffix.into()) + ); + } + + #[test] + fn parse_invalid_prefix_missing_newline() { + let text = "PRAX"; + + assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); + assert_eq!( + Header::try_from(text.as_bytes()), + Err(ParseError::InvalidPrefix.into()) + ); + } +} diff --git a/rama-haproxy/src/protocol/v1/model.rs b/rama-haproxy/src/protocol/v1/model.rs new file mode 100644 index 00000000..2f9589f9 --- /dev/null +++ b/rama-haproxy/src/protocol/v1/model.rs @@ -0,0 +1,307 @@ +//! The data model to represent the test PROXY protocol header. + +use crate::protocol::ip::{IPv4, IPv6}; +use std::borrow::Cow; +use std::fmt; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; + +/// The prefix of the PROXY protocol header. +pub const PROTOCOL_PREFIX: &str = "PROXY"; + +/// The suffix of the PROXY protocol header. +pub const PROTOCOL_SUFFIX: &str = "\r\n"; + +/// TCP protocol with IPv4 address family. +pub const TCP4: &str = "TCP4"; + +/// TCP protocol with IPv6 address family. +pub const TCP6: &str = "TCP6"; + +/// Unknown protocol and address family. Address portion of the header should be ignored. +pub const UNKNOWN: &str = "UNKNOWN"; + +/// The separator of the header parts. +pub const SEPARATOR: char = ' '; + +/// A text PROXY protocol header that borrows the input string. +/// +/// ## Examples +/// ### Worst Case (from bytes) +/// ```rust +/// use rama_haproxy::protocol::v1::{Addresses, Header, UNKNOWN}; +/// +/// let input = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; +/// let header = Header::try_from(input.as_bytes()).unwrap(); +/// +/// assert_eq!(header, Header::new(input, Addresses::Unknown)); +/// assert_eq!(header.protocol(), UNKNOWN); +/// assert_eq!(header.addresses_str(), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535"); +/// ``` +/// +/// ### UNKNOWN +/// ```rust +/// use rama_haproxy::protocol::v1::{Addresses, Header, UNKNOWN}; +/// +/// let input = "PROXY UNKNOWN\r\nhello"; +/// let header = Header::try_from(input).unwrap(); +/// +/// assert_eq!(header, Header::new("PROXY UNKNOWN\r\n", Addresses::Unknown)); +/// assert_eq!(header.protocol(), UNKNOWN); +/// assert_eq!(header.addresses_str(), ""); +/// ``` +/// +/// ### TCP4 +/// ```rust +/// use std::net::Ipv4Addr; +/// use rama_haproxy::protocol::v1::{Header, Addresses, TCP4}; +/// +/// let input = "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n"; +/// let header = Header::try_from(input).unwrap(); +/// +/// assert_eq!(header, Header::new(input, Addresses::new_tcp4(Ipv4Addr::new(127, 0, 1, 2), Ipv4Addr::new(192, 168, 1, 101), 80, 443))); +/// assert_eq!(header.protocol(), TCP4); +/// assert_eq!(header.addresses_str(), "127.0.1.2 192.168.1.101 80 443"); +/// ``` +/// +/// ### TCP6 +/// ```rust +/// use std::net::Ipv6Addr; +/// use rama_haproxy::protocol::v1::{Header, Addresses, TCP6}; +/// +/// let input = "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n"; +/// let header = Header::try_from(input).unwrap(); +/// +/// assert_eq!( +/// header, +/// Header::new( +/// input, +/// Addresses::new_tcp6( +/// Ipv6Addr::from([0x1234, 0x5678, 0x90AB, 0xCDEF, 0xFEDC, 0xBA09, 0x8765, 0x4321]), +/// Ipv6Addr::from([0x4321, 0x8765, 0xBA09, 0xFEDC, 0xCDEF, 0x90AB, 0x5678, 0x01234,]), +/// 443, +/// 65535 +/// ) +/// ) +/// ); +/// assert_eq!(header.protocol(), TCP6); +/// assert_eq!(header.addresses_str(), "1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535"); +/// ``` +/// +/// ### Invalid +/// ```rust +/// use rama_haproxy::protocol::v1::{Header, Addresses, ParseError}; +/// +/// assert_eq!(Err(ParseError::InvalidProtocol), "PROXY tcp4\r\n".parse::()); +/// ``` +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Header<'a> { + /// The original input string. + pub header: Cow<'a, str>, + /// The source and destination addresses of the header. + pub addresses: Addresses, +} + +impl<'a> Header<'a> { + /// Creates a new `Header` with the given addresses and a reference to the original input. + pub fn new, A: Into>(header: H, addresses: A) -> Self { + Header { + header: Cow::Borrowed(header.into()), + addresses: addresses.into(), + } + } + + /// Creates an owned clone of this [`Header`]. + pub fn to_owned(&self) -> Header<'static> { + Header { + header: Cow::Owned::<'static>(self.header.to_string()), + addresses: self.addresses, + } + } + + /// The protocol portion of this `Header`. + pub fn protocol(&self) -> &str { + self.addresses.protocol() + } + + /// The source and destination addresses portion of this `Header`. + pub fn addresses_str(&self) -> &str { + let start = PROTOCOL_PREFIX.len() + SEPARATOR.len_utf8() + self.protocol().len(); + let end = self.header.len() - PROTOCOL_SUFFIX.len(); + let addresses = &self.header[start..end]; + + if addresses.starts_with(SEPARATOR) { + &addresses[SEPARATOR.len_utf8()..] + } else { + addresses + } + } +} + +/// The source and destination of a header. +/// Includes IP (v4 or v6) addresses and TCP ports. +/// +/// ## Examples +/// ### Worst Case +/// ```rust +/// use rama_haproxy::protocol::v1::{Addresses, Header, UNKNOWN}; +/// +/// let header = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; +/// let addresses = Addresses::Unknown; +/// +/// assert_eq!(addresses, header.parse().unwrap()); +/// assert_ne!(addresses.to_string().as_str(), header); +/// ``` +/// +/// ### UNKNOWN +/// ```rust +/// use rama_haproxy::protocol::v1::Addresses; +/// +/// let header = "PROXY UNKNOWN\r\n"; +/// let addresses = Addresses::Unknown; +/// +/// assert_eq!(addresses, header.parse().unwrap()); +/// assert_eq!(addresses.to_string().as_str(), header); +/// ``` +/// +/// ### TCP4 +/// ```rust +/// use std::net::Ipv4Addr; +/// use rama_haproxy::protocol::v1::Addresses; +/// +/// let header = "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n"; +/// let addresses = Addresses::new_tcp4(Ipv4Addr::new(127, 0, 1, 2), Ipv4Addr::new(192, 168, 1, 101), 80, 443); +/// +/// assert_eq!(addresses, header.parse().unwrap()); +/// assert_eq!(addresses.to_string().as_str(), header); +/// ``` +/// +/// ### TCP6 +/// ```rust +/// use std::net::Ipv6Addr; +/// use rama_haproxy::protocol::v1::Addresses; +/// +/// let header = "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n"; +/// let addresses = Addresses::new_tcp6( +/// Ipv6Addr::from([0x1234, 0x5678, 0x90AB, 0xCDEF, 0xFEDC, 0xBA09, 0x8765, 0x4321]), +/// Ipv6Addr::from([0x4321, 0x8765, 0xBA09, 0xFEDC, 0xCDEF, 0x90AB, 0x5678, 0x01234,]), +/// 443, +/// 65535 +/// ); +/// +/// assert_eq!(addresses, header.parse().unwrap()); +/// assert_eq!(addresses.to_string().as_str(), header); +/// ``` +/// +/// ### Invalid +/// ```rust +/// use rama_haproxy::protocol::v1::{Addresses, ParseError}; +/// +/// assert_eq!(Err(ParseError::InvalidProtocol), "PROXY tcp4\r\n".parse::()); +/// ``` +#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash)] +pub enum Addresses { + #[default] + /// The source and destination addresses of the header are unknown. + Unknown, + /// The source and destination addresses of the header are IPv4. + Tcp4(IPv4), + /// The source and destination addresses of the header are IPv6. + Tcp6(IPv6), +} + +impl Addresses { + /// Create a new IPv4 TCP address. + pub fn new_tcp4>( + source_address: T, + destination_address: T, + source_port: u16, + destination_port: u16, + ) -> Self { + Addresses::Tcp4(IPv4 { + source_address: source_address.into(), + source_port, + destination_address: destination_address.into(), + destination_port, + }) + } + + /// Create a new IPv6 TCP address. + pub fn new_tcp6>( + source_address: T, + destination_address: T, + source_port: u16, + destination_port: u16, + ) -> Self { + Addresses::Tcp6(IPv6 { + source_address: source_address.into(), + source_port, + destination_address: destination_address.into(), + destination_port, + }) + } + + /// The protocol portion of this `Addresses`. + pub fn protocol(&self) -> &str { + match self { + Addresses::Tcp4(..) => TCP4, + Addresses::Tcp6(..) => TCP6, + Addresses::Unknown => UNKNOWN, + } + } +} + +impl From<(SocketAddr, SocketAddr)> for Addresses { + fn from(addresses: (SocketAddr, SocketAddr)) -> Self { + match addresses { + (SocketAddr::V4(source), SocketAddr::V4(destination)) => Addresses::Tcp4(IPv4::new( + *source.ip(), + *destination.ip(), + source.port(), + destination.port(), + )), + (SocketAddr::V6(source), SocketAddr::V6(destination)) => Addresses::Tcp6(IPv6::new( + *source.ip(), + *destination.ip(), + source.port(), + destination.port(), + )), + _ => Addresses::Unknown, + } + } +} + +impl From for Addresses { + fn from(addresses: IPv4) -> Self { + Addresses::Tcp4(addresses) + } +} + +impl From for Addresses { + fn from(addresses: IPv6) -> Self { + Addresses::Tcp6(addresses) + } +} + +impl<'a> fmt::Display for Header<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.header.as_ref()) + } +} + +impl fmt::Display for Addresses { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unknown => f.write_str("PROXY UNKNOWN\r\n"), + Self::Tcp4(a) => write!( + f, + "PROXY TCP4 {} {} {} {}\r\n", + a.source_address, a.destination_address, a.source_port, a.destination_port + ), + Self::Tcp6(a) => write!( + f, + "PROXY TCP6 {} {} {} {}\r\n", + a.source_address, a.destination_address, a.source_port, a.destination_port + ), + } + } +} diff --git a/rama-haproxy/src/protocol/v2/builder.rs b/rama-haproxy/src/protocol/v2/builder.rs new file mode 100644 index 00000000..20152248 --- /dev/null +++ b/rama-haproxy/src/protocol/v2/builder.rs @@ -0,0 +1,638 @@ +//! Builder pattern to generate both valid and invalid PROXY protocol v2 headers. + +use crate::protocol::v2::{ + Addresses, Protocol, Type, TypeLengthValue, TypeLengthValues, LENGTH, MINIMUM_LENGTH, + MINIMUM_TLV_LENGTH, PROTOCOL_PREFIX, +}; +use std::io::{self, Write}; + +/// `Write` interface for the builder's internal buffer. +/// Can be used to turn header parts into bytes. +/// +/// ## Examples +/// ```rust +/// use rama_haproxy::protocol::v2::{Addresses, Writer, WriteToHeader}; +/// use std::net::SocketAddr; +/// +/// let addresses: Addresses = ("127.0.0.1:80".parse::().unwrap(), "192.168.1.1:443".parse::().unwrap()).into(); +/// let mut writer = Writer::default(); +/// +/// addresses.write_to(&mut writer).unwrap(); +/// +/// assert_eq!(addresses.to_bytes().unwrap(), writer.finish()); +/// ``` +#[derive(Debug, Default)] +pub struct Writer { + bytes: Vec, +} + +/// Implementation of the builder pattern for PROXY protocol v2 headers. +/// Supports both valid and invalid headers via the `write_payload` and `write_payloads` functions. +/// +/// ## Examples +/// ```rust +/// use rama_haproxy::protocol::v2::{Addresses, AddressFamily, Builder, Command, IPv4, Protocol, PROTOCOL_PREFIX, Type, Version}; +/// let mut expected = Vec::from(PROTOCOL_PREFIX); +/// expected.extend([ +/// 0x21, 0x12, 0, 16, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 4, 0, 1, 42 +/// ]); +/// +/// let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); +/// let header = Builder::with_addresses( +/// Version::Two | Command::Proxy, +/// Protocol::Datagram, +/// addresses +/// ) +/// .write_tlv(Type::NoOp, [42].as_slice()) +/// .unwrap() +/// .build() +/// .unwrap(); +/// +/// assert_eq!(header, expected); +/// ``` +#[derive(Debug)] +pub struct Builder { + header: Option>, + version_command: u8, + address_family_protocol: u8, + addresses: Addresses, + length: Option, + additional_capacity: usize, +} + +impl Writer { + /// Consumes this `Writer` and returns the buffer holding the proxy protocol header payloads. + /// The returned bytes are not guaranteed to be a valid proxy protocol header. + pub fn finish(self) -> Vec { + self.bytes + } +} + +impl From> for Writer { + fn from(bytes: Vec) -> Self { + Writer { bytes } + } +} + +impl Write for Writer { + fn write(&mut self, buffer: &[u8]) -> io::Result { + if self.bytes.len() > (u16::MAX as usize) + MINIMUM_LENGTH { + Err(io::ErrorKind::WriteZero.into()) + } else { + self.bytes.extend_from_slice(buffer); + Ok(buffer.len()) + } + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +/// Defines how to write a type as part of a binary PROXY protocol header. +pub trait WriteToHeader { + /// Write this instance to the given `Writer`. + /// The `Writer` returns an IO error when an individual byte slice is longer than `u16::MAX`. + /// However, the total length of the buffer may exceed `u16::MAX`. + fn write_to(&self, writer: &mut Writer) -> io::Result; + + /// Writes this instance to a temporary buffer and returns the buffer. + fn to_bytes(&self) -> io::Result> { + let mut writer = Writer::default(); + + self.write_to(&mut writer)?; + + Ok(writer.finish()) + } +} + +impl WriteToHeader for Addresses { + fn write_to(&self, writer: &mut Writer) -> io::Result { + match self { + Addresses::Unspecified => (), + Addresses::IPv4(a) => { + writer.write_all(a.source_address.octets().as_slice())?; + writer.write_all(a.destination_address.octets().as_slice())?; + writer.write_all(a.source_port.to_be_bytes().as_slice())?; + writer.write_all(a.destination_port.to_be_bytes().as_slice())?; + } + Addresses::IPv6(a) => { + writer.write_all(a.source_address.octets().as_slice())?; + writer.write_all(a.destination_address.octets().as_slice())?; + writer.write_all(a.source_port.to_be_bytes().as_slice())?; + writer.write_all(a.destination_port.to_be_bytes().as_slice())?; + } + Addresses::Unix(a) => { + writer.write_all(a.source.as_slice())?; + writer.write_all(a.destination.as_slice())?; + } + }; + + Ok(self.len()) + } +} + +impl<'a> WriteToHeader for TypeLengthValue<'a> { + fn write_to(&self, writer: &mut Writer) -> io::Result { + if self.value.len() > u16::MAX as usize { + return Err(io::ErrorKind::WriteZero.into()); + } + + writer.write_all([self.kind].as_slice())?; + writer.write_all((self.value.len() as u16).to_be_bytes().as_slice())?; + writer.write_all(self.value.as_ref())?; + + Ok(MINIMUM_TLV_LENGTH + self.value.len()) + } +} + +impl<'a, T: Copy + Into> WriteToHeader for (T, &'a [u8]) { + fn write_to(&self, writer: &mut Writer) -> io::Result { + let kind = self.0.into(); + let value = self.1; + + if value.len() > u16::MAX as usize { + return Err(io::ErrorKind::WriteZero.into()); + } + + writer.write_all([kind].as_slice())?; + writer.write_all((value.len() as u16).to_be_bytes().as_slice())?; + writer.write_all(value)?; + + Ok(MINIMUM_TLV_LENGTH + value.len()) + } +} + +impl<'a> WriteToHeader for TypeLengthValues<'a> { + fn write_to(&self, writer: &mut Writer) -> io::Result { + let bytes = self.as_bytes(); + + writer.write_all(bytes)?; + + Ok(bytes.len()) + } +} + +impl WriteToHeader for [u8] { + fn write_to(&self, writer: &mut Writer) -> io::Result { + let slice = self; + + if slice.len() > u16::MAX as usize { + return Err(io::ErrorKind::WriteZero.into()); + } + + writer.write_all(slice)?; + + Ok(slice.len()) + } +} + +impl WriteToHeader for &T { + fn write_to(&self, writer: &mut Writer) -> io::Result { + (*self).write_to(writer) + } +} + +impl WriteToHeader for Type { + fn write_to(&self, writer: &mut Writer) -> io::Result { + writer.write([(*self).into()].as_slice()) + } +} + +macro_rules! impl_write_to_header { + ($t:ident) => { + impl WriteToHeader for $t { + fn write_to(&self, writer: &mut Writer) -> io::Result { + let bytes = self.to_be_bytes(); + + writer.write_all(bytes.as_slice())?; + + Ok(bytes.len()) + } + } + }; +} + +impl_write_to_header!(u8); +impl_write_to_header!(u16); +impl_write_to_header!(u32); +impl_write_to_header!(u64); +impl_write_to_header!(u128); +impl_write_to_header!(usize); + +impl_write_to_header!(i8); +impl_write_to_header!(i16); +impl_write_to_header!(i32); +impl_write_to_header!(i64); +impl_write_to_header!(i128); +impl_write_to_header!(isize); + +impl Builder { + /// Creates an instance of a `Builder` with the given header bytes. + /// No guarantee is made that any address bytes written as a payload will match the header's address family. + /// The length is determined on `build` unless `set_length` is called to set an explicit value. + pub const fn new(version_command: u8, address_family_protocol: u8) -> Self { + Builder { + header: None, + version_command, + address_family_protocol, + addresses: Addresses::Unspecified, + length: None, + additional_capacity: 0, + } + } + + /// Creates an instance of a `Builder` with the given header bytes and `Addresses`. + /// The address family is determined from the variant of the `Addresses` given. + /// The length is determined on `build` unless `set_length` is called to set an explicit value. + pub fn with_addresses>( + version_command: u8, + protocol: Protocol, + addresses: T, + ) -> Self { + let addresses = addresses.into(); + + Builder { + header: None, + version_command, + address_family_protocol: addresses.address_family() | protocol, + addresses, + length: None, + additional_capacity: 0, + } + } + + /// Reserves the requested additional capacity in the underlying buffer. + /// Helps to prevent resizing the underlying buffer when called before `write_payload`, `write_payloads`. + /// When called after `write_payload`, `write_payloads`, useful as a hint on how to resize the buffer. + pub fn reserve_capacity(mut self, capacity: usize) -> Self { + match self.header { + None => self.additional_capacity += capacity, + Some(ref mut header) => header.reserve(capacity), + } + + self + } + + /// Reserves the requested additional capacity in the underlying buffer. + /// Helps to prevent resizing the underlying buffer when called before `write_payload`, `write_payloads`. + /// When called after `write_payload`, `write_payloads`, useful as a hint on how to resize the buffer. + pub fn set_reserve_capacity(&mut self, capacity: usize) -> &mut Self { + match self.header { + None => self.additional_capacity += capacity, + Some(ref mut header) => header.reserve(capacity), + } + + self + } + + /// Overrides the length in the header. + /// When set to `Some` value, the length may be smaller or larger than the actual payload in the buffer. + pub fn set_length>>(mut self, length: T) -> Self { + self.length = length.into(); + self + } + + /// Writes a iterable set of payloads in order to the buffer. + /// No bytes are added by this `Builder` as a delimiter. + pub fn write_payloads(mut self, payloads: II) -> io::Result + where + T: WriteToHeader, + I: Iterator, + II: IntoIterator, + { + self.write_header()?; + + let mut writer = Writer::from(self.header.take().unwrap_or_default()); + + for item in payloads { + item.write_to(&mut writer)?; + } + + self.header = Some(writer.finish()); + + Ok(self) + } + + /// Writes a single payload to the buffer. + /// No surrounding bytes (terminal or otherwise) are added by this `Builder`. + pub fn write_payload(mut self, payload: T) -> io::Result { + self.write_header()?; + self.write_internal(payload)?; + + Ok(self) + } + + /// Writes a Type-Length-Value as a payload. + /// No surrounding bytes (terminal or otherwise) are added by this `Builder`. + /// The length is determined by the length of the slice. + /// An error is returned when the length of the slice exceeds `u16::MAX`. + pub fn write_tlv(self, kind: impl Into, value: &[u8]) -> io::Result { + self.write_payload(TypeLengthValue::new(kind, value)) + } + + /// Writes to the underlying buffer without first writing the header bytes. + fn write_internal(&mut self, payload: T) -> io::Result<()> { + let mut writer = Writer::from(self.header.take().unwrap_or_default()); + + payload.write_to(&mut writer)?; + + self.header = Some(writer.finish()); + + Ok(()) + } + + /// Writes the protocol prefix, version, command, address family, protocol, and optional addresses to the buffer. + /// Does nothing if the buffer is not empty. + fn write_header(&mut self) -> io::Result<()> { + if self.header.is_some() { + return Ok(()); + } + + let mut header = + Vec::with_capacity(MINIMUM_LENGTH + self.addresses.len() + self.additional_capacity); + + let length = self.length.unwrap_or_default(); + + header.extend_from_slice(PROTOCOL_PREFIX); + header.push(self.version_command); + header.push(self.address_family_protocol); + header.extend_from_slice(length.to_be_bytes().as_slice()); + + let mut writer = Writer::from(header); + + self.addresses.write_to(&mut writer)?; + self.header = Some(writer.finish()); + + Ok(()) + } + + /// Builds the header and returns the underlying buffer. + /// If no length was explicitly set, returns an error when the length of the payload portion exceeds `u16::MAX`. + pub fn build(mut self) -> io::Result> { + self.write_header()?; + + let mut header = self.header.take().unwrap_or_default(); + + if self.length.is_some() { + return Ok(header); + } + + if let Ok(payload_length) = u16::try_from(header[MINIMUM_LENGTH..].len()) { + let length = payload_length.to_be_bytes(); + header[LENGTH..LENGTH + length.len()].copy_from_slice(length.as_slice()); + Ok(header) + } else { + Err(io::ErrorKind::WriteZero.into()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::protocol::v2::{AddressFamily, Command, IPv4, IPv6, Protocol, Type, Unix, Version}; + + #[test] + fn build_length_too_small() { + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([0x21, 0x12, 0, 1, 0, 0, 0, 1]); + + let actual = Builder::new( + Version::Two | Command::Proxy, + AddressFamily::IPv4 | Protocol::Datagram, + ) + .set_length(1) + .write_payload(1u32) + .unwrap() + .build() + .unwrap(); + + assert_eq!(actual, expected); + } + + #[test] + fn build_payload_too_long() { + let error = Builder::new( + Version::Two | Command::Proxy, + AddressFamily::IPv4 | Protocol::Datagram, + ) + .write_payload(vec![0u8; (u16::MAX as usize) + 1].as_slice()) + .unwrap_err(); + + assert_eq!(error.kind(), io::ErrorKind::WriteZero); + } + + #[test] + fn build_no_payload() { + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([0x21, 0x01, 0, 0]); + + let header = Builder::new( + Version::Two | Command::Proxy, + AddressFamily::Unspecified | Protocol::Stream, + ) + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_arbitrary_payload() { + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([0x21, 0x01, 0, 1, 42]); + + let header = Builder::new( + Version::Two | Command::Proxy, + AddressFamily::Unspecified | Protocol::Stream, + ) + .write_payload(42u8) + .unwrap() + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_ipv4() { + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([ + 0x21, 0x12, 0, 12, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, + ]); + + let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); + let header = Builder::new( + Version::Two | Command::Proxy, + AddressFamily::IPv4 | Protocol::Datagram, + ) + .set_length(addresses.len() as u16) + .write_payload(addresses) + .unwrap() + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_ipv6() { + let source_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF2, + ]; + let destination_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF1, + ]; + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([0x20, 0x20, 0, 36]); + expected.extend(source_address); + expected.extend(destination_address); + expected.extend([0, 80, 1, 187]); + + let header = Builder::with_addresses( + Version::Two | Command::Local, + Protocol::Unspecified, + IPv6::new(source_address, destination_address, 80, 443), + ) + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_unix() { + let source_address = [0xFFu8; 108]; + let destination_address = [0xAAu8; 108]; + + let addresses: Addresses = Unix::new(source_address, destination_address).into(); + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([0x20, 0x31, 0, 216]); + expected.extend(source_address); + expected.extend(destination_address); + + let header = Builder::new( + Version::Two | Command::Local, + AddressFamily::Unix | Protocol::Stream, + ) + .reserve_capacity(addresses.len()) + .write_payload(addresses) + .unwrap() + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_ipv4_with_tlv() { + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([ + 0x21, 0x12, 0, 17, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 4, 0, 2, 0, 42, + ]); + + let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); + let header = + Builder::with_addresses(Version::Two | Command::Proxy, Protocol::Datagram, addresses) + .reserve_capacity(5) + .write_tlv(Type::NoOp, [0, 42].as_slice()) + .unwrap() + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_ipv4_with_nested_tlv() { + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([ + 0x21, 0x12, 0, 20, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 0x20, 0, 5, 0, 0, 0, 0, + 0, + ]); + + let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); + let header = Builder::new( + Version::Two | Command::Proxy, + AddressFamily::IPv4 | Protocol::Datagram, + ) + .write_payload(addresses) + .unwrap() + .write_payload(Type::SSL) + .unwrap() + .write_payload(5u16) + .unwrap() + .write_payload([0u8; 5].as_slice()) + .unwrap() + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_ipv6_with_tlvs() { + let source_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF2, + ]; + let destination_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF1, + ]; + let addresses: Addresses = IPv6::new(source_address, destination_address, 80, 443).into(); + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([0x20, 0x20, 0, 48]); + expected.extend(source_address); + expected.extend(destination_address); + expected.extend([0, 80, 1, 187]); + expected.extend([4, 0, 1, 0, 4, 0, 1, 0, 4, 0, 1, 42]); + + let header = Builder::new( + Version::Two | Command::Local, + AddressFamily::IPv6 | Protocol::Unspecified, + ) + .write_payload(addresses) + .unwrap() + .write_payloads([ + (Type::NoOp, [0].as_slice()), + (Type::NoOp, [0].as_slice()), + (Type::NoOp, [42].as_slice()), + ]) + .unwrap() + .build() + .unwrap(); + + assert_eq!(header, expected); + } + + #[test] + fn build_unix_with_tlv() { + let source_address = [0xFFu8; 108]; + let destination_address = [0xAAu8; 108]; + + let addresses: Addresses = Unix::new(source_address, destination_address).into(); + let mut expected = Vec::from(PROTOCOL_PREFIX); + expected.extend([0x20, 0x31, 0, 216]); + expected.extend(source_address); + expected.extend(destination_address); + expected.extend([0x20, 0, 0]); + + let header = Builder::new( + Version::Two | Command::Local, + AddressFamily::Unix | Protocol::Stream, + ) + .set_length(216) + .write_payload(addresses) + .unwrap() + .write_tlv(Type::SSL, &[]) + .unwrap() + .build() + .unwrap(); + + assert_eq!(header, expected); + } +} diff --git a/rama-haproxy/src/protocol/v2/error.rs b/rama-haproxy/src/protocol/v2/error.rs new file mode 100644 index 00000000..af38f6b0 --- /dev/null +++ b/rama-haproxy/src/protocol/v2/error.rs @@ -0,0 +1,47 @@ +//! Errors for the binary proxy protocol. + +use std::fmt; + +/// An error in parsing a binary PROXY protocol header. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ParseError { + /// Expected header to the protocol prefix plus 4 bytes after the prefix. + Incomplete(usize), + /// Expected header to start with a prefix of '\r\n\r\n\0\r\nQUIT\n'. + Prefix, + /// Expected version to be equal to 2. + Version(u8), + /// Invalid command. Command must be one of: Local, Proxy. + Command(u8), + /// Invalid Address Family. Address Family must be one of: Unspecified, IPv4, IPv6, Unix. + AddressFamily(u8), + /// Invalid protocol. Protocol must be one of: Unspecified, Stream, or Datagram. + Protocol(u8), + /// Header does not contain the advertised length of the address information and TLVs. + Partial(usize, usize), + /// Header length of {0} bytes cannot store the {1} bytes required for the address family. + InvalidAddresses(usize, usize), + /// Header is not long enough to contain TLV {0} with length {1}. + InvalidTLV(u8, u16), + /// Header contains leftover {0} bytes not accounted for by the address family or TLVs. + Leftovers(usize), +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Incomplete(len) => write!(f, "Expected header to the protocol prefix plus 4 bytes after the prefix (length {}).", len), + Self::Prefix => write!(f, "Expected header to start with a prefix of '\\r\\n\\r\\n\\0\\r\\nQUIT\\n'."), + Self::Version(version) => write!(f, "Expected version {:X} to be equal to 2.", version), + Self::Command(command) => write!(f, "Invalid command {:X}. Command must be one of: Local, Proxy.", command), + Self::AddressFamily(af) => write!(f, "Invalid Address Family {:X}. Address Family must be one of: Unspecified, IPv4, IPv6, Unix.", af), + Self::Protocol(protocol) => write!(f, "Invalid protocol {:X}. Protocol must be one of: Unspecified, Stream, or Datagram.", protocol), + Self::Partial(len, total) => write!(f, "Header does not contain the advertised length of the address information and TLVs (has {} out of {} bytes).", len, total), + Self::InvalidAddresses(len, total) => write!(f, "Header length of {} bytes cannot store the {} bytes required for the address family.", len, total), + Self::InvalidTLV(tlv, len) => write!(f, "Header is not long enough to contain TLV {} with length {}.", tlv, len), + Self::Leftovers(len) => write!(f, "Header contains leftover {} bytes not accounted for by the address family or TLVs.", len), + } + } +} + +impl std::error::Error for ParseError {} diff --git a/rama-haproxy/src/protocol/v2/mod.rs b/rama-haproxy/src/protocol/v2/mod.rs new file mode 100644 index 00000000..13c96520 --- /dev/null +++ b/rama-haproxy/src/protocol/v2/mod.rs @@ -0,0 +1,749 @@ +//! Version 2 of the HAProxy protocol (binary version). +//! +//! See + +mod builder; +mod error; +mod model; + +pub use crate::protocol::ip::{IPv4, IPv6}; +pub use builder::{Builder, WriteToHeader, Writer}; +pub use error::ParseError; +pub use model::{ + AddressFamily, Addresses, Command, Header, Protocol, Type, TypeLengthValue, TypeLengthValues, + Unix, Version, PROTOCOL_PREFIX, +}; +use model::{MINIMUM_LENGTH, MINIMUM_TLV_LENGTH}; +use std::borrow::Cow; +use std::net::{Ipv4Addr, Ipv6Addr}; + +/// Masks the right 4-bits so only the left 4-bits are present. +const LEFT_MASK: u8 = 0xF0; +/// Masks the left 4-bits so only the right 4-bits are present. +const RIGHT_MASK: u8 = 0x0F; +/// The index of the version-command byte. +const VERSION_COMMAND: usize = PROTOCOL_PREFIX.len(); +/// The index of the address family-protocol byte. +const ADDRESS_FAMILY_PROTOCOL: usize = VERSION_COMMAND + 1; +/// The index of the start of the big-endian u16 length. +const LENGTH: usize = ADDRESS_FAMILY_PROTOCOL + 1; + +/// Parses the addresses from the header payload. +fn parse_addresses(address_family: AddressFamily, bytes: &[u8]) -> Addresses { + match address_family { + AddressFamily::Unspecified => Addresses::Unspecified, + AddressFamily::IPv4 => { + let source_address = Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]); + let destination_address = Ipv4Addr::new(bytes[4], bytes[5], bytes[6], bytes[7]); + let source_port = u16::from_be_bytes([bytes[8], bytes[9]]); + let destination_port = u16::from_be_bytes([bytes[10], bytes[11]]); + + Addresses::IPv4(IPv4 { + source_address, + destination_address, + source_port, + destination_port, + }) + } + AddressFamily::IPv6 => { + let mut address = [0; 16]; + + address[..].copy_from_slice(&bytes[..16]); + let source_address = Ipv6Addr::from(address); + + address[..].copy_from_slice(&bytes[16..32]); + let destination_address = Ipv6Addr::from(address); + + let source_port = u16::from_be_bytes([bytes[32], bytes[33]]); + let destination_port = u16::from_be_bytes([bytes[34], bytes[35]]); + + Addresses::IPv6(IPv6 { + source_address, + destination_address, + source_port, + destination_port, + }) + } + AddressFamily::Unix => { + let mut source = [0; 108]; + let mut destination = [0; 108]; + + source[..].copy_from_slice(&bytes[..108]); + destination[..].copy_from_slice(&bytes[108..]); + + Addresses::Unix(Unix { + source, + destination, + }) + } + } +} + +impl<'a> TryFrom<&'a [u8]> for Header<'a> { + type Error = ParseError; + + fn try_from(input: &'a [u8]) -> Result { + if input.len() < PROTOCOL_PREFIX.len() { + if PROTOCOL_PREFIX.starts_with(input) { + return Err(ParseError::Incomplete(input.len())); + } else { + return Err(ParseError::Prefix); + } + } + + if &input[..VERSION_COMMAND] != PROTOCOL_PREFIX { + return Err(ParseError::Prefix); + } + + if input.len() < MINIMUM_LENGTH { + return Err(ParseError::Incomplete(input.len())); + } + + let version = match input[VERSION_COMMAND] & LEFT_MASK { + 0x20 => Version::Two, + v => return Err(ParseError::Version(v)), + }; + let command = match input[VERSION_COMMAND] & RIGHT_MASK { + 0x00 => Command::Local, + 0x01 => Command::Proxy, + c => return Err(ParseError::Command(c)), + }; + + let address_family = match input[ADDRESS_FAMILY_PROTOCOL] & LEFT_MASK { + 0x00 => AddressFamily::Unspecified, + 0x10 => AddressFamily::IPv4, + 0x20 => AddressFamily::IPv6, + 0x30 => AddressFamily::Unix, + a => return Err(ParseError::AddressFamily(a)), + }; + let protocol = match input[ADDRESS_FAMILY_PROTOCOL] & RIGHT_MASK { + 0x00 => Protocol::Unspecified, + 0x01 => Protocol::Stream, + 0x02 => Protocol::Datagram, + p => return Err(ParseError::Protocol(p)), + }; + + let length = u16::from_be_bytes([input[LENGTH], input[LENGTH + 1]]) as usize; + let address_family_bytes = address_family.byte_length().unwrap_or_default(); + + if length < address_family_bytes { + return Err(ParseError::InvalidAddresses(length, address_family_bytes)); + } + + let full_length = MINIMUM_LENGTH + length; + + if input.len() < full_length { + return Err(ParseError::Partial(input.len() - MINIMUM_LENGTH, length)); + } + + let header = &input[..full_length]; + let addresses = parse_addresses( + address_family, + &header[MINIMUM_LENGTH..MINIMUM_LENGTH + address_family_bytes], + ); + + Ok(Header { + header: Cow::Borrowed(header), + version, + command, + protocol, + addresses, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use model::{Type, TypeLengthValue}; + + #[test] + fn no_tlvs() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x11); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + + let expected = Header { + header: Cow::Borrowed(input.as_slice()), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Stream, + addresses: IPv4::new([127, 0, 0, 1], [127, 0, 0, 2], 80, 443).into(), + }; + let actual = Header::try_from(input.as_slice()).unwrap(); + + assert_eq!(actual, expected); + assert!(actual.tlvs().next().is_none()); + assert_eq!(actual.length(), 12); + assert_eq!(actual.address_family(), AddressFamily::IPv4); + assert_eq!( + actual.address_bytes(), + &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 1, 187] + ); + assert!(actual.tlv_bytes().is_empty()); + assert_eq!(actual.as_bytes(), input.as_slice()); + } + + #[test] + fn no_tlvs_unspec() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x00); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + + let expected = Header { + header: input.as_slice().into(), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Unspecified, + addresses: Addresses::Unspecified, + }; + let actual = Header::try_from(input.as_slice()).unwrap(); + + assert_eq!(actual, expected); + assert!(actual.tlvs().next().is_none()); + assert_eq!(actual.length(), 12); + assert_eq!(actual.address_family(), AddressFamily::Unspecified); + assert_eq!( + actual.address_bytes(), + &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 1, 187] + ); + assert!(actual.tlv_bytes().is_empty()); + assert_eq!(actual.as_bytes(), input.as_slice()); + } + + #[test] + fn no_tlvs_unspec_stream() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x01); + input.extend([0, 8]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + + let expected = Header { + header: Cow::Borrowed(input.as_slice()), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Stream, + addresses: Addresses::Unspecified, + }; + let actual = Header::try_from(input.as_slice()).unwrap(); + + assert_eq!(actual, expected); + assert!(actual.tlvs().next().is_none()); + assert_eq!(actual.length(), 8); + assert_eq!(actual.address_family(), AddressFamily::Unspecified); + assert_eq!(actual.address_bytes(), &[127, 0, 0, 1, 127, 0, 0, 2]); + assert!(actual.tlv_bytes().is_empty()); + assert_eq!(actual.as_bytes(), input.as_slice()); + } + + #[test] + fn no_tlvs_unspec_ipv4() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x10); + input.extend([0, 8]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + + let actual = Header::try_from(input.as_slice()).unwrap_err(); + + assert_eq!(actual, ParseError::InvalidAddresses(8, 12)); + } + + #[test] + fn invalid_version() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x11); + input.push(0x11); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + + let actual = Header::try_from(input.as_slice()).unwrap_err(); + + assert_eq!(actual, ParseError::Version(0x10)); + } + + #[test] + fn invalid_address_family() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x51); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + + let actual = Header::try_from(input.as_slice()).unwrap_err(); + + assert_eq!(actual, ParseError::AddressFamily(0x50)); + } + + #[test] + fn invalid_command() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x23); + input.push(0x11); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + + let actual = Header::try_from(input.as_slice()).unwrap_err(); + + assert_eq!(actual, ParseError::Command(0x03)); + } + + #[test] + fn invalid_protocol() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x20); + input.push(0x17); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + + let actual = Header::try_from(input.as_slice()).unwrap_err(); + + assert_eq!(actual, ParseError::Protocol(0x07)); + } + + #[test] + fn proxy_with_extra() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x11); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + input.extend([42]); + + let header = &input[..input.len() - 1]; + let expected = Header { + header: header.into(), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Stream, + addresses: IPv4::new([127, 0, 0, 1], [127, 0, 0, 2], 80, 443).into(), + }; + let actual = Header::try_from(input.as_slice()).unwrap(); + + assert_eq!(actual, expected); + assert!(actual.tlvs().next().is_none()); + assert_eq!(actual.length(), 12); + assert_eq!(actual.address_family(), AddressFamily::IPv4); + assert_eq!( + actual.address_bytes(), + &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 1, 187] + ); + assert!(actual.tlv_bytes().is_empty()); + assert_eq!(actual.as_bytes(), header); + } + + #[test] + fn with_tlvs() { + let source_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF2, + ]; + let destination_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF1, + ]; + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x21); + input.extend([0, 45]); + input.extend(source_address); + input.extend(destination_address); + input.extend([0, 80]); + input.extend([1, 187]); + input.extend([1, 0, 1, 5]); + input.extend([3, 0, 2, 5, 5]); + + let expected = Header { + header: input.as_slice().into(), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Stream, + addresses: IPv6::new(source_address, destination_address, 80, 443).into(), + }; + let expected_tlvs = vec![ + Ok(TypeLengthValue::new(Type::ALPN, &[5])), + Ok(TypeLengthValue::new(Type::CRC32C, &[5, 5])), + ]; + + let actual = Header::try_from(input.as_slice()).unwrap(); + let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); + + assert_eq!(actual, expected); + assert_eq!(actual_tlvs, expected_tlvs); + assert_eq!(actual.length(), 45); + assert_eq!(actual.address_family(), AddressFamily::IPv6); + assert_eq!( + actual.address_bytes(), + &[ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF1, 0, 80, 1, 187 + ] + ); + assert_eq!(actual.tlv_bytes(), &[1, 0, 1, 5, 3, 0, 2, 5, 5]); + assert_eq!(actual.as_bytes(), input.as_slice()); + } + + #[test] + fn tlvs_with_extra() { + let source_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, + ]; + let destination_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF1, + ]; + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x21); + input.extend([0, 45]); + input.extend(source_address); + input.extend(destination_address); + input.extend([0, 80]); + input.extend([1, 187]); + input.extend([1, 0, 1, 5]); + input.extend([4, 0, 2, 5, 5]); + input.extend([2, 0, 2, 5, 5]); + + let header = &input[..input.len() - 5]; + let expected = Header { + header: header.into(), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Stream, + addresses: IPv6::new(source_address, destination_address, 80, 443).into(), + }; + let expected_tlvs = vec![ + Ok(TypeLengthValue::new(Type::ALPN, &[5])), + Ok(TypeLengthValue::new(Type::NoOp, &[5, 5])), + ]; + + let actual = Header::try_from(input.as_slice()).unwrap(); + let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); + + assert_eq!(actual, expected); + assert_eq!(actual_tlvs, expected_tlvs); + assert_eq!(actual.length(), 45); + assert_eq!(actual.address_family(), AddressFamily::IPv6); + assert_eq!( + actual.address_bytes(), + &[ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF1, 0, 80, 1, 187 + ] + ); + assert_eq!(actual.tlv_bytes(), &[1, 0, 1, 5, 4, 0, 2, 5, 5]); + assert_eq!(actual.as_bytes(), header); + } + + #[test] + fn unix_tlvs_with_extra() { + let source_address = [0xFFu8; 108]; + let destination_address = [0xAAu8; 108]; + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x30); + input.extend([0, 225]); + input.extend(source_address); + input.extend(destination_address); + input.extend([2, 0, 2, 5, 5]); + input.extend([48, 0, 1, 5]); + input.extend([1, 0, 2, 5, 5]); + + let header = &input[..input.len() - 5]; + let expected = Header { + header: header.into(), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Unspecified, + addresses: Unix::new(source_address, destination_address).into(), + }; + let mut expected_address_bytes = + Vec::with_capacity(source_address.len() + destination_address.len()); + expected_address_bytes.extend(source_address); + expected_address_bytes.extend(destination_address); + + let expected_tlvs = vec![ + Ok(TypeLengthValue::new(Type::Authority, &[5, 5])), + Ok(TypeLengthValue::new(Type::NetworkNamespace, &[5])), + ]; + + let actual = Header::try_from(input.as_slice()).unwrap(); + let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); + + assert_eq!(actual, expected); + assert_eq!(actual_tlvs, expected_tlvs); + assert_eq!(actual.length(), 225); + assert_eq!(actual.address_family(), AddressFamily::Unix); + assert_eq!(actual.address_bytes(), expected_address_bytes.as_slice()); + assert_eq!(actual.tlv_bytes(), &[2, 0, 2, 5, 5, 48, 0, 1, 5]); + assert_eq!(actual.as_bytes(), header); + } + + #[test] + fn with_tlvs_without_ports() { + let source_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, + ]; + let destination_address = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF1, + ]; + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x20); + input.extend([0, 41]); + input.extend(source_address); + input.extend(destination_address); + input.extend([1, 0, 1, 5]); + input.extend([3, 0, 2, 5, 5]); + + let expected = Header { + header: input.as_slice().into(), + version: Version::Two, + command: Command::Proxy, + protocol: Protocol::Unspecified, + addresses: IPv6::new(source_address, destination_address, 256, 261).into(), + }; + let expected_tlvs = vec![Ok(TypeLengthValue::new(Type::CRC32C, &[5, 5]))]; + + let actual = Header::try_from(input.as_slice()).unwrap(); + let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); + + assert_eq!(actual, expected); + assert_eq!(actual_tlvs, expected_tlvs); + assert_eq!(actual.length(), 41); + assert_eq!(actual.address_family(), AddressFamily::IPv6); + assert_eq!( + actual.address_bytes(), + &[ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF1, 1, 0, 1, 5 + ] + ); + assert_eq!(actual.tlv_bytes(), &[3, 0, 2, 5, 5]); + assert_eq!(actual.as_bytes(), input.as_slice()); + } + + #[test] + fn partial_tlv() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x11); + input.extend([0, 15]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + input.extend([1, 0, 1]); + + let header = Header::try_from(input.as_slice()).unwrap(); + let mut tlvs = header.tlvs(); + + assert_eq!(tlvs.next().unwrap(), Err(ParseError::InvalidTLV(1, 1))); + assert_eq!(tlvs.next(), None); + } + + #[test] + fn missing_tlvs() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x11); + input.extend([0, 17]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([1, 187]); + input.extend([1, 0, 1]); + + assert_eq!( + Header::try_from(&input[..]).unwrap_err(), + ParseError::Partial(15, 17) + ); + } + + #[test] + fn partial_address() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x21); + input.push(0x11); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + + assert_eq!( + Header::try_from(&input[..]).unwrap_err(), + ParseError::Partial(10, 12) + ); + } + + #[test] + fn no_address() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x20); + input.push(0x02); + input.extend([0, 0]); + input.extend([0, 80]); + + let header = &input[..input.len() - 2]; + let expected = Header { + header: header.into(), + version: Version::Two, + command: Command::Local, + protocol: Protocol::Datagram, + addresses: Addresses::Unspecified, + }; + + let actual = Header::try_from(input.as_slice()).unwrap(); + let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); + + assert_eq!(actual, expected); + assert_eq!(actual_tlvs, vec![]); + assert_eq!(actual.length(), 0); + assert_eq!(actual.address_family(), AddressFamily::Unspecified); + assert!(actual.address_bytes().is_empty()); + assert!(actual.tlv_bytes().is_empty()); + assert_eq!(actual.as_bytes(), header); + } + + #[test] + fn unspecified_address_family() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x20); + input.push(0x02); + input.extend([0, 12]); + input.extend([127, 0, 0, 1]); + input.extend([127, 0, 0, 2]); + input.extend([0, 80]); + input.extend([0xbb, 1]); + + let expected = Header { + header: input.as_slice().into(), + version: Version::Two, + command: Command::Local, + protocol: Protocol::Datagram, + addresses: Addresses::Unspecified, + }; + let actual = Header::try_from(input.as_slice()).unwrap(); + + assert_eq!(actual, expected); + assert!(actual.tlvs().next().is_none()); + assert_eq!(actual.length(), 12); + assert_eq!(actual.address_family(), AddressFamily::Unspecified); + assert_eq!( + actual.address_bytes(), + &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 0xbb, 1] + ); + assert!(actual.tlv_bytes().is_empty()); + assert_eq!(actual.as_bytes(), input.as_slice()); + } + + #[test] + fn missing_address() { + let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); + + input.extend_from_slice(PROTOCOL_PREFIX); + input.push(0x20); + input.push(0x22); + input.extend([0, 0]); + input.extend([0, 80]); + + assert_eq!( + Header::try_from(&input[..]).unwrap_err(), + ParseError::InvalidAddresses(0, AddressFamily::IPv6.byte_length().unwrap_or_default()) + ); + } + + #[test] + fn not_prefixed() { + assert_eq!( + Header::try_from(b"\r\n\r\n\x01\r\nQUIT\n".as_slice()).unwrap_err(), + ParseError::Prefix + ); + assert_eq!( + Header::try_from(b"\r\n\r\n\x01".as_slice()).unwrap_err(), + ParseError::Prefix + ); + } + + #[test] + fn incomplete() { + assert_eq!( + Header::try_from([0x0D, 0x0A, 0x0D, 0x0A, 0x00].as_slice()).unwrap_err(), + ParseError::Incomplete(5) + ); + assert_eq!( + Header::try_from(PROTOCOL_PREFIX).unwrap_err(), + ParseError::Incomplete(PROTOCOL_PREFIX.len()) + ); + } +} diff --git a/rama-haproxy/src/protocol/v2/model.rs b/rama-haproxy/src/protocol/v2/model.rs new file mode 100644 index 00000000..5d358afd --- /dev/null +++ b/rama-haproxy/src/protocol/v2/model.rs @@ -0,0 +1,475 @@ +use crate::protocol::ip::{IPv4, IPv6}; +use crate::protocol::v2::error::ParseError; +use std::borrow::Cow; +use std::fmt; +use std::net::SocketAddr; +use std::ops::BitOr; + +/// The prefix of the PROXY protocol header. +pub const PROTOCOL_PREFIX: &[u8] = b"\r\n\r\n\0\r\nQUIT\n"; +/// The minimum length in bytes of a PROXY protocol header. +pub(crate) const MINIMUM_LENGTH: usize = 16; +/// The minimum length in bytes of a Type-Length-Value payload. +pub(crate) const MINIMUM_TLV_LENGTH: usize = 3; + +/// The number of bytes for an IPv4 addresses payload. +const IPV4_ADDRESSES_BYTES: usize = 12; +/// The number of bytes for an IPv6 addresses payload. +const IPV6_ADDRESSES_BYTES: usize = 36; +/// The number of bytes for a unix addresses payload. +const UNIX_ADDRESSES_BYTES: usize = 216; + +/// A proxy protocol version 2 header. +/// +/// ## Examples +/// ```rust +/// use rama_haproxy::protocol::v2::{Addresses, AddressFamily, Command, Header, IPv4, ParseError, Protocol, PROTOCOL_PREFIX, Type, TypeLengthValue, Version}; +/// let mut header = Vec::from(PROTOCOL_PREFIX); +/// header.extend([ +/// 0x21, 0x12, 0, 16, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 4, 0, 1, 42 +/// ]); +/// +/// let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); +/// let expected = Header { +/// header: header.as_slice().into(), +/// version: Version::Two, +/// command: Command::Proxy, +/// protocol: Protocol::Datagram, +/// addresses +/// }; +/// let actual = Header::try_from(header.as_slice()).unwrap(); +/// +/// assert_eq!(actual, expected); +/// assert_eq!(actual.tlvs().collect::, ParseError>>>(), vec![Ok(TypeLengthValue::new(Type::NoOp, &[42]))]); +/// ``` +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Header<'a> { + /// The underlying byte slice this `Header` is built on. + pub header: Cow<'a, [u8]>, + /// The version of the PROXY protocol. + pub version: Version, + /// The command of the PROXY protocol. + pub command: Command, + /// The protocol of the PROXY protocol. + pub protocol: Protocol, + /// The source and destination addresses of the PROXY protocol. + pub addresses: Addresses, +} + +/// The supported `Version`s for binary headers. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Version { + /// Version two of the PROXY protocol. + Two = 0x20, +} + +/// The supported `Command`s for a PROXY protocol header. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Command { + /// The connection is a local connection. + Local = 0, + /// The connection is a proxy connection. + Proxy, +} + +/// The supported `AddressFamily` for a PROXY protocol header. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum AddressFamily { + /// The address family is unspecified. + Unspecified = 0x00, + /// The address family is IPv4. + IPv4 = 0x10, + /// The address family is IPv6. + IPv6 = 0x20, + /// The address family is Unix. + Unix = 0x30, +} + +/// The supported `Protocol`s for a PROXY protocol header. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Protocol { + /// The protocol is unspecified. + Unspecified = 0, + /// The protocol is a stream. + Stream, + /// The protocol is a datagram. + Datagram, +} + +/// The source and destination address information for a given `AddressFamily`. +/// +/// ## Examples +/// ```rust +/// use rama_haproxy::protocol::v2::{Addresses, AddressFamily}; +/// use std::net::SocketAddr; +/// +/// let addresses: Addresses = ("127.0.0.1:80".parse::().unwrap(), "192.168.1.1:443".parse::().unwrap()).into(); +/// +/// assert_eq!(addresses.address_family(), AddressFamily::IPv4); +/// ``` +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Addresses { + /// The source and destination addresses are unspecified. + Unspecified, + /// The source and destination addresses are IPv4. + IPv4(IPv4), + /// The source and destination addresses are IPv6. + IPv6(IPv6), + /// The source and destination addresses are Unix. + Unix(Unix), +} + +/// The source and destination addresses of UNIX sockets. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Unix { + /// The source address of the UNIX socket. + pub source: [u8; 108], + /// The destination address of the UNIX socket. + pub destination: [u8; 108], +} + +/// An `Iterator` of `TypeLengthValue`s stored in a byte slice. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct TypeLengthValues<'a> { + bytes: &'a [u8], + offset: usize, +} + +/// A Type-Length-Value payload. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct TypeLengthValue<'a> { + /// The type of the `TypeLengthValue`. + pub kind: u8, + /// The value of the `TypeLengthValue`. + pub value: Cow<'a, [u8]>, +} + +/// Supported types for `TypeLengthValue` payloads. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Type { + /// The ALPN of the connection. + ALPN = 0x01, + /// The authority of the connection. + Authority, + /// The CRC32C checksum of the connection. + CRC32C, + /// NoOp + NoOp, + /// The Unique ID of the connection. + UniqueId, + /// The SSL information. + SSL = 0x20, + /// The SSL Version. + SSLVersion, + /// The SSL common name. + SSLCommonName, + /// The SSL cipher. + SSLCipher, + /// The SSL Signature Algorithm. + SSLSignatureAlgorithm, + /// The SSL Key Algorithm + SSLKeyAlgorithm, + /// The SSL Network Namespace. + NetworkNamespace = 0x30, +} + +impl<'a> fmt::Display for Header<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{:?} {:#X} {:#X} ({} bytes)", + PROTOCOL_PREFIX, + self.version | self.command, + self.protocol | self.address_family(), + self.length() + ) + } +} + +impl<'a> Header<'a> { + /// Creates an owned clone of this [`Header`]. + pub fn to_owned(&self) -> Header<'static> { + Header { + header: Cow::Owned(self.header.to_vec()), + version: self.version, + command: self.command, + protocol: self.protocol, + addresses: self.addresses, + } + } + + /// The length of this `Header`'s payload in bytes. + pub fn length(&self) -> usize { + self.header[MINIMUM_LENGTH..].len() + } + + /// The total length of this `Header` in bytes. + pub fn len(&self) -> usize { + self.header.len() + } + + /// Tests whether this `Header`'s underlying byte slice is empty. + pub fn is_empty(&self) -> bool { + self.header.is_empty() + } + + /// The `AddressFamily` of this `Header`. + pub fn address_family(&self) -> AddressFamily { + self.addresses.address_family() + } + + /// The length in bytes of the address portion of the payload. + fn address_bytes_end(&self) -> usize { + let length = self.length(); + let address_bytes = self.address_family().byte_length().unwrap_or(length); + + MINIMUM_LENGTH + std::cmp::min(address_bytes, length) + } + + /// The bytes of the address portion of the payload. + pub fn address_bytes(&self) -> &[u8] { + &self.header[MINIMUM_LENGTH..self.address_bytes_end()] + } + + /// The bytes of the `TypeLengthValue` portion of the payload. + pub fn tlv_bytes(&self) -> &[u8] { + &self.header[self.address_bytes_end()..] + } + + /// An `Iterator` of `TypeLengthValue`s. + pub fn tlvs(&self) -> TypeLengthValues<'_> { + TypeLengthValues { + bytes: self.tlv_bytes(), + offset: 0, + } + } + + /// The underlying byte slice this `Header` is built on. + pub fn as_bytes(&self) -> &[u8] { + self.header.as_ref() + } +} + +impl<'a> TypeLengthValues<'a> { + /// The underlying byte slice of the `TypeLengthValue`s portion of the `Header` payload. + pub fn as_bytes(&self) -> &[u8] { + self.bytes + } +} + +impl<'a> From<&'a [u8]> for TypeLengthValues<'a> { + fn from(bytes: &'a [u8]) -> Self { + TypeLengthValues { bytes, offset: 0 } + } +} + +impl<'a> Iterator for TypeLengthValues<'a> { + type Item = Result, ParseError>; + + fn next(&mut self) -> Option { + if self.offset >= self.bytes.len() { + return None; + } + + let remaining = &self.bytes[self.offset..]; + + if remaining.len() < MINIMUM_TLV_LENGTH { + self.offset = self.bytes.len(); + return Some(Err(ParseError::Leftovers(self.bytes.len()))); + } + + let tlv_type = remaining[0]; + let length = u16::from_be_bytes([remaining[1], remaining[2]]); + let tlv_length = MINIMUM_TLV_LENGTH + length as usize; + + if remaining.len() < tlv_length { + self.offset = self.bytes.len(); + return Some(Err(ParseError::InvalidTLV(tlv_type, length))); + } + + self.offset += tlv_length; + + Some(Ok(TypeLengthValue { + kind: tlv_type, + value: Cow::Borrowed(&remaining[MINIMUM_TLV_LENGTH..tlv_length]), + })) + } +} + +impl<'a> TypeLengthValues<'a> { + /// The number of bytes in the `TypeLengthValue` portion of the `Header`. + pub fn len(&self) -> u16 { + self.bytes.len() as u16 + } + + /// Whether there are any bytes to be interpreted as `TypeLengthValue`s. + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } +} + +impl BitOr for Version { + type Output = u8; + + fn bitor(self, command: Command) -> Self::Output { + (self as u8) | (command as u8) + } +} + +impl BitOr for Command { + type Output = u8; + + fn bitor(self, version: Version) -> Self::Output { + (self as u8) | (version as u8) + } +} + +impl BitOr for AddressFamily { + type Output = u8; + + fn bitor(self, protocol: Protocol) -> Self::Output { + (self as u8) | (protocol as u8) + } +} + +impl AddressFamily { + /// The length in bytes for this `AddressFamily`. + /// `AddressFamily::Unspecified` does not require any bytes, and is represented as `None`. + pub fn byte_length(&self) -> Option { + match self { + AddressFamily::IPv4 => Some(IPV4_ADDRESSES_BYTES), + AddressFamily::IPv6 => Some(IPV6_ADDRESSES_BYTES), + AddressFamily::Unix => Some(UNIX_ADDRESSES_BYTES), + AddressFamily::Unspecified => None, + } + } +} + +impl From for u16 { + fn from(address_family: AddressFamily) -> Self { + address_family.byte_length().unwrap_or_default() as u16 + } +} + +impl From<(SocketAddr, SocketAddr)> for Addresses { + fn from(addresses: (SocketAddr, SocketAddr)) -> Self { + match addresses { + (SocketAddr::V4(source), SocketAddr::V4(destination)) => Addresses::IPv4(IPv4::new( + *source.ip(), + *destination.ip(), + source.port(), + destination.port(), + )), + (SocketAddr::V6(source), SocketAddr::V6(destination)) => Addresses::IPv6(IPv6::new( + *source.ip(), + *destination.ip(), + source.port(), + destination.port(), + )), + _ => Addresses::Unspecified, + } + } +} + +impl From for Addresses { + fn from(addresses: IPv4) -> Self { + Addresses::IPv4(addresses) + } +} + +impl From for Addresses { + fn from(addresses: IPv6) -> Self { + Addresses::IPv6(addresses) + } +} + +impl From for Addresses { + fn from(addresses: Unix) -> Self { + Addresses::Unix(addresses) + } +} + +impl Addresses { + /// The `AddressFamily` for this `Addresses`. + pub fn address_family(&self) -> AddressFamily { + match self { + Addresses::Unspecified => AddressFamily::Unspecified, + Addresses::IPv4(..) => AddressFamily::IPv4, + Addresses::IPv6(..) => AddressFamily::IPv6, + Addresses::Unix(..) => AddressFamily::Unix, + } + } + + /// The length in bytes of the `Addresses` in the `Header`'s payload. + pub fn len(&self) -> usize { + self.address_family().byte_length().unwrap_or_default() + } + + /// Tests whether the `Addresses` consume any space in the `Header`'s payload. + /// `AddressFamily::Unspecified` does not require any bytes, and always returns true. + pub fn is_empty(&self) -> bool { + self.address_family().byte_length().is_none() + } +} + +impl Unix { + /// Creates a new instance of a source and destination address pair for Unix sockets. + pub const fn new(source: [u8; 108], destination: [u8; 108]) -> Self { + Unix { + source, + destination, + } + } +} + +impl BitOr for Protocol { + type Output = u8; + + fn bitor(self, address_family: AddressFamily) -> Self::Output { + (self as u8) | (address_family as u8) + } +} + +impl<'a, T: Into> From<(T, &'a [u8])> for TypeLengthValue<'a> { + fn from((kind, value): (T, &'a [u8])) -> Self { + TypeLengthValue { + kind: kind.into(), + value: value.into(), + } + } +} + +impl<'a> TypeLengthValue<'a> { + /// Creates an owned clone of this [`TypeLengthValue`]. + pub fn to_owned(&self) -> TypeLengthValue<'static> { + TypeLengthValue { + kind: self.kind, + value: Cow::Owned(self.value.to_vec()), + } + } + + /// Creates a new instance of a `TypeLengthValue`, where the length is determine by the length of the byte slice. + /// No check is done to ensure the byte slice's length fits in a `u16`. + pub fn new>(kind: T, value: &'a [u8]) -> Self { + TypeLengthValue { + kind: kind.into(), + value: value.into(), + } + } + + /// The length in bytes of this `TypeLengthValue`'s value. + pub fn len(&self) -> usize { + self.value.len() + } + + /// Tests whether the value of this `TypeLengthValue` is empty. + pub fn is_empty(&self) -> bool { + self.value.is_empty() + } +} + +impl From for u8 { + fn from(kind: Type) -> Self { + kind as u8 + } +} diff --git a/rama-haproxy/src/server/layer.rs b/rama-haproxy/src/server/layer.rs new file mode 100644 index 00000000..d366566a --- /dev/null +++ b/rama-haproxy/src/server/layer.rs @@ -0,0 +1,177 @@ +use crate::protocol::{v1, v2, HeaderResult, PartialResult}; +use rama_core::{error::BoxError, Context, Layer, Service}; +use rama_net::{ + forwarded::{Forwarded, ForwardedElement}, + stream::{ChainReader, HeapReader, Stream}, +}; +use std::{fmt, net::SocketAddr}; +use tokio::io::AsyncReadExt; + +/// Layer to decode the HaProxy Protocol +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct HaProxyLayer; + +impl HaProxyLayer { + /// Create a new [`HaProxyLayer`]. + pub const fn new() -> Self { + HaProxyLayer + } +} + +impl Layer for HaProxyLayer { + type Service = HaProxyService; + + fn layer(&self, inner: S) -> Self::Service { + HaProxyService { inner } + } +} + +/// Service to decode the HaProxy Protocol +/// +/// This service will decode the HaProxy Protocol header and pass the decoded +/// information to the inner service. +pub struct HaProxyService { + inner: S, +} + +impl HaProxyService { + /// Create a new [`HaProxyService`] with the given inner service. + pub const fn new(inner: S) -> Self { + HaProxyService { inner } + } +} + +impl fmt::Debug for HaProxyService { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("HaProxyService") + .field("inner", &self.inner) + .finish() + } +} + +impl Clone for HaProxyService { + fn clone(&self) -> Self { + HaProxyService { + inner: self.inner.clone(), + } + } +} + +impl Service for HaProxyService +where + State: Send + Sync + 'static, + S: Service< + State, + tokio::io::Join>, tokio::io::WriteHalf>, + Error: Into, + >, + IO: Stream + Unpin, +{ + type Response = S::Response; + type Error = BoxError; + + async fn serve( + &self, + mut ctx: Context, + mut stream: IO, + ) -> Result { + let mut buffer = [0; 512]; + let mut read = 0; + let header = loop { + read += stream.read(&mut buffer[read..]).await?; + + let header = HeaderResult::parse(&buffer[..read]); + if header.is_complete() { + break header; + } + + tracing::debug!("Incomplete header. Read {} bytes so far.", read); + }; + + let consumed = match header { + HeaderResult::V1(Ok(header)) => { + match header.addresses { + v1::Addresses::Tcp4(info) => { + let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); + let el = ForwardedElement::forwarded_for(peer_addr); + match ctx.get_mut::() { + Some(forwarded) => { + forwarded.append(el); + } + None => { + let forwarded = Forwarded::new(el); + ctx.insert(forwarded); + } + } + } + v1::Addresses::Tcp6(info) => { + let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); + let el = ForwardedElement::forwarded_for(peer_addr); + match ctx.get_mut::() { + Some(forwarded) => { + forwarded.append(el); + } + None => { + let forwarded = Forwarded::new(el); + ctx.insert(forwarded); + } + } + } + v1::Addresses::Unknown => (), + }; + header.header.len() + } + HeaderResult::V2(Ok(header)) => { + match header.addresses { + v2::Addresses::IPv4(info) => { + let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); + let el = ForwardedElement::forwarded_for(peer_addr); + match ctx.get_mut::() { + Some(forwarded) => { + forwarded.append(el); + } + None => { + let forwarded = Forwarded::new(el); + ctx.insert(forwarded); + } + } + } + v2::Addresses::IPv6(info) => { + let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); + let el = ForwardedElement::forwarded_for(peer_addr); + match ctx.get_mut::() { + Some(forwarded) => { + forwarded.append(el); + } + None => { + let forwarded = Forwarded::new(el); + ctx.insert(forwarded); + } + } + } + v2::Addresses::Unix(_) | v2::Addresses::Unspecified => (), + }; + header.header.len() + } + HeaderResult::V1(Err(error)) => { + return Err(error.into()); + } + HeaderResult::V2(Err(error)) => { + return Err(error.into()); + } + }; + + // put back the data that is read too much + let (r, w) = tokio::io::split(stream); + let mem: HeapReader = buffer[consumed..read].into(); + let r = ChainReader::new(mem, r); + let stream = tokio::io::join(r, w); + + // read the rest of the data + match self.inner.serve(ctx, stream).await { + Ok(response) => Ok(response), + Err(error) => Err(error.into()), + } + } +} diff --git a/rama-haproxy/src/server/mod.rs b/rama-haproxy/src/server/mod.rs new file mode 100644 index 00000000..dd398a40 --- /dev/null +++ b/rama-haproxy/src/server/mod.rs @@ -0,0 +1,7 @@ +//! HaProxy Protocol Server support +//! +//! + +mod layer; +#[doc(inline)] +pub use layer::{HaProxyLayer, HaProxyService}; diff --git a/rama-http-backend/Cargo.toml b/rama-http-backend/Cargo.toml index d9d596a4..f7085fc2 100644 --- a/rama-http-backend/Cargo.toml +++ b/rama-http-backend/Cargo.toml @@ -10,9 +10,26 @@ categories = { workspace = true } authors = { workspace = true } rust-version = { workspace = true } +[features] +default = [] +tls = ["dep:rama-tls", "rama-net/tls"] +rustls = ["tls", "rama-tls/rustls"] +boring = ["tls", "rama-net/boring"] +rustls-ring = ["rustls", "rama-tls/rustls-ring"] + [dependencies] -rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +rama-tls = { version = "0.2.0-alpha.2", path = "../rama-tls", optional = true } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp", features = ["http"] } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } +hyper = { workspace = true, features = ["http1", "http2", "server", "client"] } +hyper-util = { workspace = true, features = ["tokio", "server-auto"] } +h2 = { workspace = true } +tokio = { workspace = true, features = ["macros"] } +pin-project-lite = { workspace = true } +tracing = { workspace = true } [dev-dependencies] diff --git a/rama-http-backend/src/client/conn.rs b/rama-http-backend/src/client/conn.rs index 63a73499..cd404555 100644 --- a/rama-http-backend/src/client/conn.rs +++ b/rama-http-backend/src/client/conn.rs @@ -1,12 +1,14 @@ use super::{svc::SendRequest, HttpClientService}; use crate::executor::HyperExecutor; -use crate::{ +use rama_core::{ error::{BoxError, OpaqueError}, - http::{dep::http_body, Request, Version}, - net::client::{ConnectorService, EstablishedClientConnection}, - stream::Stream, Context, Layer, Service, }; +use rama_http_types::{dep::http_body, Request, Version}; +use rama_net::{ + client::{ConnectorService, EstablishedClientConnection}, + stream::Stream, +}; use hyper_util::rt::TokioIo; use rama_utils::macros::define_inner_service_accessors; use std::fmt; diff --git a/rama-http-backend/src/client/error.rs b/rama-http-backend/src/client/error.rs deleted file mode 100644 index 09b44e5d..00000000 --- a/rama-http-backend/src/client/error.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![allow(dead_code)] - -use rama_core::error::{BoxError, OpaqueError}; -use crate::Uri; - -// TODO: support perhaps also more context, such as tracing id, ... - -#[derive(Debug)] -/// An opaque error type that encapsulates all possible errors that can occur when using the -/// [`HttpClient`] service directly, as part of a stack or as a building block for other services. -/// -/// [`HttpClient`]: crate::client::HttpClient -pub struct HttpClientError { - inner: OpaqueError, - uri: Option, -} - -impl HttpClientError { - /// create a [`HttpClientError`] from an std error - pub fn from_std(err: impl std::error::Error + Send + Sync + 'static) -> Self { - Self { - inner: OpaqueError::from_std(err), - uri: None, - } - } - - /// create a [`HttpClientError`] from a display object - pub fn from_display( - err: impl std::fmt::Display + std::fmt::Debug + Send + Sync + 'static, - ) -> Self { - Self { - inner: OpaqueError::from_display(err), - uri: None, - } - } - - /// create a [`HttpClientError`] from a boxed error - pub fn from_boxed(err: BoxError) -> Self { - Self { - inner: OpaqueError::from_boxed(err), - uri: None, - } - } - - /// Attach a [`Uri`] to the error. - pub fn with_uri(mut self, uri: Uri) -> Self { - self.uri = Some(uri); - self - } - - /// Set a [`Uri`] to be attached to the error. - pub fn set_uri(&mut self, uri: Uri) -> &mut Self { - self.uri = Some(uri); - self - } - - /// Return the [`Uri`] associated with the error, if any. - pub fn uri(&self) -> Option<&Uri> { - self.uri.as_ref() - } -} - -impl std::fmt::Display for HttpClientError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.uri { - Some(uri) => write!( - f, - "http client error for uri '{}'\r\n β†ͺ {}", - uri, self.inner - ), - None => write!(f, "http client error\r\n β†ͺ {}", self.inner), - } - } -} - -impl std::error::Error for HttpClientError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.inner.source() - } -} - -impl From for HttpClientError { - fn from(err: BoxError) -> Self { - Self { - inner: OpaqueError::from_boxed(err), - uri: None, - } - } -} diff --git a/rama-http-backend/src/client/mod.rs b/rama-http-backend/src/client/mod.rs index c77ed273..6ece48fb 100644 --- a/rama-http-backend/src/client/mod.rs +++ b/rama-http-backend/src/client/mod.rs @@ -1,31 +1,23 @@ //! Rama HTTP client module, //! which provides the [`HttpClient`] type to serve HTTP requests. -use crate::{ - error::BoxError, - http::{dep::http_body, Request, Response}, - net::client::{ConnectorService, EstablishedClientConnection}, - proxy::http::client::layer::HttpProxyConnector, - tcp::client::service::TcpConnector, +use rama_core::{ + error::{BoxError, OpaqueError, ErrorExt}, Context, Service, }; +use rama_http_types::{dep::http_body, Request, Response}; +use rama_net::client::{ConnectorService, EstablishedClientConnection}; +use proxy::layer::HttpProxyConnector; +use rama_tcp::client::service::TcpConnector; // TODO: also support client config in boring... #[cfg(all(feature = "rustls", not(feature = "boring")))] -use crate::tls::backend::rustls::dep::rustls::ClientConfig; +use rama_tls::rustls::dep::rustls::ClientConfig; #[cfg(all(feature = "rustls", not(feature = "boring")))] use std::sync::Arc; #[cfg(any(feature = "rustls", feature = "boring"))] -use crate::tls::backend::std::client::HttpsConnector; - -mod error; -#[doc(inline)] -pub use error::HttpClientError; - -mod ext; -#[doc(inline)] -pub use ext::{HttpClientExt, IntoUrl, RequestBuilder}; +use rama_tls::std::client::HttpsConnector; mod svc; #[doc(inline)] @@ -35,6 +27,8 @@ mod conn; #[doc(inline)] pub use conn::{HttpConnector, HttpConnectorLayer}; +pub mod proxy; + #[derive(Debug, Clone, Default)] #[non_exhaustive] /// An opiniated http client that can be used to serve HTTP requests. @@ -83,7 +77,7 @@ where Body: http_body::Body> + Unpin + Send + 'static, { type Response = Response; - type Error = HttpClientError; + type Error = OpaqueError; async fn serve( &self, @@ -109,10 +103,10 @@ where let EstablishedClientConnection { ctx, req, conn, .. } = connector .connect(ctx, req) .await - .map_err(|err| HttpClientError::from_boxed(err).with_uri(uri.clone()))?; + .map_err(|err| OpaqueError::from_boxed(err).with_context(|| uri.to_string()))?; conn.serve(ctx, req) .await - .map_err(|err| HttpClientError::from_boxed(err).with_uri(uri)) + .map_err(|err| OpaqueError::from_boxed(err).with_context(|| uri.to_string())) } } diff --git a/rama-proxy/src/http/client/layer/mod.rs b/rama-http-backend/src/client/proxy/layer/mod.rs similarity index 100% rename from rama-proxy/src/http/client/layer/mod.rs rename to rama-http-backend/src/client/proxy/layer/mod.rs diff --git a/rama-proxy/src/http/client/layer/proxy_address.rs b/rama-http-backend/src/client/proxy/layer/proxy_address.rs similarity index 99% rename from rama-proxy/src/http/client/layer/proxy_address.rs rename to rama-http-backend/src/client/proxy/layer/proxy_address.rs index 952c2a70..660d90c0 100644 --- a/rama-proxy/src/http/client/layer/proxy_address.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_address.rs @@ -1,9 +1,9 @@ -use crate::{ +use rama_core::{ error::{ErrorContext, OpaqueError}, - net::address::ProxyAddress, Context, Layer, Service, }; use std::{fmt, future::Future}; +use rama_net::address::ProxyAddress; #[derive(Debug, Clone, Default)] /// A [`Layer`] which allows you to add a [`ProxyAddress`] diff --git a/rama-proxy/src/http/client/layer/proxy_auth_header.rs b/rama-http-backend/src/client/proxy/layer/proxy_auth_header.rs similarity index 93% rename from rama-proxy/src/http/client/layer/proxy_auth_header.rs rename to rama-http-backend/src/client/proxy/layer/proxy_auth_header.rs index 448508dd..bedfaa9a 100644 --- a/rama-proxy/src/http/client/layer/proxy_auth_header.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_auth_header.rs @@ -1,8 +1,11 @@ -use crate::{ - http::headers::{HeaderMapExt, ProxyAuthorization}, - http::{Request, RequestContext}, - net::{address::ProxyAddress, user::ProxyCredential}, - Context, Layer, Service, +use rama_http_types::{ + headers::{HeaderMapExt, ProxyAuthorization}, + Request, +}; +use rama_core::{Context, Layer, Service}; +use rama_net::{ + http::RequestContext, + address::ProxyAddress, user::ProxyCredential, }; use std::{fmt, future::Future}; diff --git a/rama-proxy/src/http/client/layer/proxy_connector/connector.rs b/rama-http-backend/src/client/proxy/layer/proxy_connector/connector.rs similarity index 96% rename from rama-proxy/src/http/client/layer/proxy_connector/connector.rs rename to rama-http-backend/src/client/proxy/layer/proxy_connector/connector.rs index 89e9b743..89801f6d 100644 --- a/rama-proxy/src/http/client/layer/proxy_connector/connector.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_connector/connector.rs @@ -2,12 +2,12 @@ //! //! As defined in . -use crate::{ - http::{ - headers::{Header, HeaderMapExt}, - HeaderMap, HeaderName, HeaderValue, - }, - net::address::Authority, +use rama_http_types::{ + headers::{Header, HeaderMapExt}, + HeaderMap, HeaderName, HeaderValue, +}; +use rama_net::{ + address::Authority, stream::Stream, }; use tokio::io::{AsyncReadExt, AsyncWriteExt}; diff --git a/rama-proxy/src/http/client/layer/proxy_connector/layer.rs b/rama-http-backend/src/client/proxy/layer/proxy_connector/layer.rs similarity index 100% rename from rama-proxy/src/http/client/layer/proxy_connector/layer.rs rename to rama-http-backend/src/client/proxy/layer/proxy_connector/layer.rs diff --git a/rama-proxy/src/http/client/layer/proxy_connector/mod.rs b/rama-http-backend/src/client/proxy/layer/proxy_connector/mod.rs similarity index 100% rename from rama-proxy/src/http/client/layer/proxy_connector/mod.rs rename to rama-http-backend/src/client/proxy/layer/proxy_connector/mod.rs diff --git a/rama-proxy/src/http/client/layer/proxy_connector/service.rs b/rama-http-backend/src/client/proxy/layer/proxy_connector/service.rs similarity index 96% rename from rama-proxy/src/http/client/layer/proxy_connector/service.rs rename to rama-http-backend/src/client/proxy/layer/proxy_connector/service.rs index c57116b7..a96e45bb 100644 --- a/rama-proxy/src/http/client/layer/proxy_connector/service.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_connector/service.rs @@ -1,16 +1,17 @@ use super::InnerHttpProxyConnector; use rama_utils::macros::define_inner_service_accessors; -use crate::{ +use rama_core::{ error::{BoxError, ErrorExt, OpaqueError}, - http::headers::ProxyAuthorization, - net::{ - address::ProxyAddress, - client::{ConnectorService, EstablishedClientConnection}, - user::ProxyCredential, - }, - stream::{transport::TryRefIntoTransportContext, Stream}, Context, Service, }; +use rama_net::{ + address::ProxyAddress, + client::{ConnectorService, EstablishedClientConnection}, + user::ProxyCredential, + stream::Stream, + transport::TryRefIntoTransportContext, +}; +use rama_http_types::headers::ProxyAuthorization; use std::fmt; #[cfg(feature = "tls")] diff --git a/rama-proxy/src/http/client/mod.rs b/rama-http-backend/src/client/proxy/mod.rs similarity index 100% rename from rama-proxy/src/http/client/mod.rs rename to rama-http-backend/src/client/proxy/mod.rs diff --git a/rama-http-backend/src/client/svc.rs b/rama-http-backend/src/client/svc.rs index ec4a16a6..dec2aed7 100644 --- a/rama-http-backend/src/client/svc.rs +++ b/rama-http-backend/src/client/svc.rs @@ -1,16 +1,16 @@ -use crate::{ +use rama_core::{ error::{BoxError, OpaqueError}, - http::{ - self, dep::http::uri::PathAndQuery, dep::http_body, header::HOST, headers::HeaderMapExt, - Request, RequestContext, Response, Version, - }, - net::address::ProxyAddress, Context, Service, }; +use rama_http_types::{ + dep::http::uri::PathAndQuery, dep::http_body, header::HOST, headers::HeaderMapExt, + Request, Response, Version, Method, +}; +use rama_net::{address::ProxyAddress, http::RequestContext}; use tokio::sync::Mutex; #[derive(Debug)] -// TODO: once we have hyper as `rama::http::core` we can +// TODO: once we have hyper as `rama_core` we can // drop this mutex as there is no inherint reason for `sender` to be mutable... pub(super) enum SendRequest { Http1(Mutex>), @@ -49,7 +49,7 @@ where SendRequest::Http2(sender) => sender.lock().await.send_request(req).await, }?; - Ok(resp.map(crate::Body::new)) + Ok(resp.map(rama_http_types::Body::new)) } } @@ -58,7 +58,7 @@ fn sanitize_client_req_header( req: Request, ) -> Result, BoxError> { Ok(match req.method() { - &http::Method::CONNECT => { + &Method::CONNECT => { // CONNECT if req.uri().host().is_none() { return Err(OpaqueError::from_display("missing host in CONNECT request").into()); @@ -91,10 +91,10 @@ fn sanitize_client_req_header( } if !parts.headers.contains_key(HOST) { - parts.headers.typed_insert(headers::Host::from(authority)); + parts.headers.typed_insert(rama_http_types::headers::Host::from(authority)); } - parts.uri = crate::Uri::from_parts(uri_parts)?; + parts.uri = rama_http_types::Uri::from_parts(uri_parts)?; Request::from_parts(parts, body) } else { req diff --git a/rama-http-backend/src/executor.rs b/rama-http-backend/src/executor.rs index 5bf533da..6468db4f 100644 --- a/rama-http-backend/src/executor.rs +++ b/rama-http-backend/src/executor.rs @@ -1,6 +1,6 @@ //! tmp executor for http (while hyper is still third party) -use crate::rt::Executor; +use rama_core::rt::Executor; #[derive(Default, Debug, Clone)] /// Newtype to be able to implement Executor interface diff --git a/rama-http-backend/src/lib.rs b/rama-http-backend/src/lib.rs index f9e47558..c4f984e5 100644 --- a/rama-http-backend/src/lib.rs +++ b/rama-http-backend/src/lib.rs @@ -54,6 +54,5 @@ pub mod server; pub mod client; -pub mod layer; mod executor; diff --git a/rama-http-backend/src/server/hyper_conn.rs b/rama-http-backend/src/server/hyper_conn.rs index 604d6fbc..50e79166 100644 --- a/rama-http-backend/src/server/hyper_conn.rs +++ b/rama-http-backend/src/server/hyper_conn.rs @@ -1,10 +1,9 @@ use super::{svc_hyper::HyperService, HttpServeResult}; use crate::executor::HyperExecutor; -use crate::stream::Stream; -use crate::tcp::utils::is_connection_error; -use crate::Context; -use crate::Service; -use crate::{IntoResponse, Request}; +use rama_net::stream::Stream; +use rama_tcp::utils::is_connection_error; +use rama_core::{Context, Service}; +use rama_http_types::{IntoResponse, Request}; use hyper::server::conn::http1::Builder as Http1Builder; use hyper::server::conn::http2::Builder as Http2Builder; use hyper_util::{rt::TokioIo, server::conn::auto::Builder as AutoBuilder}; diff --git a/rama-http-backend/src/server/layer/upgrade/layer.rs b/rama-http-backend/src/server/layer/upgrade/layer.rs index 6d99b9a9..7b8f5a5b 100644 --- a/rama-http-backend/src/server/layer/upgrade/layer.rs +++ b/rama-http-backend/src/server/layer/upgrade/layer.rs @@ -1,5 +1,5 @@ use super::{service::UpgradeHandler, UpgradeService, Upgraded}; -use crate::Request; +use rama_http_types::Request; use rama_core::{matcher::Matcher, Context, Layer, Service}; use std::{convert::Infallible, fmt, sync::Arc}; diff --git a/rama-http-backend/src/server/layer/upgrade/service.rs b/rama-http-backend/src/server/layer/upgrade/service.rs index 89f83578..0339b6a0 100644 --- a/rama-http-backend/src/server/layer/upgrade/service.rs +++ b/rama-http-backend/src/server/layer/upgrade/service.rs @@ -3,7 +3,7 @@ //! See [`UpgradeService`] for more details. use super::Upgraded; -use crate::Request; +use rama_http_types::Request; use rama_core::{context::Extensions, matcher::Matcher, service::BoxService, Context, Service}; use rama_utils::macros::define_inner_service_accessors; use std::{convert::Infallible, fmt, sync::Arc}; diff --git a/rama-http-backend/src/server/service.rs b/rama-http-backend/src/server/service.rs index 62945ff2..5dfdfc31 100644 --- a/rama-http-backend/src/server/service.rs +++ b/rama-http-backend/src/server/service.rs @@ -6,7 +6,7 @@ use crate::executor::HyperExecutor; use rama_net::stream::Stream; use rama_tcp::server::TcpListener; use rama_core::{Context, Service}; -use crate::{IntoResponse, Request}; +use rama_http_types::{IntoResponse, Request}; use hyper::server::conn::http2::Builder as H2ConnBuilder; use hyper::{rt::Timer, server::conn::http1::Builder as Http1ConnBuilder}; use hyper_util::server::conn::auto::Builder as AutoConnBuilder; diff --git a/rama-http-backend/src/server/svc_hyper.rs b/rama-http-backend/src/server/svc_hyper.rs index 046a79f7..263b8f12 100644 --- a/rama-http-backend/src/server/svc_hyper.rs +++ b/rama-http-backend/src/server/svc_hyper.rs @@ -1,4 +1,4 @@ -use crate::{BodyLimit, IntoResponse, Request}; +use rama_http_types::{BodyLimit, IntoResponse, Request}; use rama_core::{Context, Service}; use std::{convert::Infallible, fmt, future::Future, pin::Pin, sync::Arc}; @@ -30,7 +30,7 @@ where T: Service, Response: IntoResponse + Send + 'static, { - type Response = crate::Response; + type Response = rama_http_types::Response; type Error = std::convert::Infallible; type Future = Pin> + Send + 'static>>; @@ -42,14 +42,14 @@ where let body_limit = ctx.get::().cloned(); let req = match body_limit.and_then(|limit| limit.request()) { - Some(limit) => req.map(|body| crate::Body::with_limit(body, limit)), - None => req.map(crate::Body::new), + Some(limit) => req.map(|body| rama_http_types::Body::with_limit(body, limit)), + None => req.map(rama_http_types::Body::new), }; Box::pin(async move { let resp = inner.serve(ctx, req).await.into_response(); Ok(match body_limit.and_then(|limit| limit.response()) { - Some(limit) => resp.map(|body| crate::Body::with_limit(body, limit)), + Some(limit) => resp.map(|body| rama_http_types::Body::with_limit(body, limit)), // If there is no limit, we can just return the response as is. None => resp, }) diff --git a/rama-http-types/src/response/mod.rs b/rama-http-types/src/response/mod.rs index 3b62c8ef..53880f2d 100644 --- a/rama-http-types/src/response/mod.rs +++ b/rama-http-types/src/response/mod.rs @@ -81,7 +81,7 @@ pub type Response = http::Response; /// } /// } /// -/// // we can combine them using `rama::http::response::Result` and still use `?` +/// // we can combine them using `rama_http::response::Result` and still use `?` /// async fn handler() -> rama_http_types::response::Result<&'static str> { /// // the errors are automatically converted to `ErrorResponse` /// try_something()?; @@ -93,7 +93,7 @@ pub type Response = http::Response; /// /// # As a replacement for `std::result::Result` /// -/// Since `rama::http::response::Result` has a default error type you only have to specify the `Ok` type: +/// Since `rama_http::response::Result` has a default error type you only have to specify the `Ok` type: /// /// ``` /// use rama_http_types::{ @@ -108,7 +108,7 @@ pub type Response = http::Response; /// Ok("it worked!") /// } /// -/// // You can still specify the error even if you've imported `rama::http::response::Result` +/// // You can still specify the error even if you've imported `rama_http::response::Result` /// fn try_something() -> Result<(), StatusCode> { /// // ... /// # unimplemented!() diff --git a/rama-http/Cargo.toml b/rama-http/Cargo.toml index c6fe8722..2c3a754d 100644 --- a/rama-http/Cargo.toml +++ b/rama-http/Cargo.toml @@ -14,7 +14,7 @@ rust-version = { workspace = true } default = [] compression = ["dep:async-compression"] telemetry = ["rama-core/telemetry"] -tls = ["dep:rama-tls"] +tls = ["rama-net/tls"] [dependencies] async-compression = { workspace = true, features = [ @@ -41,7 +41,6 @@ rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["htt rama-ua = { version = "0.2.0-alpha.2", path = "../rama-ua" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } -rama-tls = { version = "0.2.0-alpha.2", path = "../rama-tls", optional = true } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } serde_json = { workspace = true } @@ -61,6 +60,15 @@ bitflags = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["full"] } tokio-test = { workspace = true } +itertools = { workspace = true } +parking_lot = { workspace = true } +flate2 = { workspace = true } +brotli = { workspace = true } +zstd = { workspace = true } +tempfile = { workspace = true } +rama-http-backend = { version = "0.2.0-alpha.2", path = "../rama-http-backend" } +rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp" } +tracing-subscriber = { workspace = true, features = ["env-filter"] } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-http/src/headers/common/accept.rs b/rama-http/src/headers/common/accept.rs index f013dc7b..caedd494 100644 --- a/rama-http/src/headers/common/accept.rs +++ b/rama-http/src/headers/common/accept.rs @@ -35,10 +35,10 @@ fn qitem(mime: Mime) -> QualityValue { /// # Examples /// ``` /// use std::iter::FromIterator; -/// use rama::http::headers::{Accept, QualityValue, HeaderMapExt}; -/// use rama::http::dep::mime; +/// use rama_http::headers::{Accept, QualityValue, HeaderMapExt}; +/// use rama_http::dep::mime; /// -/// let mut headers = rama::http::HeaderMap::new(); +/// let mut headers = rama_http::HeaderMap::new(); /// /// headers.typed_insert( /// Accept::from_iter(vec![ @@ -49,10 +49,10 @@ fn qitem(mime: Mime) -> QualityValue { /// /// ``` /// use std::iter::FromIterator; -/// use rama::http::headers::{Accept, QualityValue, HeaderMapExt}; -/// use rama::http::dep::mime; +/// use rama_http::headers::{Accept, QualityValue, HeaderMapExt}; +/// use rama_http::dep::mime; /// -/// let mut headers = rama::http::HeaderMap::new(); +/// let mut headers = rama_http::HeaderMap::new(); /// headers.typed_insert( /// Accept::from_iter(vec![ /// QualityValue::new(mime::APPLICATION_JSON, Default::default()), @@ -61,10 +61,10 @@ fn qitem(mime: Mime) -> QualityValue { /// ``` /// ``` /// use std::iter::FromIterator; -/// use rama::http::headers::{Accept, QualityValue, HeaderMapExt}; -/// use rama::http::dep::mime; +/// use rama_http::headers::{Accept, QualityValue, HeaderMapExt}; +/// use rama_http::dep::mime; /// -/// let mut headers = rama::http::HeaderMap::new(); +/// let mut headers = rama_http::HeaderMap::new(); /// /// headers.typed_insert( /// Accept::from_iter(vec![ diff --git a/rama-http/src/layer/auth/add_authorization.rs b/rama-http/src/layer/auth/add_authorization.rs index 2222a95c..53d1b58d 100644 --- a/rama-http/src/layer/auth/add_authorization.rs +++ b/rama-http/src/layer/auth/add_authorization.rs @@ -7,12 +7,12 @@ //! ``` //! use bytes::Bytes; //! -//! use rama::http::layer::validate_request::{ValidateRequestHeader, ValidateRequestHeaderLayer}; -//! use rama::http::layer::auth::AddAuthorizationLayer; -//! use rama::http::{Body, Request, Response, StatusCode, header::AUTHORIZATION}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::validate_request::{ValidateRequestHeader, ValidateRequestHeaderLayer}; +//! use rama_http::layer::auth::AddAuthorizationLayer; +//! use rama_http::{Body, Request, Response, StatusCode, header::AUTHORIZATION}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # async fn handle(request: Request) -> Result { //! # Ok(Response::new(Body::default())) diff --git a/rama-http/src/layer/auth/async_require_authorization.rs b/rama-http/src/layer/auth/async_require_authorization.rs index d5c84395..8980c479 100644 --- a/rama-http/src/layer/auth/async_require_authorization.rs +++ b/rama-http/src/layer/auth/async_require_authorization.rs @@ -7,11 +7,11 @@ //! ``` //! use bytes::Bytes; //! -//! use rama::http::layer::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest}; -//! use rama::http::{Body, Request, Response, StatusCode, header::AUTHORIZATION}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest}; +//! use rama_http::{Body, Request, Response, StatusCode, header::AUTHORIZATION}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! #[derive(Clone, Copy)] //! struct MyAuth; @@ -77,11 +77,11 @@ //! ``` //! use bytes::Bytes; //! -//! use rama::http::layer::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest}; -//! use rama::http::{Body, Request, Response, StatusCode}; -//! use rama::service::service_fn; -//! use rama::{Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest}; +//! use rama_http::{Body, Request, Response, StatusCode}; +//! use rama_core::service::service_fn; +//! use rama_core::{Service, Layer}; +//! use rama_core::error::BoxError; //! //! async fn check_auth(request: &Request) -> Option { //! // ... @@ -247,9 +247,9 @@ mod tests { #[allow(unused_imports)] use super::*; - use crate::service::service_fn; use crate::{header, Body, StatusCode}; use rama_core::error::BoxError; + use rama_core::service::service_fn; #[derive(Clone, Copy)] struct MyAuth; diff --git a/rama-http/src/layer/auth/require_authorization.rs b/rama-http/src/layer/auth/require_authorization.rs index fa64cd67..6571713b 100644 --- a/rama-http/src/layer/auth/require_authorization.rs +++ b/rama-http/src/layer/auth/require_authorization.rs @@ -7,11 +7,11 @@ //! ``` //! use bytes::Bytes; //! -//! use rama::http::layer::validate_request::{ValidateRequest, ValidateRequestHeader, ValidateRequestHeaderLayer}; -//! use rama::http::{Body, Request, Response, StatusCode, header::AUTHORIZATION}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::validate_request::{ValidateRequest, ValidateRequestHeader, ValidateRequestHeaderLayer}; +//! use rama_http::{Body, Request, Response, StatusCode, header::AUTHORIZATION}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! async fn handle(request: Request) -> Result { //! Ok(Response::new(Body::default())) diff --git a/rama-http/src/layer/body_limit.rs b/rama-http/src/layer/body_limit.rs index ff8e0853..1f2ccfa3 100644 --- a/rama-http/src/layer/body_limit.rs +++ b/rama-http/src/layer/body_limit.rs @@ -3,11 +3,11 @@ //! # Example //! //! ``` -//! use rama::http::{Body, Request, Response}; +//! use rama_http::{Body, Request, Response}; //! use std::convert::Infallible; -//! use rama::service::service_fn; -//! use rama::{Context, Layer, Service}; -//! use rama::http::layer::body_limit::BodyLimitLayer; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Layer, Service}; +//! use rama_http::layer::body_limit::BodyLimitLayer; //! //! async fn handle(_: Request) -> Result { //! // ... diff --git a/rama-http/src/layer/catch_panic.rs b/rama-http/src/layer/catch_panic.rs index 4f1e0a0f..81d113be 100644 --- a/rama-http/src/layer/catch_panic.rs +++ b/rama-http/src/layer/catch_panic.rs @@ -8,11 +8,11 @@ //! ```rust //! use std::convert::Infallible; //! -//! use rama::http::{Request, Response, Body, header::HeaderName}; -//! use rama::http::layer::catch_panic::CatchPanicLayer; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::{Request, Response, Body, header::HeaderName}; +//! use rama_http::layer::catch_panic::CatchPanicLayer; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -41,11 +41,11 @@ //! ```rust //! use std::{any::Any, convert::Infallible}; //! -//! use rama::http::{Body, Request, StatusCode, Response, header::{self, HeaderName}}; -//! use rama::http::layer::catch_panic::CatchPanicLayer; -//! use rama::service::{Service, service_fn}; -//! use rama::Layer; -//! use rama::error::BoxError; +//! use rama_http::{Body, Request, StatusCode, Response, header::{self, HeaderName}}; +//! use rama_http::layer::catch_panic::CatchPanicLayer; +//! use rama_core::service::{Service, service_fn}; +//! use rama_core::Layer; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -292,8 +292,10 @@ mod tests { use super::*; - use crate::{http::dep::http_body_util::BodyExt, service::service_fn}; - use hyper::Response; + use crate::dep::http_body_util::BodyExt; + use crate::{Body, Response}; + use rama_core::service::service_fn; + use rama_core::{Context, Service}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/classify/grpc_errors_as_failures.rs b/rama-http/src/layer/classify/grpc_errors_as_failures.rs index b40de1f0..8096a23a 100644 --- a/rama-http/src/layer/classify/grpc_errors_as_failures.rs +++ b/rama-http/src/layer/classify/grpc_errors_as_failures.rs @@ -162,7 +162,7 @@ impl GrpcErrorsAsFailures { /// thats likely the clients fault: /// /// ```rust - /// use rama::http::layer::classify::{GrpcErrorsAsFailures, GrpcCode}; + /// use rama_http::layer::classify::{GrpcErrorsAsFailures, GrpcCode}; /// /// let classifier = GrpcErrorsAsFailures::new() /// .with_success(GrpcCode::InvalidArgument) diff --git a/rama-http/src/layer/classify/mod.rs b/rama-http/src/layer/classify/mod.rs index 1e6e9972..5920f9b5 100644 --- a/rama-http/src/layer/classify/mod.rs +++ b/rama-http/src/layer/classify/mod.rs @@ -55,11 +55,11 @@ pub trait MakeClassifier: Send + Sync + 'static { /// /// ``` /// use std::fmt; -/// use rama::http::layer::classify::{ +/// use rama_http::layer::classify::{ /// ClassifyResponse, ClassifiedResponse, NeverClassifyEos, /// SharedClassifier, MakeClassifier, /// }; -/// use rama::http::Response; +/// use rama_http::Response; /// /// // A response classifier that only considers errors to be failures. /// #[derive(Clone, Copy)] @@ -187,7 +187,7 @@ pub trait ClassifyResponse: Send + Sync + 'static { /// # Example /// /// ``` - /// use rama::http::layer::classify::{ + /// use rama_http::layer::classify::{ /// ServerErrorsAsFailures, ServerErrorsFailureClass, /// ClassifyResponse, ClassifiedResponse /// }; diff --git a/rama-http/src/layer/compression/mod.rs b/rama-http/src/layer/compression/mod.rs index 43e48051..decf60a8 100644 --- a/rama-http/src/layer/compression/mod.rs +++ b/rama-http/src/layer/compression/mod.rs @@ -7,14 +7,14 @@ //! ```rust //! use bytes::Bytes; //! use futures_lite::stream::StreamExt; -//! use rama::error::BoxError; -//! use rama::http::dep::http_body::Frame; -//! use rama::http::dep::http_body_util::{BodyExt , StreamBody}; -//! use rama::http::dep::http_body_util::combinators::BoxBody as InnerBoxBody; -//! use rama::http::layer::compression::CompressionLayer; -//! use rama::http::{Body, Request, Response, header::ACCEPT_ENCODING}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; +//! use rama_core::error::BoxError; +//! use rama_http::dep::http_body::Frame; +//! use rama_http::dep::http_body_util::{BodyExt , StreamBody}; +//! use rama_http::dep::http_body_util::combinators::BoxBody as InnerBoxBody; +//! use rama_http::layer::compression::CompressionLayer; +//! use rama_http::{Body, Request, Response, header::ACCEPT_ENCODING}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; //! use std::convert::Infallible; //! use tokio::fs::{self, File}; //! use tokio_util::io::ReaderStream; diff --git a/rama-http/src/layer/compression/predicate.rs b/rama-http/src/layer/compression/predicate.rs index 7502f250..76e7c88d 100644 --- a/rama-http/src/layer/compression/predicate.rs +++ b/rama-http/src/layer/compression/predicate.rs @@ -99,7 +99,7 @@ where /// by combining types in this module: /// /// ```rust -/// use rama::http::layer::compression::predicate::{SizeAbove, NotForContentType, Predicate}; +/// use rama_http::layer::compression::predicate::{SizeAbove, NotForContentType, Predicate}; /// /// // slightly large min size than the default 32 /// let predicate = SizeAbove::new(256) diff --git a/rama-http/src/layer/compression/service.rs b/rama-http/src/layer/compression/service.rs index 5bd2d518..f6531f9d 100644 --- a/rama-http/src/layer/compression/service.rs +++ b/rama-http/src/layer/compression/service.rs @@ -137,15 +137,15 @@ impl Compression { /// # Changing the compression predicate /// /// ``` - /// use rama::http::layer::compression::{ + /// use rama_http::layer::compression::{ /// Compression, /// predicate::{Predicate, NotForContentType, DefaultPredicate}, /// }; - /// use rama::service::service_fn; + /// use rama_core::service::service_fn; /// /// // Placeholder service_fn /// let service = service_fn(|_: ()| async { - /// Ok::<_, std::io::Error>(rama::http::Response::new(())) + /// Ok::<_, std::io::Error>(rama_http::Response::new(())) /// }); /// /// // build our custom compression predicate diff --git a/rama-http/src/layer/cors/mod.rs b/rama-http/src/layer/cors/mod.rs index 1ae057ac..7f38d58a 100644 --- a/rama-http/src/layer/cors/mod.rs +++ b/rama-http/src/layer/cors/mod.rs @@ -6,10 +6,10 @@ //! use std::convert::Infallible; //! use bytes::Bytes; //! -//! use rama::http::{Body, Request, Response, Method, header}; -//! use rama::http::layer::cors::{Any, CorsLayer}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; +//! use rama_http::{Body, Request, Response, Method, header}; +//! use rama_http::layer::cors::{Any, CorsLayer}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; //! //! async fn handle(request: Request) -> Result { //! Ok(Response::new(Body::default())) @@ -150,7 +150,7 @@ impl CorsLayer { /// Set the [`Access-Control-Allow-Credentials`][mdn] header. /// /// ``` - /// use rama::http::layer::cors::CorsLayer; + /// use rama_http::layer::cors::CorsLayer; /// /// let layer = CorsLayer::new().allow_credentials(true); /// ``` @@ -167,8 +167,8 @@ impl CorsLayer { /// Set the value of the [`Access-Control-Allow-Headers`][mdn] header. /// /// ``` - /// use rama::http::layer::cors::CorsLayer; - /// use rama::http::header::{AUTHORIZATION, ACCEPT}; + /// use rama_http::layer::cors::CorsLayer; + /// use rama_http::header::{AUTHORIZATION, ACCEPT}; /// /// let layer = CorsLayer::new().allow_headers([AUTHORIZATION, ACCEPT]); /// ``` @@ -176,7 +176,7 @@ impl CorsLayer { /// All headers can be allowed with /// /// ``` - /// use rama::http::layer::cors::{Any, CorsLayer}; + /// use rama_http::layer::cors::{Any, CorsLayer}; /// /// let layer = CorsLayer::new().allow_headers(Any); /// ``` @@ -197,8 +197,8 @@ impl CorsLayer { /// # vec![HeaderValue::from_static("http://example.com")] /// # } /// # } - /// use rama::http::layer::cors::{CorsLayer, AllowOrigin}; - /// use rama::http::dep::http::{request::Parts as RequestParts, HeaderValue}; + /// use rama_http::layer::cors::{CorsLayer, AllowOrigin}; + /// use rama_http::dep::http::{request::Parts as RequestParts, HeaderValue}; /// /// let client = get_api_client(); /// @@ -246,7 +246,7 @@ impl CorsLayer { /// /// ``` /// use std::time::Duration; - /// use rama::http::layer::cors::CorsLayer; + /// use rama_http::layer::cors::CorsLayer; /// /// let layer = CorsLayer::new().max_age(Duration::from_secs(60) * 10); /// ``` @@ -266,8 +266,8 @@ impl CorsLayer { /// # struct MyServerConfig { cors_max_age: Duration } /// use std::time::Duration; /// - /// use rama::http::dep::http::{request::Parts as RequestParts, HeaderValue}; - /// use rama::http::layer::cors::{CorsLayer, MaxAge}; + /// use rama_http::dep::http::{request::Parts as RequestParts, HeaderValue}; + /// use rama_http::layer::cors::{CorsLayer, MaxAge}; /// /// let layer = CorsLayer::new().max_age(MaxAge::dynamic( /// |_origin: &HeaderValue, parts: &RequestParts| -> Duration { @@ -292,8 +292,8 @@ impl CorsLayer { /// Set the value of the [`Access-Control-Allow-Methods`][mdn] header. /// /// ``` - /// use rama::http::layer::cors::CorsLayer; - /// use rama::http::Method; + /// use rama_http::layer::cors::CorsLayer; + /// use rama_http::Method; /// /// let layer = CorsLayer::new().allow_methods([Method::GET, Method::POST]); /// ``` @@ -301,7 +301,7 @@ impl CorsLayer { /// All methods can be allowed with /// /// ``` - /// use rama::http::layer::cors::{Any, CorsLayer}; + /// use rama_http::layer::cors::{Any, CorsLayer}; /// /// let layer = CorsLayer::new().allow_methods(Any); /// ``` @@ -321,8 +321,8 @@ impl CorsLayer { /// Set the value of the [`Access-Control-Allow-Origin`][mdn] header. /// /// ``` - /// use rama::http::HeaderValue; - /// use rama::http::layer::cors::CorsLayer; + /// use rama_http::HeaderValue; + /// use rama_http::layer::cors::CorsLayer; /// /// let layer = CorsLayer::new().allow_origin( /// "http://example.com".parse::().unwrap(), @@ -332,7 +332,7 @@ impl CorsLayer { /// Multiple origins can be allowed with /// /// ``` - /// use rama::http::layer::cors::CorsLayer; + /// use rama_http::layer::cors::CorsLayer; /// /// let origins = [ /// "http://example.com".parse().unwrap(), @@ -345,7 +345,7 @@ impl CorsLayer { /// All origins can be allowed with /// /// ``` - /// use rama::http::layer::cors::{Any, CorsLayer}; + /// use rama_http::layer::cors::{Any, CorsLayer}; /// /// let layer = CorsLayer::new().allow_origin(Any); /// ``` @@ -353,8 +353,8 @@ impl CorsLayer { /// You can also use a closure /// /// ``` - /// use rama::http::layer::cors::{CorsLayer, AllowOrigin}; - /// use rama::http::dep::http::{request::Parts as RequestParts, HeaderValue}; + /// use rama_http::layer::cors::{CorsLayer, AllowOrigin}; + /// use rama_http::dep::http::{request::Parts as RequestParts, HeaderValue}; /// /// let layer = CorsLayer::new().allow_origin(AllowOrigin::predicate( /// |origin: &HeaderValue, _request_parts: &RequestParts| { @@ -378,8 +378,8 @@ impl CorsLayer { /// Set the value of the [`Access-Control-Expose-Headers`][mdn] header. /// /// ``` - /// use rama::http::layer::cors::CorsLayer; - /// use rama::http::header::CONTENT_ENCODING; + /// use rama_http::layer::cors::CorsLayer; + /// use rama_http::header::CONTENT_ENCODING; /// /// let layer = CorsLayer::new().expose_headers([CONTENT_ENCODING]); /// ``` @@ -387,7 +387,7 @@ impl CorsLayer { /// All headers can be allowed with /// /// ``` - /// use rama::http::layer::cors::{Any, CorsLayer}; + /// use rama_http::layer::cors::{Any, CorsLayer}; /// /// let layer = CorsLayer::new().expose_headers(Any); /// ``` @@ -407,7 +407,7 @@ impl CorsLayer { /// Set the value of the [`Access-Control-Allow-Private-Network`][wicg] header. /// /// ``` - /// use rama::http::layer::cors::CorsLayer; + /// use rama_http::layer::cors::CorsLayer; /// /// let layer = CorsLayer::new().allow_private_network(true); /// ``` diff --git a/rama-http/src/layer/decompression/mod.rs b/rama-http/src/layer/decompression/mod.rs index 6ff6f865..cdcfdaa3 100644 --- a/rama-http/src/layer/decompression/mod.rs +++ b/rama-http/src/layer/decompression/mod.rs @@ -9,12 +9,12 @@ //! use bytes::{Bytes, BytesMut}; //! use flate2::{write::GzEncoder, Compression}; //! -//! use rama::http::{Body, header, HeaderValue, Request, Response}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::http::layer::decompression::{DecompressionBody, RequestDecompressionLayer}; -//! use rama::http::dep::http_body_util::BodyExt; -//! use rama::error::BoxError; +//! use rama_http::{Body, header, HeaderValue, Request, Response}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_http::layer::decompression::{DecompressionBody, RequestDecompressionLayer}; +//! use rama_http::dep::http_body_util::BodyExt; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -51,12 +51,12 @@ //! //! use bytes::{Bytes, BytesMut}; //! -//! use rama::http::{Body, Request, Response}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::http::layer::{compression::Compression, decompression::DecompressionLayer}; -//! use rama::http::dep::http_body_util::BodyExt; -//! use rama::error::BoxError; +//! use rama_http::{Body, Request, Response}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_http::layer::{compression::Compression, decompression::DecompressionLayer}; +//! use rama_http::dep::http_body_util::BodyExt; +//! use rama_core::error::BoxError; //! //! # //! # #[tokio::main] diff --git a/rama-http/src/layer/dns/dns_map/layer.rs b/rama-http/src/layer/dns/dns_map/layer.rs index 576aa94f..f02ea9a0 100644 --- a/rama-http/src/layer/dns/dns_map/layer.rs +++ b/rama-http/src/layer/dns/dns_map/layer.rs @@ -2,11 +2,9 @@ use super::DnsMapService; use crate::HeaderName; use rama_core::Layer; -/// Layer which can extend [`Dns`] overwrites with mappings. +/// Layer which can extend `Dns` (see `rama_core`) overwrites with mappings. /// /// See [the module level documentation](crate::layer::dns) for more information. -/// -/// [`Dns`]: crate::dns::Dns #[derive(Debug, Clone)] pub struct DnsMapLayer { header_name: HeaderName, @@ -30,12 +28,9 @@ impl Layer for DnsMapLayer { #[cfg(test)] mod tests { use super::*; - use crate::{ - http::{Request, RequestContext}, - net::address::Host, - service::service_fn, - Context, Service, - }; + use crate::Request; + use rama_core::{service::service_fn, Context, Service}; + use rama_net::{address::Host, http::RequestContext}; use std::net::{IpAddr, Ipv4Addr}; #[tokio::test] diff --git a/rama-http/src/layer/dns/dns_map/service.rs b/rama-http/src/layer/dns/dns_map/service.rs index 9dc09875..040a8f8d 100644 --- a/rama-http/src/layer/dns/dns_map/service.rs +++ b/rama-http/src/layer/dns/dns_map/service.rs @@ -10,11 +10,10 @@ use rama_utils::macros::define_inner_service_accessors; /// Service to support DNS lookup overwrites. /// /// No DNS lookup is performed by this service, it only adds -/// the overwrites to the [`Dns`] data of the [`Context`]. +/// the overwrites to the `Dns` (see `rama_core`) data of the [`Context`]. /// -/// See [`Dns`] and [`DnsMapLayer`] for more information. +/// See [`DnsMapLayer`] for more information. /// -/// [`Dns`]: crate::dns::Dns /// [`DnsMapLayer`]: crate::layer::dns::DnsMapLayer pub struct DnsMapService { inner: S, diff --git a/rama-http/src/layer/dns/dns_resolve/layer.rs b/rama-http/src/layer/dns/dns_resolve/layer.rs index 36d49536..6669acef 100644 --- a/rama-http/src/layer/dns/dns_resolve/layer.rs +++ b/rama-http/src/layer/dns/dns_resolve/layer.rs @@ -2,11 +2,9 @@ use super::DnsResolveModeService; use crate::HeaderName; use rama_core::Layer; -/// Layer which can extend [`Dns`] overwrites with mappings. +/// Layer which can extend `Dns` (see `rama_core`) overwrites with mappings. /// /// See [the module level documentation](crate::layer::dns) for more information. -/// -/// [`Dns`]: crate::dns::Dns #[derive(Debug, Clone)] pub struct DnsResolveModeLayer { header_name: HeaderName, @@ -30,9 +28,8 @@ impl Layer for DnsResolveModeLayer { #[cfg(test)] mod tests { use super::*; - use crate::{ - http::layer::dns::DnsResolveMode, http::Request, service::service_fn, Context, Service, - }; + use crate::{layer::dns::DnsResolveMode, Request}; + use rama_core::{service::service_fn, Context, Service}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/dns/dns_resolve/service.rs b/rama-http/src/layer/dns/dns_resolve/service.rs index b4d39089..34362c3f 100644 --- a/rama-http/src/layer/dns/dns_resolve/service.rs +++ b/rama-http/src/layer/dns/dns_resolve/service.rs @@ -12,9 +12,7 @@ use std::fmt; /// a way to have requested the intent /// to reoslve DNS even if it is not needed. /// -/// See [`Dns`] and [`DnsResolveMode`] for more information. -/// -/// [`Dns`]: crate::dns::Dns +/// See `Dns` (`rama_core`) and [`DnsResolveMode`] for more information. pub struct DnsResolveModeService { inner: S, header_name: HeaderName, diff --git a/rama-http/src/layer/dns/mod.rs b/rama-http/src/layer/dns/mod.rs index ed9f1dfd..364c27af 100644 --- a/rama-http/src/layer/dns/mod.rs +++ b/rama-http/src/layer/dns/mod.rs @@ -8,13 +8,16 @@ //! using the [`DnsMapLayer`]. //! //! ```rust -//! use rama::{ -//! http::layer::dns::DnsMapLayer, -//! http::{HeaderName, Request, RequestContext}, -//! net::address::Host, +//! use rama_core::{ //! service::service_fn, //! Context, Service, Layer, //! }; +//! use rama_http::{ +//! layer::dns::DnsMapLayer, +//! HeaderName, Request, +//! }; +//! use rama_net::http::RequestContext; +//! use rama_net::address::Host; //! use std::{ //! convert::Infallible, //! net::{IpAddr, Ipv4Addr}, diff --git a/rama-http/src/layer/error_handling.rs b/rama-http/src/layer/error_handling.rs index 6222cc24..69f14a27 100644 --- a/rama-http/src/layer/error_handling.rs +++ b/rama-http/src/layer/error_handling.rs @@ -3,16 +3,16 @@ //! # Example //! //! ``` -//! use rama::{ -//! http::{ -//! client::HttpClientExt, -//! layer::{error_handling::ErrorHandlerLayer, timeout::TimeoutLayer}, -//! service::web::WebService, -//! Body, IntoResponse, Request, Response, StatusCode, -//! }, +//! use rama_core::{ //! service::service_fn, //! Context, Service, Layer, //! }; +//! use rama_http::{ +//! service::client::HttpClientExt, +//! layer::{error_handling::ErrorHandlerLayer, timeout::TimeoutLayer}, +//! service::web::WebService, +//! Body, IntoResponse, Request, Response, StatusCode, +//! }; //! use std::time::Duration; //! //! # async fn some_expensive_io_operation() -> Result<(), std::io::Error> { diff --git a/rama-http/src/layer/follow_redirect/mod.rs b/rama-http/src/layer/follow_redirect/mod.rs index 1fe9878a..1142d0d4 100644 --- a/rama-http/src/layer/follow_redirect/mod.rs +++ b/rama-http/src/layer/follow_redirect/mod.rs @@ -17,10 +17,10 @@ //! ## Basic usage //! //! ``` -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::http::{Body, Request, Response, StatusCode, header}; -//! use rama::http::layer::follow_redirect::{FollowRedirectLayer, RequestUri}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_http::{Body, Request, Response, StatusCode, header}; +//! use rama_http::layer::follow_redirect::{FollowRedirectLayer, RequestUri}; //! //! # #[tokio::main] //! # async fn main() -> Result<(), std::convert::Infallible> { @@ -56,15 +56,15 @@ //! # #![allow(unused)] //! //! # use std::convert::Infallible; -//! use rama::service::service_fn; -//! use rama::layer::MapErrLayer; -//! use rama::{Context, Service, Layer}; -//! use rama::http::{Body, Request, Response}; -//! use rama::http::layer::follow_redirect::{ +//! use rama_core::service::service_fn; +//! use rama_core::layer::MapErrLayer; +//! use rama_core::{Context, Service, Layer}; +//! use rama_http::{Body, Request, Response}; +//! use rama_http::layer::follow_redirect::{ //! policy::{self, PolicyExt}, //! FollowRedirectLayer, //! }; -//! use rama::error::OpaqueError; +//! use rama_core::error::OpaqueError; //! //! #[derive(Debug)] //! enum MyError { @@ -372,8 +372,8 @@ fn resolve_uri(relative: &str, base: &Uri) -> Option { #[cfg(test)] mod tests { use super::{policy::*, *}; - use crate::service::service_fn; use crate::{header::LOCATION, Body}; + use rama_core::service::service_fn; use rama_core::Layer; use std::convert::Infallible; diff --git a/rama-http/src/layer/follow_redirect/policy/mod.rs b/rama-http/src/layer/follow_redirect/policy/mod.rs index e6fd790d..917c56b7 100644 --- a/rama-http/src/layer/follow_redirect/policy/mod.rs +++ b/rama-http/src/layer/follow_redirect/policy/mod.rs @@ -32,9 +32,9 @@ use rama_core::Context; /// /// ``` /// use std::collections::HashSet; -/// use rama::Context; -/// use rama::http::{Request, Uri}; -/// use rama::http::layer::follow_redirect::policy::{Action, Attempt, Policy}; +/// use rama_core::Context; +/// use rama_http::{Request, Uri}; +/// use rama_http::layer::follow_redirect::policy::{Action, Attempt, Policy}; /// /// #[derive(Clone)] /// pub struct DetectCycle { @@ -110,8 +110,8 @@ pub trait PolicyExt { /// /// ``` /// use bytes::Bytes; - /// use rama::http::Body; - /// use rama::http::layer::follow_redirect::policy::{self, clone_body_fn, Limited, PolicyExt}; + /// use rama_http::Body; + /// use rama_http::layer::follow_redirect::policy::{self, clone_body_fn, Limited, PolicyExt}; /// /// enum MyBody { /// Bytes(Bytes), @@ -140,7 +140,7 @@ pub trait PolicyExt { /// # Example /// /// ``` - /// use rama::http::layer::follow_redirect::policy::{self, Action, Limited, PolicyExt}; + /// use rama_http::layer::follow_redirect::policy::{self, Action, Limited, PolicyExt}; /// /// #[derive(Clone)] /// enum MyError { diff --git a/rama-http/src/layer/follow_redirect/policy/or.rs b/rama-http/src/layer/follow_redirect/policy/or.rs index 65347d02..4be6860b 100644 --- a/rama-http/src/layer/follow_redirect/policy/or.rs +++ b/rama-http/src/layer/follow_redirect/policy/or.rs @@ -74,7 +74,8 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{http::Uri, Context}; + use crate::Uri; + use rama_core::Context; struct Taint

{ policy: P, diff --git a/rama-http/src/layer/forwarded/get_forwarded.rs b/rama-http/src/layer/forwarded/get_forwarded.rs index 207c8948..7c73e0b6 100644 --- a/rama-http/src/layer/forwarded/get_forwarded.rs +++ b/rama-http/src/layer/forwarded/get_forwarded.rs @@ -53,11 +53,11 @@ use std::marker::PhantomData; /// header in case your application is behind a proxy which sets this header. /// /// ```rust -/// use rama::{ -/// http::{headers::Forwarded, layer::forwarded::GetForwardedHeadersLayer, Request}, +/// use rama_core::{ /// service::service_fn, /// Context, Service, Layer, /// }; +/// use rama_http::{headers::Forwarded, layer::forwarded::GetForwardedHeadersLayer, Request}; /// use std::{convert::Infallible, net::IpAddr}; /// /// #[tokio::main] @@ -352,12 +352,8 @@ mod tests { headers::{ClientIp, TrueClientIp, XClientIp, XRealIp}, IntoResponse, Response, StatusCode, }; - use rama_core::{ - error::OpaqueError, - net::forwarded::{ForwardedProtocol, ForwardedVersion}, - service::service_fn, - Layer, - }; + use rama_core::{error::OpaqueError, service::service_fn, Layer}; + use rama_net::forwarded::{ForwardedProtocol, ForwardedVersion}; use std::{convert::Infallible, net::IpAddr}; fn assert_is_service>>(_: T) {} diff --git a/rama-http/src/layer/forwarded/set_forwarded.rs b/rama-http/src/layer/forwarded/set_forwarded.rs index d4a635f6..d10c4e4e 100644 --- a/rama-http/src/layer/forwarded/set_forwarded.rs +++ b/rama-http/src/layer/forwarded/set_forwarded.rs @@ -1,11 +1,12 @@ use crate::headers::{ ForwardHeader, HeaderMapExt, Via, XForwardedFor, XForwardedHost, XForwardedProto, }; -use crate::{Request, RequestContext}; +use crate::Request; use rama_core::error::BoxError; use rama_core::{Context, Layer, Service}; use rama_net::address::Domain; use rama_net::forwarded::{Forwarded, ForwardedElement, NodeId}; +use rama_net::http::RequestContext; use rama_net::stream::SocketInfo; use rama_utils::macros::all_the_tuples_no_last_special_case; use std::fmt; @@ -52,12 +53,11 @@ use std::marker::PhantomData; /// This example shows how you could expose the real Client IP using the [`X-Real-IP`][`crate::headers::XRealIp`] header. /// /// ```rust -/// # use rama::{http::Request, stream::SocketInfo}; -/// use rama::{ -/// http::{headers::XRealIp, layer::forwarded::SetForwardedHeadersLayer}, -/// service::service_fn, -/// Context, Service, Layer, -/// }; +/// use rama_net::stream::SocketInfo; +/// use rama_http::Request; +/// use rama_core::service::service_fn; +/// use rama_http::{headers::XRealIp, layer::forwarded::SetForwardedHeadersLayer}; +/// use rama_core::{Context, Service, Layer}; /// use std::convert::Infallible; /// /// # type Body = (); @@ -408,14 +408,10 @@ all_the_tuples_no_last_special_case!(set_forwarded_service_for_tuple); mod tests { use super::*; use crate::{ - error::OpaqueError, - http::{ - headers::{TrueClientIp, XClientIp, XRealIp}, - IntoResponse, Response, StatusCode, - }, - service::service_fn, - Layer, + headers::{TrueClientIp, XClientIp, XRealIp}, + IntoResponse, Response, StatusCode, }; + use rama_core::{error::OpaqueError, service::service_fn, Layer}; use std::{convert::Infallible, net::IpAddr}; fn assert_is_service>>(_: T) {} diff --git a/rama-http/src/layer/header_config.rs b/rama-http/src/layer/header_config.rs index 06278fab..042027ea 100644 --- a/rama-http/src/layer/header_config.rs +++ b/rama-http/src/layer/header_config.rs @@ -6,10 +6,10 @@ //! # Example //! //! ```rust -//! use rama::http::layer::header_config::{HeaderConfigLayer, HeaderConfigService}; -//! use rama::http::service::web::{WebService, extract::Extension}; -//! use rama::http::{Body, Request, StatusCode, HeaderName}; -//! use rama::{Context, Service, Layer}; +//! use rama_http::layer::header_config::{HeaderConfigLayer, HeaderConfigService}; +//! use rama_http::service::web::{WebService, extract::Extension}; +//! use rama_http::{Body, Request, StatusCode, HeaderName}; +//! use rama_core::{Context, Service, Layer}; //! use serde::Deserialize; //! //! #[derive(Debug, Deserialize, Clone)] @@ -250,7 +250,7 @@ mod test { .unwrap(); let inner_service = - crate::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { + rama_core::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { let cfg: &Config = ctx.get().unwrap(); assert_eq!(cfg.s, "E&G"); assert_eq!(cfg.n, 1); @@ -278,7 +278,7 @@ mod test { .unwrap(); let inner_service = - crate::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { + rama_core::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { let cfg: &Config = ctx.get().unwrap(); assert_eq!(cfg.s, "E&G"); assert_eq!(cfg.n, 1); @@ -305,7 +305,7 @@ mod test { .unwrap(); let inner_service = - crate::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { + rama_core::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { assert!(ctx.get::().is_none()); Ok::<_, std::convert::Infallible>(()) @@ -327,7 +327,7 @@ mod test { .body(()) .unwrap(); - let inner_service = crate::service::service_fn(|_: Request<()>| async move { + let inner_service = rama_core::service::service_fn(|_: Request<()>| async move { Ok::<_, std::convert::Infallible>(()) }); @@ -349,7 +349,7 @@ mod test { .body(()) .unwrap(); - let inner_service = crate::service::service_fn(|_: Request<()>| async move { + let inner_service = rama_core::service::service_fn(|_: Request<()>| async move { Ok::<_, std::convert::Infallible>(()) }); @@ -371,7 +371,7 @@ mod test { .body(()) .unwrap(); - let inner_service = crate::service::service_fn(|_: Request<()>| async move { + let inner_service = rama_core::service::service_fn(|_: Request<()>| async move { Ok::<_, std::convert::Infallible>(()) }); diff --git a/rama-http/src/layer/header_option_value.rs b/rama-http/src/layer/header_option_value.rs index e5673835..c690d847 100644 --- a/rama-http/src/layer/header_option_value.rs +++ b/rama-http/src/layer/header_option_value.rs @@ -222,11 +222,12 @@ mod test { .body(()) .unwrap(); - let inner_service = - crate::service::service_fn(move |ctx: Context<()>, _req: Request<()>| async move { + let inner_service = rama_core::service::service_fn( + move |ctx: Context<()>, _req: Request<()>| async move { assert_eq!(expected_output, ctx.contains::()); Ok::<_, std::convert::Infallible>(()) - }); + }, + ); let service = HeaderOptionValueService::::required( inner_service, @@ -259,11 +260,12 @@ mod test { .body(()) .unwrap(); - let inner_service = - crate::service::service_fn(move |ctx: Context<()>, _req: Request<()>| async move { + let inner_service = rama_core::service::service_fn( + move |ctx: Context<()>, _req: Request<()>| async move { assert_eq!(expected_output, ctx.contains::()); Ok::<_, std::convert::Infallible>(()) - }); + }, + ); let service = HeaderOptionValueService::::optional( inner_service, @@ -283,7 +285,7 @@ mod test { .unwrap(); let inner_service = - crate::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { + rama_core::service::service_fn(|ctx: Context<()>, _req: Request<()>| async move { assert!(!ctx.contains::()); Ok::<_, std::convert::Infallible>(()) @@ -305,7 +307,7 @@ mod test { .body(()) .unwrap(); - let inner_service = crate::service::service_fn(|_: Request<()>| async move { + let inner_service = rama_core::service::service_fn(|_: Request<()>| async move { Ok::<_, std::convert::Infallible>(()) }); @@ -330,7 +332,7 @@ mod test { .body(()) .unwrap(); - let inner_service = crate::service::service_fn(|_: Request<()>| async move { + let inner_service = rama_core::service::service_fn(|_: Request<()>| async move { Ok::<_, std::convert::Infallible>(()) }); @@ -356,7 +358,7 @@ mod test { .body(()) .unwrap(); - let inner_service = crate::service::service_fn(|_: Request<()>| async move { + let inner_service = rama_core::service::service_fn(|_: Request<()>| async move { Ok::<_, std::convert::Infallible>(()) }); diff --git a/rama-http/src/layer/map_request_body.rs b/rama-http/src/layer/map_request_body.rs index ba69fa6b..14afd4ae 100644 --- a/rama-http/src/layer/map_request_body.rs +++ b/rama-http/src/layer/map_request_body.rs @@ -3,15 +3,15 @@ //! # Example //! //! ``` -//! use rama::http::{Body, Request, Response}; -//! use rama::http::dep::http_body; +//! use rama_http::{Body, Request, Response}; +//! use rama_http::dep::http_body; //! use bytes::Bytes; //! use std::convert::Infallible; //! use std::{pin::Pin, task::{ready, Context, Poll}}; -//! use rama::{Layer, Service, context}; -//! use rama::service::service_fn; -//! use rama::http::layer::map_request_body::MapRequestBodyLayer; -//! use rama::error::BoxError; +//! use rama_core::{Layer, Service, context}; +//! use rama_core::service::service_fn; +//! use rama_http::layer::map_request_body::MapRequestBodyLayer; +//! use rama_core::error::BoxError; //! //! // A wrapper for a `Full` //! struct BodyWrapper { diff --git a/rama-http/src/layer/map_response_body.rs b/rama-http/src/layer/map_response_body.rs index f1ca5166..124abf6f 100644 --- a/rama-http/src/layer/map_response_body.rs +++ b/rama-http/src/layer/map_response_body.rs @@ -4,14 +4,14 @@ //! //! ``` //! use bytes::Bytes; -//! use rama::http::{Body, Request, Response}; -//! use rama::http::dep::http_body; +//! use rama_http::{Body, Request, Response}; +//! use rama_http::dep::http_body; //! use std::convert::Infallible; //! use std::{pin::Pin, task::{Context, Poll}}; -//! use rama::{Layer, Service, context}; -//! use rama::service::service_fn; -//! use rama::http::layer::map_response_body::MapResponseBodyLayer; -//! use rama::error::BoxError; +//! use rama_core::{Layer, Service, context}; +//! use rama_core::service::service_fn; +//! use rama_http::layer::map_response_body::MapResponseBodyLayer; +//! use rama_core::error::BoxError; //! use futures_lite::ready; //! //! // A wrapper for a `http_body::Body` that prints the size of data chunks diff --git a/rama-http/src/layer/mod.rs b/rama-http/src/layer/mod.rs index 754d2be3..d4327cbc 100644 --- a/rama-http/src/layer/mod.rs +++ b/rama-http/src/layer/mod.rs @@ -1,6 +1,6 @@ //! Http [`Layer`]s provided by Rama. //! -//! A [`Layer`], as defined in [`crate::service`], +//! A [`Layer`], as defined in [`rama_core::Service`], //! is a middleware that can modify the request and/or response of a [`Service`]s. //! It is also capable of branching between two or more [`Service`]s. //! diff --git a/rama-http/src/layer/normalize_path.rs b/rama-http/src/layer/normalize_path.rs index 81e1ff3b..cefa7a69 100644 --- a/rama-http/src/layer/normalize_path.rs +++ b/rama-http/src/layer/normalize_path.rs @@ -7,11 +7,11 @@ //! //! ``` //! use std::{iter::once, convert::Infallible}; -//! use rama::error::BoxError; -//! use rama::service::service_fn; -//! use rama::{Context, Layer, Service}; -//! use rama::http::{Body, Request, Response, StatusCode}; -//! use rama::http::layer::normalize_path::NormalizePathLayer; +//! use rama_core::error::BoxError; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Layer, Service}; +//! use rama_http::{Body, Request, Response, StatusCode}; +//! use rama_http::layer::normalize_path::NormalizePathLayer; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -170,7 +170,7 @@ fn normalize_trailing_slash(uri: &mut Uri) { #[cfg(test)] mod tests { use super::*; - use crate::service::service_fn; + use rama_core::service::service_fn; use rama_core::Layer; use std::convert::Infallible; diff --git a/rama-http/src/layer/opentelemetry.rs b/rama-http/src/layer/opentelemetry.rs index 7740c71c..e3316a76 100644 --- a/rama-http/src/layer/opentelemetry.rs +++ b/rama-http/src/layer/opentelemetry.rs @@ -4,7 +4,7 @@ use crate::{ headers::{ContentLength, HeaderMapExt, UserAgent}, - IntoResponse, Request, RequestContext, Response, + IntoResponse, Request, Response, }; use rama_core::telemetry::opentelemetry::{ global, @@ -12,6 +12,7 @@ use rama_core::telemetry::opentelemetry::{ semantic_conventions, KeyValue, }; use rama_core::{Context, Layer, Service}; +use rama_net::http::RequestContext; use rama_net::stream::SocketInfo; use rama_utils::macros::define_inner_service_accessors; use std::{fmt, sync::Arc, time::SystemTime}; @@ -31,7 +32,7 @@ const HTTP_SERVER_ACTIVE_REQUESTS: &str = "http.server.active_requests"; // TODO: do we also want to track actual calculated body size? // this would mean we _need_ to buffer the body, which is not ideal // Perhaps make it opt-in? -// NOTE: we could also make this opt-in via BytesRWTrackerHandle (rama::stream::BytesRWTrackerHandle) +// NOTE: we could also make this opt-in via BytesRWTrackerHandle (rama_core::servicestream::BytesRWTrackerHandle) // this would however not work properly (I think) with h2/h3... // const HTTP_SERVER_REQUEST_SIZE: &str = "http.server.request.size"; // const HTTP_SERVER_RESPONSE_SIZE: &str = "http.server.response.size"; diff --git a/rama-http/src/layer/propagate_headers.rs b/rama-http/src/layer/propagate_headers.rs index 138ba58b..f7826692 100644 --- a/rama-http/src/layer/propagate_headers.rs +++ b/rama-http/src/layer/propagate_headers.rs @@ -4,11 +4,11 @@ //! //! ```rust //! use std::convert::Infallible; -//! use rama::error::BoxError; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::http::{Body, Request, Response, header::HeaderName}; -//! use rama::http::layer::propagate_headers::PropagateHeaderLayer; +//! use rama_core::error::BoxError; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_http::{Body, Request, Response, header::HeaderName}; +//! use rama_http::layer::propagate_headers::PropagateHeaderLayer; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { diff --git a/rama-http/src/layer/proxy_auth.rs b/rama-http/src/layer/proxy_auth.rs index afac23dc..a84a7cc2 100644 --- a/rama-http/src/layer/proxy_auth.rs +++ b/rama-http/src/layer/proxy_auth.rs @@ -54,12 +54,11 @@ impl ProxyAuthLayer { /// Overwrite the Labels extract type /// /// This is used if the username contains labels that you need to extract out. - /// Example implementations are [`UsernameOpaqueLabelParser`] and [`ProxyFilterUsernameParser`]. + /// Example implementation is the [`UsernameOpaqueLabelParser`]. /// /// You can provide your own extractor by implementing the [`UsernameLabelParser`] trait. /// /// [`UsernameOpaqueLabelParser`]: rama_core::username::UsernameOpaqueLabelParser - /// [`ProxyFilterUsernameParser`]: crate::proxy::ProxyFilterUsernameParser /// [`UsernameLabelParser`]: rama_core::username::UsernameLabelParser pub fn with_labels(self) -> ProxyAuthLayer { ProxyAuthLayer { diff --git a/rama-http/src/layer/remove_header/request.rs b/rama-http/src/layer/remove_header/request.rs index 915c7080..238635c9 100644 --- a/rama-http/src/layer/remove_header/request.rs +++ b/rama-http/src/layer/remove_header/request.rs @@ -3,11 +3,11 @@ //! # Example //! //! ``` -//! use rama::http::layer::remove_header::RemoveRequestHeaderLayer; -//! use rama::http::{Body, Request, Response, header::{self, HeaderValue}}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::remove_header::RemoveRequestHeaderLayer; +//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -172,11 +172,8 @@ where #[cfg(test)] mod test { use super::*; - use crate::{ - http::{Body, Response}, - service::service_fn, - Layer, Service, - }; + use crate::{Body, Response}; + use rama_core::{service::service_fn, Layer, Service}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/remove_header/response.rs b/rama-http/src/layer/remove_header/response.rs index 1c16563e..17fb5121 100644 --- a/rama-http/src/layer/remove_header/response.rs +++ b/rama-http/src/layer/remove_header/response.rs @@ -3,11 +3,11 @@ //! # Example //! //! ``` -//! use rama::http::layer::remove_header::RemoveResponseHeaderLayer; -//! use rama::http::{Body, Request, Response, header::{self, HeaderValue}}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::remove_header::RemoveResponseHeaderLayer; +//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -172,10 +172,9 @@ where #[cfg(test)] mod test { - use http::Response; - use super::*; - use crate::{http::Body, service::service_fn, Layer, Service}; + use crate::{Body, Response}; + use rama_core::{service::service_fn, Layer, Service}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/request_id.rs b/rama-http/src/layer/request_id.rs index f35b4692..c7ca63b3 100644 --- a/rama-http/src/layer/request_id.rs +++ b/rama-http/src/layer/request_id.rs @@ -3,13 +3,13 @@ //! # Example //! //! ``` -//! use rama::http::layer::request_id::{ +//! use rama_http::layer::request_id::{ //! SetRequestIdLayer, PropagateRequestIdLayer, MakeRequestId, RequestId, //! }; -//! use rama::http::{Body, Request, Response, header::HeaderName}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::{Body, Request, Response, header::HeaderName}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! use std::sync::{Arc, atomic::{AtomicU64, Ordering}}; //! //! # #[tokio::main] @@ -388,8 +388,8 @@ impl MakeRequestId for MakeRequestUuid { #[cfg(test)] mod tests { use crate::layer::set_header; - use crate::service::service_fn; use crate::{Body, Response}; + use rama_core::service::service_fn; use rama_core::Layer; use std::{ convert::Infallible, diff --git a/rama-http/src/layer/required_header/request.rs b/rama-http/src/layer/required_header/request.rs index f3d9e7bf..655fc9f7 100644 --- a/rama-http/src/layer/required_header/request.rs +++ b/rama-http/src/layer/required_header/request.rs @@ -6,12 +6,13 @@ use crate::{ header::{self, HOST, RAMA_ID_HEADER_VALUE, USER_AGENT}, headers::HeaderMapExt, - Request, RequestContext, Response, + Request, Response, }; use rama_core::{ error::{BoxError, ErrorContext}, Context, Layer, Service, }; +use rama_net::http::RequestContext; use rama_utils::macros::define_inner_service_accessors; use std::fmt; diff --git a/rama-http/src/layer/required_header/response.rs b/rama-http/src/layer/required_header/response.rs index e60f2cae..ca1a66c4 100644 --- a/rama-http/src/layer/required_header/response.rs +++ b/rama-http/src/layer/required_header/response.rs @@ -139,7 +139,8 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{http::Body, service::service_fn, Layer}; + use crate::Body; + use rama_core::{service::service_fn, Layer}; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/retry/managed.rs b/rama-http/src/layer/retry/managed.rs index c6dc8104..c3e2da15 100644 --- a/rama-http/src/layer/retry/managed.rs +++ b/rama-http/src/layer/retry/managed.rs @@ -306,10 +306,8 @@ mod private { #[cfg(test)] mod tests { use super::*; - use crate::{ - http::{IntoResponse, StatusCode}, - utils::{backoff::ExponentialBackoff, rng::HasherRng}, - }; + use crate::{IntoResponse, StatusCode}; + use rama_utils::{backoff::ExponentialBackoff, rng::HasherRng}; use std::time::Duration; fn assert_clone_input_none( diff --git a/rama-http/src/layer/retry/mod.rs b/rama-http/src/layer/retry/mod.rs index f694ae4c..32b4f4d2 100644 --- a/rama-http/src/layer/retry/mod.rs +++ b/rama-http/src/layer/retry/mod.rs @@ -171,13 +171,10 @@ where mod test { use super::*; use crate::{ - http::{ - layer::retry::managed::DoNotRetry, BodyExtractExt, IntoResponse, Response, StatusCode, - }, - service::service_fn, - utils::{backoff::ExponentialBackoff, rng::HasherRng}, - Context, Layer, + layer::retry::managed::DoNotRetry, BodyExtractExt, IntoResponse, Response, StatusCode, }; + use rama_core::{service::service_fn, Context, Layer}; + use rama_utils::{backoff::ExponentialBackoff, rng::HasherRng}; use std::{ sync::{atomic::AtomicUsize, Arc}, time::Duration, diff --git a/rama-http/src/layer/retry/policy.rs b/rama-http/src/layer/retry/policy.rs index 6117b9ba..a192aaa5 100644 --- a/rama-http/src/layer/retry/policy.rs +++ b/rama-http/src/layer/retry/policy.rs @@ -8,9 +8,9 @@ use std::future::Future; /// # Example /// /// ``` -/// use rama::Context; -/// use rama::http::Request; -/// use rama::http::layer::retry::{Policy, PolicyResult, RetryBody}; +/// use rama_core::Context; +/// use rama_http::Request; +/// use rama_http::layer::retry::{Policy, PolicyResult, RetryBody}; /// use std::sync::Arc; /// use parking_lot::Mutex; /// diff --git a/rama-http/src/layer/retry/tests.rs b/rama-http/src/layer/retry/tests.rs index eb3503ed..763b9260 100644 --- a/rama-http/src/layer/retry/tests.rs +++ b/rama-http/src/layer/retry/tests.rs @@ -1,9 +1,9 @@ use super::*; use crate::{response::IntoResponse, BodyExtractExt}; -use crate::{Layer, Service}; use crate::{Request, Response}; use parking_lot::Mutex; use rama_core::error::{error, OpaqueError}; +use rama_core::{Layer, Service}; use std::sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, diff --git a/rama-http/src/layer/sensitive_headers.rs b/rama-http/src/layer/sensitive_headers.rs index 813f78f2..a3700545 100644 --- a/rama-http/src/layer/sensitive_headers.rs +++ b/rama-http/src/layer/sensitive_headers.rs @@ -5,11 +5,11 @@ //! # Example //! //! ``` -//! use rama::http::layer::sensitive_headers::SetSensitiveHeadersLayer; -//! use rama::http::{Body, Request, Response, header::AUTHORIZATION}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::sensitive_headers::SetSensitiveHeadersLayer; +//! use rama_http::{Body, Request, Response, header::AUTHORIZATION}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! use std::{iter::once, convert::Infallible}; //! //! async fn handle(req: Request) -> Result { @@ -38,7 +38,7 @@ //! # } //! ``` -use crate::{HeaderName, Request, Response}; +use crate::{header, HeaderName, Request, Response}; use rama_core::{Context, Layer, Service}; use rama_utils::macros::define_inner_service_accessors; use std::sync::Arc; @@ -174,7 +174,7 @@ where ) -> Result { let headers = req.headers_mut(); for header in &*self.headers { - if let http::header::Entry::Occupied(mut entry) = headers.entry(header) { + if let header::Entry::Occupied(mut entry) = headers.entry(header) { for value in entry.iter_mut() { value.set_sensitive(true); } @@ -272,7 +272,7 @@ where let headers = res.headers_mut(); for header in self.headers.iter() { - if let http::header::Entry::Occupied(mut entry) = headers.entry(header) { + if let header::Entry::Occupied(mut entry) = headers.entry(header) { for value in entry.iter_mut() { value.set_sensitive(true); } @@ -286,11 +286,12 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{http::header, service::service_fn}; + use crate::{header, HeaderValue, Request, Response}; + use rama_core::service::service_fn; #[tokio::test] async fn multiple_value_header() { - async fn response_set_cookie(req: http::Request<()>) -> Result, ()> { + async fn response_set_cookie(req: Request<()>) -> Result, ()> { let mut iter = req.headers().get_all(header::COOKIE).iter().peekable(); assert!(iter.peek().is_some()); @@ -299,23 +300,15 @@ mod tests { assert!(value.is_sensitive()) } - let mut resp = http::Response::new(()); - resp.headers_mut().append( - header::CONTENT_TYPE, - http::HeaderValue::from_static("text/html"), - ); - resp.headers_mut().append( - header::SET_COOKIE, - http::HeaderValue::from_static("cookie-1"), - ); - resp.headers_mut().append( - header::SET_COOKIE, - http::HeaderValue::from_static("cookie-2"), - ); - resp.headers_mut().append( - header::SET_COOKIE, - http::HeaderValue::from_static("cookie-3"), - ); + let mut resp = Response::new(()); + resp.headers_mut() + .append(header::CONTENT_TYPE, HeaderValue::from_static("text/html")); + resp.headers_mut() + .append(header::SET_COOKIE, HeaderValue::from_static("cookie-1")); + resp.headers_mut() + .append(header::SET_COOKIE, HeaderValue::from_static("cookie-2")); + resp.headers_mut() + .append(header::SET_COOKIE, HeaderValue::from_static("cookie-3")); Ok(resp) } @@ -325,11 +318,11 @@ mod tests { ) .layer(service_fn(response_set_cookie)); - let mut req = http::Request::new(()); + let mut req = Request::new(()); req.headers_mut() - .append(header::COOKIE, http::HeaderValue::from_static("cookie+1")); + .append(header::COOKIE, HeaderValue::from_static("cookie+1")); req.headers_mut() - .append(header::COOKIE, http::HeaderValue::from_static("cookie+2")); + .append(header::COOKIE, HeaderValue::from_static("cookie+2")); let resp = service.serve(Context::default(), req).await.unwrap(); diff --git a/rama-http/src/layer/set_header/request.rs b/rama-http/src/layer/set_header/request.rs index 01ac926e..2ff309c2 100644 --- a/rama-http/src/layer/set_header/request.rs +++ b/rama-http/src/layer/set_header/request.rs @@ -9,11 +9,11 @@ //! Setting a header from a fixed value provided when the middleware is constructed: //! //! ``` -//! use rama::http::layer::set_header::SetRequestHeaderLayer; -//! use rama::http::{Body, Request, Response, header::{self, HeaderValue}}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::set_header::SetRequestHeaderLayer; +//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -43,11 +43,11 @@ //! Setting a header based on a value determined dynamically from the request: //! //! ``` -//! use rama::http::{Body, Request, Response, header::{self, HeaderValue}}; -//! use rama::http::layer::set_header::SetRequestHeaderLayer; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}}; +//! use rama_http::layer::set_header::SetRequestHeaderLayer; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { diff --git a/rama-http/src/layer/set_header/response.rs b/rama-http/src/layer/set_header/response.rs index 842f824e..e1be1ffa 100644 --- a/rama-http/src/layer/set_header/response.rs +++ b/rama-http/src/layer/set_header/response.rs @@ -9,11 +9,11 @@ //! Setting a header from a fixed value provided when the middleware is constructed: //! //! ``` -//! use rama::http::layer::set_header::SetResponseHeaderLayer; -//! use rama::http::{Body, Request, Response, header::{self, HeaderValue}}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::set_header::SetResponseHeaderLayer; +//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -45,12 +45,12 @@ //! Setting a header based on a value determined dynamically from the response: //! //! ``` -//! use rama::http::layer::set_header::SetResponseHeaderLayer; -//! use rama::http::{Body, Request, Response, header::{self, HeaderValue}}; -//! use crate::rama::http::dep::http_body::Body as _; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::set_header::SetResponseHeaderLayer; +//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}}; +//! use crate::rama_http::dep::http_body::Body as _; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! # #[tokio::main] //! # async fn main() -> Result<(), BoxError> { @@ -366,8 +366,8 @@ where mod tests { use super::*; - use crate::service::service_fn; use crate::{header, Body, HeaderValue, Request, Response}; + use rama_core::service::service_fn; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/set_status.rs b/rama-http/src/layer/set_status.rs index 0a2b877a..df0b2270 100644 --- a/rama-http/src/layer/set_status.rs +++ b/rama-http/src/layer/set_status.rs @@ -5,11 +5,11 @@ //! ``` //! use std::{iter::once, convert::Infallible}; //! use bytes::Bytes; -//! use rama::http::layer::set_status::SetStatusLayer; -//! use rama::http::{Body, Request, Response, StatusCode}; -//! use rama::service::service_fn; -//! use rama::{Context, Layer, Service}; -//! use rama::error::BoxError; +//! use rama_http::layer::set_status::SetStatusLayer; +//! use rama_http::{Body, Request, Response, StatusCode}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Layer, Service}; +//! use rama_core::error::BoxError; //! //! async fn handle(req: Request) -> Result { //! // ... diff --git a/rama-http/src/layer/timeout.rs b/rama-http/src/layer/timeout.rs index bf38b015..7b1ff01c 100644 --- a/rama-http/src/layer/timeout.rs +++ b/rama-http/src/layer/timeout.rs @@ -3,9 +3,9 @@ //! If the request does not complete within the specified timeout it will be aborted and a `408 //! Request Timeout` response will be sent. //! -//! # Differences from `rama::service::layer::Timeout` +//! # Differences from `rama_core::service::layer::Timeout` //! -//! The generic [`Timeout`](crate::layer::timeout::Timeout) middleware uses an error to signal timeout, i.e. +//! The generic [`Timeout`] middleware uses an error to signal timeout, i.e. //! it changes the error type to [`BoxError`](rama_core::error::BoxError). For HTTP services that is rarely //! what you want as returning errors will terminate the connection without sending a response. //! @@ -18,11 +18,11 @@ //! ``` //! use std::{convert::Infallible, time::Duration}; //! -//! use rama::Layer; -//! use rama::service::service_fn; -//! use rama::http::{Body, Request, Response}; -//! use rama::http::layer::timeout::TimeoutLayer; -//! use rama::error::BoxError; +//! use rama_core::Layer; +//! use rama_core::service::service_fn; +//! use rama_http::{Body, Request, Response}; +//! use rama_http::layer::timeout::TimeoutLayer; +//! use rama_core::error::BoxError; //! //! async fn handle(_: Request) -> Result { //! // ... diff --git a/rama-http/src/layer/trace/mod.rs b/rama-http/src/layer/trace/mod.rs index 5d7f7a50..eab2447e 100644 --- a/rama-http/src/layer/trace/mod.rs +++ b/rama-http/src/layer/trace/mod.rs @@ -5,10 +5,10 @@ //! Adding tracing to your service can be as simple as: //! //! ```rust -//! use rama::http::{Body, Request, Response}; -//! use rama::service::service_fn; -//! use rama::{Context, Layer, Service}; -//! use rama::http::layer::trace::TraceLayer; +//! use rama_http::{Body, Request, Response}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Layer, Service}; +//! use rama_http::layer::trace::TraceLayer; //! use std::convert::Infallible; //! //! async fn handle(request: Request) -> Result { @@ -34,8 +34,8 @@ //! If you run this application with `RUST_LOG=rama=trace cargo run` you should see logs like: //! //! ```text -//! Mar 05 20:50:28.523 DEBUG request{method=GET path="/foo"}: rama::http::layer::trace::on_request: started processing request -//! Mar 05 20:50:28.524 DEBUG request{method=GET path="/foo"}: rama::http::layer::trace::on_response: finished processing request latency=1 ms status=200 +//! Mar 05 20:50:28.523 DEBUG request{method=GET path="/foo"}: rama_http::layer::trace::on_request: started processing request +//! Mar 05 20:50:28.524 DEBUG request{method=GET path="/foo"}: rama_http::layer::trace::on_response: finished processing request latency=1 ms status=200 //! ``` //! //! # Customization @@ -45,14 +45,14 @@ //! The default behaviour supports some customization: //! //! ```rust -//! use rama::http::{Body, Request, Response, HeaderMap, StatusCode}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; +//! use rama_http::{Body, Request, Response, HeaderMap, StatusCode}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; //! use tracing::Level; -//! use rama::http::layer::trace::{ +//! use rama_http::layer::trace::{ //! TraceLayer, DefaultMakeSpan, DefaultOnRequest, DefaultOnResponse, //! }; -//! use rama::utils::latency::LatencyUnit; +//! use rama_utils::latency::LatencyUnit; //! use std::time::Duration; //! use std::convert::Infallible; //! @@ -89,10 +89,10 @@ //! However for maximum control you can provide callbacks: //! //! ```rust -//! use rama::http::{Body, Request, Response, HeaderMap, StatusCode}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::http::layer::{classify::ServerErrorsFailureClass, trace::TraceLayer}; +//! use rama_http::{Body, Request, Response, HeaderMap, StatusCode}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_http::layer::{classify::ServerErrorsFailureClass, trace::TraceLayer}; //! use std::time::Duration; //! use tracing::Span; //! use std::convert::Infallible; @@ -139,10 +139,10 @@ //! Setting the behaviour to `()` will be disable that particular step: //! //! ```rust -//! use rama::http::{Body, Request, Response, StatusCode}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::http::layer::{classify::ServerErrorsFailureClass, trace::TraceLayer}; +//! use rama_http::{Body, Request, Response, StatusCode}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_http::layer::{classify::ServerErrorsFailureClass, trace::TraceLayer}; //! use std::time::Duration; //! use tracing::Span; //! # use std::convert::Infallible; @@ -222,10 +222,10 @@ //! field values][record] that weren't known when the span was created. //! //! ```rust -//! use rama::http::{Body, Request, Response, HeaderMap, StatusCode}; -//! use rama::service::service_fn; -//! use rama::Layer; -//! use rama::http::layer::trace::TraceLayer; +//! use rama_http::{Body, Request, Response, HeaderMap, StatusCode}; +//! use rama_core::service::service_fn; +//! use rama_core::Layer; +//! use rama_http::layer::trace::TraceLayer; //! use tracing::Span; //! use std::time::Duration; //! use std::convert::Infallible; @@ -264,10 +264,10 @@ //! A [`MakeClassifier`] can be provided when creating a [`TraceLayer`]: //! //! ```rust -//! use rama::http::{Body, Request, Response}; -//! use rama::service::service_fn; -//! use rama::Layer; -//! use rama::http::layer::{ +//! use rama_http::{Body, Request, Response}; +//! use rama_core::service::service_fn; +//! use rama_core::Layer; +//! use rama_http::layer::{ //! trace::TraceLayer, //! classify::{ //! MakeClassifier, ClassifyResponse, ClassifiedResponse, NeverClassifyEos, @@ -345,8 +345,8 @@ //! responses. //! //! [tracing]: https://crates.io/crates/tracing -//! [`Service`]: crate::Service -//! [`Service::serve`]: crate::Service::serve +//! [`Service`]: rama_core::Service +//! [`Service::serve`]: rama_core::Service::serve //! [`MakeClassifier`]: crate::layer::classify::MakeClassifier //! [`ClassifyResponse`]: crate::layer::classify::ClassifyResponse //! [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record diff --git a/rama-http/src/layer/trace/service.rs b/rama-http/src/layer/trace/service.rs index 755f3f48..d931c4f9 100644 --- a/rama-http/src/layer/trace/service.rs +++ b/rama-http/src/layer/trace/service.rs @@ -18,7 +18,7 @@ use std::{fmt, time::Instant}; /// See the [module docs](crate::layer::trace) for an example. /// /// [tracing]: https://crates.io/crates/tracing -/// [`Service`]: crate::Service +/// [`Service`]: rama_core::Service pub struct Trace< S, M, diff --git a/rama-http/src/layer/ua.rs b/rama-http/src/layer/ua.rs index f3218c3e..5cc01d37 100644 --- a/rama-http/src/layer/ua.rs +++ b/rama-http/src/layer/ua.rs @@ -4,7 +4,7 @@ //! //! ``` //! use rama_http::{ -//! client::HttpClientExt, IntoResponse, Request, Response, StatusCode, +//! service::client::HttpClientExt, IntoResponse, Request, Response, StatusCode, //! layer::ua::{PlatformKind, UserAgent, UserAgentClassifierLayer, UserAgentKind, UserAgentInfo}, //! }; //! use rama_core::{Context, Layer, service::service_fn}; @@ -41,7 +41,6 @@ use crate::{ }; use rama_core::{Context, Layer, Service}; use rama_utils::macros::define_inner_service_accessors; -use serde::{Deserialize, Serialize}; use std::{ fmt::{self, Debug}, future::Future, @@ -202,13 +201,11 @@ impl Layer for UserAgentClassifierLayer { #[cfg(test)] mod tests { use super::*; - use crate::client::HttpClientExt; - use crate::headers; use crate::layer::required_header::AddRequiredRequestHeadersLayer; - use crate::service::service_fn; - use crate::ua::{PlatformKind, UserAgentKind}; - use crate::{http::Response, Context}; - use crate::{IntoResponse, StatusCode}; + use crate::service::client::HttpClientExt; + use crate::{headers, IntoResponse, Response, StatusCode}; + use rama_core::service::service_fn; + use rama_core::Context; use std::convert::Infallible; #[tokio::test] diff --git a/rama-http/src/layer/validate_request/mod.rs b/rama-http/src/layer/validate_request/mod.rs index 8d9232d9..4c2c82ef 100644 --- a/rama-http/src/layer/validate_request/mod.rs +++ b/rama-http/src/layer/validate_request/mod.rs @@ -3,11 +3,11 @@ //! # Example //! //! ``` -//! use rama::http::layer::validate_request::ValidateRequestHeaderLayer; -//! use rama::http::{Body, Request, Response, StatusCode, header::ACCEPT}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::validate_request::ValidateRequestHeaderLayer; +//! use rama_http::{Body, Request, Response, StatusCode, header::ACCEPT}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! async fn handle(request: Request) -> Result { //! Ok(Response::new(Body::empty())) @@ -50,11 +50,11 @@ //! Custom validation can be made by implementing [`ValidateRequest`]: //! //! ``` -//! use rama::http::layer::validate_request::{ValidateRequestHeaderLayer, ValidateRequest}; -//! use rama::http::{Body, Request, Response, StatusCode, header::ACCEPT}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::layer::validate_request::{ValidateRequestHeaderLayer, ValidateRequest}; +//! use rama_http::{Body, Request, Response, StatusCode, header::ACCEPT}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! #[derive(Clone, Copy)] //! pub struct MyHeader { /* ... */ } @@ -105,11 +105,11 @@ //! //! ``` //! use bytes::Bytes; -//! use rama::http::{Body, Request, Response, StatusCode, header::ACCEPT}; -//! use rama::http::layer::validate_request::{ValidateRequestHeaderLayer, ValidateRequest}; -//! use rama::service::service_fn; -//! use rama::{Context, Service, Layer}; -//! use rama::error::BoxError; +//! use rama_http::{Body, Request, Response, StatusCode, header::ACCEPT}; +//! use rama_http::layer::validate_request::{ValidateRequestHeaderLayer, ValidateRequest}; +//! use rama_core::service::service_fn; +//! use rama_core::{Context, Service, Layer}; +//! use rama_core::error::BoxError; //! //! async fn handle(request: Request) -> Result { //! # Ok(Response::builder().body(Body::empty()).unwrap()) diff --git a/rama-http/src/layer/validate_request/validate_request_header.rs b/rama-http/src/layer/validate_request/validate_request_header.rs index e40911b5..d587561d 100644 --- a/rama-http/src/layer/validate_request/validate_request_header.rs +++ b/rama-http/src/layer/validate_request/validate_request_header.rs @@ -44,7 +44,7 @@ impl ValidateRequestHeaderLayer> { /// # Example /// /// ``` - /// use rama::http::layer::validate_request::{AcceptHeader, ValidateRequestHeaderLayer}; + /// use rama_http::layer::validate_request::{AcceptHeader, ValidateRequestHeaderLayer}; /// /// let layer = ValidateRequestHeaderLayer::::accept("application/json"); /// ``` @@ -185,8 +185,8 @@ mod tests { #[allow(unused_imports)] use super::*; - use crate::{error::BoxError, service::service_fn, Layer}; use crate::{header, Body, StatusCode}; + use rama_core::{error::BoxError, service::service_fn, Layer}; #[tokio::test] async fn valid_accept_header() { diff --git a/rama-http/src/lib.rs b/rama-http/src/lib.rs index 07b59e14..a89bafe9 100644 --- a/rama-http/src/lib.rs +++ b/rama-http/src/lib.rs @@ -69,8 +69,7 @@ pub mod service; pub mod io; -#[doc(hidden)] -mod utils; +pub mod utils; pub mod dep { //! Dependencies for rama http modules. diff --git a/rama-http/src/matcher/domain.rs b/rama-http/src/matcher/domain.rs index b0b349d5..b078c147 100644 --- a/rama-http/src/matcher/domain.rs +++ b/rama-http/src/matcher/domain.rs @@ -1,6 +1,7 @@ -use crate::{Request, RequestContext}; +use crate::Request; use rama_core::{context::Extensions, Context}; use rama_net::address::{Domain, Host}; +use rama_net::http::RequestContext; #[derive(Debug, Clone)] /// Matcher based on the (sub)domain of the request's URI. diff --git a/rama-http-backend/src/client/ext.rs b/rama-http/src/service/client/ext.rs similarity index 87% rename from rama-http-backend/src/client/ext.rs rename to rama-http/src/service/client/ext.rs index 5f2728bd..e44eae35 100644 --- a/rama-http-backend/src/client/ext.rs +++ b/rama-http/src/service/client/ext.rs @@ -1,11 +1,12 @@ -use super::HttpClientError; -use crate::{ - error::BoxError, - http::{headers::HeaderExt, Method, Request, Response, Uri}, +use crate::{headers::HeaderExt, Method, Request, Response, Uri}; +use rama_core::{ + error::{BoxError, ErrorExt, OpaqueError}, Context, Service, }; use std::future::Future; +// TODO: integrate client ext into rama-http, as it is backend agnostic!, can live under service?! + /// Extends an Http Client with high level features, /// to facilitate the creation and sending of http requests, /// in a more ergonomic way. @@ -208,137 +209,134 @@ impl IntoHeaderValue for &[u8] {} mod private { use http::HeaderName; - use crate::net::Protocol; + use rama_net::Protocol; use super::*; pub trait IntoUrlSealed { - fn into_url(self) -> Result; + fn into_url(self) -> Result; } impl IntoUrlSealed for Uri { - fn into_url(self) -> Result { + fn into_url(self) -> Result { let protocol: Option = self.scheme().map(Into::into); match protocol { Some(protocol) => { if protocol.is_http() { Ok(self) } else { - Err(HttpClientError::from_display(format!( + Err(OpaqueError::from_display(format!( "Unsupported protocol: {protocol}" ))) } } - None => Err(HttpClientError::from_display("Missing scheme in URI")), + None => Err(OpaqueError::from_display("Missing scheme in URI")), } } } impl IntoUrlSealed for &str { - fn into_url(self) -> Result { + fn into_url(self) -> Result { match self.parse::() { Ok(uri) => uri.into_url(), - Err(_) => Err(HttpClientError::from_display(format!( - "Invalid URL: {}", - self - ))), + Err(_) => Err(OpaqueError::from_display(format!("Invalid URL: {}", self))), } } } impl IntoUrlSealed for String { - fn into_url(self) -> Result { + fn into_url(self) -> Result { self.as_str().into_url() } } impl IntoUrlSealed for &String { - fn into_url(self) -> Result { + fn into_url(self) -> Result { self.as_str().into_url() } } pub trait IntoHeaderNameSealed { - fn into_header_name(self) -> Result; + fn into_header_name(self) -> Result; } impl IntoHeaderNameSealed for HeaderName { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { Ok(self) } } impl IntoHeaderNameSealed for Option { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { match self { Some(name) => Ok(name), - None => Err(HttpClientError::from_display("Header name is required")), + None => Err(OpaqueError::from_display("Header name is required")), } } } impl IntoHeaderNameSealed for &str { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { let name = self .parse::() - .map_err(HttpClientError::from_std)?; + .map_err(OpaqueError::from_std)?; Ok(name) } } impl IntoHeaderNameSealed for String { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { self.as_str().into_header_name() } } impl IntoHeaderNameSealed for &String { - fn into_header_name(self) -> Result { + fn into_header_name(self) -> Result { self.as_str().into_header_name() } } impl IntoHeaderNameSealed for &[u8] { - fn into_header_name(self) -> Result { - let name = crate::HeaderName::from_bytes(self).map_err(HttpClientError::from_std)?; + fn into_header_name(self) -> Result { + let name = crate::HeaderName::from_bytes(self).map_err(OpaqueError::from_std)?; Ok(name) } } pub trait IntoHeaderValueSealed { - fn into_header_value(self) -> Result; + fn into_header_value(self) -> Result; } impl IntoHeaderValueSealed for crate::HeaderValue { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { Ok(self) } } impl IntoHeaderValueSealed for &str { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { let value = self .parse::() - .map_err(HttpClientError::from_std)?; + .map_err(OpaqueError::from_std)?; Ok(value) } } impl IntoHeaderValueSealed for String { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { self.as_str().into_header_value() } } impl IntoHeaderValueSealed for &String { - fn into_header_value(self) -> Result { + fn into_header_value(self) -> Result { self.as_str().into_header_value() } } impl IntoHeaderValueSealed for &[u8] { - fn into_header_value(self) -> Result { - let value = crate::HeaderValue::from_bytes(self).map_err(HttpClientError::from_std)?; + fn into_header_value(self) -> Result { + let value = crate::HeaderValue::from_bytes(self).map_err(OpaqueError::from_std)?; Ok(value) } } @@ -376,7 +374,7 @@ where enum RequestBuilderState { PreBody(crate::dep::http::request::Builder), PostBody(crate::Request), - Error(HttpClientError), + Error(OpaqueError), } impl<'a, S, State, Body> RequestBuilder<'a, S, State, Response> @@ -476,7 +474,7 @@ where RequestBuilderState::Error(original_err) => { RequestBuilderState::Error(original_err) } - _ => RequestBuilderState::Error(HttpClientError::from_std(err)), + _ => RequestBuilderState::Error(OpaqueError::from_std(err)), }; return self; } @@ -496,16 +494,16 @@ where RequestBuilderState::PreBody(builder) => match body.try_into() { Ok(body) => match builder.body(body) { Ok(req) => RequestBuilderState::PostBody(req), - Err(err) => RequestBuilderState::Error(HttpClientError::from_std(err)), + Err(err) => RequestBuilderState::Error(OpaqueError::from_std(err)), }, - Err(err) => RequestBuilderState::Error(HttpClientError::from_boxed(err.into())), + Err(err) => RequestBuilderState::Error(OpaqueError::from_boxed(err.into())), }, RequestBuilderState::PostBody(mut req) => match body.try_into() { Ok(body) => { *req.body_mut() = body; RequestBuilderState::PostBody(req) } - Err(err) => RequestBuilderState::Error(HttpClientError::from_boxed(err.into())), + Err(err) => RequestBuilderState::Error(OpaqueError::from_boxed(err.into())), }, RequestBuilderState::Error(err) => RequestBuilderState::Error(err), }; @@ -538,10 +536,10 @@ where }; match builder.body(body.into()) { Ok(req) => RequestBuilderState::PostBody(req), - Err(err) => RequestBuilderState::Error(HttpClientError::from_std(err)), + Err(err) => RequestBuilderState::Error(OpaqueError::from_std(err)), } } - Err(err) => RequestBuilderState::Error(HttpClientError::from_std(err)), + Err(err) => RequestBuilderState::Error(OpaqueError::from_std(err)), }, RequestBuilderState::PostBody(mut req) => match serde_html_form::to_string(form) { Ok(body) => { @@ -554,7 +552,7 @@ where *req.body_mut() = body.into(); RequestBuilderState::PostBody(req) } - Err(err) => RequestBuilderState::Error(HttpClientError::from_std(err)), + Err(err) => RequestBuilderState::Error(OpaqueError::from_std(err)), }, RequestBuilderState::Error(err) => RequestBuilderState::Error(err), }; @@ -585,10 +583,10 @@ where }; match builder.body(body.into()) { Ok(req) => RequestBuilderState::PostBody(req), - Err(err) => RequestBuilderState::Error(HttpClientError::from_std(err)), + Err(err) => RequestBuilderState::Error(OpaqueError::from_std(err)), } } - Err(err) => RequestBuilderState::Error(HttpClientError::from_std(err)), + Err(err) => RequestBuilderState::Error(OpaqueError::from_std(err)), }, RequestBuilderState::PostBody(mut req) => match serde_json::to_vec(json) { Ok(body) => { @@ -601,7 +599,7 @@ where *req.body_mut() = body.into(); RequestBuilderState::PostBody(req) } - Err(err) => RequestBuilderState::Error(HttpClientError::from_std(err)), + Err(err) => RequestBuilderState::Error(OpaqueError::from_std(err)), }, RequestBuilderState::Error(err) => RequestBuilderState::Error(err), }; @@ -634,11 +632,11 @@ where /// # Errors /// /// This method fails if there was an error while sending [`Request`]. - pub async fn send(self, ctx: Context) -> Result, HttpClientError> { + pub async fn send(self, ctx: Context) -> Result, OpaqueError> { let request = match self.state { RequestBuilderState::PreBody(builder) => builder .body(crate::Body::empty()) - .map_err(HttpClientError::from_std)?, + .map_err(OpaqueError::from_std)?, RequestBuilderState::PostBody(request) => request, RequestBuilderState::Error(err) => return Err(err), }; @@ -646,7 +644,7 @@ where let uri = request.uri().clone(); match self.http_client_service.serve(ctx, request).await { Ok(response) => Ok(response), - Err(err) => Err(HttpClientError::from_boxed(err.into()).with_uri(uri)), + Err(err) => Err(OpaqueError::from_boxed(err.into()).context(uri.to_string())), } } } @@ -657,18 +655,18 @@ mod test { use super::*; use crate::{ - http::{ - layer::{ - required_header::AddRequiredRequestHeadersLayer, - retry::{ManagedPolicy, RetryLayer}, - trace::TraceLayer, - }, - IntoResponse, + layer::{ + required_header::AddRequiredRequestHeadersLayer, + retry::{ManagedPolicy, RetryLayer}, + trace::TraceLayer, }, + IntoResponse, + }; + use rama_core::{ layer::{Layer, MapResultLayer}, service::{service_fn, BoxService}, - utils::backoff::ExponentialBackoff, }; + use rama_utils::backoff::ExponentialBackoff; use std::convert::Infallible; async fn fake_client_fn( @@ -706,8 +704,8 @@ mod test { } } - type HttpClientError = rama_core::error::BoxError; - type HttpClient = BoxService; + type OpaqueError = rama_core::error::BoxError; + type HttpClient = BoxService; fn client() -> HttpClient { let builder = ( diff --git a/rama-http/src/service/client/mod.rs b/rama-http/src/service/client/mod.rs new file mode 100644 index 00000000..4ca63c87 --- /dev/null +++ b/rama-http/src/service/client/mod.rs @@ -0,0 +1,5 @@ +//! service utilities for (http) clients + +mod ext; +#[doc(inline)] +pub use ext::{HttpClientExt, IntoUrl, RequestBuilder}; diff --git a/rama-http/src/service/fs/serve_dir/mod.rs b/rama-http/src/service/fs/serve_dir/mod.rs index c9e912dd..160b478b 100644 --- a/rama-http/src/service/fs/serve_dir/mod.rs +++ b/rama-http/src/service/fs/serve_dir/mod.rs @@ -39,12 +39,13 @@ const DEFAULT_CAPACITY: usize = 65536; /// # Example /// /// ```rust,no_run -/// use rama::{ -/// http::{server::HttpServer, service::fs::ServeDir}, +/// use rama_http_backend::server::HttpServer; +/// use rama_http::service::fs::{ServeDir, ServeFile}; +/// use rama_core::{ /// rt::Executor, -/// tcp::server::TcpListener, /// Layer, layer::TraceErrLayer, /// }; +/// use rama_tcp::server::TcpListener; /// /// #[tokio::main] /// async fn main() { @@ -311,15 +312,13 @@ impl ServeDir { /// This can be used to respond with a different file: /// /// ```rust,no_run - /// use rama::{ - /// http::{ - /// server::HttpServer, - /// service::fs::{ServeDir, ServeFile}, - /// }, + /// use rama_core::{ /// rt::Executor, /// Layer, layer::TraceErrLayer, - /// tcp::server::TcpListener, /// }; + /// use rama_tcp::server::TcpListener; + /// use rama_http_backend::server::HttpServer; + /// use rama_http::service::fs::{ServeDir, ServeFile}; /// /// #[tokio::main] /// async fn main() { @@ -360,16 +359,14 @@ impl ServeDir { /// This can be used to respond with a different file: /// /// ```rust,no_run - /// use rama::{ - /// http::{ - /// server::HttpServer, - /// service::fs::{ServeDir, ServeFile}, - /// }, + /// use rama_core::{ /// rt::Executor, /// layer::TraceErrLayer, - /// tcp::server::TcpListener, /// Layer, /// }; + /// use rama_tcp::server::TcpListener; + /// use rama_http_backend::server::HttpServer; + /// use rama_http::service::fs::{ServeDir, ServeFile}; /// /// #[tokio::main] /// async fn main() { @@ -426,14 +423,16 @@ impl ServeDir { /// # Example /// /// ```rust,no_run - /// use rama::{ - /// http::{server::HttpServer, service::fs::ServeDir, Body, Request, Response, StatusCode}, + /// use rama_core::{ /// rt::Executor, /// service::service_fn, /// layer::TraceErrLayer, - /// tcp::server::TcpListener, /// Context, Layer, /// }; + /// use rama_tcp::server::TcpListener; + /// use rama_http_backend::server::HttpServer; + /// use rama_http::service::fs::ServeDir; + /// use rama_http::{Body, Request, Response, StatusCode}; /// use std::convert::Infallible; /// /// #[tokio::main] diff --git a/rama-http/src/service/fs/serve_dir/tests.rs b/rama-http/src/service/fs/serve_dir/tests.rs index 954859c1..1e037a26 100644 --- a/rama-http/src/service/fs/serve_dir/tests.rs +++ b/rama-http/src/service/fs/serve_dir/tests.rs @@ -15,7 +15,7 @@ use std::io::Read; #[tokio::test] async fn basic() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") @@ -28,13 +28,13 @@ async fn basic() { let body = body_into_text(res.into_body()).await; - let contents = std::fs::read_to_string("./README.md").unwrap(); + let contents = std::fs::read_to_string("../README.md").unwrap(); assert_eq!(body, contents); } #[tokio::test] async fn basic_with_index() { - let svc = ServeDir::new("./test-files"); + let svc = ServeDir::new("../test-files"); let req = Request::new(Body::empty()); let res = svc.serve(Context::default(), req).await.unwrap(); @@ -52,7 +52,7 @@ async fn basic_with_index() { #[tokio::test] async fn head_request() { - let svc = ServeDir::new("./test-files"); + let svc = ServeDir::new("../test-files"); let req = Request::builder() .uri("/precompressed.txt") @@ -73,7 +73,7 @@ async fn head_request() { #[tokio::test] async fn precompresed_head_request() { - let svc = ServeDir::new("./test-files").precompressed_gzip(); + let svc = ServeDir::new("../test-files").precompressed_gzip(); let req = Request::builder() .uri("/precompressed.txt") @@ -92,7 +92,7 @@ async fn precompresed_head_request() { #[tokio::test] async fn with_custom_chunk_size() { - let svc = ServeDir::new(".").with_buf_chunk_size(1024 * 32); + let svc = ServeDir::new("..").with_buf_chunk_size(1024 * 32); let req = Request::builder() .uri("/README.md") @@ -105,13 +105,13 @@ async fn with_custom_chunk_size() { let body = body_into_text(res.into_body()).await; - let contents = std::fs::read_to_string("./README.md").unwrap(); + let contents = std::fs::read_to_string("../README.md").unwrap(); assert_eq!(body, contents); } #[tokio::test] async fn precompressed_gzip() { - let svc = ServeDir::new("./test-files").precompressed_gzip(); + let svc = ServeDir::new("../test-files").precompressed_gzip(); let req = Request::builder() .uri("/precompressed.txt") @@ -132,7 +132,7 @@ async fn precompressed_gzip() { #[tokio::test] async fn precompressed_br() { - let svc = ServeDir::new("./test-files").precompressed_br(); + let svc = ServeDir::new("../test-files").precompressed_br(); let req = Request::builder() .uri("/precompressed.txt") @@ -153,7 +153,7 @@ async fn precompressed_br() { #[tokio::test] async fn precompressed_deflate() { - let svc = ServeDir::new("./test-files").precompressed_deflate(); + let svc = ServeDir::new("../test-files").precompressed_deflate(); let request = Request::builder() .uri("/precompressed.txt") .header("Accept-Encoding", "deflate,br") @@ -173,7 +173,7 @@ async fn precompressed_deflate() { #[tokio::test] async fn unsupported_precompression_algorithm_fallbacks_to_uncompressed() { - let svc = ServeDir::new("./test-files").precompressed_gzip(); + let svc = ServeDir::new("../test-files").precompressed_gzip(); let request = Request::builder() .uri("/precompressed.txt") @@ -192,7 +192,7 @@ async fn unsupported_precompression_algorithm_fallbacks_to_uncompressed() { #[tokio::test] async fn only_precompressed_variant_existing() { - let svc = ServeDir::new("./test-files").precompressed_gzip(); + let svc = ServeDir::new("../test-files").precompressed_gzip(); let request = Request::builder() .uri("/only_gzipped.txt") @@ -226,7 +226,7 @@ async fn only_precompressed_variant_existing() { #[tokio::test] async fn missing_precompressed_variant_fallbacks_to_uncompressed() { - let svc = ServeDir::new("./test-files").precompressed_gzip(); + let svc = ServeDir::new("../test-files").precompressed_gzip(); let request = Request::builder() .uri("/missing_precompressed.txt") @@ -246,7 +246,7 @@ async fn missing_precompressed_variant_fallbacks_to_uncompressed() { #[tokio::test] async fn missing_precompressed_variant_fallbacks_to_uncompressed_for_head_request() { - let svc = ServeDir::new("./test-files").precompressed_gzip(); + let svc = ServeDir::new("../test-files").precompressed_gzip(); let request = Request::builder() .uri("/missing_precompressed.txt") @@ -269,7 +269,7 @@ async fn missing_precompressed_variant_fallbacks_to_uncompressed_for_head_reques #[tokio::test] async fn access_to_sub_dirs() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/Cargo.toml") @@ -282,13 +282,13 @@ async fn access_to_sub_dirs() { let body = body_into_text(res.into_body()).await; - let contents = std::fs::read_to_string("Cargo.toml").unwrap(); + let contents = std::fs::read_to_string("../Cargo.toml").unwrap(); assert_eq!(body, contents); } #[tokio::test] async fn not_found() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/not-found") @@ -306,7 +306,7 @@ async fn not_found() { #[cfg(unix)] #[tokio::test] async fn not_found_when_not_a_directory() { - let svc = ServeDir::new("./test-files"); + let svc = ServeDir::new("../test-files"); // `index.html` is a file, and we are trying to request // it as a directory. @@ -326,7 +326,7 @@ async fn not_found_when_not_a_directory() { #[tokio::test] async fn not_found_precompressed() { - let svc = ServeDir::new("./test-files").precompressed_gzip(); + let svc = ServeDir::new("../test-files").precompressed_gzip(); let req = Request::builder() .uri("/not-found") @@ -344,7 +344,7 @@ async fn not_found_precompressed() { #[tokio::test] async fn fallbacks_to_different_precompressed_variant_if_not_found_for_head_request() { - let svc = ServeDir::new("./test-files") + let svc = ServeDir::new("../test-files") .precompressed_gzip() .precompressed_br(); @@ -365,7 +365,7 @@ async fn fallbacks_to_different_precompressed_variant_if_not_found_for_head_requ #[tokio::test] async fn fallbacks_to_different_precompressed_variant_if_not_found() { - let svc = ServeDir::new("./test-files") + let svc = ServeDir::new("../test-files") .precompressed_gzip() .precompressed_br(); @@ -388,7 +388,7 @@ async fn fallbacks_to_different_precompressed_variant_if_not_found() { #[tokio::test] async fn redirect_to_trailing_slash_on_dir() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder().uri("/src").body(Body::empty()).unwrap(); let res = svc.serve(Context::default(), req).await.unwrap(); @@ -401,7 +401,7 @@ async fn redirect_to_trailing_slash_on_dir() { #[tokio::test] async fn empty_directory_without_index() { - let svc = ServeDir::new(".").append_index_html_on_directories(false); + let svc = ServeDir::new("..").append_index_html_on_directories(false); let req = Request::new(Body::empty()); let res = svc.serve(Context::default(), req).await.unwrap(); @@ -443,7 +443,7 @@ async fn access_cjk_percent_encoded_uri_path() { // percent encoding present of δ½ ε₯½δΈ–η•Œ.txt let cjk_filename_encoded = "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C.txt"; - let svc = ServeDir::new("./test-files"); + let svc = ServeDir::new("../test-files"); let req = Request::builder() .uri(format!("/{}", cjk_filename_encoded)) @@ -459,7 +459,7 @@ async fn access_cjk_percent_encoded_uri_path() { async fn access_space_percent_encoded_uri_path() { let encoded_filename = "filename%20with%20space.txt"; - let svc = ServeDir::new("./test-files"); + let svc = ServeDir::new("../test-files"); let req = Request::builder() .uri(format!("/{}", encoded_filename)) @@ -473,7 +473,7 @@ async fn access_space_percent_encoded_uri_path() { #[tokio::test] async fn read_partial_in_bounds() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let bytes_start_incl = 9; let bytes_end_incl = 1023; @@ -487,7 +487,7 @@ async fn read_partial_in_bounds() { .unwrap(); let res = svc.serve(Context::default(), req).await.unwrap(); - let file_contents = std::fs::read("./README.md").unwrap(); + let file_contents = std::fs::read("../README.md").unwrap(); assert_eq!(res.status(), StatusCode::PARTIAL_CONTENT); assert_eq!( res.headers()["content-length"], @@ -511,7 +511,7 @@ async fn read_partial_in_bounds() { #[tokio::test] async fn read_partial_accepts_out_of_bounds_range() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let bytes_start_incl = 0; let bytes_end_excl = 9999999; let requested_len = bytes_end_excl - bytes_start_incl; @@ -527,7 +527,7 @@ async fn read_partial_accepts_out_of_bounds_range() { let res = svc.serve(Context::default(), req).await.unwrap(); assert_eq!(res.status(), StatusCode::PARTIAL_CONTENT); - let file_contents = std::fs::read("./README.md").unwrap(); + let file_contents = std::fs::read("../README.md").unwrap(); assert_eq!( res.headers()["content-range"], &format!( @@ -540,7 +540,7 @@ async fn read_partial_accepts_out_of_bounds_range() { #[tokio::test] async fn read_partial_errs_on_garbage_header() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .header("Range", "bad_format") @@ -548,7 +548,7 @@ async fn read_partial_errs_on_garbage_header() { .unwrap(); let res = svc.serve(Context::default(), req).await.unwrap(); assert_eq!(res.status(), StatusCode::RANGE_NOT_SATISFIABLE); - let file_contents = std::fs::read("./README.md").unwrap(); + let file_contents = std::fs::read("../README.md").unwrap(); assert_eq!( res.headers()["content-range"], &format!("bytes */{}", file_contents.len()) @@ -557,7 +557,7 @@ async fn read_partial_errs_on_garbage_header() { #[tokio::test] async fn read_partial_errs_on_bad_range() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .header("Range", "bytes=-1-15") @@ -565,7 +565,7 @@ async fn read_partial_errs_on_bad_range() { .unwrap(); let res = svc.serve(Context::default(), req).await.unwrap(); assert_eq!(res.status(), StatusCode::RANGE_NOT_SATISFIABLE); - let file_contents = std::fs::read("./README.md").unwrap(); + let file_contents = std::fs::read("../README.md").unwrap(); assert_eq!( res.headers()["content-range"], &format!("bytes */{}", file_contents.len()) @@ -574,7 +574,7 @@ async fn read_partial_errs_on_bad_range() { #[tokio::test] async fn accept_encoding_identity() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .header("Accept-Encoding", "identity") @@ -588,7 +588,7 @@ async fn accept_encoding_identity() { #[tokio::test] async fn last_modified() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .body(Body::empty()) @@ -603,7 +603,7 @@ async fn last_modified() { // -- If-Modified-Since - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .header(header::IF_MODIFIED_SINCE, last_modified) @@ -614,7 +614,7 @@ async fn last_modified() { assert_eq!(res.status(), StatusCode::NOT_MODIFIED); assert!(res.into_body().frame().await.is_none()); - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .header(header::IF_MODIFIED_SINCE, "Fri, 09 Aug 1996 14:21:40 GMT") @@ -629,7 +629,7 @@ async fn last_modified() { // -- If-Unmodified-Since - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .header(header::IF_UNMODIFIED_SINCE, last_modified) @@ -641,7 +641,7 @@ async fn last_modified() { let body = res.into_body().collect().await.unwrap().to_bytes(); assert_eq!(body.as_ref(), readme_bytes); - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .uri("/README.md") .header(header::IF_UNMODIFIED_SINCE, "Fri, 09 Aug 1996 14:21:40 GMT") @@ -662,7 +662,7 @@ async fn with_fallback_svc() { )))) } - let svc = ServeDir::new(".").fallback(service_fn(fallback)); + let svc = ServeDir::new("..").fallback(service_fn(fallback)); let req = Request::builder() .uri("/doesnt-exist") @@ -678,7 +678,7 @@ async fn with_fallback_svc() { #[tokio::test] async fn with_fallback_serve_file() { - let svc = ServeDir::new(".").fallback(ServeFile::new("./README.md")); + let svc = ServeDir::new("..").fallback(ServeFile::new("../README.md")); let req = Request::builder() .uri("/doesnt-exist") @@ -691,13 +691,13 @@ async fn with_fallback_serve_file() { let body = body_into_text(res.into_body()).await; - let contents = std::fs::read_to_string("./README.md").unwrap(); + let contents = std::fs::read_to_string("../README.md").unwrap(); assert_eq!(body, contents); } #[tokio::test] async fn method_not_allowed() { - let svc = ServeDir::new("."); + let svc = ServeDir::new(".."); let req = Request::builder() .method(Method::POST) @@ -719,7 +719,7 @@ async fn calling_fallback_on_not_allowed() { )))) } - let svc = ServeDir::new(".") + let svc = ServeDir::new("..") .call_fallback_on_method_not_allowed(true) .fallback(service_fn(fallback)); @@ -745,7 +745,7 @@ async fn with_fallback_svc_and_not_append_index_html_on_directories() { )))) } - let svc = ServeDir::new(".") + let svc = ServeDir::new("..") .append_index_html_on_directories(false) .fallback(service_fn(fallback)); @@ -767,7 +767,7 @@ async fn calls_fallback_on_invalid_paths() { Ok(res) } - let svc = ServeDir::new(".").fallback(service_fn(fallback)); + let svc = ServeDir::new("..").fallback(service_fn(fallback)); let req = Request::builder() .uri("/weird_%c3%28_path") diff --git a/rama-http/src/service/fs/serve_file.rs b/rama-http/src/service/fs/serve_file.rs index e78e462e..66ea0c48 100644 --- a/rama-http/src/service/fs/serve_file.rs +++ b/rama-http/src/service/fs/serve_file.rs @@ -151,7 +151,7 @@ mod compression_tests { use http_body_util::BodyExt; use tokio::io::AsyncReadExt; - let svc = ServeFile::new("./test-files/precompressed.txt").precompressed_zstd(); + let svc = ServeFile::new("../test-files/precompressed.txt").precompressed_zstd(); let request = Request::builder() .header("Accept-Encoding", "zstd,br") .body(Body::empty()) @@ -187,7 +187,7 @@ mod tests { #[tokio::test] async fn basic() { - let svc = ServeFile::new("./README.md"); + let svc = ServeFile::new("../README.md"); let res = svc .serve(Context::default(), Request::new(Body::empty())) @@ -204,7 +204,7 @@ mod tests { #[tokio::test] async fn basic_with_mime() { - let svc = ServeFile::new_with_mime("./README.md", &Mime::from_str("image/jpg").unwrap()); + let svc = ServeFile::new_with_mime("../README.md", &Mime::from_str("image/jpg").unwrap()); let res = svc .serve(Context::default(), Request::new(Body::empty())) @@ -221,7 +221,7 @@ mod tests { #[tokio::test] async fn head_request() { - let svc = ServeFile::new("./test-files/precompressed.txt"); + let svc = ServeFile::new("../test-files/precompressed.txt"); let mut request = Request::new(Body::empty()); *request.method_mut() = Method::HEAD; @@ -239,7 +239,7 @@ mod tests { #[tokio::test] async fn precompresed_head_request() { - let svc = ServeFile::new("./test-files/precompressed.txt").precompressed_gzip(); + let svc = ServeFile::new("../test-files/precompressed.txt").precompressed_gzip(); let request = Request::builder() .header("Accept-Encoding", "gzip") @@ -257,7 +257,7 @@ mod tests { #[tokio::test] async fn precompressed_gzip() { - let svc = ServeFile::new("./test-files/precompressed.txt").precompressed_gzip(); + let svc = ServeFile::new("../test-files/precompressed.txt").precompressed_gzip(); let request = Request::builder() .header("Accept-Encoding", "gzip") @@ -277,7 +277,7 @@ mod tests { #[tokio::test] async fn unsupported_precompression_algorithm_fallbacks_to_uncompressed() { - let svc = ServeFile::new("./test-files/precompressed.txt").precompressed_gzip(); + let svc = ServeFile::new("../test-files/precompressed.txt").precompressed_gzip(); let request = Request::builder() .header("Accept-Encoding", "br") @@ -295,7 +295,7 @@ mod tests { #[tokio::test] async fn missing_precompressed_variant_fallbacks_to_uncompressed() { - let svc = ServeFile::new("./test-files/missing_precompressed.txt").precompressed_gzip(); + let svc = ServeFile::new("../test-files/missing_precompressed.txt").precompressed_gzip(); let request = Request::builder() .header("Accept-Encoding", "gzip") @@ -314,7 +314,7 @@ mod tests { #[tokio::test] async fn missing_precompressed_variant_fallbacks_to_uncompressed_head_request() { - let svc = ServeFile::new("./test-files/missing_precompressed.txt").precompressed_gzip(); + let svc = ServeFile::new("../test-files/missing_precompressed.txt").precompressed_gzip(); let request = Request::builder() .header("Accept-Encoding", "gzip") @@ -336,7 +336,7 @@ mod tests { #[tokio::test] async fn only_precompressed_variant_existing() { - let svc = ServeFile::new("./test-files/only_gzipped.txt").precompressed_gzip(); + let svc = ServeFile::new("../test-files/only_gzipped.txt").precompressed_gzip(); let request = Request::builder().body(Body::empty()).unwrap(); let res = svc @@ -366,7 +366,7 @@ mod tests { #[tokio::test] async fn precompressed_br() { - let svc = ServeFile::new("./test-files/precompressed.txt").precompressed_br(); + let svc = ServeFile::new("../test-files/precompressed.txt").precompressed_br(); let request = Request::builder() .header("Accept-Encoding", "gzip,br") @@ -386,7 +386,7 @@ mod tests { #[tokio::test] async fn precompressed_deflate() { - let svc = ServeFile::new("./test-files/precompressed.txt").precompressed_deflate(); + let svc = ServeFile::new("../test-files/precompressed.txt").precompressed_deflate(); let request = Request::builder() .header("Accept-Encoding", "deflate,br") .body(Body::empty()) @@ -405,7 +405,7 @@ mod tests { #[tokio::test] async fn multi_precompressed() { - let svc = ServeFile::new("./test-files/precompressed.txt") + let svc = ServeFile::new("../test-files/precompressed.txt") .precompressed_gzip() .precompressed_br(); @@ -450,7 +450,7 @@ mod tests { #[tokio::test] async fn with_custom_chunk_size() { - let svc = ServeFile::new("./README.md").with_buf_chunk_size(1024 * 32); + let svc = ServeFile::new("../README.md").with_buf_chunk_size(1024 * 32); let res = svc .serve(Context::default(), Request::new(Body::empty())) @@ -467,7 +467,7 @@ mod tests { #[tokio::test] async fn fallbacks_to_different_precompressed_variant_if_not_found() { - let svc = ServeFile::new("./test-files/precompressed_br.txt") + let svc = ServeFile::new("../test-files/precompressed_br.txt") .precompressed_gzip() .precompressed_deflate() .precompressed_br(); @@ -490,7 +490,7 @@ mod tests { #[tokio::test] async fn fallbacks_to_different_precompressed_variant_if_not_found_head_request() { - let svc = ServeFile::new("./test-files/precompressed_br.txt") + let svc = ServeFile::new("../test-files/precompressed_br.txt") .precompressed_gzip() .precompressed_deflate() .precompressed_br(); @@ -538,7 +538,7 @@ mod tests { #[tokio::test] async fn last_modified() { - let svc = ServeFile::new("./README.md"); + let svc = ServeFile::new("../README.md"); let req = Request::builder().body(Body::empty()).unwrap(); let res = svc.serve(Context::default(), req).await.unwrap(); @@ -552,7 +552,7 @@ mod tests { // -- If-Modified-Since - let svc = ServeFile::new("./README.md"); + let svc = ServeFile::new("../README.md"); let req = Request::builder() .header(header::IF_MODIFIED_SINCE, last_modified) .body(Body::empty()) @@ -562,7 +562,7 @@ mod tests { assert_eq!(res.status(), StatusCode::NOT_MODIFIED); assert!(res.into_body().frame().await.is_none()); - let svc = ServeFile::new("./README.md"); + let svc = ServeFile::new("../README.md"); let req = Request::builder() .header(header::IF_MODIFIED_SINCE, "Fri, 09 Aug 1996 14:21:40 GMT") .body(Body::empty()) @@ -576,7 +576,7 @@ mod tests { // -- If-Unmodified-Since - let svc = ServeFile::new("./README.md"); + let svc = ServeFile::new("../README.md"); let req = Request::builder() .header(header::IF_UNMODIFIED_SINCE, last_modified) .body(Body::empty()) @@ -587,7 +587,7 @@ mod tests { let body = res.into_body().collect().await.unwrap().to_bytes(); assert_eq!(body.as_ref(), readme_bytes); - let svc = ServeFile::new("./README.md"); + let svc = ServeFile::new("../README.md"); let req = Request::builder() .header(header::IF_UNMODIFIED_SINCE, "Fri, 09 Aug 1996 14:21:40 GMT") .body(Body::empty()) diff --git a/rama-http/src/service/mod.rs b/rama-http/src/service/mod.rs index 37b34d25..891226da 100644 --- a/rama-http/src/service/mod.rs +++ b/rama-http/src/service/mod.rs @@ -1,5 +1,6 @@ //! Http Services provided by Rama. +pub mod client; pub mod fs; pub mod redirect; pub mod web; diff --git a/rama-http/src/service/web/endpoint/extract/authority.rs b/rama-http/src/service/web/endpoint/extract/authority.rs index 9b9642e4..4d03523c 100644 --- a/rama-http/src/service/web/endpoint/extract/authority.rs +++ b/rama-http/src/service/web/endpoint/extract/authority.rs @@ -1,9 +1,9 @@ use super::FromRequestParts; use crate::dep::http::request::Parts; use crate::utils::macros::define_http_rejection; -use crate::RequestContext; use rama_core::Context; use rama_net::address; +use rama_net::http::RequestContext; use rama_utils::macros::impl_deref; /// Extractor that resolves the authority of the request. @@ -56,9 +56,9 @@ mod tests { use crate::header::X_FORWARDED_HOST; use crate::layer::forwarded::GetForwardedHeadersService; use crate::service::web::WebService; - use crate::Service; use crate::StatusCode; use crate::{Body, HeaderName, Request}; + use rama_core::Service; async fn test_authority_from_request(authority: &str, headers: Vec<(&HeaderName, &str)>) { let svc = GetForwardedHeadersService::x_forwarded_host( diff --git a/rama-http/src/service/web/endpoint/extract/body/bytes.rs b/rama-http/src/service/web/endpoint/extract/body/bytes.rs index 41eb2ea7..a3ad3ffd 100644 --- a/rama-http/src/service/web/endpoint/extract/body/bytes.rs +++ b/rama-http/src/service/web/endpoint/extract/body/bytes.rs @@ -38,8 +38,9 @@ where #[cfg(test)] mod test { use super::*; - use crate::{self, StatusCode}; - use crate::{http::service::web::WebService, service::Service}; + use crate::service::web::WebService; + use crate::{Method, Request, StatusCode}; + use rama_core::Service; #[tokio::test] async fn test_bytes() { @@ -47,8 +48,8 @@ mod test { assert_eq!(body, "test"); }); - let req = http::Request::builder() - .method(http::Method::GET) + let req = Request::builder() + .method(Method::GET) .body("test".into()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); diff --git a/rama-http/src/service/web/endpoint/extract/body/form.rs b/rama-http/src/service/web/endpoint/extract/body/form.rs index 8a6eadf8..e7b216cc 100644 --- a/rama-http/src/service/web/endpoint/extract/body/form.rs +++ b/rama-http/src/service/web/endpoint/extract/body/form.rs @@ -77,9 +77,9 @@ where #[cfg(test)] mod test { use super::*; - use crate; - use crate::StatusCode; - use crate::{http::service::web::WebService, service::Service}; + use crate::service::web::WebService; + use crate::{Body, Method, Request, StatusCode}; + use rama_core::Service; #[tokio::test] async fn test_form_post_form_urlencoded() { @@ -94,9 +94,9 @@ mod test { assert_eq!(body.age, 29); }); - let req = http::Request::builder() + let req = Request::builder() .uri("/") - .method(http::Method::POST) + .method(Method::POST) .header("content-type", "application/x-www-form-urlencoded") .body(r#"name=Devan&age=29"#.into()) .unwrap(); @@ -117,9 +117,9 @@ mod test { panic!("should not reach here"); }); - let req = http::Request::builder() + let req = Request::builder() .uri("/") - .method(http::Method::POST) + .method(Method::POST) .header("content-type", "application/x-www-form-urlencoded") .body(r#"age=29"#.into()) .unwrap(); @@ -140,9 +140,9 @@ mod test { panic!("should not reach here"); }); - let req = http::Request::builder() + let req = Request::builder() .uri("/") - .method(http::Method::GET) + .method(Method::GET) .header("content-type", "application/x-www-form-urlencoded") .body(r#"name=Devan&age=29"#.into()) .unwrap(); @@ -163,10 +163,10 @@ mod test { assert_eq!(body.age, 29); }); - let req = http::Request::builder() + let req = Request::builder() .uri("/?name=Devan&age=29") - .method(http::Method::GET) - .body(http::Body::empty()) + .method(Method::GET) + .body(Body::empty()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); assert_eq!(resp.status(), StatusCode::OK); @@ -185,10 +185,10 @@ mod test { panic!("should not reach here"); }); - let req = http::Request::builder() + let req = Request::builder() .uri("/?name=Devan") - .method(http::Method::GET) - .body(http::Body::empty()) + .method(Method::GET) + .body(Body::empty()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); diff --git a/rama-http/src/service/web/endpoint/extract/body/json.rs b/rama-http/src/service/web/endpoint/extract/body/json.rs index b2f31098..fb0b9416 100644 --- a/rama-http/src/service/web/endpoint/extract/body/json.rs +++ b/rama-http/src/service/web/endpoint/extract/body/json.rs @@ -68,8 +68,9 @@ where #[cfg(test)] mod test { use super::*; + use crate::service::web::WebService; use crate::StatusCode; - use crate::{http::service::web::WebService, service::Service}; + use rama_core::Service; #[tokio::test] async fn test_json() { diff --git a/rama-http/src/service/web/endpoint/extract/body/mod.rs b/rama-http/src/service/web/endpoint/extract/body/mod.rs index 048a4dae..39118385 100644 --- a/rama-http/src/service/web/endpoint/extract/body/mod.rs +++ b/rama-http/src/service/web/endpoint/extract/body/mod.rs @@ -41,8 +41,9 @@ where mod test { use super::*; use crate::dep::http_body_util::BodyExt; - use crate::{self, StatusCode}; - use crate::{http::service::web::WebService, service::Service}; + use crate::service::web::WebService; + use crate::{Method, Request, StatusCode}; + use rama_core::Service; #[tokio::test] async fn test_body() { @@ -51,8 +52,8 @@ mod test { assert_eq!(body, "test"); }); - let req = http::Request::builder() - .method(http::Method::GET) + let req = Request::builder() + .method(Method::GET) .body("test".into()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); diff --git a/rama-http/src/service/web/endpoint/extract/body/text.rs b/rama-http/src/service/web/endpoint/extract/body/text.rs index a3fdb50e..abeefd37 100644 --- a/rama-http/src/service/web/endpoint/extract/body/text.rs +++ b/rama-http/src/service/web/endpoint/extract/body/text.rs @@ -67,8 +67,9 @@ where #[cfg(test)] mod test { use super::*; - use crate::{self, StatusCode}; - use crate::{http::service::web::WebService, service::Service}; + use crate::service::web::WebService; + use crate::{header, Method, Request, StatusCode}; + use rama_core::Service; #[tokio::test] async fn test_text() { @@ -76,9 +77,9 @@ mod test { assert_eq!(body, "test"); }); - let req = http::Request::builder() - .method(http::Method::POST) - .header(http::header::CONTENT_TYPE, "text/plain") + let req = Request::builder() + .method(Method::POST) + .header(header::CONTENT_TYPE, "text/plain") .body("test".into()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); @@ -91,8 +92,8 @@ mod test { unreachable!(); }); - let req = http::Request::builder() - .method(http::Method::POST) + let req = Request::builder() + .method(Method::POST) .body("test".into()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); @@ -105,9 +106,9 @@ mod test { unreachable!(); }); - let req = http::Request::builder() - .method(http::Method::POST) - .header(http::header::CONTENT_TYPE, "application/json") + let req = Request::builder() + .method(Method::POST) + .header(header::CONTENT_TYPE, "application/json") .body("test".into()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); @@ -120,9 +121,9 @@ mod test { unreachable!(); }); - let req = http::Request::builder() - .method(http::Method::POST) - .header(http::header::CONTENT_TYPE, "text/plain") + let req = Request::builder() + .method(Method::POST) + .header(header::CONTENT_TYPE, "text/plain") .body(vec![0, 159, 146, 150].into()) .unwrap(); let resp = service.serve(Context::default(), req).await.unwrap(); diff --git a/rama-http/src/service/web/endpoint/extract/dns.rs b/rama-http/src/service/web/endpoint/extract/dns.rs index e1d9ff8d..af0441ef 100644 --- a/rama-http/src/service/web/endpoint/extract/dns.rs +++ b/rama-http/src/service/web/endpoint/extract/dns.rs @@ -7,7 +7,7 @@ use std::ops::Deref; #[derive(Debug, Clone)] /// Extractor to get a clone of the [`Dns`] from the [`Context`]. /// -/// [`Dns`]: crate::dns::Dns +/// [`Dns`]: rama_core::dns::Dns /// [`Context`]: rama_core::Context pub struct Dns(pub rama_core::dns::Dns); diff --git a/rama-http/src/service/web/endpoint/extract/host.rs b/rama-http/src/service/web/endpoint/extract/host.rs index 509c0edb..8a9ab93c 100644 --- a/rama-http/src/service/web/endpoint/extract/host.rs +++ b/rama-http/src/service/web/endpoint/extract/host.rs @@ -1,9 +1,9 @@ use super::FromRequestParts; use crate::dep::http::request::Parts; use crate::utils::macros::define_http_rejection; -use crate::RequestContext; use rama_core::Context; use rama_net::address; +use rama_net::http::RequestContext; use rama_utils::macros::impl_deref; /// Extractor that resolves the hostname of the request. @@ -57,9 +57,9 @@ mod tests { use crate::header::X_FORWARDED_HOST; use crate::layer::forwarded::GetForwardedHeadersService; use crate::service::web::WebService; - use crate::Service; use crate::StatusCode; use crate::{Body, HeaderName, Request}; + use rama_core::Service; async fn test_host_from_request(host: &str, headers: Vec<(&HeaderName, &str)>) { let svc = GetForwardedHeadersService::x_forwarded_host( diff --git a/rama-http/src/service/web/endpoint/extract/typed_header.rs b/rama-http/src/service/web/endpoint/extract/typed_header.rs index e1980595..374bf03b 100644 --- a/rama-http/src/service/web/endpoint/extract/typed_header.rs +++ b/rama-http/src/service/web/endpoint/extract/typed_header.rs @@ -130,13 +130,11 @@ impl std::error::Error for TypedHeaderRejection { #[cfg(test)] mod tests { use crate::{ - http::{ - headers::ContentType, - service::web::extract::{FromRequestParts, TypedHeader}, - Body, Request, - }, - Context, + headers::ContentType, + service::web::extract::{FromRequestParts, TypedHeader}, + Body, Request, }; + use rama_core::Context; #[tokio::test] async fn test_get_typed_header() { diff --git a/rama-http/src/service/web/endpoint/mod.rs b/rama-http/src/service/web/endpoint/mod.rs index 689c2763..1030565e 100644 --- a/rama-http/src/service/web/endpoint/mod.rs +++ b/rama-http/src/service/web/endpoint/mod.rs @@ -12,7 +12,7 @@ pub(crate) struct Endpoint { /// utility trait to accept multiple types as an endpoint service for [`super::WebService`] pub trait IntoEndpointService: private::Sealed { - /// convert the type into a [`crate::Service`]. + /// convert the type into a [`rama_core::Service`]. fn into_endpoint_service( self, ) -> impl Service; @@ -266,7 +266,7 @@ mod private { #[cfg(test)] mod tests { use super::*; - use crate::{self, dep::http_body_util::BodyExt, Body, Method, Request, StatusCode}; + use crate::{dep::http_body_util::BodyExt, Body, Method, Request, StatusCode}; use extract::*; fn assert_into_endpoint_service(_: I) @@ -287,7 +287,7 @@ mod tests { #[derive(Debug, Clone)] struct OkService; - impl Service for OkService + impl Service for OkService where State: Send + Sync + 'static, { @@ -297,7 +297,7 @@ mod tests { async fn serve( &self, _ctx: Context, - _req: http::Request, + _req: Request, ) -> Result { Ok(StatusCode::OK) } @@ -307,7 +307,7 @@ mod tests { let resp = svc .serve( Context::default(), - http::Request::builder() + Request::builder() .uri("http://example.com") .body(Body::empty()) .unwrap(), @@ -333,7 +333,7 @@ mod tests { let resp = svc .serve( Context::default(), - http::Request::builder() + Request::builder() .uri("http://example.com") .body(Body::empty()) .unwrap(), @@ -351,7 +351,7 @@ mod tests { let resp = svc .serve( Context::default(), - http::Request::builder() + Request::builder() .uri("http://example.com") .body(Body::empty()) .unwrap(), @@ -371,7 +371,7 @@ mod tests { let resp = svc .serve( Context::default(), - http::Request::builder() + Request::builder() .uri("http://example.com") .body(Body::empty()) .unwrap(), @@ -401,7 +401,7 @@ mod tests { let resp = svc .serve( Context::default(), - http::Request::builder() + Request::builder() .uri("http://example.com/42/bar") .body(Body::empty()) .unwrap(), diff --git a/rama-http/src/service/web/endpoint/service.rs b/rama-http/src/service/web/endpoint/service.rs index b9555153..b4c5e612 100644 --- a/rama-http/src/service/web/endpoint/service.rs +++ b/rama-http/src/service/web/endpoint/service.rs @@ -4,7 +4,7 @@ use rama_core::Context; use rama_utils::macros::all_the_tuples_no_last_special_case; use std::future::Future; -/// [`crate::Service`] implemented for functions taking extractors. +/// [`rama_core::Service`] implemented for functions taking extractors. pub trait EndpointServiceFn: private::Sealed + Clone + Send + Sync + 'static { /// Serve a response for the given request. /// diff --git a/rama-http/src/service/web/service.rs b/rama-http/src/service/web/service.rs index 8fce9abc..a8b096a3 100644 --- a/rama-http/src/service/web/service.rs +++ b/rama-http/src/service/web/service.rs @@ -265,14 +265,14 @@ where /// # Example /// /// ```rust -/// use rama::http::matcher::{HttpMatcher, MethodMatcher}; -/// use rama::http::{Body, Request, Response, StatusCode}; -/// use rama::http::dep::http_body_util::BodyExt; -/// use rama::{Context, Service}; +/// use rama_http::matcher::{HttpMatcher, MethodMatcher}; +/// use rama_http::{Body, Request, Response, StatusCode}; +/// use rama_http::dep::http_body_util::BodyExt; +/// use rama_core::{Context, Service}; /// /// #[tokio::main] /// async fn main() { -/// let svc = rama::http::service::web::match_service! { +/// let svc = rama_http::service::web::match_service! { /// HttpMatcher::get("/hello") => "hello", /// HttpMatcher::post("/world") => "world", /// MethodMatcher::CONNECT => "connect", @@ -292,11 +292,11 @@ where /// Which is short for the following: /// /// ```rust -/// use rama::http::matcher::{HttpMatcher, MethodMatcher}; -/// use rama::http::{Body, Request, Response, StatusCode}; -/// use rama::http::dep::http_body_util::BodyExt; -/// use rama::http::service::web::IntoEndpointService; -/// use rama::{Context, Service}; +/// use rama_http::matcher::{HttpMatcher, MethodMatcher}; +/// use rama_http::{Body, Request, Response, StatusCode}; +/// use rama_http::dep::http_body_util::BodyExt; +/// use rama_http::service::web::IntoEndpointService; +/// use rama_core::{Context, Service}; /// /// #[tokio::main] /// async fn main() { @@ -332,8 +332,8 @@ pub use __match_service as match_service; #[cfg(test)] mod test { use crate::dep::http_body_util::BodyExt; + use crate::matcher::MethodMatcher; use crate::Body; - use rama_core::MethodMatcher; use super::*; diff --git a/rama-http/src/utils/macros/http_error.rs b/rama-http/src/utils/macros/http_error.rs index 19115415..3984d87f 100644 --- a/rama-http/src/utils/macros/http_error.rs +++ b/rama-http/src/utils/macros/http_error.rs @@ -7,7 +7,7 @@ macro_rules! __log_http_rejection { status = $status:expr, ) => { tracing::event!( - target: "rama::rejection", + target: "rama_core::servicerejection", tracing::Level::TRACE, status = $status.as_u16(), body = $body_text, diff --git a/rama-http/src/utils/mod.rs b/rama-http/src/utils/mod.rs index 715755cf..a50b2187 100644 --- a/rama-http/src/utils/mod.rs +++ b/rama-http/src/utils/mod.rs @@ -4,5 +4,6 @@ mod header_value; #[doc(inline)] pub use header_value::{HeaderValueErr, HeaderValueGetter}; +#[doc(hidden)] #[macro_use] pub(crate) mod macros; diff --git a/rama-net/src/http/request_context.rs b/rama-net/src/http/request_context.rs index 3f5e3445..54d75d0d 100644 --- a/rama-net/src/http/request_context.rs +++ b/rama-net/src/http/request_context.rs @@ -12,9 +12,7 @@ use rama_http_types::{dep::http::request::Parts, Request, Uri, Version}; use crate::tls::SecureTransport; #[derive(Debug, Clone, PartialEq, Eq)] -/// The context of the [`Request`] being served by the [`HttpServer`] -/// -/// [`HttpServer`]: crate::server::HttpServer +/// The context of the [`Request`]. pub struct RequestContext { /// The HTTP Version. pub http_version: Version, diff --git a/rama-proxy/src/http/mod.rs b/rama-proxy/src/http/mod.rs deleted file mode 100644 index d2b57708..00000000 --- a/rama-proxy/src/http/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Http Proxy Support -//! -//! As defined in . -//! -//! Client side lives in the [`client`] module. -//! -//! There is no explicit server side support for HTTP Proxies, -//! as this is achieved by using the [`HttpServer`] in combination -//! with the upgrade mechanism to establish a tunnel for https -//! or forwarding the request to the target server for http. -//! -//! [`HttpServer`]: crate::http::server::HttpServer - -pub mod client; diff --git a/rama-proxy/src/lib.rs b/rama-proxy/src/lib.rs index 27057ea5..71aaee17 100644 --- a/rama-proxy/src/lib.rs +++ b/rama-proxy/src/lib.rs @@ -1,4 +1,9 @@ -//! proxy protocols and upstream proxy support. +//! rama proxy types and utilities +//! +//! proxy protocols are implemented in their relevant crates: +//! +//! - HaProxy: `rama-haproxy` +//! - HttpProxy: `rama-http-backend` //! //! See the [`ProxyFilter`] for more information on how to select a proxy, //! and the [`ProxyDB`] trait for how to implement a proxy database. @@ -38,7 +43,6 @@ mod username; pub use username::ProxyFilterUsernameParser; -pub mod http; pub mod pp; mod proxydb; diff --git a/rama-ua/src/info.rs b/rama-ua/src/info.rs index f5013bdc..bf1bfc6a 100644 --- a/rama-ua/src/info.rs +++ b/rama-ua/src/info.rs @@ -6,7 +6,7 @@ use std::{convert::Infallible, fmt, str::FromStr}; /// User Agent (UA) information. /// -/// See [the module level documentation](crate::ua) for more information. +/// See [the module level documentation](crate) for more information. #[derive(Debug, Clone)] pub struct UserAgent { pub(super) header: String, @@ -44,7 +44,7 @@ pub struct UserAgentInfo { } impl UserAgent { - /// Create a new [`UserAgent`] from a [`User-Agent` header](crate::http::headers::UserAgent) value. + /// Create a new [`UserAgent`] from a `User-Agent` (header) value. pub fn new(header: impl Into) -> Self { parse_http_user_agent_header(header.into()) } @@ -61,7 +61,7 @@ impl UserAgent { self } - /// Preserve the incoming [`User-Agent` header](crate::http::headers::UserAgent) value. + /// Preserve the incoming `User-Agent` (header) value. /// /// This is used to indicate to emulators that they should respect the User-Agent header /// attached to this [`UserAgent`], if possible. @@ -76,7 +76,7 @@ impl UserAgent { self.preserve_ua_header } - /// returns [the 'User-Agent' http header](crate::http::headers::UserAgent) value used by the [`UserAgent`]. + /// returns the `User-Agent` (header) value used by the [`UserAgent`]. pub fn header_str(&self) -> &str { &self.header } @@ -124,7 +124,7 @@ impl UserAgent { /// returns the [`HttpAgent`] used by the [`UserAgent`]. /// - /// [`UserAgent`]: crate::ua::UserAgent + /// [`UserAgent`]: super::UserAgent pub fn http_agent(&self) -> HttpAgent { match &self.http_agent_overwrite { Some(agent) => agent.clone(), @@ -143,7 +143,7 @@ impl UserAgent { /// returns the [`TlsAgent`] used by the [`UserAgent`]. /// - /// [`UserAgent`]: crate::ua::UserAgent + /// [`UserAgent`]: super::UserAgent pub fn tls_agent(&self) -> TlsAgent { match &self.tls_agent_overwrite { Some(agent) => agent.clone(), @@ -170,8 +170,6 @@ impl FromStr for UserAgent { } /// The kind of [`UserAgent`] -/// -/// [`UserAgent`]: crate::ua::UserAgent #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum UserAgentKind { /// Chromium Browser diff --git a/rama-ua/src/lib.rs b/rama-ua/src/lib.rs index 450152e5..65df0759 100644 --- a/rama-ua/src/lib.rs +++ b/rama-ua/src/lib.rs @@ -1,8 +1,8 @@ //! User Agent (UA) parser and types. //! //! This module provides a parser ([`UserAgent::new`]) for User Agents -//! as well as a classifier ([`UserAgentClassifierLayer`]) that can be used to -//! classify incoming requests based on their [User Agent (header)](crate::http::headers::UserAgent). +//! as well as a classifier (`UserAgentClassifierLayer` in `rama_http`) that can be used to +//! classify incoming requests based on their User Agent (header). //! //! Learn more about User Agents (UA) and why Rama supports it //! at . @@ -102,24 +102,24 @@ pub use info::{ mod parse; use parse::parse_http_user_agent_header; -/// Information that can be used to overwrite the [`UserAgent`] of a [`Request`]. +/// Information that can be used to overwrite the [`UserAgent`] of an http request. /// -/// Used by the [`UserAgentClassifier`] to overwrite the specified +/// Used by the `UserAgentClassifier` (see `rama-http`) to overwrite the specified /// information duing the classification of the [`UserAgent`]. #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct UserAgentOverwrites { - /// Overwrite the [`UserAgent`] of the [`Request`] with a custom value. + /// Overwrite the [`UserAgent`] of the http `Request` with a custom value. /// /// This value will be used instead of - /// [the 'User-Agent' http header](crate::http::headers::UserAgent) value. + /// the 'User-Agent' http (header) value. /// /// This is useful in case you cannot set the User-Agent header in your request. pub ua: Option, - /// Overwrite the [`HttpAgent`] of the [`Request`] with a custom value. + /// Overwrite the [`HttpAgent`] of the http `Request` with a custom value. pub http: Option, - /// Overwrite the [`TlsAgent`] of the [`Request`] with a custom value. + /// Overwrite the [`TlsAgent`] of the http `Request` with a custom value. pub tls: Option, - /// Preserve the original [`UserAgent`] header of the [`Request`]. + /// Preserve the original [`UserAgent`] header of the http `Request`. pub preserve_ua: Option, } diff --git a/src/lib.rs b/src/lib.rs index 93f889fb..208137a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -296,8 +296,16 @@ pub use ::rama_net as net; #[cfg(feature = "http")] pub mod http; -#[cfg(feature = "proxy")] -pub use ::rama_proxy as proxy; +#[cfg(any(feature = "proxy", feature = "haproxy"))] +pub mod proxy { + //! rama proxy support + + #[cfg(feature = "proxy")] + pub use ::rama_proxy::*; + + #[cfg(feature = "haproxy")] + pub use ::rama_haproxy as haproxy; +} #[cfg(feature = "ua")] pub use ::rama_ua as ua; From cdfe461f24148a4ff73baab0f35361b00c6d449d Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 16:11:24 +0200 Subject: [PATCH 09/24] fix fmt/check/doc/test for rama-http-backend --- rama-http-backend/src/client/conn.rs | 2 +- rama-http-backend/src/client/mod.rs | 4 ++-- .../src/client/proxy/layer/proxy_address.rs | 10 +++++----- .../client/proxy/layer/proxy_auth_header.rs | 7 ++----- .../proxy/layer/proxy_connector/connector.rs | 5 +---- .../proxy/layer/proxy_connector/layer.rs | 8 ++++---- .../proxy/layer/proxy_connector/service.rs | 8 ++++---- rama-http-backend/src/client/svc.rs | 8 +++++--- rama-http-backend/src/executor.rs | 2 +- rama-http-backend/src/lib.rs | 2 +- rama-http-backend/src/server/hyper_conn.rs | 8 ++++---- .../src/server/layer/upgrade/layer.rs | 4 ++-- .../src/server/layer/upgrade/service.rs | 2 +- rama-http-backend/src/server/service.rs | 20 +++++++++---------- rama-http-backend/src/server/svc_hyper.rs | 2 +- 15 files changed, 44 insertions(+), 48 deletions(-) diff --git a/rama-http-backend/src/client/conn.rs b/rama-http-backend/src/client/conn.rs index cd404555..0b0f9f3d 100644 --- a/rama-http-backend/src/client/conn.rs +++ b/rama-http-backend/src/client/conn.rs @@ -1,5 +1,6 @@ use super::{svc::SendRequest, HttpClientService}; use crate::executor::HyperExecutor; +use hyper_util::rt::TokioIo; use rama_core::{ error::{BoxError, OpaqueError}, Context, Layer, Service, @@ -9,7 +10,6 @@ use rama_net::{ client::{ConnectorService, EstablishedClientConnection}, stream::Stream, }; -use hyper_util::rt::TokioIo; use rama_utils::macros::define_inner_service_accessors; use std::fmt; use tokio::sync::Mutex; diff --git a/rama-http-backend/src/client/mod.rs b/rama-http-backend/src/client/mod.rs index 6ece48fb..7e2ebc05 100644 --- a/rama-http-backend/src/client/mod.rs +++ b/rama-http-backend/src/client/mod.rs @@ -1,13 +1,13 @@ //! Rama HTTP client module, //! which provides the [`HttpClient`] type to serve HTTP requests. +use proxy::layer::HttpProxyConnector; use rama_core::{ - error::{BoxError, OpaqueError, ErrorExt}, + error::{BoxError, ErrorExt, OpaqueError}, Context, Service, }; use rama_http_types::{dep::http_body, Request, Response}; use rama_net::client::{ConnectorService, EstablishedClientConnection}; -use proxy::layer::HttpProxyConnector; use rama_tcp::client::service::TcpConnector; // TODO: also support client config in boring... diff --git a/rama-http-backend/src/client/proxy/layer/proxy_address.rs b/rama-http-backend/src/client/proxy/layer/proxy_address.rs index 660d90c0..b6ae1daf 100644 --- a/rama-http-backend/src/client/proxy/layer/proxy_address.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_address.rs @@ -2,8 +2,8 @@ use rama_core::{ error::{ErrorContext, OpaqueError}, Context, Layer, Service, }; -use std::{fmt, future::Future}; use rama_net::address::ProxyAddress; +use std::{fmt, future::Future}; #[derive(Debug, Clone, Default)] /// A [`Layer`] which allows you to add a [`ProxyAddress`] @@ -12,8 +12,8 @@ use rama_net::address::ProxyAddress; /// /// See [`HttpProxyAddressService`] for more information. /// -/// [`Context`]: crate::Context -/// [`HttpProxyConnectorLayer`]: crate::proxy::http::client::layer::HttpProxyConnectorLayer +/// [`Context`]: rama_core::Context +/// [`HttpProxyConnectorLayer`]: crate::client::proxy::layer::HttpProxyConnectorLayer pub struct HttpProxyAddressLayer { address: Option, preserve: bool, @@ -88,8 +88,8 @@ impl Layer for HttpProxyAddressLayer { /// to the [`Context`] in order to have your client connector /// make a connection via this proxy (e.g. by using [`HttpProxyConnectorLayer`]). /// -/// [`Context`]: crate::Context -/// [`HttpProxyConnectorLayer`]: crate::proxy::http::client::layer::HttpProxyConnectorLayer +/// [`Context`]: rama_core::Context +/// [`HttpProxyConnectorLayer`]: crate::client::proxy::layer::HttpProxyConnectorLayer pub struct HttpProxyAddressService { inner: S, address: Option, diff --git a/rama-http-backend/src/client/proxy/layer/proxy_auth_header.rs b/rama-http-backend/src/client/proxy/layer/proxy_auth_header.rs index bedfaa9a..6a00cc71 100644 --- a/rama-http-backend/src/client/proxy/layer/proxy_auth_header.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_auth_header.rs @@ -1,12 +1,9 @@ +use rama_core::{Context, Layer, Service}; use rama_http_types::{ headers::{HeaderMapExt, ProxyAuthorization}, Request, }; -use rama_core::{Context, Layer, Service}; -use rama_net::{ - http::RequestContext, - address::ProxyAddress, user::ProxyCredential, -}; +use rama_net::{address::ProxyAddress, http::RequestContext, user::ProxyCredential}; use std::{fmt, future::Future}; #[derive(Debug, Clone, Default)] diff --git a/rama-http-backend/src/client/proxy/layer/proxy_connector/connector.rs b/rama-http-backend/src/client/proxy/layer/proxy_connector/connector.rs index 89801f6d..ab03e7b5 100644 --- a/rama-http-backend/src/client/proxy/layer/proxy_connector/connector.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_connector/connector.rs @@ -6,10 +6,7 @@ use rama_http_types::{ headers::{Header, HeaderMapExt}, HeaderMap, HeaderName, HeaderValue, }; -use rama_net::{ - address::Authority, - stream::Stream, -}; +use rama_net::{address::Authority, stream::Stream}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; #[derive(Debug, Clone)] diff --git a/rama-http-backend/src/client/proxy/layer/proxy_connector/layer.rs b/rama-http-backend/src/client/proxy/layer/proxy_connector/layer.rs index cdf85e22..f821c102 100644 --- a/rama-http-backend/src/client/proxy/layer/proxy_connector/layer.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_connector/layer.rs @@ -14,8 +14,8 @@ impl HttpProxyConnectorLayer { /// which will only connect via an http proxy in case the [`ProxyAddress`] is available /// in the [`Context`]. /// - /// [`Context`]: crate::Context - /// [`ProxyAddress`]: crate::net::address::ProxyAddress + /// [`Context`]: rama_core::Context + /// [`ProxyAddress`]: rama_net::address::ProxyAddress pub fn optional() -> Self { Self { required: false } } @@ -24,8 +24,8 @@ impl HttpProxyConnectorLayer { /// which will always connect via an http proxy, but fail in case the [`ProxyAddress`] is /// not available in the [`Context`]. /// - /// [`Context`]: crate::Context - /// [`ProxyAddress`]: crate::net::address::ProxyAddress + /// [`Context`]: rama_core::Context + /// [`ProxyAddress`]: rama_net::address::ProxyAddress pub fn required() -> Self { Self { required: true } } diff --git a/rama-http-backend/src/client/proxy/layer/proxy_connector/service.rs b/rama-http-backend/src/client/proxy/layer/proxy_connector/service.rs index a96e45bb..55d29d8f 100644 --- a/rama-http-backend/src/client/proxy/layer/proxy_connector/service.rs +++ b/rama-http-backend/src/client/proxy/layer/proxy_connector/service.rs @@ -1,21 +1,21 @@ use super::InnerHttpProxyConnector; -use rama_utils::macros::define_inner_service_accessors; use rama_core::{ error::{BoxError, ErrorExt, OpaqueError}, Context, Service, }; +use rama_http_types::headers::ProxyAuthorization; use rama_net::{ address::ProxyAddress, client::{ConnectorService, EstablishedClientConnection}, - user::ProxyCredential, stream::Stream, transport::TryRefIntoTransportContext, + user::ProxyCredential, }; -use rama_http_types::headers::ProxyAuthorization; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; #[cfg(feature = "tls")] -use crate::tls::HttpsTunnel; +use rama_net::tls::HttpsTunnel; /// A connector which can be used to establish a connection over an HTTP Proxy. /// diff --git a/rama-http-backend/src/client/svc.rs b/rama-http-backend/src/client/svc.rs index dec2aed7..55e6f6a5 100644 --- a/rama-http-backend/src/client/svc.rs +++ b/rama-http-backend/src/client/svc.rs @@ -3,8 +3,8 @@ use rama_core::{ Context, Service, }; use rama_http_types::{ - dep::http::uri::PathAndQuery, dep::http_body, header::HOST, headers::HeaderMapExt, - Request, Response, Version, Method, + dep::http::uri::PathAndQuery, dep::http_body, header::HOST, headers::HeaderMapExt, Method, + Request, Response, Version, }; use rama_net::{address::ProxyAddress, http::RequestContext}; use tokio::sync::Mutex; @@ -91,7 +91,9 @@ fn sanitize_client_req_header( } if !parts.headers.contains_key(HOST) { - parts.headers.typed_insert(rama_http_types::headers::Host::from(authority)); + parts + .headers + .typed_insert(rama_http_types::headers::Host::from(authority)); } parts.uri = rama_http_types::Uri::from_parts(uri_parts)?; diff --git a/rama-http-backend/src/executor.rs b/rama-http-backend/src/executor.rs index 6468db4f..e1b02c9a 100644 --- a/rama-http-backend/src/executor.rs +++ b/rama-http-backend/src/executor.rs @@ -43,7 +43,7 @@ mod tests { let counter = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0)); let (tx, rx) = oneshot::channel(); - let shutdown = crate::graceful::Shutdown::new(async move { + let shutdown = rama_core::graceful::Shutdown::new(async move { rx.await.unwrap(); }); diff --git a/rama-http-backend/src/lib.rs b/rama-http-backend/src/lib.rs index c4f984e5..1bb35331 100644 --- a/rama-http-backend/src/lib.rs +++ b/rama-http-backend/src/lib.rs @@ -52,7 +52,7 @@ #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] -pub mod server; pub mod client; +pub mod server; mod executor; diff --git a/rama-http-backend/src/server/hyper_conn.rs b/rama-http-backend/src/server/hyper_conn.rs index 50e79166..9aaeb1d5 100644 --- a/rama-http-backend/src/server/hyper_conn.rs +++ b/rama-http-backend/src/server/hyper_conn.rs @@ -1,12 +1,12 @@ use super::{svc_hyper::HyperService, HttpServeResult}; use crate::executor::HyperExecutor; -use rama_net::stream::Stream; -use rama_tcp::utils::is_connection_error; -use rama_core::{Context, Service}; -use rama_http_types::{IntoResponse, Request}; use hyper::server::conn::http1::Builder as Http1Builder; use hyper::server::conn::http2::Builder as Http2Builder; use hyper_util::{rt::TokioIo, server::conn::auto::Builder as AutoBuilder}; +use rama_core::{Context, Service}; +use rama_http_types::{IntoResponse, Request}; +use rama_net::stream::Stream; +use rama_tcp::utils::is_connection_error; use rama_utils::future::Fuse; use std::convert::Infallible; use std::error::Error; diff --git a/rama-http-backend/src/server/layer/upgrade/layer.rs b/rama-http-backend/src/server/layer/upgrade/layer.rs index 7b8f5a5b..33aa090e 100644 --- a/rama-http-backend/src/server/layer/upgrade/layer.rs +++ b/rama-http-backend/src/server/layer/upgrade/layer.rs @@ -1,13 +1,13 @@ use super::{service::UpgradeHandler, UpgradeService, Upgraded}; -use rama_http_types::Request; use rama_core::{matcher::Matcher, Context, Layer, Service}; +use rama_http_types::Request; use std::{convert::Infallible, fmt, sync::Arc}; /// UpgradeLayer is a middleware that can be used to upgrade a request. /// /// See [`UpgradeService`] for more details. /// -/// [`UpgradeService`]: crate::layer::upgrade::UpgradeService +/// [`UpgradeService`]: crate::server::layer::upgrade::UpgradeService pub struct UpgradeLayer { handlers: Vec>>, } diff --git a/rama-http-backend/src/server/layer/upgrade/service.rs b/rama-http-backend/src/server/layer/upgrade/service.rs index 0339b6a0..15fb5794 100644 --- a/rama-http-backend/src/server/layer/upgrade/service.rs +++ b/rama-http-backend/src/server/layer/upgrade/service.rs @@ -3,8 +3,8 @@ //! See [`UpgradeService`] for more details. use super::Upgraded; -use rama_http_types::Request; use rama_core::{context::Extensions, matcher::Matcher, service::BoxService, Context, Service}; +use rama_http_types::Request; use rama_utils::macros::define_inner_service_accessors; use std::{convert::Infallible, fmt, sync::Arc}; diff --git a/rama-http-backend/src/server/service.rs b/rama-http-backend/src/server/service.rs index 5dfdfc31..8d4c9dbb 100644 --- a/rama-http-backend/src/server/service.rs +++ b/rama-http-backend/src/server/service.rs @@ -3,10 +3,6 @@ use super::hyper_conn::HyperConnServer; use super::HttpServeResult; use crate::executor::HyperExecutor; -use rama_net::stream::Stream; -use rama_tcp::server::TcpListener; -use rama_core::{Context, Service}; -use rama_http_types::{IntoResponse, Request}; use hyper::server::conn::http2::Builder as H2ConnBuilder; use hyper::{rt::Timer, server::conn::http1::Builder as Http1ConnBuilder}; use hyper_util::server::conn::auto::Builder as AutoConnBuilder; @@ -14,6 +10,10 @@ use hyper_util::server::conn::auto::Http1Builder as InnerAutoHttp1Builder; use hyper_util::server::conn::auto::Http2Builder as InnerAutoHttp2Builder; use rama_core::graceful::ShutdownGuard; use rama_core::rt::Executor; +use rama_core::{Context, Service}; +use rama_http_types::{IntoResponse, Request}; +use rama_net::stream::Stream; +use rama_tcp::server::TcpListener; use std::convert::Infallible; use std::fmt; use std::future::Future; @@ -25,7 +25,7 @@ use tokio::net::ToSocketAddrs; /// /// Supported Protocols: HTTP/1, H2, Auto (HTTP/1 + H2) /// -/// [`Service`]: crate::Service +/// [`Service`]: rama_core::Service pub struct HttpServer { builder: B, } @@ -660,7 +660,7 @@ where /// Same as [`Self::listen`], but it will respect the given [`ShutdownGuard`], /// and also pass it to the service. /// - /// [`ShutdownGuard`]: crate::graceful::ShutdownGuard + /// [`ShutdownGuard`]: rama_core::graceful::ShutdownGuard pub async fn listen_graceful( self, guard: ShutdownGuard, @@ -683,8 +683,8 @@ where /// /// Same as [`Self::listen`], but including the given state in the [`Service`]'s [`Context`]. /// - /// [`Service`]: crate::Service - /// [`Context`]: crate::Context + /// [`Service`]: rama_core::Service + /// [`Context`]: rama_core::Context pub async fn listen_with_state( self, state: State, @@ -709,8 +709,8 @@ where /// /// Same as [`Self::listen_graceful`], but including the given state in the [`Service`]'s [`Context`]. /// - /// [`Service`]: crate::Service - /// [`Context`]: crate::Context + /// [`Service`]: rama_core::Service + /// [`Context`]: rama_core::Context pub async fn listen_graceful_with_state( self, guard: ShutdownGuard, diff --git a/rama-http-backend/src/server/svc_hyper.rs b/rama-http-backend/src/server/svc_hyper.rs index 263b8f12..0bbc19b9 100644 --- a/rama-http-backend/src/server/svc_hyper.rs +++ b/rama-http-backend/src/server/svc_hyper.rs @@ -1,5 +1,5 @@ -use rama_http_types::{BodyLimit, IntoResponse, Request}; use rama_core::{Context, Service}; +use rama_http_types::{BodyLimit, IntoResponse, Request}; use std::{convert::Infallible, fmt, future::Future, pin::Pin, sync::Arc}; /// Wrapper service that implements [`hyper::service::Service`]. From 210321c615e1c2c53f4e1aa34041603b380199cf Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 20:19:52 +0200 Subject: [PATCH 10/24] fix rama-proxy: check/test/fmt/doc --- Cargo.lock | 12 + rama-proxy/Cargo.toml | 21 +- rama-proxy/README.md | 2 +- rama-proxy/src/lib.rs | 264 ++++- rama-proxy/src/pp/client/layer.rs | 843 --------------- rama-proxy/src/pp/client/mod.rs | 7 - rama-proxy/src/pp/mod.rs | 7 - rama-proxy/src/pp/protocol/ip.rs | 62 -- rama-proxy/src/pp/protocol/mod.rs | 126 --- rama-proxy/src/pp/protocol/v1/error.rs | 116 -- rama-proxy/src/pp/protocol/v1/mod.rs | 701 ------------ rama-proxy/src/pp/protocol/v1/model.rs | 307 ------ rama-proxy/src/pp/protocol/v2/builder.rs | 640 ----------- rama-proxy/src/pp/protocol/v2/error.rs | 47 - rama-proxy/src/pp/protocol/v2/mod.rs | 749 ------------- rama-proxy/src/pp/protocol/v2/model.rs | 475 --------- rama-proxy/src/pp/server/layer.rs | 180 ---- rama-proxy/src/pp/server/mod.rs | 7 - rama-proxy/src/proxydb/csv.rs | 167 ++- rama-proxy/src/proxydb/internal.rs | 1241 +--------------------- rama-proxy/src/proxydb/layer.rs | 252 +---- rama-proxy/src/proxydb/mod.rs | 41 +- rama-proxy/src/proxydb/update.rs | 17 +- rama-proxy/src/username.rs | 18 +- 24 files changed, 507 insertions(+), 5795 deletions(-) delete mode 100644 rama-proxy/src/pp/client/layer.rs delete mode 100644 rama-proxy/src/pp/client/mod.rs delete mode 100644 rama-proxy/src/pp/mod.rs delete mode 100644 rama-proxy/src/pp/protocol/ip.rs delete mode 100644 rama-proxy/src/pp/protocol/mod.rs delete mode 100644 rama-proxy/src/pp/protocol/v1/error.rs delete mode 100644 rama-proxy/src/pp/protocol/v1/mod.rs delete mode 100644 rama-proxy/src/pp/protocol/v1/model.rs delete mode 100644 rama-proxy/src/pp/protocol/v2/builder.rs delete mode 100644 rama-proxy/src/pp/protocol/v2/error.rs delete mode 100644 rama-proxy/src/pp/protocol/v2/mod.rs delete mode 100644 rama-proxy/src/pp/protocol/v2/model.rs delete mode 100644 rama-proxy/src/pp/server/layer.rs delete mode 100644 rama-proxy/src/pp/server/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 6e46b062..b50a7a49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2002,7 +2002,19 @@ name = "rama-proxy" version = "0.2.0-alpha.2" dependencies = [ "arc-swap", + "itertools 0.13.0", "rama-core", + "rama-http-types", + "rama-net", + "rama-tcp", + "rama-utils", + "serde", + "serde_html_form", + "serde_json", + "tokio", + "tokio-test", + "tracing", + "unicode-normalization", "venndb", ] diff --git a/rama-proxy/Cargo.toml b/rama-proxy/Cargo.toml index c32a3d3d..aecdaf5e 100644 --- a/rama-proxy/Cargo.toml +++ b/rama-proxy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rama-proxy" -description = "proxy protocols and upstream proxy support for rama" +description = "proxy types and utilities for rama" version = { workspace = true } license = { workspace = true } edition = { workspace = true } @@ -12,16 +12,31 @@ rust-version = { workspace = true } [features] default = ["memory-db", "csv"] -memory-db = ["dep:venndb", "rama-core/venndb"] +memory-db = ["dep:venndb", "rama-core/venndb", "rama-net/venndb"] live-update = ["dep:arc-swap"] -csv = [] +http = ["rama-net/http"] +csv = ["dep:tokio", "tokio/fs"] [dependencies] arc-swap = { workspace = true, optional = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } venndb = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +tokio = { workspace = true, optional = true } +unicode-normalization = { workspace = true } +tracing = { workspace = true } [dev-dependencies] +tokio = { workspace = true, features = ["macros"] } +tokio-test = { workspace = true } +itertools = { workspace = true } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } +rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp", features = ["http"] } +serde_json = { workspace = true } +serde_html_form = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-proxy/README.md b/rama-proxy/README.md index 33936206..2660fad7 100644 --- a/rama-proxy/README.md +++ b/rama-proxy/README.md @@ -39,7 +39,7 @@ The reasons behind the creation of rama can be read in [the "Why Rama" chapter]( ## rama-proxy -Proxy protocols and upstream proxy support for rama. +Proxy types and utilities for rama. Learn more about `rama`: diff --git a/rama-proxy/src/lib.rs b/rama-proxy/src/lib.rs index 71aaee17..d16169a1 100644 --- a/rama-proxy/src/lib.rs +++ b/rama-proxy/src/lib.rs @@ -1,6 +1,6 @@ //! rama proxy types and utilities //! -//! proxy protocols are implemented in their relevant crates: +//! Proxy protocols are implemented in their relevant crates: //! //! - HaProxy: `rama-haproxy` //! - HttpProxy: `rama-http-backend` @@ -15,11 +15,6 @@ //! The [`ProxyDB`] is used by Connection Pools to connect via a proxy, //! in case a [`ProxyFilter`] is present in the [`Context`]'s [`Extensions`]. //! -//! # Proxy Protocols -//! -//! - use [`http`] for http proxy support; -//! - use [`pp`] for HaProxy (Proxy Protocol) support; -//! //! # DB Live Reloads //! //! [`ProxyDB`] implementations like the [`MemoryProxyDB`] feel static in nature, and they are. @@ -38,18 +33,269 @@ //! //! [`Context`]: rama_core::Context //! [`Extensions`]: rama_core::context::Extensions +//! +//! ## ProxyDB layer +//! +//! [`ProxyDB`] layer support to select a proxy based on the given [`Context`]. +//! +//! This layer expects a [`ProxyFilter`] to be available in the [`Context`], +//! which can be added by using the `HeaderConfigLayer` (`rama-http`) +//! when operating on the HTTP layer and/or by parsing it via the TCP proxy username labels (e.g. `john-country-us-residential`), +//! in case you support that as part of your transport-layer authentication. And of course you can +//! combine the two approaches. +//! +//! You can also give a single [`Proxy`] as "proxy db". +//! +//! The end result is that a [`ProxyAddress`] will be set in case a proxy was selected, +//! an error is returned in case no proxy could be selected while one was expected +//! or of course because the inner [`Service`][`rama_core::Service`] failed. +//! +//! [`ProxyAddress`]: rama_net::address::ProxyAddress +//! [`ProxyDB`]: ProxyDB +//! [`Context`]: rama_core::Context +//! +//! # Example +//! +//! ```rust +//! use rama_http_types::{Body, Version, Request}; +//! use rama_proxy::{ +//! MemoryProxyDB, MemoryProxyDBQueryError, ProxyCsvRowReader, Proxy, +//! ProxyDBLayer, ProxyFilterMode, +//! ProxyFilter, +//! }; +//! use rama_core::{ +//! service::service_fn, +//! Context, Service, Layer, +//! }; +//! use rama_net::address::ProxyAddress; +//! use rama_utils::str::NonEmptyString; +//! use itertools::Itertools; +//! use std::{convert::Infallible, sync::Arc}; +//! +//! #[tokio::main] +//! async fn main() { +//! let db = MemoryProxyDB::try_from_iter([ +//! Proxy { +//! id: NonEmptyString::from_static("42"), +//! address: "12.34.12.34:8080".try_into().unwrap(), +//! tcp: true, +//! udp: true, +//! http: true, +//! https: false, +//! socks5: true, +//! socks5h: false, +//! datacenter: false, +//! residential: true, +//! mobile: true, +//! pool_id: None, +//! continent: Some("*".into()), +//! country: Some("*".into()), +//! state: Some("*".into()), +//! city: Some("*".into()), +//! carrier: Some("*".into()), +//! asn: None, +//! }, +//! Proxy { +//! id: NonEmptyString::from_static("100"), +//! address: "123.123.123.123:8080".try_into().unwrap(), +//! tcp: true, +//! udp: false, +//! http: true, +//! https: false, +//! socks5: false, +//! socks5h: false, +//! datacenter: true, +//! residential: false, +//! mobile: false, +//! pool_id: None, +//! continent: None, +//! country: Some("US".into()), +//! state: None, +//! city: None, +//! carrier: None, +//! asn: None, +//! }, +//! ]) +//! .unwrap(); +//! +//! let service = +//! ProxyDBLayer::new(Arc::new(db)).filter_mode(ProxyFilterMode::Default) +//! .layer(service_fn(|ctx: Context<()>, _: Request| async move { +//! Ok::<_, Infallible>(ctx.get::().unwrap().clone()) +//! })); +//! +//! let mut ctx = Context::default(); +//! ctx.insert(ProxyFilter { +//! country: Some(vec!["BE".into()]), +//! mobile: Some(true), +//! residential: Some(true), +//! ..Default::default() +//! }); +//! +//! let req = Request::builder() +//! .version(Version::HTTP_3) +//! .method("GET") +//! .uri("https://example.com") +//! .body(Body::empty()) +//! .unwrap(); +//! +//! let proxy_address = service.serve(ctx, req).await.unwrap(); +//! assert_eq!(proxy_address.authority.to_string(), "12.34.12.34:8080"); +//! } +//! ``` +//! +//! ## Single Proxy Router +//! +//! Another example is a single proxy through which +//! one can connect with config for further downstream proxies +//! passed by username labels. +//! +//! Note that the username formatter is available for any proxy db, +//! it is not specific to the usage of a single proxy. +//! +//! ```rust +//! use rama_http_types::{Body, Version, Request}; +//! use rama_proxy::{ +//! Proxy, +//! ProxyDBLayer, ProxyFilterMode, +//! ProxyFilter, +//! }; +//! use rama_core::{ +//! service::service_fn, +//! Context, Service, Layer, +//! }; +//! use rama_net::address::ProxyAddress; +//! use rama_utils::str::NonEmptyString; +//! use itertools::Itertools; +//! use std::{convert::Infallible, sync::Arc}; +//! +//! #[tokio::main] +//! async fn main() { +//! let proxy = Proxy { +//! id: NonEmptyString::from_static("1"), +//! address: "john:secret@proxy.example.com:60000".try_into().unwrap(), +//! tcp: true, +//! udp: true, +//! http: true, +//! https: false, +//! socks5: true, +//! socks5h: false, +//! datacenter: false, +//! residential: true, +//! mobile: false, +//! pool_id: None, +//! continent: Some("*".into()), +//! country: Some("*".into()), +//! state: Some("*".into()), +//! city: Some("*".into()), +//! carrier: Some("*".into()), +//! asn: None, +//! }; +//! +//! let service = ProxyDBLayer::new(Arc::new(proxy)) +//! .filter_mode(ProxyFilterMode::Default) +//! .username_formatter(|_ctx: &Context<()>, proxy: &Proxy, filter: &ProxyFilter, username: &str| { +//! use std::fmt::Write; +//! +//! let mut output = String::new(); +//! +//! if let Some(countries) = +//! filter.country.as_ref().filter(|t| !t.is_empty()) +//! { +//! let _ = write!(output, "country-{}", countries[0]); +//! } +//! if let Some(states) = +//! filter.state.as_ref().filter(|t| !t.is_empty()) +//! { +//! let _ = write!(output, "state-{}", states[0]); +//! } +//! +//! (!output.is_empty()).then(|| format!("{username}-{output}")) +//! }) +//! .layer(service_fn(|ctx: Context<()>, _: Request| async move { +//! Ok::<_, Infallible>(ctx.get::().unwrap().clone()) +//! })); +//! +//! let mut ctx = Context::default(); +//! ctx.insert(ProxyFilter { +//! country: Some(vec!["BE".into()]), +//! residential: Some(true), +//! ..Default::default() +//! }); +//! +//! let req = Request::builder() +//! .version(Version::HTTP_3) +//! .method("GET") +//! .uri("https://example.com") +//! .body(Body::empty()) +//! .unwrap(); +//! +//! let proxy_address = service.serve(ctx, req).await.unwrap(); +//! assert_eq!( +//! "socks5://john-country-be:secret@proxy.example.com:60000", +//! proxy_address.to_string() +//! ); +//! } +//! ``` -mod username; +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] +mod username; +#[doc(inline)] pub use username::ProxyFilterUsernameParser; -pub mod pp; - mod proxydb; #[doc(inline)] pub use proxydb::{Proxy, ProxyDB, ProxyFilter, ProxyID, ProxyQueryPredicate, StringFilter}; +#[cfg(feature = "http")] +#[doc(inline)] +pub use proxydb::layer::{ProxyDBLayer, ProxyDBService, ProxyFilterMode, UsernameFormatter}; + #[cfg(feature = "live-update")] #[doc(inline)] pub use proxydb::{proxy_db_updater, LiveUpdateProxyDB, LiveUpdateProxyDBSetter}; diff --git a/rama-proxy/src/pp/client/layer.rs b/rama-proxy/src/pp/client/layer.rs deleted file mode 100644 index 2e1dd568..00000000 --- a/rama-proxy/src/pp/client/layer.rs +++ /dev/null @@ -1,843 +0,0 @@ -use std::{fmt, marker::PhantomData, net::IpAddr}; - -use crate::{ - error::{BoxError, ErrorContext, OpaqueError}, - net::{ - client::{ConnectorService, EstablishedClientConnection}, - forwarded::Forwarded, - }, - proxy::pp::protocol::{v1, v2}, - stream::{SocketInfo, Stream}, - Context, Layer, Service, -}; -use tokio::io::AsyncWriteExt; - -/// Layer to encode and write the HaProxy Protocol, -/// as a client on the connected stream. -/// -/// This connector should in most cases -/// happen as the first thing after establishing the connection. -#[derive(Debug, Clone)] -pub struct HaProxyLayer

{ - version: V, - _phantom: PhantomData, -} - -impl HaProxyLayer { - /// Create a new [`HaProxyLayer`] for the TCP protocol (default). - /// - /// This is in the PROXY spec referred to as: - /// - /// - TCP4 (for IPv4, v1) - /// - TCP6 (for IPv6, v1) - /// - Stream (v2) - pub fn tcp() -> Self { - HaProxyLayer { - version: Default::default(), - _phantom: PhantomData, - } - } - - /// Use version one of PROXY protocol, instead of the - /// default version two. - /// - /// Version one makes use of a less advanced text protocol, - /// instead the more advanced binary v2 protocol. - /// - /// Use this only if you have no control over a v1-only server. - pub fn v1(self) -> HaProxyLayer { - HaProxyLayer { - version: Default::default(), - _phantom: PhantomData, - } - } -} - -impl HaProxyLayer { - /// Create a new [`HaProxyLayer`] for the UDP protocol, - /// instead of the default TCP protocol. - /// - /// This is in the PROXY spec referred to as: - /// - /// - Datagram (v2) - pub fn udp() -> Self { - HaProxyLayer { - version: Default::default(), - _phantom: PhantomData, - } - } -} - -impl

HaProxyLayer

{ - /// Attach a custom bytes payload to the PROXY header. - /// - /// NOTE this is only possible in Version two of the PROXY Protocol. - /// In case you downgrade this [`HaProxyLayer`] to version one later - /// using [`Self::v1`] this payload will be dropped. - pub fn payload(mut self, payload: Vec) -> Self { - self.version.payload = Some(payload); - self - } - - /// Attach a custom bytes payload to the PROXY header. - /// - /// NOTE this is only possible in Version two of the PROXY Protocol. - /// In case you downgrade this [`HaProxyLayer`] to version one later - /// using [`Self::v1`] this payload will be dropped. - pub fn set_payload(&mut self, payload: Vec) -> &mut Self { - self.version.payload = Some(payload); - self - } -} - -impl Layer for HaProxyLayer { - type Service = HaProxyService; - - fn layer(&self, inner: S) -> Self::Service { - HaProxyService { - inner, - version: self.version.clone(), - _phantom: PhantomData, - } - } -} - -/// Service to encode and write the HaProxy Protocol -/// as a client on the connected stream. -/// -/// This connector should in most cases -/// happen as the first thing after establishing the connection. -pub struct HaProxyService { - inner: S, - version: V, - _phantom: PhantomData, -} - -impl HaProxyService { - /// Create a new [`HaProxyService`] for the TCP protocol (default). - /// - /// This is in the PROXY spec referred to as: - /// - /// - TCP4 (for IPv4, v1) - /// - TCP6 (for IPv6, v1) - /// - Stream (v2) - pub fn tcp(inner: S) -> Self { - HaProxyService { - inner, - version: Default::default(), - _phantom: PhantomData, - } - } - - /// Use version one of PROXY protocol, instead of the - /// default version two. - /// - /// Version one makes use of a less advanced text protocol, - /// instead the more advanced binary v2 protocol. - /// - /// Use this only if you have no control over a v1-only server. - pub fn v1(self) -> HaProxyService { - HaProxyService { - inner: self.inner, - version: Default::default(), - _phantom: PhantomData, - } - } -} - -impl HaProxyService { - /// Create a new [`HaProxyService`] for the UDP protocol, - /// instead of the default TCP protocol. - /// - /// This is in the PROXY spec referred to as: - /// - /// - Datagram (v2) - pub fn udp(inner: S) -> Self { - HaProxyService { - inner, - version: Default::default(), - _phantom: PhantomData, - } - } -} - -impl HaProxyService { - /// Attach a custom bytes payload to the PROXY header. - /// - /// NOTE this is only possible in Version two of the PROXY Protocol. - /// In case you downgrade this [`HaProxyLayer`] to version one later - /// using [`Self::v1`] this payload will be dropped. - pub fn payload(mut self, payload: Vec) -> Self { - self.version.payload = Some(payload); - self - } - - /// Attach a custom bytes payload to the PROXY header. - /// - /// NOTE this is only possible in Version two of the PROXY Protocol. - /// In case you downgrade this [`HaProxyLayer`] to version one later - /// using [`Self::v1`] this payload will be dropped. - pub fn set_payload(&mut self, payload: Vec) -> &mut Self { - self.version.payload = Some(payload); - self - } -} - -impl fmt::Debug for HaProxyService { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("HaProxyService") - .field("inner", &self.inner) - .field("version", &self.version) - .field( - "_phantom", - &format_args!("{}", std::any::type_name::()), - ) - .finish() - } -} - -impl Clone for HaProxyService { - fn clone(&self) -> Self { - HaProxyService { - inner: self.inner.clone(), - version: self.version.clone(), - _phantom: PhantomData, - } - } -} - -impl Service for HaProxyService -where - S: ConnectorService>, - P: Send + 'static, - State: Send + Sync + 'static, - Request: Send + 'static, -{ - type Response = EstablishedClientConnection; - type Error = BoxError; - - async fn serve( - &self, - ctx: Context, - req: Request, - ) -> Result { - let EstablishedClientConnection { - ctx, - req, - mut conn, - addr, - } = self.inner.connect(ctx, req).await.map_err(Into::into)?; - - let src = ctx - .get::() - .and_then(|f| f.client_socket_addr()) - .or_else(|| ctx.get::().map(|info| *info.peer_addr())) - .ok_or_else(|| { - OpaqueError::from_display("PROXY client (v1): missing src socket address") - })?; - - let addresses = match (src.ip(), addr.ip()) { - (IpAddr::V4(src_ip), IpAddr::V4(dst_ip)) => { - v1::Addresses::new_tcp4(src_ip, dst_ip, src.port(), addr.port()) - } - (IpAddr::V6(src_ip), IpAddr::V6(dst_ip)) => { - v1::Addresses::new_tcp6(src_ip, dst_ip, src.port(), addr.port()) - } - (_, _) => { - return Err(OpaqueError::from_display( - "PROXY client (v1): IP version mismatch between src and dest", - ) - .into()) - } - }; - - conn.write_all(addresses.to_string().as_bytes()) - .await - .context("PROXY client (v1): write addresses")?; - - Ok(EstablishedClientConnection { - ctx, - req, - conn, - addr, - }) - } -} - -impl Service for HaProxyService -where - S: Service< - State, - Request, - Response = EstablishedClientConnection, - Error: Into, - >, - P: protocol::Protocol + Send + 'static, - State: Send + Sync + 'static, - Request: Send + 'static, - T: Stream + Unpin, -{ - type Response = EstablishedClientConnection; - type Error = BoxError; - - async fn serve( - &self, - ctx: Context, - req: Request, - ) -> Result { - let EstablishedClientConnection { - ctx, - req, - mut conn, - addr, - } = self.inner.serve(ctx, req).await.map_err(Into::into)?; - - let src = ctx - .get::() - .and_then(|f| f.client_socket_addr()) - .or_else(|| ctx.get::().map(|info| *info.peer_addr())) - .ok_or_else(|| { - OpaqueError::from_display("PROXY client (v2): missing src socket address") - })?; - - let builder = match (src.ip(), addr.ip()) { - (IpAddr::V4(src_ip), IpAddr::V4(dst_ip)) => v2::Builder::with_addresses( - v2::Version::Two | v2::Command::Proxy, - P::v2_protocol(), - v2::IPv4::new(src_ip, dst_ip, src.port(), addr.port()), - ), - (IpAddr::V6(src_ip), IpAddr::V6(dst_ip)) => v2::Builder::with_addresses( - v2::Version::Two | v2::Command::Proxy, - P::v2_protocol(), - v2::IPv6::new(src_ip, dst_ip, src.port(), addr.port()), - ), - (_, _) => { - return Err(OpaqueError::from_display( - "PROXY client (v2): IP version mismatch between src and dest", - ) - .into()) - } - }; - - let builder = if let Some(payload) = self.version.payload.as_deref() { - builder - .write_payload(payload) - .context("PROXY client (v2): write custom binary payload to to header")? - } else { - builder - }; - - let header = builder - .build() - .context("PROXY client (v2): encode header")?; - conn.write_all(&header[..]) - .await - .context("PROXY client (v2): write header")?; - - Ok(EstablishedClientConnection { - ctx, - req, - conn, - addr, - }) - } -} - -pub mod version { - //! Marker traits for the HaProxy (PROXY) version to be used by client layer (service). - - #[derive(Debug, Clone, Default)] - /// Use version 1 of the PROXY protocol. - /// - /// See [`crate::proxy::pp::protocol`] for more information. - #[non_exhaustive] - pub struct One; - - #[derive(Debug, Clone, Default)] - /// Use version 2 of the PROXY protocol. - /// - /// See [`crate::proxy::pp::protocol`] for more information. - pub struct Two { - pub(crate) payload: Option>, - } -} - -pub mod protocol { - //! Marker traits for the HaProxy (PROXY) protocol to be used by client layer (service). - - use crate::proxy::pp::protocol::v2; - - #[derive(Debug, Clone)] - /// Encode the data for the TCP protocol (possible in [`super::version::One`] and [`super::version::Two`]). - /// - /// See [`crate::proxy::pp::protocol`] for more information. - pub struct Tcp; - - #[derive(Debug, Clone)] - /// Encode the data for the UDP protocol (possible only in [`super::version::Two`]). - /// - /// See [`crate::proxy::pp::protocol`] for more information. - pub struct Udp; - - pub(super) trait Protocol { - /// Return the v2 PROXY protocol linked to the protocol implementation. - fn v2_protocol() -> v2::Protocol; - } - - impl Protocol for Tcp { - fn v2_protocol() -> v2::Protocol { - v2::Protocol::Stream - } - } - - impl Protocol for Udp { - fn v2_protocol() -> v2::Protocol { - v2::Protocol::Datagram - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - net::forwarded::{ForwardedElement, NodeId}, - service::service_fn, - Layer, - }; - use std::convert::Infallible; - use tokio_test::io::Builder; - - #[tokio::test] - async fn test_v1_tcp() { - for (expected_line, input_ctx, target_addr) in [ - ( - "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n", - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); - ctx - }, - "192.168.1.101:443", - ), - ( - "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n", - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443".parse().unwrap())); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for(NodeId::try_from("127.0.1.2:80").unwrap()))); - ctx - }, - "192.168.1.101:443", - ), - ( - "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n", - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443".parse().unwrap())); - ctx - }, - "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", - ), - ( - "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n", - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for(NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443").unwrap()))); - ctx - }, - "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", - ), - ] { - let svc = HaProxyLayer::tcp().v1() - .layer(service_fn(move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new().write(expected_line.as_bytes()).build(), - addr: target_addr.parse().unwrap(), - }) - })); - svc.serve(input_ctx, ()).await.unwrap(); - } - } - - #[tokio::test] - async fn test_v1_tcp_ip_version_mismatch() { - for (input_ctx, target_addr) in [ - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" - .parse() - .unwrap(), - )); - ctx - }, - "192.168.1.101:443", - ), - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), - ))); - ctx - }, - "192.168.1.101:443", - ), - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); - ctx - }, - "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", - ), - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" - .parse() - .unwrap(), - )); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("127.0.1.2:80").unwrap(), - ))); - ctx - }, - "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", - ), - ] { - let svc = HaProxyLayer::tcp() - .v1() - .layer(service_fn(move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new().build(), - addr: target_addr.parse().unwrap(), - }) - })); - assert!(svc.serve(input_ctx, ()).await.is_err()); - } - } - - #[tokio::test] - async fn test_v1_tcp_missing_src() { - for (input_ctx, target_addr) in [ - (Context::default(), "192.168.1.101:443"), - ( - Context::default(), - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443", - ), - ] { - let svc = HaProxyLayer::tcp() - .v1() - .layer(service_fn(move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new().build(), - addr: target_addr.parse().unwrap(), - }) - })); - assert!(svc.serve(input_ctx, ()).await.is_err()); - } - } - - #[tokio::test] - async fn test_v2_tcp4() { - for input_ctx in [ - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); - ctx - }, - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443" - .parse() - .unwrap(), - )); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("127.0.0.1:80").unwrap(), - ))); - ctx - }, - ] { - let svc = HaProxyLayer::tcp().payload(vec![42]).layer(service_fn( - move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new() - .write(&[ - b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', - b'T', b'\n', 0x21, 0x11, 0, 13, 127, 0, 0, 1, 192, 168, 1, 1, 0, - 80, 1, 187, 42, - ]) - .build(), - addr: "192.168.1.1:443".parse().unwrap(), - }) - }, - )); - svc.serve(input_ctx, ()).await.unwrap(); - } - } - - #[tokio::test] - async fn test_v2_udp4() { - for input_ctx in [ - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); - ctx - }, - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443" - .parse() - .unwrap(), - )); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("127.0.0.1:80").unwrap(), - ))); - ctx - }, - ] { - let svc = HaProxyLayer::udp().payload(vec![42]).layer(service_fn( - move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new() - .write(&[ - b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', - b'T', b'\n', 0x21, 0x12, 0, 13, 127, 0, 0, 1, 192, 168, 1, 1, 0, - 80, 1, 187, 42, - ]) - .build(), - addr: "192.168.1.1:443".parse().unwrap(), - }) - }, - )); - svc.serve(input_ctx, ()).await.unwrap(); - } - } - - #[tokio::test] - async fn test_v2_tcp6() { - for input_ctx in [ - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" - .parse() - .unwrap(), - )); - ctx - }, - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), - ))); - ctx - }, - ] { - let svc = HaProxyLayer::tcp().payload(vec![42]).layer(service_fn( - move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new() - .write(&[ - b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', - b'T', b'\n', 0x21, 0x21, 0, 37, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, - 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0x43, - 0x21, 0x87, 0x65, 0xba, 0x09, 0xfe, 0xdc, 0xcd, 0xef, 0x90, 0xab, - 0x56, 0x78, 0x12, 0x34, 0, 80, 1, 187, 42, - ]) - .build(), - addr: "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:443" - .parse() - .unwrap(), - }) - }, - )); - svc.serve(input_ctx, ()).await.unwrap(); - } - } - - #[tokio::test] - async fn test_v2_udp6() { - for input_ctx in [ - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" - .parse() - .unwrap(), - )); - ctx - }, - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.0.1:80".parse().unwrap())); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), - ))); - ctx - }, - ] { - let svc = HaProxyLayer::udp().payload(vec![42]).layer(service_fn( - move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new() - .write(&[ - b'\r', b'\n', b'\r', b'\n', b'\0', b'\r', b'\n', b'Q', b'U', b'I', - b'T', b'\n', 0x21, 0x22, 0, 37, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, - 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0x43, - 0x21, 0x87, 0x65, 0xba, 0x09, 0xfe, 0xdc, 0xcd, 0xef, 0x90, 0xab, - 0x56, 0x78, 0x12, 0x34, 0, 80, 1, 187, 42, - ]) - .build(), - addr: "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:443" - .parse() - .unwrap(), - }) - }, - )); - svc.serve(input_ctx, ()).await.unwrap(); - } - } - - #[tokio::test] - async fn test_v2_ip_version_mismatch() { - for (input_ctx, target_addr) in [ - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" - .parse() - .unwrap(), - )); - ctx - }, - "192.168.1.101:443", - ), - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80").unwrap(), - ))); - ctx - }, - "192.168.1.101:443", - ), - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new(None, "127.0.1.2:80".parse().unwrap())); - ctx - }, - "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", - ), - ( - { - let mut ctx = Context::default(); - ctx.insert(SocketInfo::new( - None, - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:80" - .parse() - .unwrap(), - )); - ctx.insert(Forwarded::new(ForwardedElement::forwarded_for( - NodeId::try_from("127.0.1.2:80").unwrap(), - ))); - ctx - }, - "[4321:8765:ba09:fedc:cdef:90ab:5678:1234]:65535", - ), - ] { - // TCP - - let svc = HaProxyLayer::tcp().layer(service_fn(move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new().build(), - addr: target_addr.parse().unwrap(), - }) - })); - assert!(svc.serve(input_ctx.clone(), ()).await.is_err()); - - // UDP - - let svc = HaProxyLayer::udp().layer(service_fn(move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new().build(), - addr: target_addr.parse().unwrap(), - }) - })); - assert!(svc.serve(input_ctx, ()).await.is_err()); - } - } - - #[tokio::test] - async fn test_v2_missing_src() { - for (input_ctx, target_addr) in [ - (Context::default(), "192.168.1.101:443"), - ( - Context::default(), - "[1234:5678:90ab:cdef:fedc:ba09:8765:4321]:443", - ), - ] { - // TCP - - let svc = HaProxyLayer::tcp().layer(service_fn(move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new().build(), - addr: target_addr.parse().unwrap(), - }) - })); - assert!(svc.serve(input_ctx.clone(), ()).await.is_err()); - - // UDP - - let svc = HaProxyLayer::udp().layer(service_fn(move |ctx, req| async move { - Ok::<_, Infallible>(EstablishedClientConnection { - ctx, - req, - conn: Builder::new().build(), - addr: target_addr.parse().unwrap(), - }) - })); - assert!(svc.serve(input_ctx.clone(), ()).await.is_err()); - } - } -} diff --git a/rama-proxy/src/pp/client/mod.rs b/rama-proxy/src/pp/client/mod.rs deleted file mode 100644 index 4a1d196e..00000000 --- a/rama-proxy/src/pp/client/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! HaProxy Protocol Client support -//! -//! - -mod layer; -#[doc(inline)] -pub use layer::{protocol, version, HaProxyLayer, HaProxyService}; diff --git a/rama-proxy/src/pp/mod.rs b/rama-proxy/src/pp/mod.rs deleted file mode 100644 index c1796a10..00000000 --- a/rama-proxy/src/pp/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Proxy Protocol support -//! -//! - -pub mod client; -pub mod protocol; -pub mod server; diff --git a/rama-proxy/src/pp/protocol/ip.rs b/rama-proxy/src/pp/protocol/ip.rs deleted file mode 100644 index d4cfcc5c..00000000 --- a/rama-proxy/src/pp/protocol/ip.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Models for storing IP v4 and v6 addresses and ports. - -use std::net::{Ipv4Addr, Ipv6Addr}; - -/// The source and destination IPv4 addresses and TCP ports of a header. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct IPv4 { - /// The source IPv4 address. - pub source_address: Ipv4Addr, - /// The source TCP/UDP port. - pub source_port: u16, - /// The destination IPv4 address. - pub destination_address: Ipv4Addr, - /// The destination TCP/UDP port. - pub destination_port: u16, -} - -impl IPv4 { - /// Create a new IPv4 addresses. - pub fn new>( - source_address: T, - destination_address: T, - source_port: u16, - destination_port: u16, - ) -> Self { - IPv4 { - source_address: source_address.into(), - source_port, - destination_address: destination_address.into(), - destination_port, - } - } -} -/// The source and destination IPv6 addresses and TCP ports of a header. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct IPv6 { - /// The source IPv6 address. - pub source_address: Ipv6Addr, - /// The source TCP/UDP port. - pub source_port: u16, - /// The destination IPv6 address. - pub destination_address: Ipv6Addr, - /// The destination TCP/UDP port. - pub destination_port: u16, -} - -impl IPv6 { - /// Create a new IPv6 addresses. - pub fn new>( - source_address: T, - destination_address: T, - source_port: u16, - destination_port: u16, - ) -> Self { - IPv6 { - source_address: source_address.into(), - source_port, - destination_address: destination_address.into(), - destination_port, - } - } -} diff --git a/rama-proxy/src/pp/protocol/mod.rs b/rama-proxy/src/pp/protocol/mod.rs deleted file mode 100644 index 5c517ca0..00000000 --- a/rama-proxy/src/pp/protocol/mod.rs +++ /dev/null @@ -1,126 +0,0 @@ -//! A Proxy Protocol Parser written in Rust. -//! Supports both text and binary versions of the header protocol. -//! -//! Forked from (Apache-2.0 license), -//! a crate originally developed by Miguel D. Salcedo. The fork happened -//! on commit `28c5db92fda7337fc1ef36e6f19db96d511cd319`. - -mod ip; - -pub mod v1; -pub mod v2; - -/// The canonical way to determine when a streamed header should be retried in a streaming context. -/// The protocol states that servers may choose to support partial headers or to close the connection if the header is not present all at once. -pub trait PartialResult { - /// Tests whether this `Result` is successful or whether the error is terminal. - /// A terminal error will not result in a success even with more bytes. - /// Retrying with the same -- or more -- input will not change the result. - fn is_complete(&self) -> bool { - !self.is_incomplete() - } - - /// Tests whether this `Result` is incomplete. - /// An action that leads to an incomplete result may have a different result with more bytes. - /// Retrying with the same input will not change the result. - fn is_incomplete(&self) -> bool; -} - -impl PartialResult for Result { - fn is_incomplete(&self) -> bool { - match self { - Ok(_) => false, - Err(error) => error.is_incomplete(), - } - } -} - -impl PartialResult for v1::ParseError { - fn is_incomplete(&self) -> bool { - matches!( - self, - v1::ParseError::Partial - | v1::ParseError::MissingPrefix - | v1::ParseError::MissingProtocol - | v1::ParseError::MissingSourceAddress - | v1::ParseError::MissingDestinationAddress - | v1::ParseError::MissingSourcePort - | v1::ParseError::MissingDestinationPort - | v1::ParseError::MissingNewLine - ) - } -} - -impl PartialResult for v1::BinaryParseError { - fn is_incomplete(&self) -> bool { - match self { - v1::BinaryParseError::Parse(error) => error.is_incomplete(), - v1::BinaryParseError::InvalidUtf8(_) => false, - } - } -} - -impl PartialResult for v2::ParseError { - fn is_incomplete(&self) -> bool { - matches!( - self, - v2::ParseError::Incomplete(..) | v2::ParseError::Partial(..) - ) - } -} - -/// An enumeration of the supported header version's parse results. -/// Useful for parsing either version 1 or version 2 of the PROXY protocol. -/// -/// ## Examples -/// ```rust -/// use rama::proxy::pp::protocol::{HeaderResult, PartialResult, v1, v2}; -/// -/// let input = "PROXY UNKNOWN\r\n"; -/// let header = HeaderResult::parse(input.as_bytes()); -/// -/// assert_eq!(header, Ok(v1::Header::new(input, v1::Addresses::Unknown)).into()); -/// ``` -#[derive(Debug, Clone, PartialEq, Eq)] -#[must_use = "this `HeaderResult` may contain a V1 or V2 `Err` variant, which should be handled"] -pub enum HeaderResult<'a> { - /// Version 1 of the PROXY protocol header. - V1(Result, v1::BinaryParseError>), - /// Version 2 of the PROXY protocol header. - V2(Result, v2::ParseError>), -} - -impl<'a> From, v1::BinaryParseError>> for HeaderResult<'a> { - fn from(result: Result, v1::BinaryParseError>) -> Self { - HeaderResult::V1(result) - } -} - -impl<'a> From, v2::ParseError>> for HeaderResult<'a> { - fn from(result: Result, v2::ParseError>) -> Self { - HeaderResult::V2(result) - } -} - -impl<'a> PartialResult for HeaderResult<'a> { - fn is_incomplete(&self) -> bool { - match self { - Self::V1(result) => result.is_incomplete(), - Self::V2(result) => result.is_incomplete(), - } - } -} - -impl<'a> HeaderResult<'a> { - /// Parses a PROXY protocol version 2 `Header`. - /// If the input is not a valid version 2 `Header`, attempts to parse a version 1 `Header`. - pub fn parse(input: &'a [u8]) -> HeaderResult<'a> { - let header = v2::Header::try_from(input); - - if header.is_complete() && header.is_err() { - v1::Header::try_from(input).into() - } else { - header.into() - } - } -} diff --git a/rama-proxy/src/pp/protocol/v1/error.rs b/rama-proxy/src/pp/protocol/v1/error.rs deleted file mode 100644 index dbe88bf1..00000000 --- a/rama-proxy/src/pp/protocol/v1/error.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Errors for the text proxy protocol. - -use std::fmt; - -/// An error in parsing a text PROXY protocol header. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ParseError { - /// Header must start with 'PROXY'. - InvalidPrefix, - /// Header is only partially present. - Partial, - /// Header is empty. - MissingPrefix, - /// Header does not end with the string '\r\n'. - MissingNewLine, - /// Header missing protocol. - MissingProtocol, - /// Header missing source address. - MissingSourceAddress, - /// Header missing destination address. - MissingDestinationAddress, - /// Header missing source port. - MissingSourcePort, - /// Header missing destination port. - MissingDestinationPort, - /// Header does not fit within the expected buffer size of 107 bytes (plus 1 byte for null-terminated strings). - HeaderTooLong, - /// Header has an invalid protocol. - InvalidProtocol, - /// Header must end in '\r\n'. - InvalidSuffix, - /// Header contains invalid IP address for the source. - InvalidSourceAddress(std::net::AddrParseError), - /// Header contains invalid IP address for the destination. - InvalidDestinationAddress(std::net::AddrParseError), - /// Header contains invalid TCP port for the source. - InvalidSourcePort(Option), - /// Header contains invalid TCP port for the destination.] - InvalidDestinationPort(Option), -} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidPrefix => write!(f, "Header must start with 'PROXY'."), - Self::Partial => write!(f, "Header is only partially present."), - Self::MissingPrefix => write!(f, "Header is empty."), - Self::MissingNewLine => write!(f, "Header does not end with the string '\\r\\n'."), - Self::MissingProtocol => write!(f, "Header missing protocol."), - Self::MissingSourceAddress => write!(f, "Header missing source address."), - Self::MissingDestinationAddress => write!(f, "Header missing destination address."), - Self::MissingSourcePort => write!(f, "Header missing source port."), - Self::MissingDestinationPort => write!(f, "Header missing destination port."), - Self::HeaderTooLong => write!(f, "Header does not fit within the expected buffer size of 107 bytes (plus 1 byte for null-terminated strings)."), - Self::InvalidProtocol => write!(f, "Header has an invalid protocol."), - Self::InvalidSuffix => write!(f, "Header must end in '\r\n'."), - Self::InvalidSourceAddress(source) => write!(f, "Header contains invalid IP address for the source: {}", source), - Self::InvalidDestinationAddress(destination) => write!(f, "Header contains invalid IP address for the destination: {}", destination), - Self::InvalidSourcePort(port) => write!(f, "Header contains invalid TCP port for the source: {}", port.as_ref().map(|e| e.to_string()).unwrap_or_default()), - Self::InvalidDestinationPort(port) => write!(f, "Header contains invalid TCP port for the destination: {}", port.as_ref().map(|e| e.to_string()).unwrap_or_default()), - } - } -} - -impl std::error::Error for ParseError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::InvalidSourceAddress(source) => Some(source), - Self::InvalidDestinationAddress(destination) => Some(destination), - Self::InvalidSourcePort(port) => port.as_ref().map(|e| e as &dyn std::error::Error), - Self::InvalidDestinationPort(port) => { - port.as_ref().map(|e| e as &dyn std::error::Error) - } - _ => None, - } - } -} - -/// An error in parsing a text PROXY protocol header that is represented as a byte slice. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum BinaryParseError { - /// An error in parsing a binary PROXY protocol header. - Parse(ParseError), - /// Header is not valid UTF-8. - InvalidUtf8(std::str::Utf8Error), -} - -impl From for BinaryParseError { - fn from(error: ParseError) -> Self { - Self::Parse(error) - } -} - -impl From for BinaryParseError { - fn from(error: std::str::Utf8Error) -> Self { - Self::InvalidUtf8(error) - } -} - -impl fmt::Display for BinaryParseError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Parse(error) => write!(f, "{}", error), - Self::InvalidUtf8(error) => write!(f, "Header is not valid UTF-8: {}", error), - } - } -} - -impl std::error::Error for BinaryParseError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::Parse(error) => Some(error), - Self::InvalidUtf8(error) => Some(error), - } - } -} diff --git a/rama-proxy/src/pp/protocol/v1/mod.rs b/rama-proxy/src/pp/protocol/v1/mod.rs deleted file mode 100644 index 58faf591..00000000 --- a/rama-proxy/src/pp/protocol/v1/mod.rs +++ /dev/null @@ -1,701 +0,0 @@ -//! Version 1 of the HAProxy protocol (text version). -//! -//! See - -mod error; -mod model; - -pub use crate::proxy::pp::protocol::ip::{IPv4, IPv6}; -pub use error::{BinaryParseError, ParseError}; -pub use model::{Addresses, Header, SEPARATOR, TCP4, TCP6, UNKNOWN}; -pub use model::{PROTOCOL_PREFIX, PROTOCOL_SUFFIX}; -use std::borrow::Cow; -use std::net::{AddrParseError, Ipv4Addr, Ipv6Addr}; -use std::str::{from_utf8, FromStr}; - -const ZERO: &str = "0"; -const NEWLINE: &str = "\n"; -const CARRIAGE_RETURN: char = '\r'; - -/// The maximum length of a header in bytes. -const MAX_LENGTH: usize = 107; -/// The total number of parts in the header. -const PARTS: usize = 7; - -/// Parses a text PROXY protocol header. -/// The given string is expected to only include the header and to end in \r\n. -fn parse_header(header: &str) -> Result { - if header.is_empty() { - return Err(ParseError::MissingPrefix); - } else if header.len() > MAX_LENGTH { - return Err(ParseError::HeaderTooLong); - } - - let mut iterator = header - .splitn(PARTS, |c| c == SEPARATOR || c == CARRIAGE_RETURN) - .peekable(); - - let prefix = iterator.next().ok_or(ParseError::MissingPrefix)?; - - if !prefix.is_empty() && PROTOCOL_PREFIX.starts_with(prefix) && header.ends_with(prefix) { - return Err(ParseError::Partial); - } else if prefix != PROTOCOL_PREFIX { - return Err(ParseError::InvalidPrefix); - } - - let addresses = match iterator.next() { - Some(TCP4) => { - let (source_address, destination_address, source_port, destination_port) = - parse_addresses::(&mut iterator)?; - - Addresses::Tcp4(IPv4 { - source_address, - source_port, - destination_address, - destination_port, - }) - } - Some(TCP6) => { - let (source_address, destination_address, source_port, destination_port) = - parse_addresses::(&mut iterator)?; - - Addresses::Tcp6(IPv6 { - source_address, - source_port, - destination_address, - destination_port, - }) - } - Some(UNKNOWN) => { - while iterator.next_if(|&s| s != NEWLINE).is_some() {} - - Addresses::Unknown - } - Some(protocol) if protocol.is_empty() && iterator.peek().is_none() => { - return Err(ParseError::MissingProtocol) - } - Some(protocol) - if !protocol.is_empty() - && header.ends_with(protocol) - && (TCP4.starts_with(protocol) || UNKNOWN.starts_with(protocol)) => - { - return Err(ParseError::Partial) - } - Some(_) => return Err(ParseError::InvalidProtocol), - None => return Err(ParseError::MissingProtocol), - }; - - let newline = iterator - .next() - .filter(|s| !s.is_empty()) - .ok_or(ParseError::MissingNewLine)?; - - if newline != NEWLINE { - return Err(ParseError::InvalidSuffix); - } - - Ok(Header { - header: Cow::Borrowed(header), - addresses, - }) -} - -/// Parses the addresses and ports from a PROXY protocol header for IPv4 and IPv6. -fn parse_addresses<'a, T: FromStr, I: Iterator>( - iterator: &mut I, -) -> Result<(T, T, u16, u16), ParseError> { - let source_address = iterator.next().ok_or(ParseError::MissingSourceAddress)?; - let destination_address = iterator - .next() - .ok_or(ParseError::MissingDestinationAddress)?; - let source_port = iterator.next().ok_or(ParseError::MissingSourcePort)?; - let destination_port = iterator.next().ok_or(ParseError::MissingDestinationPort)?; - - let source_address = source_address - .parse::() - .map_err(ParseError::InvalidSourceAddress)?; - let destination_address = destination_address - .parse::() - .map_err(ParseError::InvalidDestinationAddress)?; - - if source_port.starts_with(ZERO) && source_port != ZERO { - return Err(ParseError::InvalidSourcePort(None)); - } - - let source_port = source_port - .parse::() - .map_err(|e| ParseError::InvalidSourcePort(Some(e)))?; - - if destination_port.starts_with(ZERO) && destination_port != ZERO { - return Err(ParseError::InvalidDestinationPort(None)); - } - - let destination_port = destination_port - .parse::() - .map_err(|e| ParseError::InvalidDestinationPort(Some(e)))?; - - Ok(( - source_address, - destination_address, - source_port, - destination_port, - )) -} - -impl<'a> TryFrom<&'a str> for Header<'a> { - type Error = ParseError; - - fn try_from(input: &'a str) -> Result { - let length = match input.find(CARRIAGE_RETURN) { - Some(suffix) => suffix + PROTOCOL_SUFFIX.len(), - None if input.len() >= MAX_LENGTH => return Err(ParseError::HeaderTooLong), - None => input.len(), - }; - - parse_header(&input[..length]) - } -} - -impl<'a> TryFrom<&'a [u8]> for Header<'a> { - type Error = BinaryParseError; - - fn try_from(input: &'a [u8]) -> Result { - let length = match input.iter().position(|&c| CARRIAGE_RETURN == (c as char)) { - Some(suffix) => suffix + PROTOCOL_SUFFIX.len(), - None if input.len() >= MAX_LENGTH => return Err(ParseError::HeaderTooLong.into()), - None => input.len(), - }; - let header = from_utf8(&input[..length])?; - - parse_header(header).map_err(BinaryParseError::Parse) - } -} - -impl FromStr for Addresses { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - Ok(Header::try_from(s)?.addresses) - } -} - -impl FromStr for Header<'static> { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - Ok(Header::try_from(s)?.to_owned()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[allow(invalid_from_utf8)] - fn bytes_invalid_utf8() { - let text = b"Hello \xF0\x90\x80World\r\n"; - - assert_eq!( - Header::try_from(&text[..]).unwrap_err(), - BinaryParseError::InvalidUtf8(from_utf8(text).unwrap_err()) - ); - } - - #[test] - fn exact_tcp4() { - let ip: Ipv4Addr = "255.255.255.255".parse().unwrap(); - let port = 65535; - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; - let expected = Header::new(text, Addresses::new_tcp4(ip, ip, port, port)); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn valid_tcp4() { - let ip: Ipv4Addr = "255.255.255.255".parse().unwrap(); - let port = 65535; - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\nFoobar"; - let expected = Header::new( - "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n", - Addresses::new_tcp4(ip, ip, port, port), - ); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn parse_partial() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535"; - - assert_eq!( - Header::try_from(text).unwrap_err(), - ParseError::MissingNewLine - ); - assert_eq!( - Header::try_from(text.as_bytes()).unwrap_err(), - ParseError::MissingNewLine.into() - ); - } - - #[test] - fn parse_tcp4_invalid() { - let text = "PROXY TCP4 255.255.255.255 256.255.255.255 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidDestinationAddress( - "".parse::().unwrap_err() - )) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidDestinationAddress("".parse::().unwrap_err()).into()) - ); - } - - #[test] - fn parse_tcp4_leading_zeroes() { - let text = "PROXY TCP4 255.0255.255.255 255.255.255.255 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidSourceAddress( - "".parse::().unwrap_err() - )) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) - ); - } - - #[test] - fn parse_unknown_connection() { - let text = "PROXY UNKNOWN\r\nTwo"; - - assert_eq!( - Header::try_from(text), - Ok(Header::new("PROXY UNKNOWN\r\n", Addresses::default())) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Ok(Header::new("PROXY UNKNOWN\r\n", Addresses::default())) - ); - } - - #[test] - fn valid_tcp6() { - let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); - let port = 65535; - let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\nHi!"; - let expected = Header::new("PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n", Addresses::new_tcp6(ip, ip, port, port)); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn valid_tcp6_short() { - let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); - let port = 65535; - let short_ip = "::1".parse().unwrap(); - let text = "PROXY TCP6 ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\nHi!"; - let expected = Header::new( - "PROXY TCP6 ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n", - Addresses::new_tcp6(short_ip, ip, port, port), - ); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn parse_tcp6_invalid() { - let text = "PROXY TCP6 ffff:gggg:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidSourceAddress( - "".parse::().unwrap_err() - )) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) - ); - } - - #[test] - fn parse_tcp6_leading_zeroes() { - let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:0ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidDestinationAddress( - "".parse::().unwrap_err() - )) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidDestinationAddress("".parse::().unwrap_err()).into()) - ); - } - - #[test] - fn parse_tcp6_shortened_connection() { - let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); - let short_ip = "ffff::ffff".parse().unwrap(); - let port = 65535; - let text = "PROXY TCP6 ffff::ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn parse_tcp6_single_zero() { - let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); - let short_ip = "ffff:ffff:ffff:ffff::ffff:ffff:ffff".parse().unwrap(); - let port = 65535; - let text = "PROXY TCP6 ffff:ffff:ffff:ffff::ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn parse_tcp6_wildcard() { - let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); - let short_ip = "::".parse().unwrap(); - let port = 65535; - let text = "PROXY TCP6 :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn parse_tcp6_implied() { - let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); - let short_ip = "ffff::".parse().unwrap(); - let port = 65535; - let text = "PROXY TCP6 ffff:: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn parse_tcp6_over_shortened() { - let text = "PROXY TCP6 ffff::ffff:ffff:ffff:ffff::ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidSourceAddress( - "".parse::().unwrap_err() - )) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) - ); - } - - #[test] - fn parse_worst_case() { - let text = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; - let expected = Header::new(text, Addresses::Unknown); - - assert_eq!(Header::try_from(text), Ok(expected.to_owned())); - assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); - } - - #[test] - fn parse_leading_zeroes_in_source_port() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 05535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidSourcePort(None)) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSourcePort(None).into()) - ); - } - - #[test] - fn parse_leading_zeroes_in_destination_port() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 05535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidDestinationPort(None)) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidDestinationPort(None).into()) - ); - } - - #[test] - fn parse_source_port_too_large() { - let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65536 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidSourcePort(Some( - "65536".parse::().unwrap_err() - ))) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSourcePort(Some("65536".parse::().unwrap_err())).into()) - ); - } - - #[test] - fn parse_destination_port_too_large() { - let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65536\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidDestinationPort(Some( - "65536".parse::().unwrap_err() - ))) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err( - ParseError::InvalidDestinationPort(Some("65536".parse::().unwrap_err())) - .into() - ) - ); - } - - #[test] - fn parse_lowercase_proxy() { - let text = "proxy UNKNOWN\r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidPrefix.into()) - ); - } - - #[test] - fn parse_lowercase_protocol_family() { - let text = "PROXY tcp4\r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidProtocol.into()) - ); - } - - #[test] - fn parse_too_long() { - let text = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535 \r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::HeaderTooLong)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::HeaderTooLong.into()) - ); - } - - #[test] - fn parse_more_than_one_space() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidProtocol.into()) - ); - } - - #[test] - fn parse_more_than_one_space_source_address() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidSourceAddress( - "".parse::().unwrap_err() - )) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSourceAddress("".parse::().unwrap_err()).into()) - ); - } - - #[test] - fn parse_more_than_one_space_destination_address() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidDestinationAddress( - "".parse::().unwrap_err() - )) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidDestinationAddress("".parse::().unwrap_err()).into()) - ); - } - - #[test] - fn parse_more_than_one_space_source_port() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidSourcePort(Some( - "".parse::().unwrap_err() - ))) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSourcePort(Some("".parse::().unwrap_err())).into()) - ); - } - - #[test] - fn parse_more_than_one_space_destination_port() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; - - assert_eq!( - Header::try_from(text), - Err(ParseError::InvalidDestinationPort(Some( - "".parse::().unwrap_err() - ))) - ); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidDestinationPort(Some("".parse::().unwrap_err())).into()) - ); - } - - #[test] - fn parse_more_than_one_space_end() { - let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535 \r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidSuffix)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSuffix.into()) - ); - } - - #[test] - fn parse_partial_prefix() { - let text = "PROX\r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidPrefix.into()) - ); - } - - #[test] - fn parse_empty_newline() { - let text = "\r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidPrefix.into()) - ); - } - - #[test] - fn parse_partial_prefix_missing_newline() { - let text = "PROX"; - - assert_eq!(Header::try_from(text), Err(ParseError::Partial)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::Partial.into()) - ); - } - - #[test] - fn parse_partial_protocol_missing_newline() { - let text = "PROXY UNKN"; - - assert_eq!(Header::try_from(text), Err(ParseError::Partial)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::Partial.into()) - ); - } - - #[test] - fn parse_partial_protocol_with_newline() { - let text = "PROXY UNKN\r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidProtocol.into()) - ); - } - - #[test] - fn parse_empty_protocol_with_newline() { - let text = "PROXY \r\n"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidProtocol.into()) - ); - } - - #[test] - fn parse_empty() { - let text = ""; - - assert_eq!(Header::try_from(text), Err(ParseError::MissingPrefix)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::MissingPrefix.into()) - ); - } - - #[test] - fn parse_no_new_line() { - let text = "PROXY TCP4 127.0.0.1 192.168.1.1 80 443\r\t"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidSuffix)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidSuffix.into()) - ); - } - - #[test] - fn parse_invalid_prefix_missing_newline() { - let text = "PRAX"; - - assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); - assert_eq!( - Header::try_from(text.as_bytes()), - Err(ParseError::InvalidPrefix.into()) - ); - } -} diff --git a/rama-proxy/src/pp/protocol/v1/model.rs b/rama-proxy/src/pp/protocol/v1/model.rs deleted file mode 100644 index e8f35129..00000000 --- a/rama-proxy/src/pp/protocol/v1/model.rs +++ /dev/null @@ -1,307 +0,0 @@ -//! The data model to represent the test PROXY protocol header. - -use crate::proxy::pp::protocol::ip::{IPv4, IPv6}; -use std::borrow::Cow; -use std::fmt; -use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; - -/// The prefix of the PROXY protocol header. -pub const PROTOCOL_PREFIX: &str = "PROXY"; - -/// The suffix of the PROXY protocol header. -pub const PROTOCOL_SUFFIX: &str = "\r\n"; - -/// TCP protocol with IPv4 address family. -pub const TCP4: &str = "TCP4"; - -/// TCP protocol with IPv6 address family. -pub const TCP6: &str = "TCP6"; - -/// Unknown protocol and address family. Address portion of the header should be ignored. -pub const UNKNOWN: &str = "UNKNOWN"; - -/// The separator of the header parts. -pub const SEPARATOR: char = ' '; - -/// A text PROXY protocol header that borrows the input string. -/// -/// ## Examples -/// ### Worst Case (from bytes) -/// ```rust -/// use rama::proxy::pp::protocol::v1::{Addresses, Header, UNKNOWN}; -/// -/// let input = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; -/// let header = Header::try_from(input.as_bytes()).unwrap(); -/// -/// assert_eq!(header, Header::new(input, Addresses::Unknown)); -/// assert_eq!(header.protocol(), UNKNOWN); -/// assert_eq!(header.addresses_str(), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535"); -/// ``` -/// -/// ### UNKNOWN -/// ```rust -/// use rama::proxy::pp::protocol::v1::{Addresses, Header, UNKNOWN}; -/// -/// let input = "PROXY UNKNOWN\r\nhello"; -/// let header = Header::try_from(input).unwrap(); -/// -/// assert_eq!(header, Header::new("PROXY UNKNOWN\r\n", Addresses::Unknown)); -/// assert_eq!(header.protocol(), UNKNOWN); -/// assert_eq!(header.addresses_str(), ""); -/// ``` -/// -/// ### TCP4 -/// ```rust -/// use std::net::Ipv4Addr; -/// use rama::proxy::pp::protocol::v1::{Header, Addresses, TCP4}; -/// -/// let input = "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n"; -/// let header = Header::try_from(input).unwrap(); -/// -/// assert_eq!(header, Header::new(input, Addresses::new_tcp4(Ipv4Addr::new(127, 0, 1, 2), Ipv4Addr::new(192, 168, 1, 101), 80, 443))); -/// assert_eq!(header.protocol(), TCP4); -/// assert_eq!(header.addresses_str(), "127.0.1.2 192.168.1.101 80 443"); -/// ``` -/// -/// ### TCP6 -/// ```rust -/// use std::net::Ipv6Addr; -/// use rama::proxy::pp::protocol::v1::{Header, Addresses, TCP6}; -/// -/// let input = "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n"; -/// let header = Header::try_from(input).unwrap(); -/// -/// assert_eq!( -/// header, -/// Header::new( -/// input, -/// Addresses::new_tcp6( -/// Ipv6Addr::from([0x1234, 0x5678, 0x90AB, 0xCDEF, 0xFEDC, 0xBA09, 0x8765, 0x4321]), -/// Ipv6Addr::from([0x4321, 0x8765, 0xBA09, 0xFEDC, 0xCDEF, 0x90AB, 0x5678, 0x01234,]), -/// 443, -/// 65535 -/// ) -/// ) -/// ); -/// assert_eq!(header.protocol(), TCP6); -/// assert_eq!(header.addresses_str(), "1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535"); -/// ``` -/// -/// ### Invalid -/// ```rust -/// use rama::proxy::pp::protocol::v1::{Header, Addresses, ParseError}; -/// -/// assert_eq!(Err(ParseError::InvalidProtocol), "PROXY tcp4\r\n".parse::()); -/// ``` -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Header<'a> { - /// The original input string. - pub header: Cow<'a, str>, - /// The source and destination addresses of the header. - pub addresses: Addresses, -} - -impl<'a> Header<'a> { - /// Creates a new `Header` with the given addresses and a reference to the original input. - pub fn new, A: Into>(header: H, addresses: A) -> Self { - Header { - header: Cow::Borrowed(header.into()), - addresses: addresses.into(), - } - } - - /// Creates an owned clone of this [`Header`]. - pub fn to_owned(&self) -> Header<'static> { - Header { - header: Cow::Owned::<'static>(self.header.to_string()), - addresses: self.addresses, - } - } - - /// The protocol portion of this `Header`. - pub fn protocol(&self) -> &str { - self.addresses.protocol() - } - - /// The source and destination addresses portion of this `Header`. - pub fn addresses_str(&self) -> &str { - let start = PROTOCOL_PREFIX.len() + SEPARATOR.len_utf8() + self.protocol().len(); - let end = self.header.len() - PROTOCOL_SUFFIX.len(); - let addresses = &self.header[start..end]; - - if addresses.starts_with(SEPARATOR) { - &addresses[SEPARATOR.len_utf8()..] - } else { - addresses - } - } -} - -/// The source and destination of a header. -/// Includes IP (v4 or v6) addresses and TCP ports. -/// -/// ## Examples -/// ### Worst Case -/// ```rust -/// use rama::proxy::pp::protocol::v1::{Addresses, Header, UNKNOWN}; -/// -/// let header = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; -/// let addresses = Addresses::Unknown; -/// -/// assert_eq!(addresses, header.parse().unwrap()); -/// assert_ne!(addresses.to_string().as_str(), header); -/// ``` -/// -/// ### UNKNOWN -/// ```rust -/// use rama::proxy::pp::protocol::v1::Addresses; -/// -/// let header = "PROXY UNKNOWN\r\n"; -/// let addresses = Addresses::Unknown; -/// -/// assert_eq!(addresses, header.parse().unwrap()); -/// assert_eq!(addresses.to_string().as_str(), header); -/// ``` -/// -/// ### TCP4 -/// ```rust -/// use std::net::Ipv4Addr; -/// use rama::proxy::pp::protocol::v1::Addresses; -/// -/// let header = "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n"; -/// let addresses = Addresses::new_tcp4(Ipv4Addr::new(127, 0, 1, 2), Ipv4Addr::new(192, 168, 1, 101), 80, 443); -/// -/// assert_eq!(addresses, header.parse().unwrap()); -/// assert_eq!(addresses.to_string().as_str(), header); -/// ``` -/// -/// ### TCP6 -/// ```rust -/// use std::net::Ipv6Addr; -/// use rama::proxy::pp::protocol::v1::Addresses; -/// -/// let header = "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n"; -/// let addresses = Addresses::new_tcp6( -/// Ipv6Addr::from([0x1234, 0x5678, 0x90AB, 0xCDEF, 0xFEDC, 0xBA09, 0x8765, 0x4321]), -/// Ipv6Addr::from([0x4321, 0x8765, 0xBA09, 0xFEDC, 0xCDEF, 0x90AB, 0x5678, 0x01234,]), -/// 443, -/// 65535 -/// ); -/// -/// assert_eq!(addresses, header.parse().unwrap()); -/// assert_eq!(addresses.to_string().as_str(), header); -/// ``` -/// -/// ### Invalid -/// ```rust -/// use rama::proxy::pp::protocol::v1::{Addresses, ParseError}; -/// -/// assert_eq!(Err(ParseError::InvalidProtocol), "PROXY tcp4\r\n".parse::()); -/// ``` -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash)] -pub enum Addresses { - #[default] - /// The source and destination addresses of the header are unknown. - Unknown, - /// The source and destination addresses of the header are IPv4. - Tcp4(IPv4), - /// The source and destination addresses of the header are IPv6. - Tcp6(IPv6), -} - -impl Addresses { - /// Create a new IPv4 TCP address. - pub fn new_tcp4>( - source_address: T, - destination_address: T, - source_port: u16, - destination_port: u16, - ) -> Self { - Addresses::Tcp4(IPv4 { - source_address: source_address.into(), - source_port, - destination_address: destination_address.into(), - destination_port, - }) - } - - /// Create a new IPv6 TCP address. - pub fn new_tcp6>( - source_address: T, - destination_address: T, - source_port: u16, - destination_port: u16, - ) -> Self { - Addresses::Tcp6(IPv6 { - source_address: source_address.into(), - source_port, - destination_address: destination_address.into(), - destination_port, - }) - } - - /// The protocol portion of this `Addresses`. - pub fn protocol(&self) -> &str { - match self { - Addresses::Tcp4(..) => TCP4, - Addresses::Tcp6(..) => TCP6, - Addresses::Unknown => UNKNOWN, - } - } -} - -impl From<(SocketAddr, SocketAddr)> for Addresses { - fn from(addresses: (SocketAddr, SocketAddr)) -> Self { - match addresses { - (SocketAddr::V4(source), SocketAddr::V4(destination)) => Addresses::Tcp4(IPv4::new( - *source.ip(), - *destination.ip(), - source.port(), - destination.port(), - )), - (SocketAddr::V6(source), SocketAddr::V6(destination)) => Addresses::Tcp6(IPv6::new( - *source.ip(), - *destination.ip(), - source.port(), - destination.port(), - )), - _ => Addresses::Unknown, - } - } -} - -impl From for Addresses { - fn from(addresses: IPv4) -> Self { - Addresses::Tcp4(addresses) - } -} - -impl From for Addresses { - fn from(addresses: IPv6) -> Self { - Addresses::Tcp6(addresses) - } -} - -impl<'a> fmt::Display for Header<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.header.as_ref()) - } -} - -impl fmt::Display for Addresses { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Unknown => f.write_str("PROXY UNKNOWN\r\n"), - Self::Tcp4(a) => write!( - f, - "PROXY TCP4 {} {} {} {}\r\n", - a.source_address, a.destination_address, a.source_port, a.destination_port - ), - Self::Tcp6(a) => write!( - f, - "PROXY TCP6 {} {} {} {}\r\n", - a.source_address, a.destination_address, a.source_port, a.destination_port - ), - } - } -} diff --git a/rama-proxy/src/pp/protocol/v2/builder.rs b/rama-proxy/src/pp/protocol/v2/builder.rs deleted file mode 100644 index b09d63d2..00000000 --- a/rama-proxy/src/pp/protocol/v2/builder.rs +++ /dev/null @@ -1,640 +0,0 @@ -//! Builder pattern to generate both valid and invalid PROXY protocol v2 headers. - -use crate::proxy::pp::protocol::v2::{ - Addresses, Protocol, Type, TypeLengthValue, TypeLengthValues, LENGTH, MINIMUM_LENGTH, - MINIMUM_TLV_LENGTH, PROTOCOL_PREFIX, -}; -use std::io::{self, Write}; - -/// `Write` interface for the builder's internal buffer. -/// Can be used to turn header parts into bytes. -/// -/// ## Examples -/// ```rust -/// use rama::proxy::pp::protocol::v2::{Addresses, Writer, WriteToHeader}; -/// use std::net::SocketAddr; -/// -/// let addresses: Addresses = ("127.0.0.1:80".parse::().unwrap(), "192.168.1.1:443".parse::().unwrap()).into(); -/// let mut writer = Writer::default(); -/// -/// addresses.write_to(&mut writer).unwrap(); -/// -/// assert_eq!(addresses.to_bytes().unwrap(), writer.finish()); -/// ``` -#[derive(Debug, Default)] -pub struct Writer { - bytes: Vec, -} - -/// Implementation of the builder pattern for PROXY protocol v2 headers. -/// Supports both valid and invalid headers via the `write_payload` and `write_payloads` functions. -/// -/// ## Examples -/// ```rust -/// use rama::proxy::pp::protocol::v2::{Addresses, AddressFamily, Builder, Command, IPv4, Protocol, PROTOCOL_PREFIX, Type, Version}; -/// let mut expected = Vec::from(PROTOCOL_PREFIX); -/// expected.extend([ -/// 0x21, 0x12, 0, 16, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 4, 0, 1, 42 -/// ]); -/// -/// let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); -/// let header = Builder::with_addresses( -/// Version::Two | Command::Proxy, -/// Protocol::Datagram, -/// addresses -/// ) -/// .write_tlv(Type::NoOp, [42].as_slice()) -/// .unwrap() -/// .build() -/// .unwrap(); -/// -/// assert_eq!(header, expected); -/// ``` -#[derive(Debug)] -pub struct Builder { - header: Option>, - version_command: u8, - address_family_protocol: u8, - addresses: Addresses, - length: Option, - additional_capacity: usize, -} - -impl Writer { - /// Consumes this `Writer` and returns the buffer holding the proxy protocol header payloads. - /// The returned bytes are not guaranteed to be a valid proxy protocol header. - pub fn finish(self) -> Vec { - self.bytes - } -} - -impl From> for Writer { - fn from(bytes: Vec) -> Self { - Writer { bytes } - } -} - -impl Write for Writer { - fn write(&mut self, buffer: &[u8]) -> io::Result { - if self.bytes.len() > (u16::MAX as usize) + MINIMUM_LENGTH { - Err(io::ErrorKind::WriteZero.into()) - } else { - self.bytes.extend_from_slice(buffer); - Ok(buffer.len()) - } - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -/// Defines how to write a type as part of a binary PROXY protocol header. -pub trait WriteToHeader { - /// Write this instance to the given `Writer`. - /// The `Writer` returns an IO error when an individual byte slice is longer than `u16::MAX`. - /// However, the total length of the buffer may exceed `u16::MAX`. - fn write_to(&self, writer: &mut Writer) -> io::Result; - - /// Writes this instance to a temporary buffer and returns the buffer. - fn to_bytes(&self) -> io::Result> { - let mut writer = Writer::default(); - - self.write_to(&mut writer)?; - - Ok(writer.finish()) - } -} - -impl WriteToHeader for Addresses { - fn write_to(&self, writer: &mut Writer) -> io::Result { - match self { - Addresses::Unspecified => (), - Addresses::IPv4(a) => { - writer.write_all(a.source_address.octets().as_slice())?; - writer.write_all(a.destination_address.octets().as_slice())?; - writer.write_all(a.source_port.to_be_bytes().as_slice())?; - writer.write_all(a.destination_port.to_be_bytes().as_slice())?; - } - Addresses::IPv6(a) => { - writer.write_all(a.source_address.octets().as_slice())?; - writer.write_all(a.destination_address.octets().as_slice())?; - writer.write_all(a.source_port.to_be_bytes().as_slice())?; - writer.write_all(a.destination_port.to_be_bytes().as_slice())?; - } - Addresses::Unix(a) => { - writer.write_all(a.source.as_slice())?; - writer.write_all(a.destination.as_slice())?; - } - }; - - Ok(self.len()) - } -} - -impl<'a> WriteToHeader for TypeLengthValue<'a> { - fn write_to(&self, writer: &mut Writer) -> io::Result { - if self.value.len() > u16::MAX as usize { - return Err(io::ErrorKind::WriteZero.into()); - } - - writer.write_all([self.kind].as_slice())?; - writer.write_all((self.value.len() as u16).to_be_bytes().as_slice())?; - writer.write_all(self.value.as_ref())?; - - Ok(MINIMUM_TLV_LENGTH + self.value.len()) - } -} - -impl<'a, T: Copy + Into> WriteToHeader for (T, &'a [u8]) { - fn write_to(&self, writer: &mut Writer) -> io::Result { - let kind = self.0.into(); - let value = self.1; - - if value.len() > u16::MAX as usize { - return Err(io::ErrorKind::WriteZero.into()); - } - - writer.write_all([kind].as_slice())?; - writer.write_all((value.len() as u16).to_be_bytes().as_slice())?; - writer.write_all(value)?; - - Ok(MINIMUM_TLV_LENGTH + value.len()) - } -} - -impl<'a> WriteToHeader for TypeLengthValues<'a> { - fn write_to(&self, writer: &mut Writer) -> io::Result { - let bytes = self.as_bytes(); - - writer.write_all(bytes)?; - - Ok(bytes.len()) - } -} - -impl WriteToHeader for [u8] { - fn write_to(&self, writer: &mut Writer) -> io::Result { - let slice = self; - - if slice.len() > u16::MAX as usize { - return Err(io::ErrorKind::WriteZero.into()); - } - - writer.write_all(slice)?; - - Ok(slice.len()) - } -} - -impl WriteToHeader for &T { - fn write_to(&self, writer: &mut Writer) -> io::Result { - (*self).write_to(writer) - } -} - -impl WriteToHeader for Type { - fn write_to(&self, writer: &mut Writer) -> io::Result { - writer.write([(*self).into()].as_slice()) - } -} - -macro_rules! impl_write_to_header { - ($t:ident) => { - impl WriteToHeader for $t { - fn write_to(&self, writer: &mut Writer) -> io::Result { - let bytes = self.to_be_bytes(); - - writer.write_all(bytes.as_slice())?; - - Ok(bytes.len()) - } - } - }; -} - -impl_write_to_header!(u8); -impl_write_to_header!(u16); -impl_write_to_header!(u32); -impl_write_to_header!(u64); -impl_write_to_header!(u128); -impl_write_to_header!(usize); - -impl_write_to_header!(i8); -impl_write_to_header!(i16); -impl_write_to_header!(i32); -impl_write_to_header!(i64); -impl_write_to_header!(i128); -impl_write_to_header!(isize); - -impl Builder { - /// Creates an instance of a `Builder` with the given header bytes. - /// No guarantee is made that any address bytes written as a payload will match the header's address family. - /// The length is determined on `build` unless `set_length` is called to set an explicit value. - pub const fn new(version_command: u8, address_family_protocol: u8) -> Self { - Builder { - header: None, - version_command, - address_family_protocol, - addresses: Addresses::Unspecified, - length: None, - additional_capacity: 0, - } - } - - /// Creates an instance of a `Builder` with the given header bytes and `Addresses`. - /// The address family is determined from the variant of the `Addresses` given. - /// The length is determined on `build` unless `set_length` is called to set an explicit value. - pub fn with_addresses>( - version_command: u8, - protocol: Protocol, - addresses: T, - ) -> Self { - let addresses = addresses.into(); - - Builder { - header: None, - version_command, - address_family_protocol: addresses.address_family() | protocol, - addresses, - length: None, - additional_capacity: 0, - } - } - - /// Reserves the requested additional capacity in the underlying buffer. - /// Helps to prevent resizing the underlying buffer when called before `write_payload`, `write_payloads`. - /// When called after `write_payload`, `write_payloads`, useful as a hint on how to resize the buffer. - pub fn reserve_capacity(mut self, capacity: usize) -> Self { - match self.header { - None => self.additional_capacity += capacity, - Some(ref mut header) => header.reserve(capacity), - } - - self - } - - /// Reserves the requested additional capacity in the underlying buffer. - /// Helps to prevent resizing the underlying buffer when called before `write_payload`, `write_payloads`. - /// When called after `write_payload`, `write_payloads`, useful as a hint on how to resize the buffer. - pub fn set_reserve_capacity(&mut self, capacity: usize) -> &mut Self { - match self.header { - None => self.additional_capacity += capacity, - Some(ref mut header) => header.reserve(capacity), - } - - self - } - - /// Overrides the length in the header. - /// When set to `Some` value, the length may be smaller or larger than the actual payload in the buffer. - pub fn set_length>>(mut self, length: T) -> Self { - self.length = length.into(); - self - } - - /// Writes a iterable set of payloads in order to the buffer. - /// No bytes are added by this `Builder` as a delimiter. - pub fn write_payloads(mut self, payloads: II) -> io::Result - where - T: WriteToHeader, - I: Iterator, - II: IntoIterator, - { - self.write_header()?; - - let mut writer = Writer::from(self.header.take().unwrap_or_default()); - - for item in payloads { - item.write_to(&mut writer)?; - } - - self.header = Some(writer.finish()); - - Ok(self) - } - - /// Writes a single payload to the buffer. - /// No surrounding bytes (terminal or otherwise) are added by this `Builder`. - pub fn write_payload(mut self, payload: T) -> io::Result { - self.write_header()?; - self.write_internal(payload)?; - - Ok(self) - } - - /// Writes a Type-Length-Value as a payload. - /// No surrounding bytes (terminal or otherwise) are added by this `Builder`. - /// The length is determined by the length of the slice. - /// An error is returned when the length of the slice exceeds `u16::MAX`. - pub fn write_tlv(self, kind: impl Into, value: &[u8]) -> io::Result { - self.write_payload(TypeLengthValue::new(kind, value)) - } - - /// Writes to the underlying buffer without first writing the header bytes. - fn write_internal(&mut self, payload: T) -> io::Result<()> { - let mut writer = Writer::from(self.header.take().unwrap_or_default()); - - payload.write_to(&mut writer)?; - - self.header = Some(writer.finish()); - - Ok(()) - } - - /// Writes the protocol prefix, version, command, address family, protocol, and optional addresses to the buffer. - /// Does nothing if the buffer is not empty. - fn write_header(&mut self) -> io::Result<()> { - if self.header.is_some() { - return Ok(()); - } - - let mut header = - Vec::with_capacity(MINIMUM_LENGTH + self.addresses.len() + self.additional_capacity); - - let length = self.length.unwrap_or_default(); - - header.extend_from_slice(PROTOCOL_PREFIX); - header.push(self.version_command); - header.push(self.address_family_protocol); - header.extend_from_slice(length.to_be_bytes().as_slice()); - - let mut writer = Writer::from(header); - - self.addresses.write_to(&mut writer)?; - self.header = Some(writer.finish()); - - Ok(()) - } - - /// Builds the header and returns the underlying buffer. - /// If no length was explicitly set, returns an error when the length of the payload portion exceeds `u16::MAX`. - pub fn build(mut self) -> io::Result> { - self.write_header()?; - - let mut header = self.header.take().unwrap_or_default(); - - if self.length.is_some() { - return Ok(header); - } - - if let Ok(payload_length) = u16::try_from(header[MINIMUM_LENGTH..].len()) { - let length = payload_length.to_be_bytes(); - header[LENGTH..LENGTH + length.len()].copy_from_slice(length.as_slice()); - Ok(header) - } else { - Err(io::ErrorKind::WriteZero.into()) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::proxy::pp::protocol::v2::{ - AddressFamily, Command, IPv4, IPv6, Protocol, Type, Unix, Version, - }; - - #[test] - fn build_length_too_small() { - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([0x21, 0x12, 0, 1, 0, 0, 0, 1]); - - let actual = Builder::new( - Version::Two | Command::Proxy, - AddressFamily::IPv4 | Protocol::Datagram, - ) - .set_length(1) - .write_payload(1u32) - .unwrap() - .build() - .unwrap(); - - assert_eq!(actual, expected); - } - - #[test] - fn build_payload_too_long() { - let error = Builder::new( - Version::Two | Command::Proxy, - AddressFamily::IPv4 | Protocol::Datagram, - ) - .write_payload(vec![0u8; (u16::MAX as usize) + 1].as_slice()) - .unwrap_err(); - - assert_eq!(error.kind(), io::ErrorKind::WriteZero); - } - - #[test] - fn build_no_payload() { - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([0x21, 0x01, 0, 0]); - - let header = Builder::new( - Version::Two | Command::Proxy, - AddressFamily::Unspecified | Protocol::Stream, - ) - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_arbitrary_payload() { - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([0x21, 0x01, 0, 1, 42]); - - let header = Builder::new( - Version::Two | Command::Proxy, - AddressFamily::Unspecified | Protocol::Stream, - ) - .write_payload(42u8) - .unwrap() - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_ipv4() { - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([ - 0x21, 0x12, 0, 12, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, - ]); - - let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); - let header = Builder::new( - Version::Two | Command::Proxy, - AddressFamily::IPv4 | Protocol::Datagram, - ) - .set_length(addresses.len() as u16) - .write_payload(addresses) - .unwrap() - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_ipv6() { - let source_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF2, - ]; - let destination_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF1, - ]; - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([0x20, 0x20, 0, 36]); - expected.extend(source_address); - expected.extend(destination_address); - expected.extend([0, 80, 1, 187]); - - let header = Builder::with_addresses( - Version::Two | Command::Local, - Protocol::Unspecified, - IPv6::new(source_address, destination_address, 80, 443), - ) - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_unix() { - let source_address = [0xFFu8; 108]; - let destination_address = [0xAAu8; 108]; - - let addresses: Addresses = Unix::new(source_address, destination_address).into(); - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([0x20, 0x31, 0, 216]); - expected.extend(source_address); - expected.extend(destination_address); - - let header = Builder::new( - Version::Two | Command::Local, - AddressFamily::Unix | Protocol::Stream, - ) - .reserve_capacity(addresses.len()) - .write_payload(addresses) - .unwrap() - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_ipv4_with_tlv() { - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([ - 0x21, 0x12, 0, 17, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 4, 0, 2, 0, 42, - ]); - - let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); - let header = - Builder::with_addresses(Version::Two | Command::Proxy, Protocol::Datagram, addresses) - .reserve_capacity(5) - .write_tlv(Type::NoOp, [0, 42].as_slice()) - .unwrap() - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_ipv4_with_nested_tlv() { - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([ - 0x21, 0x12, 0, 20, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 0x20, 0, 5, 0, 0, 0, 0, - 0, - ]); - - let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); - let header = Builder::new( - Version::Two | Command::Proxy, - AddressFamily::IPv4 | Protocol::Datagram, - ) - .write_payload(addresses) - .unwrap() - .write_payload(Type::SSL) - .unwrap() - .write_payload(5u16) - .unwrap() - .write_payload([0u8; 5].as_slice()) - .unwrap() - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_ipv6_with_tlvs() { - let source_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF2, - ]; - let destination_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF1, - ]; - let addresses: Addresses = IPv6::new(source_address, destination_address, 80, 443).into(); - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([0x20, 0x20, 0, 48]); - expected.extend(source_address); - expected.extend(destination_address); - expected.extend([0, 80, 1, 187]); - expected.extend([4, 0, 1, 0, 4, 0, 1, 0, 4, 0, 1, 42]); - - let header = Builder::new( - Version::Two | Command::Local, - AddressFamily::IPv6 | Protocol::Unspecified, - ) - .write_payload(addresses) - .unwrap() - .write_payloads([ - (Type::NoOp, [0].as_slice()), - (Type::NoOp, [0].as_slice()), - (Type::NoOp, [42].as_slice()), - ]) - .unwrap() - .build() - .unwrap(); - - assert_eq!(header, expected); - } - - #[test] - fn build_unix_with_tlv() { - let source_address = [0xFFu8; 108]; - let destination_address = [0xAAu8; 108]; - - let addresses: Addresses = Unix::new(source_address, destination_address).into(); - let mut expected = Vec::from(PROTOCOL_PREFIX); - expected.extend([0x20, 0x31, 0, 216]); - expected.extend(source_address); - expected.extend(destination_address); - expected.extend([0x20, 0, 0]); - - let header = Builder::new( - Version::Two | Command::Local, - AddressFamily::Unix | Protocol::Stream, - ) - .set_length(216) - .write_payload(addresses) - .unwrap() - .write_tlv(Type::SSL, &[]) - .unwrap() - .build() - .unwrap(); - - assert_eq!(header, expected); - } -} diff --git a/rama-proxy/src/pp/protocol/v2/error.rs b/rama-proxy/src/pp/protocol/v2/error.rs deleted file mode 100644 index af38f6b0..00000000 --- a/rama-proxy/src/pp/protocol/v2/error.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Errors for the binary proxy protocol. - -use std::fmt; - -/// An error in parsing a binary PROXY protocol header. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ParseError { - /// Expected header to the protocol prefix plus 4 bytes after the prefix. - Incomplete(usize), - /// Expected header to start with a prefix of '\r\n\r\n\0\r\nQUIT\n'. - Prefix, - /// Expected version to be equal to 2. - Version(u8), - /// Invalid command. Command must be one of: Local, Proxy. - Command(u8), - /// Invalid Address Family. Address Family must be one of: Unspecified, IPv4, IPv6, Unix. - AddressFamily(u8), - /// Invalid protocol. Protocol must be one of: Unspecified, Stream, or Datagram. - Protocol(u8), - /// Header does not contain the advertised length of the address information and TLVs. - Partial(usize, usize), - /// Header length of {0} bytes cannot store the {1} bytes required for the address family. - InvalidAddresses(usize, usize), - /// Header is not long enough to contain TLV {0} with length {1}. - InvalidTLV(u8, u16), - /// Header contains leftover {0} bytes not accounted for by the address family or TLVs. - Leftovers(usize), -} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Incomplete(len) => write!(f, "Expected header to the protocol prefix plus 4 bytes after the prefix (length {}).", len), - Self::Prefix => write!(f, "Expected header to start with a prefix of '\\r\\n\\r\\n\\0\\r\\nQUIT\\n'."), - Self::Version(version) => write!(f, "Expected version {:X} to be equal to 2.", version), - Self::Command(command) => write!(f, "Invalid command {:X}. Command must be one of: Local, Proxy.", command), - Self::AddressFamily(af) => write!(f, "Invalid Address Family {:X}. Address Family must be one of: Unspecified, IPv4, IPv6, Unix.", af), - Self::Protocol(protocol) => write!(f, "Invalid protocol {:X}. Protocol must be one of: Unspecified, Stream, or Datagram.", protocol), - Self::Partial(len, total) => write!(f, "Header does not contain the advertised length of the address information and TLVs (has {} out of {} bytes).", len, total), - Self::InvalidAddresses(len, total) => write!(f, "Header length of {} bytes cannot store the {} bytes required for the address family.", len, total), - Self::InvalidTLV(tlv, len) => write!(f, "Header is not long enough to contain TLV {} with length {}.", tlv, len), - Self::Leftovers(len) => write!(f, "Header contains leftover {} bytes not accounted for by the address family or TLVs.", len), - } - } -} - -impl std::error::Error for ParseError {} diff --git a/rama-proxy/src/pp/protocol/v2/mod.rs b/rama-proxy/src/pp/protocol/v2/mod.rs deleted file mode 100644 index 38740a34..00000000 --- a/rama-proxy/src/pp/protocol/v2/mod.rs +++ /dev/null @@ -1,749 +0,0 @@ -//! Version 2 of the HAProxy protocol (binary version). -//! -//! See - -mod builder; -mod error; -mod model; - -pub use crate::proxy::pp::protocol::ip::{IPv4, IPv6}; -pub use builder::{Builder, WriteToHeader, Writer}; -pub use error::ParseError; -pub use model::{ - AddressFamily, Addresses, Command, Header, Protocol, Type, TypeLengthValue, TypeLengthValues, - Unix, Version, PROTOCOL_PREFIX, -}; -use model::{MINIMUM_LENGTH, MINIMUM_TLV_LENGTH}; -use std::borrow::Cow; -use std::net::{Ipv4Addr, Ipv6Addr}; - -/// Masks the right 4-bits so only the left 4-bits are present. -const LEFT_MASK: u8 = 0xF0; -/// Masks the left 4-bits so only the right 4-bits are present. -const RIGHT_MASK: u8 = 0x0F; -/// The index of the version-command byte. -const VERSION_COMMAND: usize = PROTOCOL_PREFIX.len(); -/// The index of the address family-protocol byte. -const ADDRESS_FAMILY_PROTOCOL: usize = VERSION_COMMAND + 1; -/// The index of the start of the big-endian u16 length. -const LENGTH: usize = ADDRESS_FAMILY_PROTOCOL + 1; - -/// Parses the addresses from the header payload. -fn parse_addresses(address_family: AddressFamily, bytes: &[u8]) -> Addresses { - match address_family { - AddressFamily::Unspecified => Addresses::Unspecified, - AddressFamily::IPv4 => { - let source_address = Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]); - let destination_address = Ipv4Addr::new(bytes[4], bytes[5], bytes[6], bytes[7]); - let source_port = u16::from_be_bytes([bytes[8], bytes[9]]); - let destination_port = u16::from_be_bytes([bytes[10], bytes[11]]); - - Addresses::IPv4(IPv4 { - source_address, - destination_address, - source_port, - destination_port, - }) - } - AddressFamily::IPv6 => { - let mut address = [0; 16]; - - address[..].copy_from_slice(&bytes[..16]); - let source_address = Ipv6Addr::from(address); - - address[..].copy_from_slice(&bytes[16..32]); - let destination_address = Ipv6Addr::from(address); - - let source_port = u16::from_be_bytes([bytes[32], bytes[33]]); - let destination_port = u16::from_be_bytes([bytes[34], bytes[35]]); - - Addresses::IPv6(IPv6 { - source_address, - destination_address, - source_port, - destination_port, - }) - } - AddressFamily::Unix => { - let mut source = [0; 108]; - let mut destination = [0; 108]; - - source[..].copy_from_slice(&bytes[..108]); - destination[..].copy_from_slice(&bytes[108..]); - - Addresses::Unix(Unix { - source, - destination, - }) - } - } -} - -impl<'a> TryFrom<&'a [u8]> for Header<'a> { - type Error = ParseError; - - fn try_from(input: &'a [u8]) -> Result { - if input.len() < PROTOCOL_PREFIX.len() { - if PROTOCOL_PREFIX.starts_with(input) { - return Err(ParseError::Incomplete(input.len())); - } else { - return Err(ParseError::Prefix); - } - } - - if &input[..VERSION_COMMAND] != PROTOCOL_PREFIX { - return Err(ParseError::Prefix); - } - - if input.len() < MINIMUM_LENGTH { - return Err(ParseError::Incomplete(input.len())); - } - - let version = match input[VERSION_COMMAND] & LEFT_MASK { - 0x20 => Version::Two, - v => return Err(ParseError::Version(v)), - }; - let command = match input[VERSION_COMMAND] & RIGHT_MASK { - 0x00 => Command::Local, - 0x01 => Command::Proxy, - c => return Err(ParseError::Command(c)), - }; - - let address_family = match input[ADDRESS_FAMILY_PROTOCOL] & LEFT_MASK { - 0x00 => AddressFamily::Unspecified, - 0x10 => AddressFamily::IPv4, - 0x20 => AddressFamily::IPv6, - 0x30 => AddressFamily::Unix, - a => return Err(ParseError::AddressFamily(a)), - }; - let protocol = match input[ADDRESS_FAMILY_PROTOCOL] & RIGHT_MASK { - 0x00 => Protocol::Unspecified, - 0x01 => Protocol::Stream, - 0x02 => Protocol::Datagram, - p => return Err(ParseError::Protocol(p)), - }; - - let length = u16::from_be_bytes([input[LENGTH], input[LENGTH + 1]]) as usize; - let address_family_bytes = address_family.byte_length().unwrap_or_default(); - - if length < address_family_bytes { - return Err(ParseError::InvalidAddresses(length, address_family_bytes)); - } - - let full_length = MINIMUM_LENGTH + length; - - if input.len() < full_length { - return Err(ParseError::Partial(input.len() - MINIMUM_LENGTH, length)); - } - - let header = &input[..full_length]; - let addresses = parse_addresses( - address_family, - &header[MINIMUM_LENGTH..MINIMUM_LENGTH + address_family_bytes], - ); - - Ok(Header { - header: Cow::Borrowed(header), - version, - command, - protocol, - addresses, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use model::{Type, TypeLengthValue}; - - #[test] - fn no_tlvs() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x11); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - - let expected = Header { - header: Cow::Borrowed(input.as_slice()), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Stream, - addresses: IPv4::new([127, 0, 0, 1], [127, 0, 0, 2], 80, 443).into(), - }; - let actual = Header::try_from(input.as_slice()).unwrap(); - - assert_eq!(actual, expected); - assert!(actual.tlvs().next().is_none()); - assert_eq!(actual.length(), 12); - assert_eq!(actual.address_family(), AddressFamily::IPv4); - assert_eq!( - actual.address_bytes(), - &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 1, 187] - ); - assert!(actual.tlv_bytes().is_empty()); - assert_eq!(actual.as_bytes(), input.as_slice()); - } - - #[test] - fn no_tlvs_unspec() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x00); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - - let expected = Header { - header: input.as_slice().into(), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Unspecified, - addresses: Addresses::Unspecified, - }; - let actual = Header::try_from(input.as_slice()).unwrap(); - - assert_eq!(actual, expected); - assert!(actual.tlvs().next().is_none()); - assert_eq!(actual.length(), 12); - assert_eq!(actual.address_family(), AddressFamily::Unspecified); - assert_eq!( - actual.address_bytes(), - &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 1, 187] - ); - assert!(actual.tlv_bytes().is_empty()); - assert_eq!(actual.as_bytes(), input.as_slice()); - } - - #[test] - fn no_tlvs_unspec_stream() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x01); - input.extend([0, 8]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - - let expected = Header { - header: Cow::Borrowed(input.as_slice()), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Stream, - addresses: Addresses::Unspecified, - }; - let actual = Header::try_from(input.as_slice()).unwrap(); - - assert_eq!(actual, expected); - assert!(actual.tlvs().next().is_none()); - assert_eq!(actual.length(), 8); - assert_eq!(actual.address_family(), AddressFamily::Unspecified); - assert_eq!(actual.address_bytes(), &[127, 0, 0, 1, 127, 0, 0, 2]); - assert!(actual.tlv_bytes().is_empty()); - assert_eq!(actual.as_bytes(), input.as_slice()); - } - - #[test] - fn no_tlvs_unspec_ipv4() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x10); - input.extend([0, 8]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - - let actual = Header::try_from(input.as_slice()).unwrap_err(); - - assert_eq!(actual, ParseError::InvalidAddresses(8, 12)); - } - - #[test] - fn invalid_version() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x11); - input.push(0x11); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - - let actual = Header::try_from(input.as_slice()).unwrap_err(); - - assert_eq!(actual, ParseError::Version(0x10)); - } - - #[test] - fn invalid_address_family() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x51); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - - let actual = Header::try_from(input.as_slice()).unwrap_err(); - - assert_eq!(actual, ParseError::AddressFamily(0x50)); - } - - #[test] - fn invalid_command() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x23); - input.push(0x11); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - - let actual = Header::try_from(input.as_slice()).unwrap_err(); - - assert_eq!(actual, ParseError::Command(0x03)); - } - - #[test] - fn invalid_protocol() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x20); - input.push(0x17); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - - let actual = Header::try_from(input.as_slice()).unwrap_err(); - - assert_eq!(actual, ParseError::Protocol(0x07)); - } - - #[test] - fn proxy_with_extra() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x11); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - input.extend([42]); - - let header = &input[..input.len() - 1]; - let expected = Header { - header: header.into(), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Stream, - addresses: IPv4::new([127, 0, 0, 1], [127, 0, 0, 2], 80, 443).into(), - }; - let actual = Header::try_from(input.as_slice()).unwrap(); - - assert_eq!(actual, expected); - assert!(actual.tlvs().next().is_none()); - assert_eq!(actual.length(), 12); - assert_eq!(actual.address_family(), AddressFamily::IPv4); - assert_eq!( - actual.address_bytes(), - &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 1, 187] - ); - assert!(actual.tlv_bytes().is_empty()); - assert_eq!(actual.as_bytes(), header); - } - - #[test] - fn with_tlvs() { - let source_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF2, - ]; - let destination_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF1, - ]; - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x21); - input.extend([0, 45]); - input.extend(source_address); - input.extend(destination_address); - input.extend([0, 80]); - input.extend([1, 187]); - input.extend([1, 0, 1, 5]); - input.extend([3, 0, 2, 5, 5]); - - let expected = Header { - header: input.as_slice().into(), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Stream, - addresses: IPv6::new(source_address, destination_address, 80, 443).into(), - }; - let expected_tlvs = vec![ - Ok(TypeLengthValue::new(Type::ALPN, &[5])), - Ok(TypeLengthValue::new(Type::CRC32C, &[5, 5])), - ]; - - let actual = Header::try_from(input.as_slice()).unwrap(); - let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); - - assert_eq!(actual, expected); - assert_eq!(actual_tlvs, expected_tlvs); - assert_eq!(actual.length(), 45); - assert_eq!(actual.address_family(), AddressFamily::IPv6); - assert_eq!( - actual.address_bytes(), - &[ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF1, 0, 80, 1, 187 - ] - ); - assert_eq!(actual.tlv_bytes(), &[1, 0, 1, 5, 3, 0, 2, 5, 5]); - assert_eq!(actual.as_bytes(), input.as_slice()); - } - - #[test] - fn tlvs_with_extra() { - let source_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, - ]; - let destination_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF1, - ]; - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x21); - input.extend([0, 45]); - input.extend(source_address); - input.extend(destination_address); - input.extend([0, 80]); - input.extend([1, 187]); - input.extend([1, 0, 1, 5]); - input.extend([4, 0, 2, 5, 5]); - input.extend([2, 0, 2, 5, 5]); - - let header = &input[..input.len() - 5]; - let expected = Header { - header: header.into(), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Stream, - addresses: IPv6::new(source_address, destination_address, 80, 443).into(), - }; - let expected_tlvs = vec![ - Ok(TypeLengthValue::new(Type::ALPN, &[5])), - Ok(TypeLengthValue::new(Type::NoOp, &[5, 5])), - ]; - - let actual = Header::try_from(input.as_slice()).unwrap(); - let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); - - assert_eq!(actual, expected); - assert_eq!(actual_tlvs, expected_tlvs); - assert_eq!(actual.length(), 45); - assert_eq!(actual.address_family(), AddressFamily::IPv6); - assert_eq!( - actual.address_bytes(), - &[ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF1, 0, 80, 1, 187 - ] - ); - assert_eq!(actual.tlv_bytes(), &[1, 0, 1, 5, 4, 0, 2, 5, 5]); - assert_eq!(actual.as_bytes(), header); - } - - #[test] - fn unix_tlvs_with_extra() { - let source_address = [0xFFu8; 108]; - let destination_address = [0xAAu8; 108]; - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x30); - input.extend([0, 225]); - input.extend(source_address); - input.extend(destination_address); - input.extend([2, 0, 2, 5, 5]); - input.extend([48, 0, 1, 5]); - input.extend([1, 0, 2, 5, 5]); - - let header = &input[..input.len() - 5]; - let expected = Header { - header: header.into(), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Unspecified, - addresses: Unix::new(source_address, destination_address).into(), - }; - let mut expected_address_bytes = - Vec::with_capacity(source_address.len() + destination_address.len()); - expected_address_bytes.extend(source_address); - expected_address_bytes.extend(destination_address); - - let expected_tlvs = vec![ - Ok(TypeLengthValue::new(Type::Authority, &[5, 5])), - Ok(TypeLengthValue::new(Type::NetworkNamespace, &[5])), - ]; - - let actual = Header::try_from(input.as_slice()).unwrap(); - let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); - - assert_eq!(actual, expected); - assert_eq!(actual_tlvs, expected_tlvs); - assert_eq!(actual.length(), 225); - assert_eq!(actual.address_family(), AddressFamily::Unix); - assert_eq!(actual.address_bytes(), expected_address_bytes.as_slice()); - assert_eq!(actual.tlv_bytes(), &[2, 0, 2, 5, 5, 48, 0, 1, 5]); - assert_eq!(actual.as_bytes(), header); - } - - #[test] - fn with_tlvs_without_ports() { - let source_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, - ]; - let destination_address = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF1, - ]; - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x20); - input.extend([0, 41]); - input.extend(source_address); - input.extend(destination_address); - input.extend([1, 0, 1, 5]); - input.extend([3, 0, 2, 5, 5]); - - let expected = Header { - header: input.as_slice().into(), - version: Version::Two, - command: Command::Proxy, - protocol: Protocol::Unspecified, - addresses: IPv6::new(source_address, destination_address, 256, 261).into(), - }; - let expected_tlvs = vec![Ok(TypeLengthValue::new(Type::CRC32C, &[5, 5]))]; - - let actual = Header::try_from(input.as_slice()).unwrap(); - let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); - - assert_eq!(actual, expected); - assert_eq!(actual_tlvs, expected_tlvs); - assert_eq!(actual.length(), 41); - assert_eq!(actual.address_family(), AddressFamily::IPv6); - assert_eq!( - actual.address_bytes(), - &[ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF1, 1, 0, 1, 5 - ] - ); - assert_eq!(actual.tlv_bytes(), &[3, 0, 2, 5, 5]); - assert_eq!(actual.as_bytes(), input.as_slice()); - } - - #[test] - fn partial_tlv() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x11); - input.extend([0, 15]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - input.extend([1, 0, 1]); - - let header = Header::try_from(input.as_slice()).unwrap(); - let mut tlvs = header.tlvs(); - - assert_eq!(tlvs.next().unwrap(), Err(ParseError::InvalidTLV(1, 1))); - assert_eq!(tlvs.next(), None); - } - - #[test] - fn missing_tlvs() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x11); - input.extend([0, 17]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([1, 187]); - input.extend([1, 0, 1]); - - assert_eq!( - Header::try_from(&input[..]).unwrap_err(), - ParseError::Partial(15, 17) - ); - } - - #[test] - fn partial_address() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x21); - input.push(0x11); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - - assert_eq!( - Header::try_from(&input[..]).unwrap_err(), - ParseError::Partial(10, 12) - ); - } - - #[test] - fn no_address() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x20); - input.push(0x02); - input.extend([0, 0]); - input.extend([0, 80]); - - let header = &input[..input.len() - 2]; - let expected = Header { - header: header.into(), - version: Version::Two, - command: Command::Local, - protocol: Protocol::Datagram, - addresses: Addresses::Unspecified, - }; - - let actual = Header::try_from(input.as_slice()).unwrap(); - let actual_tlvs: Vec, ParseError>> = actual.tlvs().collect(); - - assert_eq!(actual, expected); - assert_eq!(actual_tlvs, vec![]); - assert_eq!(actual.length(), 0); - assert_eq!(actual.address_family(), AddressFamily::Unspecified); - assert!(actual.address_bytes().is_empty()); - assert!(actual.tlv_bytes().is_empty()); - assert_eq!(actual.as_bytes(), header); - } - - #[test] - fn unspecified_address_family() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x20); - input.push(0x02); - input.extend([0, 12]); - input.extend([127, 0, 0, 1]); - input.extend([127, 0, 0, 2]); - input.extend([0, 80]); - input.extend([0xbb, 1]); - - let expected = Header { - header: input.as_slice().into(), - version: Version::Two, - command: Command::Local, - protocol: Protocol::Datagram, - addresses: Addresses::Unspecified, - }; - let actual = Header::try_from(input.as_slice()).unwrap(); - - assert_eq!(actual, expected); - assert!(actual.tlvs().next().is_none()); - assert_eq!(actual.length(), 12); - assert_eq!(actual.address_family(), AddressFamily::Unspecified); - assert_eq!( - actual.address_bytes(), - &[127, 0, 0, 1, 127, 0, 0, 2, 0, 80, 0xbb, 1] - ); - assert!(actual.tlv_bytes().is_empty()); - assert_eq!(actual.as_bytes(), input.as_slice()); - } - - #[test] - fn missing_address() { - let mut input: Vec = Vec::with_capacity(PROTOCOL_PREFIX.len()); - - input.extend_from_slice(PROTOCOL_PREFIX); - input.push(0x20); - input.push(0x22); - input.extend([0, 0]); - input.extend([0, 80]); - - assert_eq!( - Header::try_from(&input[..]).unwrap_err(), - ParseError::InvalidAddresses(0, AddressFamily::IPv6.byte_length().unwrap_or_default()) - ); - } - - #[test] - fn not_prefixed() { - assert_eq!( - Header::try_from(b"\r\n\r\n\x01\r\nQUIT\n".as_slice()).unwrap_err(), - ParseError::Prefix - ); - assert_eq!( - Header::try_from(b"\r\n\r\n\x01".as_slice()).unwrap_err(), - ParseError::Prefix - ); - } - - #[test] - fn incomplete() { - assert_eq!( - Header::try_from([0x0D, 0x0A, 0x0D, 0x0A, 0x00].as_slice()).unwrap_err(), - ParseError::Incomplete(5) - ); - assert_eq!( - Header::try_from(PROTOCOL_PREFIX).unwrap_err(), - ParseError::Incomplete(PROTOCOL_PREFIX.len()) - ); - } -} diff --git a/rama-proxy/src/pp/protocol/v2/model.rs b/rama-proxy/src/pp/protocol/v2/model.rs deleted file mode 100644 index a745be3d..00000000 --- a/rama-proxy/src/pp/protocol/v2/model.rs +++ /dev/null @@ -1,475 +0,0 @@ -use crate::proxy::pp::protocol::ip::{IPv4, IPv6}; -use crate::proxy::pp::protocol::v2::error::ParseError; -use std::borrow::Cow; -use std::fmt; -use std::net::SocketAddr; -use std::ops::BitOr; - -/// The prefix of the PROXY protocol header. -pub const PROTOCOL_PREFIX: &[u8] = b"\r\n\r\n\0\r\nQUIT\n"; -/// The minimum length in bytes of a PROXY protocol header. -pub(crate) const MINIMUM_LENGTH: usize = 16; -/// The minimum length in bytes of a Type-Length-Value payload. -pub(crate) const MINIMUM_TLV_LENGTH: usize = 3; - -/// The number of bytes for an IPv4 addresses payload. -const IPV4_ADDRESSES_BYTES: usize = 12; -/// The number of bytes for an IPv6 addresses payload. -const IPV6_ADDRESSES_BYTES: usize = 36; -/// The number of bytes for a unix addresses payload. -const UNIX_ADDRESSES_BYTES: usize = 216; - -/// A proxy protocol version 2 header. -/// -/// ## Examples -/// ```rust -/// use rama::proxy::pp::protocol::v2::{Addresses, AddressFamily, Command, Header, IPv4, ParseError, Protocol, PROTOCOL_PREFIX, Type, TypeLengthValue, Version}; -/// let mut header = Vec::from(PROTOCOL_PREFIX); -/// header.extend([ -/// 0x21, 0x12, 0, 16, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 4, 0, 1, 42 -/// ]); -/// -/// let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into(); -/// let expected = Header { -/// header: header.as_slice().into(), -/// version: Version::Two, -/// command: Command::Proxy, -/// protocol: Protocol::Datagram, -/// addresses -/// }; -/// let actual = Header::try_from(header.as_slice()).unwrap(); -/// -/// assert_eq!(actual, expected); -/// assert_eq!(actual.tlvs().collect::, ParseError>>>(), vec![Ok(TypeLengthValue::new(Type::NoOp, &[42]))]); -/// ``` -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Header<'a> { - /// The underlying byte slice this `Header` is built on. - pub header: Cow<'a, [u8]>, - /// The version of the PROXY protocol. - pub version: Version, - /// The command of the PROXY protocol. - pub command: Command, - /// The protocol of the PROXY protocol. - pub protocol: Protocol, - /// The source and destination addresses of the PROXY protocol. - pub addresses: Addresses, -} - -/// The supported `Version`s for binary headers. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Version { - /// Version two of the PROXY protocol. - Two = 0x20, -} - -/// The supported `Command`s for a PROXY protocol header. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Command { - /// The connection is a local connection. - Local = 0, - /// The connection is a proxy connection. - Proxy, -} - -/// The supported `AddressFamily` for a PROXY protocol header. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum AddressFamily { - /// The address family is unspecified. - Unspecified = 0x00, - /// The address family is IPv4. - IPv4 = 0x10, - /// The address family is IPv6. - IPv6 = 0x20, - /// The address family is Unix. - Unix = 0x30, -} - -/// The supported `Protocol`s for a PROXY protocol header. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Protocol { - /// The protocol is unspecified. - Unspecified = 0, - /// The protocol is a stream. - Stream, - /// The protocol is a datagram. - Datagram, -} - -/// The source and destination address information for a given `AddressFamily`. -/// -/// ## Examples -/// ```rust -/// use rama::proxy::pp::protocol::v2::{Addresses, AddressFamily}; -/// use std::net::SocketAddr; -/// -/// let addresses: Addresses = ("127.0.0.1:80".parse::().unwrap(), "192.168.1.1:443".parse::().unwrap()).into(); -/// -/// assert_eq!(addresses.address_family(), AddressFamily::IPv4); -/// ``` -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Addresses { - /// The source and destination addresses are unspecified. - Unspecified, - /// The source and destination addresses are IPv4. - IPv4(IPv4), - /// The source and destination addresses are IPv6. - IPv6(IPv6), - /// The source and destination addresses are Unix. - Unix(Unix), -} - -/// The source and destination addresses of UNIX sockets. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct Unix { - /// The source address of the UNIX socket. - pub source: [u8; 108], - /// The destination address of the UNIX socket. - pub destination: [u8; 108], -} - -/// An `Iterator` of `TypeLengthValue`s stored in a byte slice. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct TypeLengthValues<'a> { - bytes: &'a [u8], - offset: usize, -} - -/// A Type-Length-Value payload. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct TypeLengthValue<'a> { - /// The type of the `TypeLengthValue`. - pub kind: u8, - /// The value of the `TypeLengthValue`. - pub value: Cow<'a, [u8]>, -} - -/// Supported types for `TypeLengthValue` payloads. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Type { - /// The ALPN of the connection. - ALPN = 0x01, - /// The authority of the connection. - Authority, - /// The CRC32C checksum of the connection. - CRC32C, - /// NoOp - NoOp, - /// The Unique ID of the connection. - UniqueId, - /// The SSL information. - SSL = 0x20, - /// The SSL Version. - SSLVersion, - /// The SSL common name. - SSLCommonName, - /// The SSL cipher. - SSLCipher, - /// The SSL Signature Algorithm. - SSLSignatureAlgorithm, - /// The SSL Key Algorithm - SSLKeyAlgorithm, - /// The SSL Network Namespace. - NetworkNamespace = 0x30, -} - -impl<'a> fmt::Display for Header<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{:?} {:#X} {:#X} ({} bytes)", - PROTOCOL_PREFIX, - self.version | self.command, - self.protocol | self.address_family(), - self.length() - ) - } -} - -impl<'a> Header<'a> { - /// Creates an owned clone of this [`Header`]. - pub fn to_owned(&self) -> Header<'static> { - Header { - header: Cow::Owned(self.header.to_vec()), - version: self.version, - command: self.command, - protocol: self.protocol, - addresses: self.addresses, - } - } - - /// The length of this `Header`'s payload in bytes. - pub fn length(&self) -> usize { - self.header[MINIMUM_LENGTH..].len() - } - - /// The total length of this `Header` in bytes. - pub fn len(&self) -> usize { - self.header.len() - } - - /// Tests whether this `Header`'s underlying byte slice is empty. - pub fn is_empty(&self) -> bool { - self.header.is_empty() - } - - /// The `AddressFamily` of this `Header`. - pub fn address_family(&self) -> AddressFamily { - self.addresses.address_family() - } - - /// The length in bytes of the address portion of the payload. - fn address_bytes_end(&self) -> usize { - let length = self.length(); - let address_bytes = self.address_family().byte_length().unwrap_or(length); - - MINIMUM_LENGTH + std::cmp::min(address_bytes, length) - } - - /// The bytes of the address portion of the payload. - pub fn address_bytes(&self) -> &[u8] { - &self.header[MINIMUM_LENGTH..self.address_bytes_end()] - } - - /// The bytes of the `TypeLengthValue` portion of the payload. - pub fn tlv_bytes(&self) -> &[u8] { - &self.header[self.address_bytes_end()..] - } - - /// An `Iterator` of `TypeLengthValue`s. - pub fn tlvs(&self) -> TypeLengthValues<'_> { - TypeLengthValues { - bytes: self.tlv_bytes(), - offset: 0, - } - } - - /// The underlying byte slice this `Header` is built on. - pub fn as_bytes(&self) -> &[u8] { - self.header.as_ref() - } -} - -impl<'a> TypeLengthValues<'a> { - /// The underlying byte slice of the `TypeLengthValue`s portion of the `Header` payload. - pub fn as_bytes(&self) -> &[u8] { - self.bytes - } -} - -impl<'a> From<&'a [u8]> for TypeLengthValues<'a> { - fn from(bytes: &'a [u8]) -> Self { - TypeLengthValues { bytes, offset: 0 } - } -} - -impl<'a> Iterator for TypeLengthValues<'a> { - type Item = Result, ParseError>; - - fn next(&mut self) -> Option { - if self.offset >= self.bytes.len() { - return None; - } - - let remaining = &self.bytes[self.offset..]; - - if remaining.len() < MINIMUM_TLV_LENGTH { - self.offset = self.bytes.len(); - return Some(Err(ParseError::Leftovers(self.bytes.len()))); - } - - let tlv_type = remaining[0]; - let length = u16::from_be_bytes([remaining[1], remaining[2]]); - let tlv_length = MINIMUM_TLV_LENGTH + length as usize; - - if remaining.len() < tlv_length { - self.offset = self.bytes.len(); - return Some(Err(ParseError::InvalidTLV(tlv_type, length))); - } - - self.offset += tlv_length; - - Some(Ok(TypeLengthValue { - kind: tlv_type, - value: Cow::Borrowed(&remaining[MINIMUM_TLV_LENGTH..tlv_length]), - })) - } -} - -impl<'a> TypeLengthValues<'a> { - /// The number of bytes in the `TypeLengthValue` portion of the `Header`. - pub fn len(&self) -> u16 { - self.bytes.len() as u16 - } - - /// Whether there are any bytes to be interpreted as `TypeLengthValue`s. - pub fn is_empty(&self) -> bool { - self.bytes.is_empty() - } -} - -impl BitOr for Version { - type Output = u8; - - fn bitor(self, command: Command) -> Self::Output { - (self as u8) | (command as u8) - } -} - -impl BitOr for Command { - type Output = u8; - - fn bitor(self, version: Version) -> Self::Output { - (self as u8) | (version as u8) - } -} - -impl BitOr for AddressFamily { - type Output = u8; - - fn bitor(self, protocol: Protocol) -> Self::Output { - (self as u8) | (protocol as u8) - } -} - -impl AddressFamily { - /// The length in bytes for this `AddressFamily`. - /// `AddressFamily::Unspecified` does not require any bytes, and is represented as `None`. - pub fn byte_length(&self) -> Option { - match self { - AddressFamily::IPv4 => Some(IPV4_ADDRESSES_BYTES), - AddressFamily::IPv6 => Some(IPV6_ADDRESSES_BYTES), - AddressFamily::Unix => Some(UNIX_ADDRESSES_BYTES), - AddressFamily::Unspecified => None, - } - } -} - -impl From for u16 { - fn from(address_family: AddressFamily) -> Self { - address_family.byte_length().unwrap_or_default() as u16 - } -} - -impl From<(SocketAddr, SocketAddr)> for Addresses { - fn from(addresses: (SocketAddr, SocketAddr)) -> Self { - match addresses { - (SocketAddr::V4(source), SocketAddr::V4(destination)) => Addresses::IPv4(IPv4::new( - *source.ip(), - *destination.ip(), - source.port(), - destination.port(), - )), - (SocketAddr::V6(source), SocketAddr::V6(destination)) => Addresses::IPv6(IPv6::new( - *source.ip(), - *destination.ip(), - source.port(), - destination.port(), - )), - _ => Addresses::Unspecified, - } - } -} - -impl From for Addresses { - fn from(addresses: IPv4) -> Self { - Addresses::IPv4(addresses) - } -} - -impl From for Addresses { - fn from(addresses: IPv6) -> Self { - Addresses::IPv6(addresses) - } -} - -impl From for Addresses { - fn from(addresses: Unix) -> Self { - Addresses::Unix(addresses) - } -} - -impl Addresses { - /// The `AddressFamily` for this `Addresses`. - pub fn address_family(&self) -> AddressFamily { - match self { - Addresses::Unspecified => AddressFamily::Unspecified, - Addresses::IPv4(..) => AddressFamily::IPv4, - Addresses::IPv6(..) => AddressFamily::IPv6, - Addresses::Unix(..) => AddressFamily::Unix, - } - } - - /// The length in bytes of the `Addresses` in the `Header`'s payload. - pub fn len(&self) -> usize { - self.address_family().byte_length().unwrap_or_default() - } - - /// Tests whether the `Addresses` consume any space in the `Header`'s payload. - /// `AddressFamily::Unspecified` does not require any bytes, and always returns true. - pub fn is_empty(&self) -> bool { - self.address_family().byte_length().is_none() - } -} - -impl Unix { - /// Creates a new instance of a source and destination address pair for Unix sockets. - pub const fn new(source: [u8; 108], destination: [u8; 108]) -> Self { - Unix { - source, - destination, - } - } -} - -impl BitOr for Protocol { - type Output = u8; - - fn bitor(self, address_family: AddressFamily) -> Self::Output { - (self as u8) | (address_family as u8) - } -} - -impl<'a, T: Into> From<(T, &'a [u8])> for TypeLengthValue<'a> { - fn from((kind, value): (T, &'a [u8])) -> Self { - TypeLengthValue { - kind: kind.into(), - value: value.into(), - } - } -} - -impl<'a> TypeLengthValue<'a> { - /// Creates an owned clone of this [`TypeLengthValue`]. - pub fn to_owned(&self) -> TypeLengthValue<'static> { - TypeLengthValue { - kind: self.kind, - value: Cow::Owned(self.value.to_vec()), - } - } - - /// Creates a new instance of a `TypeLengthValue`, where the length is determine by the length of the byte slice. - /// No check is done to ensure the byte slice's length fits in a `u16`. - pub fn new>(kind: T, value: &'a [u8]) -> Self { - TypeLengthValue { - kind: kind.into(), - value: value.into(), - } - } - - /// The length in bytes of this `TypeLengthValue`'s value. - pub fn len(&self) -> usize { - self.value.len() - } - - /// Tests whether the value of this `TypeLengthValue` is empty. - pub fn is_empty(&self) -> bool { - self.value.is_empty() - } -} - -impl From for u8 { - fn from(kind: Type) -> Self { - kind as u8 - } -} diff --git a/rama-proxy/src/pp/server/layer.rs b/rama-proxy/src/pp/server/layer.rs deleted file mode 100644 index ca85ab36..00000000 --- a/rama-proxy/src/pp/server/layer.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::{fmt, net::SocketAddr}; - -use crate::{ - error::BoxError, - http::headers::Forwarded, - net::forwarded::ForwardedElement, - proxy::pp::protocol::{v1, v2, HeaderResult, PartialResult}, - stream::{ChainReader, HeapReader, Stream}, - Context, Layer, Service, -}; -use tokio::io::AsyncReadExt; - -/// Layer to decode the HaProxy Protocol -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct HaProxyLayer; - -impl HaProxyLayer { - /// Create a new [`HaProxyLayer`]. - pub const fn new() -> Self { - HaProxyLayer - } -} - -impl Layer for HaProxyLayer { - type Service = HaProxyService; - - fn layer(&self, inner: S) -> Self::Service { - HaProxyService { inner } - } -} - -/// Service to decode the HaProxy Protocol -/// -/// This service will decode the HaProxy Protocol header and pass the decoded -/// information to the inner service. -pub struct HaProxyService { - inner: S, -} - -impl HaProxyService { - /// Create a new [`HaProxyService`] with the given inner service. - pub const fn new(inner: S) -> Self { - HaProxyService { inner } - } -} - -impl fmt::Debug for HaProxyService { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("HaProxyService") - .field("inner", &self.inner) - .finish() - } -} - -impl Clone for HaProxyService { - fn clone(&self) -> Self { - HaProxyService { - inner: self.inner.clone(), - } - } -} - -impl Service for HaProxyService -where - State: Send + Sync + 'static, - S: Service< - State, - tokio::io::Join>, tokio::io::WriteHalf>, - Error: Into, - >, - IO: Stream + Unpin, -{ - type Response = S::Response; - type Error = BoxError; - - async fn serve( - &self, - mut ctx: Context, - mut stream: IO, - ) -> Result { - let mut buffer = [0; 512]; - let mut read = 0; - let header = loop { - read += stream.read(&mut buffer[read..]).await?; - - let header = HeaderResult::parse(&buffer[..read]); - if header.is_complete() { - break header; - } - - tracing::debug!("Incomplete header. Read {} bytes so far.", read); - }; - - let consumed = match header { - HeaderResult::V1(Ok(header)) => { - match header.addresses { - v1::Addresses::Tcp4(info) => { - let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); - let el = ForwardedElement::forwarded_for(peer_addr); - match ctx.get_mut::() { - Some(forwarded) => { - forwarded.append(el); - } - None => { - let forwarded = Forwarded::new(el); - ctx.insert(forwarded); - } - } - } - v1::Addresses::Tcp6(info) => { - let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); - let el = ForwardedElement::forwarded_for(peer_addr); - match ctx.get_mut::() { - Some(forwarded) => { - forwarded.append(el); - } - None => { - let forwarded = Forwarded::new(el); - ctx.insert(forwarded); - } - } - } - v1::Addresses::Unknown => (), - }; - header.header.len() - } - HeaderResult::V2(Ok(header)) => { - match header.addresses { - v2::Addresses::IPv4(info) => { - let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); - let el = ForwardedElement::forwarded_for(peer_addr); - match ctx.get_mut::() { - Some(forwarded) => { - forwarded.append(el); - } - None => { - let forwarded = Forwarded::new(el); - ctx.insert(forwarded); - } - } - } - v2::Addresses::IPv6(info) => { - let peer_addr: SocketAddr = (info.source_address, info.source_port).into(); - let el = ForwardedElement::forwarded_for(peer_addr); - match ctx.get_mut::() { - Some(forwarded) => { - forwarded.append(el); - } - None => { - let forwarded = Forwarded::new(el); - ctx.insert(forwarded); - } - } - } - v2::Addresses::Unix(_) | v2::Addresses::Unspecified => (), - }; - header.header.len() - } - HeaderResult::V1(Err(error)) => { - return Err(error.into()); - } - HeaderResult::V2(Err(error)) => { - return Err(error.into()); - } - }; - - // put back the data that is read too much - let (r, w) = tokio::io::split(stream); - let mem: HeapReader = buffer[consumed..read].into(); - let r = ChainReader::new(mem, r); - let stream = tokio::io::join(r, w); - - // read the rest of the data - match self.inner.serve(ctx, stream).await { - Ok(response) => Ok(response), - Err(error) => Err(error.into()), - } - } -} diff --git a/rama-proxy/src/pp/server/mod.rs b/rama-proxy/src/pp/server/mod.rs deleted file mode 100644 index dd398a40..00000000 --- a/rama-proxy/src/pp/server/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! HaProxy Protocol Server support -//! -//! - -mod layer; -#[doc(inline)] -pub use layer::{HaProxyLayer, HaProxyService}; diff --git a/rama-proxy/src/proxydb/csv.rs b/rama-proxy/src/proxydb/csv.rs index ce5b0a94..e3bfc579 100644 --- a/rama-proxy/src/proxydb/csv.rs +++ b/rama-proxy/src/proxydb/csv.rs @@ -1,7 +1,17 @@ +use super::{Proxy, StringFilter}; +use rama_net::{ + address::ProxyAddress, + asn::{Asn, InvalidAsn}, + user::ProxyCredential, +}; +use std::path::Path; +use tokio::{ + fs::File, + io::{AsyncBufReadExt, BufReader, Lines}, +}; + #[derive(Debug)] -/// A CSV Reader that can be used to create a [`MemoryProxyDB`] from a CSV file or raw data. -/// -/// [`MemoryProxyDB`]: crate::proxy::proxydb::MemoryProxyDB +/// A CSV Reader that can be used to create a [`Proxy`] database from a CSV file or raw data. pub struct ProxyCsvRowReader { data: ProxyCsvRowReaderData, } @@ -63,7 +73,7 @@ fn strip_csv_quotes(p: &str) -> &str { .unwrap_or(p) } -fn parse_csv_row(row: &str) -> Option { +pub(crate) fn parse_csv_row(row: &str) -> Option { let mut iter = row.split(',').map(strip_csv_quotes); let id = iter.next().and_then(|s| s.try_into().ok())?; @@ -130,7 +140,7 @@ fn parse_csv_row(row: &str) -> Option { } fn parse_csv_bool(value: &str) -> Option { - match_ignore_ascii_case_str! { + rama_utils::macros::match_ignore_ascii_case_str! { match(value) { "true" | "1" => Some(true), "" | "false" | "0" | "null" | "nil" => Some(false), @@ -204,13 +214,14 @@ impl From for ProxyCsvRowReaderError { #[cfg(test)] mod tests { - use std::str::FromStr; - - use itertools::Itertools; - - use crate::net::Protocol; - use super::*; + use crate::ProxyFilter; + use rama_net::{ + transport::{TransportContext, TransportProtocol}, + Protocol, + }; + use rama_utils::str::NonEmptyString; + use std::str::FromStr; #[test] fn test_parse_csv_bool() { @@ -523,4 +534,138 @@ mod tests { let mut reader = ProxyCsvRowReader::raw(",,,,,,,,,,,"); assert!(reader.next().await.is_err()); } + + #[test] + fn test_proxy_is_match_happy_path_proxy_with_any_filter_string_cases() { + let proxy = parse_csv_row("id,1,,1,,,,,,,authority,*,*,*,*,*,*,0").unwrap(); + let ctx = TransportContext { + protocol: TransportProtocol::Tcp, + app_protocol: Some(Protocol::HTTPS), + http_version: None, + authority: "localhost:8443".try_into().unwrap(), + }; + + for filter in [ + ProxyFilter::default(), + ProxyFilter { + pool_id: Some(vec![StringFilter::new("pool_a")]), + country: Some(vec![StringFilter::new("country_a")]), + city: Some(vec![StringFilter::new("city_a")]), + carrier: Some(vec![StringFilter::new("carrier_a")]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("pool_a")]), + ..Default::default() + }, + ProxyFilter { + continent: Some(vec![StringFilter::new("continent_a")]), + ..Default::default() + }, + ProxyFilter { + country: Some(vec![StringFilter::new("country_a")]), + ..Default::default() + }, + ProxyFilter { + state: Some(vec![StringFilter::new("state_a")]), + ..Default::default() + }, + ProxyFilter { + city: Some(vec![StringFilter::new("city_a")]), + carrier: Some(vec![StringFilter::new("carrier_a")]), + ..Default::default() + }, + ProxyFilter { + carrier: Some(vec![StringFilter::new("carrier_a")]), + ..Default::default() + }, + ] { + assert!(proxy.is_match(&ctx, &filter), "filter: {:?}", filter); + } + } + + #[test] + fn test_proxy_is_match_happy_path_proxy_with_any_filters_cases() { + let proxy = + parse_csv_row("id,1,,1,,,,,,,authority,pool,continent,country,state,city,carrier,42") + .unwrap(); + let ctx = TransportContext { + protocol: TransportProtocol::Tcp, + app_protocol: Some(Protocol::HTTPS), + http_version: None, + authority: "localhost:8443".try_into().unwrap(), + }; + + for filter in [ + ProxyFilter::default(), + ProxyFilter { + pool_id: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + continent: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + country: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + state: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + city: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + carrier: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("pool")]), + continent: Some(vec![StringFilter::new("continent")]), + country: Some(vec![StringFilter::new("country")]), + state: Some(vec![StringFilter::new("state")]), + city: Some(vec![StringFilter::new("city")]), + carrier: Some(vec![StringFilter::new("carrier")]), + asn: Some(vec![Asn::from_static(42)]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("*")]), + country: Some(vec![StringFilter::new("country")]), + city: Some(vec![StringFilter::new("city")]), + carrier: Some(vec![StringFilter::new("carrier")]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("pool")]), + country: Some(vec![StringFilter::new("*")]), + city: Some(vec![StringFilter::new("city")]), + carrier: Some(vec![StringFilter::new("carrier")]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("pool")]), + country: Some(vec![StringFilter::new("country")]), + city: Some(vec![StringFilter::new("*")]), + carrier: Some(vec![StringFilter::new("carrier")]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("pool")]), + country: Some(vec![StringFilter::new("country")]), + city: Some(vec![StringFilter::new("city")]), + carrier: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + continent: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ] { + assert!(proxy.is_match(&ctx, &filter), "filter: {:?}", filter); + } + } } diff --git a/rama-proxy/src/proxydb/internal.rs b/rama-proxy/src/proxydb/internal.rs index 6e590d27..e437753a 100644 --- a/rama-proxy/src/proxydb/internal.rs +++ b/rama-proxy/src/proxydb/internal.rs @@ -1,25 +1,16 @@ use super::{ProxyFilter, StringFilter}; -use rama_utils::macros::match_ignore_ascii_case_str; -use crate::{ - net::{ - address::ProxyAddress, - asn::{Asn, InvalidAsn}, - user::ProxyCredential, - }, - stream::transport::{TransportContext, TransportProtocol}, - utils::str::NonEmptyString, +use rama_net::{ + address::ProxyAddress, + asn::Asn, + transport::{TransportContext, TransportProtocol}, }; +use rama_utils::str::NonEmptyString; use serde::Deserialize; -use std::path::Path; -use tokio::{ - fs::File, - io::{AsyncBufReadExt, BufReader, Lines}, -}; #[cfg(feature = "memory-db")] use venndb::VennDB; -#[derive(Debug, Clone, Deserialize, VennDB)] +#[derive(Debug, Clone, Deserialize)] #[cfg_attr(feature = "memory-db", derive(VennDB))] #[cfg_attr(feature = "memory-db", venndb(validator = proxydb_insert_validator))] /// The selected proxy to use to connect to the proxy. @@ -184,1226 +175,12 @@ impl Proxy { } } -#[derive(Debug)] -/// A CSV Reader that can be used to create a [`MemoryProxyDB`] from a CSV file or raw data. -/// -/// [`MemoryProxyDB`]: crate::proxy::proxydb::MemoryProxyDB -pub struct ProxyCsvRowReader { - data: ProxyCsvRowReaderData, -} - -impl ProxyCsvRowReader { - /// Create a new [`ProxyCsvRowReader`] from the given CSV file. - pub async fn open(path: impl AsRef) -> Result { - let file = tokio::fs::File::open(path).await?; - let reader = BufReader::new(file); - let lines = reader.lines(); - Ok(ProxyCsvRowReader { - data: ProxyCsvRowReaderData::File(lines), - }) - } - - /// Create a new [`ProxyCsvRowReader`] from the given CSV data. - pub fn raw(data: impl AsRef) -> Self { - let lines: Vec<_> = data.as_ref().lines().rev().map(str::to_owned).collect(); - ProxyCsvRowReader { - data: ProxyCsvRowReaderData::Raw(lines), - } - } - - /// Read the next row from the CSV file. - pub async fn next(&mut self) -> Result, ProxyCsvRowReaderError> { - match &mut self.data { - ProxyCsvRowReaderData::File(lines) => { - let line = lines.next_line().await?; - match line { - Some(line) => Ok(Some(match parse_csv_row(&line) { - Some(proxy) => proxy, - None => { - return Err(ProxyCsvRowReaderError { - kind: ProxyCsvRowReaderErrorKind::InvalidRow(line), - }); - } - })), - None => Ok(None), - } - } - ProxyCsvRowReaderData::Raw(lines) => match lines.pop() { - Some(line) => Ok(Some(match parse_csv_row(&line) { - Some(proxy) => proxy, - None => { - return Err(ProxyCsvRowReaderError { - kind: ProxyCsvRowReaderErrorKind::InvalidRow(line), - }); - } - })), - None => Ok(None), - }, - } - } -} - -fn strip_csv_quotes(p: &str) -> &str { - p.strip_prefix('"') - .and_then(|p| p.strip_suffix('"')) - .unwrap_or(p) -} - -fn parse_csv_row(row: &str) -> Option { - let mut iter = row.split(',').map(strip_csv_quotes); - - let id = iter.next().and_then(|s| s.try_into().ok())?; - - let tcp = iter.next().and_then(parse_csv_bool)?; - let udp = iter.next().and_then(parse_csv_bool)?; - let http = iter.next().and_then(parse_csv_bool)?; - let https = iter.next().and_then(parse_csv_bool)?; - let socks5 = iter.next().and_then(parse_csv_bool)?; - let socks5h = iter.next().and_then(parse_csv_bool)?; - let datacenter = iter.next().and_then(parse_csv_bool)?; - let residential = iter.next().and_then(parse_csv_bool)?; - let mobile = iter.next().and_then(parse_csv_bool)?; - let mut address = iter.next().and_then(|s| { - if s.is_empty() { - None - } else { - ProxyAddress::try_from(s).ok() - } - })?; - let pool_id = parse_csv_opt_string_filter(iter.next()?); - let continent = parse_csv_opt_string_filter(iter.next()?); - let country = parse_csv_opt_string_filter(iter.next()?); - let state = parse_csv_opt_string_filter(iter.next()?); - let city = parse_csv_opt_string_filter(iter.next()?); - let carrier = parse_csv_opt_string_filter(iter.next()?); - let asn = parse_csv_opt_asn(iter.next()?).ok()?; - - // support header format or cleartext format - if let Some(value) = iter.next() { - if !value.is_empty() { - let credential = ProxyCredential::try_from_header_str(value) - .or_else(|_| ProxyCredential::try_from_clear_str(value.to_owned())) - .ok()?; - address.credential = Some(credential); - } - } - - // Ensure there are no more values in the row - if iter.next().is_some() { - return None; - } - - Some(Proxy { - id, - address, - tcp, - udp, - http, - https, - socks5, - socks5h, - datacenter, - residential, - mobile, - pool_id, - continent, - country, - state, - city, - carrier, - asn, - }) -} - -fn parse_csv_bool(value: &str) -> Option { - match_ignore_ascii_case_str! { - match(value) { - "true" | "1" => Some(true), - "" | "false" | "0" | "null" | "nil" => Some(false), - _ => None, - } - } -} - -fn parse_csv_opt_string_filter(value: &str) -> Option { - if value.is_empty() { - None - } else { - Some(StringFilter::from(value)) - } -} - -fn parse_csv_opt_asn(value: &str) -> Result, InvalidAsn> { - if value.is_empty() { - Ok(None) - } else { - Asn::try_from(value).map(Some) - } -} - -#[derive(Debug)] -enum ProxyCsvRowReaderData { - File(Lines>), - Raw(Vec), -} - -#[derive(Debug)] -/// An error that can occur when reading a Proxy CSV row. -pub struct ProxyCsvRowReaderError { - kind: ProxyCsvRowReaderErrorKind, -} - -#[derive(Debug)] -/// The kind of error that can occur when reading a Proxy CSV row. -pub enum ProxyCsvRowReaderErrorKind { - /// An I/O error occurred while reading the CSV row. - IoError(std::io::Error), - /// The CSV row is invalid, and could not be parsed. - InvalidRow(String), -} - -impl std::fmt::Display for ProxyCsvRowReaderError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.kind { - ProxyCsvRowReaderErrorKind::IoError(err) => write!(f, "I/O error: {}", err), - ProxyCsvRowReaderErrorKind::InvalidRow(row) => write!(f, "Invalid row: {}", row), - } - } -} - -impl std::error::Error for ProxyCsvRowReaderError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match &self.kind { - ProxyCsvRowReaderErrorKind::IoError(err) => Some(err), - ProxyCsvRowReaderErrorKind::InvalidRow(_) => None, - } - } -} - -impl From for ProxyCsvRowReaderError { - fn from(err: std::io::Error) -> Self { - Self { - kind: ProxyCsvRowReaderErrorKind::IoError(err), - } - } -} - +#[cfg(feature = "csv")] #[cfg(test)] mod tests { - use std::str::FromStr; - - use itertools::Itertools; - - use crate::net::Protocol; - use super::*; - - #[test] - fn test_parse_csv_bool() { - for (input, output) in &[ - ("1", Some(true)), - ("true", Some(true)), - ("True", Some(true)), - ("TRUE", Some(true)), - ("0", Some(false)), - ("false", Some(false)), - ("False", Some(false)), - ("FALSE", Some(false)), - ("null", Some(false)), - ("nil", Some(false)), - ("NULL", Some(false)), - ("NIL", Some(false)), - ("", Some(false)), - ("invalid", None), - ] { - assert_eq!(parse_csv_bool(input), *output); - } - } - - #[test] - fn test_parse_csv_opt_string_filter() { - for (input, output) in [ - ("", None), - ("value", Some("value")), - ("*", Some("*")), - ("Foo", Some("foo")), - (" ok ", Some("ok")), - (" NO ", Some("no")), - ] { - assert_eq!( - parse_csv_opt_string_filter(input) - .as_ref() - .map(|f| f.as_ref()), - output, - ); - } - } - - #[test] - fn test_parse_csv_opt_string_filter_is_any() { - let filter = parse_csv_opt_string_filter("*").unwrap(); - assert!(venndb::Any::is_any(&filter)); - } - - #[test] - fn test_parse_csv_row_happy_path() { - for (input, output) in [ - // most minimal - ( - "id,,,,,,,,,,authority,,,,,,,,", - Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: false, - udp: false, - http: false, - https: false, - socks5: false, - socks5h: false, - datacenter: false, - residential: false, - mobile: false, - pool_id: None, - continent: None, - country: None, - state: None, - city: None, - carrier: None, - asn: None, - }, - ), - // more happy row tests - ( - "id,true,false,true,,false,,true,false,true,authority,pool_id,,country,,city,carrier,,Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("username:password@authority").unwrap(), - tcp: true, - udp: false, - http: true, - https: false, - socks5: false, - socks5h: false, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: None, - country: Some("country".into()), - state: None, - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: None, - }, - ), - ( - "123,1,0,False,,True,,null,false,true,host:1234,,americas,*,*,*,carrier,13335,", - Proxy { - id: NonEmptyString::from_static("123"), - address: ProxyAddress::from_str("host:1234").unwrap(), - tcp: true, - udp: false, - http: false, - https: false, - socks5: true, - socks5h: false, - datacenter: false, - residential: false, - mobile: true, - pool_id: None, - continent: Some("americas".into()), - country: Some("*".into()), - state: Some("*".into()), - city: Some("*".into()), - carrier: Some("carrier".into()), - asn: Some(Asn::from_static(13335)), - }, - ), - ( - "123,1,0,False,,True,,null,false,true,host:1234,,europe,*,,*,carrier,0", - Proxy { - id: NonEmptyString::from_static("123"), - address: ProxyAddress::from_str("host:1234").unwrap(), - tcp: true, - udp: false, - http: false, - https: false, - socks5: true, - socks5h: false, - datacenter: false, - residential: false, - mobile: true, - pool_id: None, - continent: Some("europe".into()), - country: Some("*".into()), - state: None, - city: Some("*".into()), - carrier: Some("carrier".into()), - asn: Some(Asn::unspecified()), - }, - ), - ( - "foo,1,0,1,,0,,1,0,0,bar,baz,,US,,,,", - Proxy { - id: NonEmptyString::from_static("foo"), - address: ProxyAddress::from_str("bar").unwrap(), - tcp: true, - udp: false, - http: true, - https: false, - socks5: false, - socks5h: false, - datacenter: true, - residential: false, - mobile: false, - pool_id: Some("baz".into()), - continent: None, - country: Some("us".into()), - state: None, - city: None, - carrier: None, - asn: None, - }, - ), - ] { - let proxy = parse_csv_row(input).unwrap(); - assert_eq!(proxy.id, output.id); - assert_eq!(proxy.address, output.address); - assert_eq!(proxy.tcp, output.tcp); - assert_eq!(proxy.udp, output.udp); - assert_eq!(proxy.http, output.http); - assert_eq!(proxy.socks5, output.socks5); - assert_eq!(proxy.datacenter, output.datacenter); - assert_eq!(proxy.residential, output.residential); - assert_eq!(proxy.mobile, output.mobile); - assert_eq!(proxy.pool_id, output.pool_id); - assert_eq!(proxy.continent, output.continent); - assert_eq!(proxy.country, output.country); - assert_eq!(proxy.state, output.state); - assert_eq!(proxy.city, output.city); - assert_eq!(proxy.carrier, output.carrier); - assert_eq!(proxy.asn, output.asn); - } - } - - #[test] - fn test_parse_csv_row_mistakes() { - for input in [ - // garbage rows - "", - ",", - ",,,,,,", - ",,,,,,,,,,,,,,,,,,,,", - ",,,,,,,,,,,,,,,,,,,,,,", - ",,,,,,,,,,,,,,,,,,,,,,,", - // too many rows - "id,true,false,true,false,true,false,true,authority,pool_id,continent,country,state,city,carrier,15169,Basic dXNlcm5hbWU6cGFzc3dvcmQ=,", - // missing authority - "id,,,,,,,,,,,,,,,,", - // missing proxy id - ",,,,,,,,authority,,,,,,,,", - // invalid bool values - "id,foo,,,,,,,,,authority,,,,,,,,", - "id,,foo,,,,,,,,authority,,,,,,,,", - "id,,,foo,,,,,,,authority,,,,,,,,", - "id,,,,,foo,,,,,authority,,,,,,,,", - "id,,,,,,foo,,,,authority,,,,,,,,", - "id,,,,,,,,foo,,authority,,,,,,,,", - "id,,,,,,,foo,authority,,,,,,,,", - // invalid credentials - "id,,,,,,,,authority,,,,,:foo", - ] { - assert!(parse_csv_row(input).is_none(), "input: {}", input); - } - } - - #[tokio::test] - async fn test_proxy_csv_row_reader_happy_one_row() { - let mut reader = ProxyCsvRowReader::raw("id,true,false,true,,false,,true,false,true,authority,pool_id,continent,country,state,city,carrier,13335,Basic dXNlcm5hbWU6cGFzc3dvcmQ="); - let proxy = reader.next().await.unwrap().unwrap(); - - assert_eq!(proxy.id, "id"); - assert_eq!( - proxy.address, - ProxyAddress::from_str("username:password@authority").unwrap() - ); - assert!(proxy.tcp); - assert!(!proxy.udp); - assert!(proxy.http); - assert!(!proxy.socks5); - assert!(proxy.datacenter); - assert!(!proxy.residential); - assert!(proxy.mobile); - assert_eq!(proxy.pool_id, Some("pool_id".into())); - assert_eq!(proxy.continent, Some("continent".into())); - assert_eq!(proxy.country, Some("country".into())); - assert_eq!(proxy.state, Some("state".into())); - assert_eq!(proxy.city, Some("city".into())); - assert_eq!(proxy.carrier, Some("carrier".into())); - assert_eq!(proxy.asn, Some(Asn::from_static(13335))); - - // no more rows to read - assert!(reader.next().await.unwrap().is_none()); - } - - #[tokio::test] - async fn test_proxy_csv_row_reader_happy_multi_row() { - let mut reader = ProxyCsvRowReader::raw("id,true,false,false,true,true,false,true,false,true,authority,pool_id,continent,country,state,city,carrier,42,Basic dXNlcm5hbWU6cGFzc3dvcmQ=\nid2,1,0,0,0,0,0,1,0,0,authority2,pool_id2,continent2,country2,state2,city2,carrier2,1"); - - let proxy = reader.next().await.unwrap().unwrap(); - assert_eq!(proxy.id, "id"); - assert_eq!( - proxy.address, - ProxyAddress::from_str("username:password@authority").unwrap() - ); - assert!(proxy.tcp); - assert!(!proxy.udp); - assert!(!proxy.http); - assert!(proxy.https); - assert!(proxy.socks5); - assert!(!proxy.socks5h); - assert!(proxy.datacenter); - assert!(!proxy.residential); - assert!(proxy.mobile); - assert_eq!(proxy.pool_id, Some("pool_id".into())); - assert_eq!(proxy.continent, Some("continent".into())); - assert_eq!(proxy.country, Some("country".into())); - assert_eq!(proxy.state, Some("state".into())); - assert_eq!(proxy.city, Some("city".into())); - assert_eq!(proxy.carrier, Some("carrier".into())); - assert_eq!(proxy.asn, Some(Asn::from_static(42))); - - let proxy = reader.next().await.unwrap().unwrap(); - - assert_eq!(proxy.id, "id2"); - assert_eq!(proxy.address, ProxyAddress::from_str("authority2").unwrap()); - assert!(proxy.tcp); - assert!(!proxy.udp); - assert!(!proxy.http); - assert!(!proxy.https); - assert!(!proxy.socks5); - assert!(!proxy.socks5h); - assert!(proxy.datacenter); - assert!(!proxy.residential); - assert!(!proxy.mobile); - assert_eq!(proxy.pool_id, Some("pool_id2".into())); - assert_eq!(proxy.continent, Some("continent2".into())); - assert_eq!(proxy.country, Some("country2".into())); - assert_eq!(proxy.city, Some("city2".into())); - assert_eq!(proxy.state, Some("state2".into())); - assert_eq!(proxy.carrier, Some("carrier2".into())); - assert_eq!(proxy.asn, Some(Asn::from_static(1))); - - // no more rows to read - assert!(reader.next().await.unwrap().is_none()); - } - - #[tokio::test] - async fn test_proxy_csv_row_reader_failure_empty_data() { - let mut reader = ProxyCsvRowReader::raw(""); - assert!(reader.next().await.unwrap().is_none()); - } - - #[tokio::test] - async fn test_proxy_csv_row_reader_failure_invalid_row() { - let mut reader = ProxyCsvRowReader::raw(",,,,,,,,,,,"); - assert!(reader.next().await.is_err()); - } - - #[test] - fn test_proxy_is_match_happy_path_explicit_h2() { - let proxy = Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: true, - udp: false, - http: true, - https: false, - socks5: false, - socks5h: false, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: Some("continent".into()), - country: Some("country".into()), - state: Some("state".into()), - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: Some(Asn::from_static(1)), - }; - - let ctx = TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - let filter = ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - continent: Some(vec![StringFilter::new("continent")]), - country: Some(vec![StringFilter::new("country")]), - state: Some(vec![StringFilter::new("state")]), - city: Some(vec![StringFilter::new("city")]), - pool_id: Some(vec![StringFilter::new("pool_id")]), - carrier: Some(vec![StringFilter::new("carrier")]), - asn: Some(vec![Asn::from_static(1)]), - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - }; - - assert!(proxy.is_match(&ctx, &filter)); - } - - #[test] - fn test_proxy_is_match_happy_path_explicit_h2_https() { - let proxy = Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: true, - udp: false, - http: false, - https: true, - socks5: false, - socks5h: false, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: Some("continent".into()), - country: Some("country".into()), - state: Some("state".into()), - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: Some(Asn::from_static(1)), - }; - - let ctx = TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - let filter = ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - continent: Some(vec![StringFilter::new("continent")]), - country: Some(vec![StringFilter::new("country")]), - state: Some(vec![StringFilter::new("state")]), - city: Some(vec![StringFilter::new("city")]), - pool_id: Some(vec![StringFilter::new("pool_id")]), - carrier: Some(vec![StringFilter::new("carrier")]), - asn: Some(vec![Asn::from_static(1)]), - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - }; - - assert!(proxy.is_match(&ctx, &filter)); - } - - #[test] - fn test_proxy_is_match_failure_tcp_explicit_h2() { - let proxy = Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: false, - udp: false, - http: true, - https: false, - socks5: false, - socks5h: false, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: Some("continent".into()), - country: Some("country".into()), - state: Some("state".into()), - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: Some(Asn::from_static(1)), - }; - - let ctx = TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - let filter = ProxyFilter { - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - ..Default::default() - }; - - assert!(!proxy.is_match(&ctx, &filter)); - } - - #[test] - fn test_proxy_is_match_happy_path_explicit_h3() { - let proxy = Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: false, - udp: true, - http: false, - https: false, - socks5: true, - socks5h: false, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: None, - country: Some("country".into()), - state: None, - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: None, - }; - - let ctx = TransportContext { - protocol: TransportProtocol::Udp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - let filter = ProxyFilter { - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - ..Default::default() - }; - - assert!(proxy.is_match(&ctx, &filter)); - } - - #[test] - fn test_proxy_is_match_happy_path_explicit_h3_socks5h() { - let proxy = Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: false, - udp: true, - http: false, - https: false, - socks5: false, - socks5h: true, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: None, - country: Some("country".into()), - state: None, - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: None, - }; - - let ctx = TransportContext { - protocol: TransportProtocol::Udp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - let filter = ProxyFilter { - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - ..Default::default() - }; - - assert!(proxy.is_match(&ctx, &filter)); - } - - #[test] - fn test_proxy_is_match_failure_udp_explicit_h3() { - let proxy = Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: false, - udp: false, - http: false, - https: false, - socks5: true, - socks5h: false, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: None, - country: Some("country".into()), - state: None, - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: None, - }; - - let ctx = TransportContext { - protocol: TransportProtocol::Udp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - let filter = ProxyFilter { - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - ..Default::default() - }; - - assert!(!proxy.is_match(&ctx, &filter)); - } - - #[test] - fn test_proxy_is_match_failure_socks5_explicit_h3() { - let proxy = Proxy { - id: NonEmptyString::from_static("id"), - address: ProxyAddress::from_str("authority").unwrap(), - tcp: false, - udp: true, - http: false, - https: false, - socks5: false, - socks5h: false, - datacenter: true, - residential: false, - mobile: true, - pool_id: Some("pool_id".into()), - continent: None, - country: Some("country".into()), - state: None, - city: Some("city".into()), - carrier: Some("carrier".into()), - asn: None, - }; - - let ctx = TransportContext { - protocol: TransportProtocol::Udp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - let filter = ProxyFilter { - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - ..Default::default() - }; - - assert!(!proxy.is_match(&ctx, &filter)); - } - - #[test] - fn test_proxy_is_match_happy_path_filter_cases() { - for (proxy_csv, filter) in [ - ("id,1,,1,,,,,,,authority,,,,,,,,", ProxyFilter::default()), - ( - "id,1,,1,,,,,,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(false), - residential: Some(false), - mobile: Some(false), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,1,,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(true), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,1,,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(true), - residential: Some(false), - mobile: Some(false), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,1,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - residential: Some(true), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,1,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(false), - residential: Some(true), - mobile: Some(false), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,1,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - mobile: Some(true), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,1,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(false), - residential: Some(false), - mobile: Some(true), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,FooBAR,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - pool_id: Some(vec![StringFilter::new(" FooBar")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,FooBAR,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - continent: Some(vec![StringFilter::new(" FooBar")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,FooBAR,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - country: Some(vec![StringFilter::new(" FooBar")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,FooBAR,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - state: Some(vec![StringFilter::new(" FooBar")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,,FooBAR,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - city: Some(vec![StringFilter::new(" FooBar")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,,,FooBAR,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - carrier: Some(vec![StringFilter::new(" FooBar")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,,,,42,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - asn: Some(vec![Asn::from_static(42)]), - ..Default::default() - }, - ), - ] { - let proxy = match parse_csv_row(proxy_csv) { - Some(proxy) => proxy, - None => panic!("failed to parse proxy row: `{proxy_csv}`"), - }; - let ctx = TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - assert!(proxy.is_match(&ctx, &filter), "filter: {:?}", filter); - } - } - - #[test] - fn test_proxy_is_match_failure_filter_cases() { - for (proxy_csv, filter) in [ - ( - "id,1,,1,,,,,,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(true), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - residential: Some(true), - mobile: Some(true), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,1,,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(false), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,1,,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - residential: Some(false), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,1,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - mobile: Some(false), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,1,authority,,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - datacenter: Some(false), - residential: Some(true), - mobile: Some(true), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,FooBAR,,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - pool_id: Some(vec![StringFilter::new("baz")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,FooBAR,,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - continent: Some(vec![StringFilter::new("baz")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,FooBAR,,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - country: Some(vec![StringFilter::new("baz")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,FooBAR,,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - state: Some(vec![StringFilter::new("baz")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,,FooBAR,,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - city: Some(vec![StringFilter::new("baz")]), - ..Default::default() - }, - ), - ( - "id,1,,1,,,,,,,authority,,,,,,FooBAR,,", - ProxyFilter { - id: Some(NonEmptyString::from_static("id")), - carrier: Some(vec![StringFilter::new("baz")]), - ..Default::default() - }, - ), - ] { - let proxy = parse_csv_row(proxy_csv).unwrap(); - let ctx = TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - assert!( - !proxy.is_match(&ctx, &filter), - "filter: {:?}; proxy: {:?}", - filter, - proxy - ); - } - } - - #[test] - fn test_proxy_is_match_happy_path_proxy_with_any_filter_string_cases() { - let proxy = parse_csv_row("id,1,,1,,,,,,,authority,*,*,*,*,*,*,0").unwrap(); - let ctx = TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - for filter in [ - ProxyFilter::default(), - ProxyFilter { - pool_id: Some(vec![StringFilter::new("pool_a")]), - country: Some(vec![StringFilter::new("country_a")]), - city: Some(vec![StringFilter::new("city_a")]), - carrier: Some(vec![StringFilter::new("carrier_a")]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("pool_a")]), - ..Default::default() - }, - ProxyFilter { - continent: Some(vec![StringFilter::new("continent_a")]), - ..Default::default() - }, - ProxyFilter { - country: Some(vec![StringFilter::new("country_a")]), - ..Default::default() - }, - ProxyFilter { - state: Some(vec![StringFilter::new("state_a")]), - ..Default::default() - }, - ProxyFilter { - city: Some(vec![StringFilter::new("city_a")]), - carrier: Some(vec![StringFilter::new("carrier_a")]), - ..Default::default() - }, - ProxyFilter { - carrier: Some(vec![StringFilter::new("carrier_a")]), - ..Default::default() - }, - ] { - assert!(proxy.is_match(&ctx, &filter), "filter: {:?}", filter); - } - } - - #[test] - fn test_proxy_is_match_happy_path_proxy_with_any_filters_cases() { - let proxy = - parse_csv_row("id,1,,1,,,,,,,authority,pool,continent,country,state,city,carrier,42") - .unwrap(); - let ctx = TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), - }; - - for filter in [ - ProxyFilter::default(), - ProxyFilter { - pool_id: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - continent: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - country: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - state: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - city: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - carrier: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("pool")]), - continent: Some(vec![StringFilter::new("continent")]), - country: Some(vec![StringFilter::new("country")]), - state: Some(vec![StringFilter::new("state")]), - city: Some(vec![StringFilter::new("city")]), - carrier: Some(vec![StringFilter::new("carrier")]), - asn: Some(vec![Asn::from_static(42)]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("*")]), - country: Some(vec![StringFilter::new("country")]), - city: Some(vec![StringFilter::new("city")]), - carrier: Some(vec![StringFilter::new("carrier")]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("pool")]), - country: Some(vec![StringFilter::new("*")]), - city: Some(vec![StringFilter::new("city")]), - carrier: Some(vec![StringFilter::new("carrier")]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("pool")]), - country: Some(vec![StringFilter::new("country")]), - city: Some(vec![StringFilter::new("*")]), - carrier: Some(vec![StringFilter::new("carrier")]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("pool")]), - country: Some(vec![StringFilter::new("country")]), - city: Some(vec![StringFilter::new("city")]), - carrier: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - continent: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ] { - assert!(proxy.is_match(&ctx, &filter), "filter: {:?}", filter); - } - } + use crate::proxydb::csv::{parse_csv_row, ProxyCsvRowReader}; + use itertools::Itertools; #[test] fn test_proxy_db_happy_path_basic() { diff --git a/rama-proxy/src/proxydb/layer.rs b/rama-proxy/src/proxydb/layer.rs index 38c5e1a9..8767eabc 100644 --- a/rama-proxy/src/proxydb/layer.rs +++ b/rama-proxy/src/proxydb/layer.rs @@ -1,218 +1,15 @@ -//! [`ProxyDB`] layer support to select a proxy based on the given [`Context`]. -//! -//! This layer expects a [`ProxyFilter`] to be available in the [`Context`], -//! which can be added by using the [`HeaderConfigLayer`] -//! when operating on the HTTP layer and/or by parsing it via the TCP proxy username labels (e.g. `john-country-us-residential`), -//! in case you support that as part of your transport-layer authentication. And of course you can -//! combine the two approaches. -//! -//! You can also give a single [`Proxy`] as "proxy db". -//! -//! The end result is that a [`ProxyAddress`] will be set in case a proxy was selected, -//! an error is returned in case no proxy could be selected while one was expected -//! or of course because the inner [`Service`] failed. -//! -//! [`ProxyAddress`]: crate::net::address::ProxyAddress -//! [`ProxyDB`]: crate::proxy::ProxyDB -//! [`Context`]: rama_core::Context -//! [`HeaderConfigLayer`]: crate::http::layer::header_config::HeaderConfigLayer -//! -//! # Example -//! -//! ```rust -//! use rama::{ -//! http::{Body, Version, Request}, -//! proxy::{ -//! MemoryProxyDB, MemoryProxyDBQueryError, ProxyCsvRowReader, Proxy, -//! layer::{ProxyDBLayer, ProxyFilterMode}, -//! ProxyFilter, -//! }, -//! service::service_fn, -//! Context, Service, Layer, -//! net::address::ProxyAddress, -//! utils::str::NonEmptyString, -//! }; -//! use itertools::Itertools; -//! use std::{convert::Infallible, sync::Arc}; -//! -//! #[tokio::main] -//! async fn main() { -//! let db = MemoryProxyDB::try_from_iter([ -//! Proxy { -//! id: NonEmptyString::from_static("42"), -//! address: "12.34.12.34:8080".try_into().unwrap(), -//! tcp: true, -//! udp: true, -//! http: true, -//! https: false, -//! socks5: true, -//! socks5h: false, -//! datacenter: false, -//! residential: true, -//! mobile: true, -//! pool_id: None, -//! continent: Some("*".into()), -//! country: Some("*".into()), -//! state: Some("*".into()), -//! city: Some("*".into()), -//! carrier: Some("*".into()), -//! asn: None, -//! }, -//! Proxy { -//! id: NonEmptyString::from_static("100"), -//! address: "123.123.123.123:8080".try_into().unwrap(), -//! tcp: true, -//! udp: false, -//! http: true, -//! https: false, -//! socks5: false, -//! socks5h: false, -//! datacenter: true, -//! residential: false, -//! mobile: false, -//! pool_id: None, -//! continent: None, -//! country: Some("US".into()), -//! state: None, -//! city: None, -//! carrier: None, -//! asn: None, -//! }, -//! ]) -//! .unwrap(); -//! -//! let service = -//! ProxyDBLayer::new(Arc::new(db)).filter_mode(ProxyFilterMode::Default) -//! .layer(service_fn(|ctx: Context<()>, _: Request| async move { -//! Ok::<_, Infallible>(ctx.get::().unwrap().clone()) -//! })); -//! -//! let mut ctx = Context::default(); -//! ctx.insert(ProxyFilter { -//! country: Some(vec!["BE".into()]), -//! mobile: Some(true), -//! residential: Some(true), -//! ..Default::default() -//! }); -//! -//! let req = Request::builder() -//! .version(Version::HTTP_3) -//! .method("GET") -//! .uri("https://example.com") -//! .body(Body::empty()) -//! .unwrap(); -//! -//! let proxy_address = service.serve(ctx, req).await.unwrap(); -//! assert_eq!(proxy_address.authority.to_string(), "12.34.12.34:8080"); -//! } -//! ``` -//! -//! ## Single Proxy Router -//! -//! Another example is a single proxy through which -//! one can connect with config for further downstream proxies -//! passed by username labels. -//! -//! Note that the username formatter is available for any proxy db, -//! it is not specific to the usage of a single proxy. -//! -//! ```rust -//! use rama::{ -//! http::{Body, Version, Request}, -//! proxy::{ -//! Proxy, -//! layer::{ProxyDBLayer, ProxyFilterMode}, -//! ProxyFilter, -//! }, -//! service::service_fn, -//! Context, Service, Layer, -//! net::address::ProxyAddress, -//! utils::str::NonEmptyString, -//! }; -//! use itertools::Itertools; -//! use std::{convert::Infallible, sync::Arc}; -//! -//! #[tokio::main] -//! async fn main() { -//! let proxy = Proxy { -//! id: NonEmptyString::from_static("1"), -//! address: "john:secret@proxy.example.com:60000".try_into().unwrap(), -//! tcp: true, -//! udp: true, -//! http: true, -//! https: false, -//! socks5: true, -//! socks5h: false, -//! datacenter: false, -//! residential: true, -//! mobile: false, -//! pool_id: None, -//! continent: Some("*".into()), -//! country: Some("*".into()), -//! state: Some("*".into()), -//! city: Some("*".into()), -//! carrier: Some("*".into()), -//! asn: None, -//! }; -//! -//! let service = ProxyDBLayer::new(Arc::new(proxy)) -//! .filter_mode(ProxyFilterMode::Default) -//! .username_formatter(|_ctx: &Context<()>, proxy: &Proxy, filter: &ProxyFilter, username: &str| { -//! use std::fmt::Write; -//! -//! let mut output = String::new(); -//! -//! if let Some(countries) = -//! filter.country.as_ref().filter(|t| !t.is_empty()) -//! { -//! let _ = write!(output, "country-{}", countries[0]); -//! } -//! if let Some(states) = -//! filter.state.as_ref().filter(|t| !t.is_empty()) -//! { -//! let _ = write!(output, "state-{}", states[0]); -//! } -//! -//! (!output.is_empty()).then(|| format!("{username}-{output}")) -//! }) -//! .layer(service_fn(|ctx: Context<()>, _: Request| async move { -//! Ok::<_, Infallible>(ctx.get::().unwrap().clone()) -//! })); -//! -//! let mut ctx = Context::default(); -//! ctx.insert(ProxyFilter { -//! country: Some(vec!["BE".into()]), -//! residential: Some(true), -//! ..Default::default() -//! }); -//! -//! let req = Request::builder() -//! .version(Version::HTTP_3) -//! .method("GET") -//! .uri("https://example.com") -//! .body(Body::empty()) -//! .unwrap(); -//! -//! let proxy_address = service.serve(ctx, req).await.unwrap(); -//! assert_eq!( -//! "socks5://john-country-be:secret@proxy.example.com:60000", -//! proxy_address.to_string() -//! ); -//! } -//! ``` - use super::{Proxy, ProxyDB, ProxyFilter, ProxyQueryPredicate}; -use rama_utils::macros::define_inner_service_accessors; -use crate::{ +use rama_core::{ error::{BoxError, ErrorContext, ErrorExt, OpaqueError}, - net::{ - address::ProxyAddress, - user::{Basic, ProxyCredential}, - Protocol, - }, - stream::transport::{TransportProtocol, TryRefIntoTransportContext}, Context, Layer, Service, }; +use rama_net::{ + address::ProxyAddress, + transport::{TransportProtocol, TryRefIntoTransportContext}, + user::{Basic, ProxyCredential}, + Protocol, +}; +use rama_utils::macros::define_inner_service_accessors; use std::fmt; /// A [`Service`] which selects a [`Proxy`] based on the given [`Context`]. @@ -223,9 +20,9 @@ use std::fmt; /// A predicate can be used to provide additional filtering on the found proxies, /// that otherwise did match the used [`ProxyFilter`]. /// -/// See [the module docs](self) for examples and more info on the usage of this service. +/// See [the crate docs](crate) for examples and more info on the usage of this service. /// -/// [`Proxy`]: crate::proxy::Proxy +/// [`Proxy`]: crate::Proxy pub struct ProxyDBService { inner: S, db: D, @@ -358,7 +155,7 @@ impl ProxyDBService { } } - /// Set a [`UsernameFormatter`] that will be used to format + /// Set a [`UsernameFormatter`][crate::UsernameFormatter] that will be used to format /// the username based on the selected [`Proxy`]. This is required /// in case the proxy is a router that accepts or maybe even requires /// username labels to configure proxies further down/up stream. @@ -508,7 +305,7 @@ where /// A [`Layer`] which wraps an inner [`Service`] to select a [`Proxy`] based on the given [`Context`], /// and insert, if a [`Proxy`] is selected, it in the [`Context`] for further processing. /// -/// See [the module docs](self) for examples and more info on the usage of this service. +/// See [the crate docs](crate) for examples and more info on the usage of this service. pub struct ProxyDBLayer { db: D, mode: ProxyFilterMode, @@ -597,7 +394,7 @@ impl ProxyDBLayer { } } - /// Set a [`UsernameFormatter`] that will be used to format + /// Set a [`UsernameFormatter`][crate::UsernameFormatter] that will be used to format /// the username based on the selected [`Proxy`]. This is required /// in case the proxy is a router that accepts or maybe even requires /// username labels to configure proxies further down/up stream. @@ -674,20 +471,17 @@ where #[cfg(test)] mod tests { - use itertools::Itertools; - use super::*; - use crate::{ - http::{Body, Request, Version}, - net::{ - address::{Authority, ProxyAddress}, - asn::Asn, - Protocol, - }, - proxy::{MemoryProxyDB, Proxy, ProxyCsvRowReader, StringFilter}, - service::service_fn, - utils::str::NonEmptyString, + use crate::{MemoryProxyDB, Proxy, ProxyCsvRowReader, StringFilter}; + use itertools::Itertools; + use rama_core::service::service_fn; + use rama_http_types::{Body, Request, Version}; + use rama_net::{ + address::{Authority, ProxyAddress}, + asn::Asn, + Protocol, }; + use rama_utils::str::NonEmptyString; use std::{convert::Infallible, str::FromStr, sync::Arc}; #[tokio::test] @@ -951,7 +745,7 @@ mod tests { ..Default::default() }); - let req = crate::tcp::client::Request::new("www.example.com:443".parse().unwrap()) + let req = rama_tcp::client::Request::new("www.example.com:443".parse().unwrap()) .with_protocol(Protocol::HTTPS); let proxy_address = service.serve(ctx, req).await.unwrap(); diff --git a/rama-proxy/src/proxydb/mod.rs b/rama-proxy/src/proxydb/mod.rs index 00310be2..2c2beef7 100644 --- a/rama-proxy/src/proxydb/mod.rs +++ b/rama-proxy/src/proxydb/mod.rs @@ -1,9 +1,9 @@ -use crate::{ - error::BoxError, - net::asn::Asn, - stream::transport::{TransportContext, TransportProtocol}, - utils::str::NonEmptyString, +use rama_core::error::BoxError; +use rama_net::{ + asn::Asn, + transport::{TransportContext, TransportProtocol}, }; +use rama_utils::str::NonEmptyString; use serde::Deserialize; use std::{fmt, future::Future}; @@ -20,15 +20,16 @@ mod csv; #[cfg(feature = "csv")] pub use csv::{ProxyCsvRowReader, ProxyCsvRowReaderError, ProxyCsvRowReaderErrorKind}; -pub mod layer; +#[cfg(feature = "http")] +pub(super) mod layer; mod str; #[doc(inline)] pub use str::StringFilter; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -/// `ID` of the selected proxy. Inserted by the [`layer::ProxyDBService`], -/// if and only if a proxy is selected. +/// `ID` of the selected proxy. To be inserted into the `Context`, +/// only if that proxy is selected. pub struct ProxyID(NonEmptyString); impl ProxyID { @@ -71,14 +72,12 @@ impl From for ProxyID { /// /// ## Usage /// -/// - Use [`HeaderConfigLayer`] to have this proxy filter be given by the [`Request`] headers, +/// - Use `HeaderConfigLayer` (`rama-http`) to have this proxy filter be given by the http `Request` headers, /// which will add the extracted and parsed [`ProxyFilter`] to the [`Context`]'s [`Extensions`]. -/// - Or extract yourself from the username/token validated in the [`ProxyAuthLayer`] +/// - Or extract yourself from the username/token validated in the `ProxyAuthLayer` (`rama-http`) /// to add it manually to the [`Context`]'s [`Extensions`]. /// -/// [`HeaderConfigLayer`]: crate::http::layer::header_config::HeaderConfigLayer /// [`Request`]: crate::http::Request -/// [`ProxyAuthLayer`]: crate::http::layer::proxy_auth::ProxyAuthLayer /// [`Context`]: rama_core::Context /// [`Extensions`]: rama_core::context::Extensions pub struct ProxyFilter { @@ -175,7 +174,7 @@ where macro_rules! impl_proxydb_either { ($id:ident, $($param:ident),+ $(,)?) => { - impl<$($param),+> ProxyDB for crate::combinators::$id<$($param),+> + impl<$($param),+> ProxyDB for rama_core::combinators::$id<$($param),+> where $( $param: ProxyDB>, @@ -192,7 +191,7 @@ macro_rules! impl_proxydb_either { ) -> Result { match self { $( - crate::combinators::$id::$param(s) => s.get_proxy_if(ctx, filter, predicate).await.map_err(Into::into), + rama_core::combinators::$id::$param(s) => s.get_proxy_if(ctx, filter, predicate).await.map_err(Into::into), )+ } } @@ -205,7 +204,7 @@ macro_rules! impl_proxydb_either { ) -> Result { match self { $( - crate::combinators::$id::$param(s) => s.get_proxy(ctx, filter).await.map_err(Into::into), + rama_core::combinators::$id::$param(s) => s.get_proxy(ctx, filter).await.map_err(Into::into), )+ } } @@ -213,7 +212,7 @@ macro_rules! impl_proxydb_either { }; } -crate::combinators::impl_either!(impl_proxydb_either); +rama_core::combinators::impl_either!(impl_proxydb_either); /// Trait that is used by the [`ProxyDB`] for providing an optional /// filter predicate to rule out returned results. @@ -512,15 +511,11 @@ impl MemoryProxyDBQueryError { #[cfg(test)] mod tests { - use std::str::FromStr; - - use crate::{ - net::{address::ProxyAddress, Protocol}, - utils::str::NonEmptyString, - }; - use super::*; use itertools::Itertools; + use rama_net::{address::ProxyAddress, Protocol}; + use rama_utils::str::NonEmptyString; + use std::str::FromStr; const RAW_CSV_DATA: &str = include_str!("./test_proxydb_rows.csv"); diff --git a/rama-proxy/src/proxydb/update.rs b/rama-proxy/src/proxydb/update.rs index 9785f181..d6b31e99 100644 --- a/rama-proxy/src/proxydb/update.rs +++ b/rama-proxy/src/proxydb/update.rs @@ -1,7 +1,6 @@ -use crate::error::{BoxError, OpaqueError}; - use super::ProxyDB; use arc_swap::ArcSwap; +use rama_core::error::{BoxError, OpaqueError}; use std::{fmt, ops::Deref, sync::Arc}; /// Create a new [`ProxyDB`] updater which allows you to have a (typically in-memory) [`ProxyDB`] @@ -62,7 +61,7 @@ where async fn get_proxy_if( &self, - ctx: crate::stream::transport::TransportContext, + ctx: rama_net::transport::TransportContext, filter: super::ProxyFilter, predicate: impl super::ProxyQueryPredicate, ) -> Result { @@ -80,7 +79,7 @@ where async fn get_proxy( &self, - ctx: crate::stream::transport::TransportContext, + ctx: rama_net::transport::TransportContext, filter: super::ProxyFilter, ) -> Result { match self.0.load().deref().deref() { @@ -119,12 +118,12 @@ impl fmt::Debug for LiveUpdateProxyDBSetter { #[cfg(test)] mod tests { - use crate::{ - net::asn::Asn, - proxy::{Proxy, ProxyFilter}, - stream::transport::{TransportContext, TransportProtocol}, - utils::str::NonEmptyString, + use crate::{Proxy, ProxyFilter}; + use rama_net::{ + asn::Asn, + transport::{TransportContext, TransportProtocol}, }; + use rama_utils::str::NonEmptyString; use super::*; diff --git a/rama-proxy/src/username.rs b/rama-proxy/src/username.rs index 0e5792de..8ba4a4bb 100644 --- a/rama-proxy/src/username.rs +++ b/rama-proxy/src/username.rs @@ -1,10 +1,10 @@ use super::ProxyFilter; -use rama_utils::macros::match_ignore_ascii_case_str; -use crate::{ +use rama_core::{ context::Extensions, error::{error, OpaqueError}, - utils::username::{UsernameLabelParser, UsernameLabelState, UsernameLabelWriter}, + username::{UsernameLabelParser, UsernameLabelState, UsernameLabelWriter}, }; +use rama_utils::macros::match_ignore_ascii_case_str; #[derive(Debug, Clone, Default)] #[non_exhaustive] @@ -259,14 +259,10 @@ impl UsernameLabelWriter for ProxyFilter { #[cfg(test)] mod tests { use super::*; - use crate::{ - net::asn::Asn, - proxy::StringFilter, - utils::{ - str::NonEmptyString, - username::{compose_username, parse_username}, - }, - }; + use crate::StringFilter; + use rama_core::username::{compose_username, parse_username}; + use rama_net::asn::Asn; + use rama_utils::str::NonEmptyString; #[test] fn test_username_config() { From 661b76b8fbc49929733853dce4923d042099013a Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 20:53:20 +0200 Subject: [PATCH 11/24] fix rama root crate --- Cargo.lock | 446 ++----------------------------------- Cargo.toml | 73 ++---- rama-cli/src/cmd/fp/mod.rs | 4 +- src/cli/args.rs | 2 +- src/cli/forward.rs | 2 +- src/cli/mod.rs | 5 +- src/cli/service/echo.rs | 18 +- src/cli/service/ip.rs | 7 +- src/cli/tls/boring.rs | 8 +- src/cli/tls/rustls.rs | 4 +- src/http.rs | 15 +- src/lib.rs | 14 +- 12 files changed, 80 insertions(+), 518 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b50a7a49..14b5e655 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,12 +114,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - [[package]] name = "arbitrary" version = "1.3.2" @@ -220,53 +214,6 @@ dependencies = [ "paste", ] -[[package]] -name = "axum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 1.0.1", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 0.1.2", - "tower-layer", - "tower-service", -] - [[package]] name = "backtrace" version = "0.3.73" @@ -485,7 +432,6 @@ dependencies = [ "anstyle", "clap_lex", "strsim", - "terminal_size", ] [[package]] @@ -521,12 +467,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" -[[package]] -name = "condtype" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" - [[package]] name = "const_format" version = "0.2.32" @@ -616,31 +556,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "divan" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d567df2c9c2870a43f3f2bd65aaeb18dbce1c18f217c3e564b4fbaeb3ee56c" -dependencies = [ - "cfg-if", - "clap", - "condtype", - "divan-macros", - "libc", - "regex-lite", -] - -[[package]] -name = "divan-macros" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27540baf49be0d484d8f0130d7d8da3011c32a44d4fc873368154f1510e574a2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "dunce" version = "1.0.5" @@ -691,18 +606,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "escargot" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000f23e9d459aef148b7267e02b03b94a0aaacf4ec64c65612f67e02f525fb6" -dependencies = [ - "log", - "once_cell", - "serde", - "serde_json", -] - [[package]] name = "fastrand" version = "2.1.1" @@ -924,19 +827,13 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.5.0", + "indexmap", "slab", "tokio", "tokio-util", "tracing", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.5" @@ -1120,19 +1017,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-timeout" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" -dependencies = [ - "hyper", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.7" @@ -1140,17 +1024,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", - "futures-channel", "futures-util", "http", "http-body", "hyper", "pin-project-lite", - "socket2", "tokio", - "tower", - "tower-service", - "tracing", ] [[package]] @@ -1173,16 +1052,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.5.0" @@ -1190,7 +1059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown", ] [[package]] @@ -1293,7 +1162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1358,12 +1227,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "memchr" version = "2.7.4" @@ -1489,36 +1352,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "opentelemetry-otlp" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b925a602ffb916fb7421276b86756027b37ee708f9dce2dbdcc51739f07e727" -dependencies = [ - "async-trait", - "futures-core", - "http", - "opentelemetry", - "opentelemetry-proto", - "opentelemetry_sdk", - "prost", - "thiserror", - "tokio", - "tonic", -] - -[[package]] -name = "opentelemetry-proto" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee9f20bff9c984511a02f082dc8ede839e4a9bf15cc2487c8d6fea5ad850d9" -dependencies = [ - "opentelemetry", - "opentelemetry_sdk", - "prost", - "tonic", -] - [[package]] name = "opentelemetry-semantic-conventions" version = "0.16.0" @@ -1535,15 +1368,11 @@ dependencies = [ "futures-channel", "futures-executor", "futures-util", - "glob", "once_cell", "opentelemetry", "percent-encoding", "rand", - "serde_json", "thiserror", - "tokio", - "tokio-stream", ] [[package]] @@ -1578,7 +1407,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1609,26 +1438,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1681,29 +1490,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prost" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" -dependencies = [ - "anyhow", - "itertools 0.13.0", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "quickcheck" version = "1.0.3" @@ -1735,36 +1521,8 @@ name = "rama" version = "0.2.0-alpha.2" dependencies = [ "base64 0.22.1", - "bitflags", - "brotli", "bytes", - "const_format", - "divan", - "escargot", - "flate2", - "futures-core", - "futures-lite", - "h2", - "headers", "hex", - "http", - "http-body", - "http-body-util", - "http-range-header", - "httpdate", - "ipnet", - "iri-string", - "itertools 0.13.0", - "mime", - "mime_guess", - "opentelemetry", - "opentelemetry-otlp", - "opentelemetry-semantic-conventions", - "opentelemetry_sdk", - "parking_lot", - "paste", - "percent-encoding", - "pin-project-lite", "rama-core", "rama-haproxy", "rama-http", @@ -1776,21 +1534,11 @@ dependencies = [ "rama-tls", "rama-ua", "rama-utils", - "regex", "rustversion", - "serde", "serde_html_form", "serde_json", - "sync_wrapper 1.0.1", - "tempfile", "tokio", - "tokio-test", - "tokio-util", "tracing", - "tracing-subscriber", - "unicode-normalization", - "uuid", - "zstd", ] [[package]] @@ -1897,7 +1645,7 @@ dependencies = [ "serde", "serde_html_form", "serde_json", - "sync_wrapper 1.0.1", + "sync_wrapper", "tempfile", "tokio", "tokio-test", @@ -1947,7 +1695,7 @@ dependencies = [ "serde", "serde_html_form", "serde_json", - "sync_wrapper 1.0.1", + "sync_wrapper", "tokio", "tokio-test", "tracing", @@ -2161,12 +1909,6 @@ dependencies = [ "regex-syntax 0.8.4", ] -[[package]] -name = "regex-lite" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" - [[package]] name = "regex-syntax" version = "0.6.29" @@ -2359,7 +2101,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de514ef58196f1fc96dcaef80fe6170a1ce6215df9687a93fe8300e773fefc5" dependencies = [ "form_urlencoded", - "indexmap 2.5.0", + "indexmap", "itoa", "ryu", "serde", @@ -2475,12 +2217,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.1" @@ -2525,16 +2261,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "terminal_size" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" -dependencies = [ - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "thiserror" version = "1.0.63" @@ -2728,75 +2454,13 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.5.0", + "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] -[[package]] -name = "tonic" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "socket2", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - [[package]] name = "tracing" version = "0.1.40" @@ -2965,7 +2629,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ed0d279917911e77093bb5f6a86870c5420cf288e2393c70bcc3a802f0fa63" dependencies = [ "bitvec", - "hashbrown 0.14.5", + "hashbrown", "rand", "venndb-macros", ] @@ -3116,7 +2780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ "windows-core", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3129,7 +2793,7 @@ dependencies = [ "windows-interface", "windows-result", "windows-strings", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3160,7 +2824,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3170,16 +2834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -3188,7 +2843,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3197,22 +2852,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -3221,46 +2861,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3273,48 +2895,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index f7a68019..68b14da6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,49 +135,36 @@ rust-version = { workspace = true } [features] default = [] -telemetry = ["rama-core/telemetry"] +telemetry = ["rama-core/telemetry", "rama-net/telemetry", "rama-http/telemetry"] compression = ["http", "rama-http/compression"] -tls = [] -rustls = ["tls", "rama-tls/rustls"] +tls = ["net", "rama-net/tls", "rama-http/tls", "rama-http-backend/tls"] +rustls = ["tls", "rama-tls/rustls", "rama-net/rustls", "rama-http-backend/rustls"] rustls-ring = ["tls", "rama-tls/rustls-ring"] -boring = ["tls", "rama-tls/boring"] -cli = [] +boring = ["tls", "rama-tls/boring", "rama-net/boring", "rama-http-backend/boring"] +cli = ["dep:base64", "dep:bytes", "dep:hex", "dep:serde_json", "dep:serde_html_form", "dep:tracing", "dep:tokio", "http"] net = [] tcp = ["net"] -http = ["dep:rama-http", "dep:rama-http-backend", "net", "ua"] +http = ["net", "dep:rama-http", "net", "ua", "rama-core/http", "rama-net/http", "rama-proxy/http", "rama-tcp/http"] +http-full = ["http", "dep:rama-http-backend"] proxy = ["dep:rama-proxy"] haproxy = ["dep:rama-haproxy"] ua = ["dep:rama-ua"] +proxy-memory-db = ["proxy", "rama-proxy/memory-db", "rama-core/venndb", "rama-net/venndb"] +proxy-live-update = ["proxy", "rama-proxy/live-update"] +proxy-csv = ["proxy", "rama-proxy/csv"] +proxy-full = ["proxy-memory-db", "proxy-live-update", "proxy-csv", "haproxy"] [build-dependencies] rustversion = { workspace = true } [dependencies] -base64 = { workspace = true } -bitflags = { workspace = true } -bytes = { workspace = true } -const_format = { workspace = true } -futures-core = { workspace = true } -futures-lite = { workspace = true } -h2 = { workspace = true } -headers = { workspace = true } -hex = { workspace = true } -http = { workspace = true } -http-body = { workspace = true } -http-body-util = { workspace = true } -http-range-header = { workspace = true } -httpdate = { workspace = true } -ipnet = { workspace = true } -iri-string = { workspace = true } -mime = { workspace = true } -mime_guess = { workspace = true } -opentelemetry = { workspace = true, optional = true } -opentelemetry-semantic-conventions = { workspace = true, optional = true } -opentelemetry_sdk = { workspace = true, optional = true } -parking_lot = { workspace = true } -paste = { workspace = true } -percent-encoding = { workspace = true } -pin-project-lite = { workspace = true } +base64 = { workspace = true, optional = true } +bytes = { workspace = true, optional = true } +hex = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true } +serde_html_form = { workspace = true, optional = true } +tracing = { workspace = true, optional = true } +tokio = { workspace = true, features = ["macros", "io-std"], optional = true } rama-core = { version = "0.2.0-alpha.2", path = "rama-core" } rama-net = { version = "0.2.0-alpha.2", path = "rama-net", optional = true } rama-http = { version = "0.2.0-alpha.2", path = "rama-http", optional = true } @@ -189,32 +176,8 @@ rama-tls = { version = "0.2.0-alpha.2", path = "rama-tls", optional = true } rama-ua = { version = "0.2.0-alpha.2", path = "rama-ua", optional = true } rama-utils = { version = "0.2.0-alpha.2", path = "rama-utils" } rama-tcp = { version = "0.2.0-alpha.2", path = "rama-tcp", optional = true } -regex = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_html_form = { workspace = true } -serde_json = { workspace = true } -sync_wrapper = { workspace = true } -tokio = { workspace = true, features = ["macros", "fs", "io-std"] } -tokio-util = { workspace = true } -tracing = { workspace = true } -unicode-normalization = { workspace = true } -uuid = { workspace = true, features = ["v4"] } [dev-dependencies] -brotli = { workspace = true } -divan = { workspace = true } -escargot = { workspace = true } -flate2 = { workspace = true } -itertools = { workspace = true } -opentelemetry-otlp = { workspace = true } -opentelemetry_sdk = { workspace = true, features = [ "rt-tokio"] } -rustversion = { workspace = true } -tempfile = { workspace = true } -tokio = { workspace = true, features = ["full"] } -tokio-test = { workspace = true } -tracing = { workspace = true } -tracing-subscriber = { workspace = true, features = ["env-filter"] } -zstd = { workspace = true } [profile.dev.package."*"] opt-level = 3 diff --git a/rama-cli/src/cmd/fp/mod.rs b/rama-cli/src/cmd/fp/mod.rs index 7e65f246..c439158c 100644 --- a/rama-cli/src/cmd/fp/mod.rs +++ b/rama-cli/src/cmd/fp/mod.rs @@ -22,12 +22,12 @@ use rama::{ limit::policy::ConcurrentPolicy, ConsumeErrLayer, HijackLayer, Layer, LimitLayer, TimeoutLayer, }, - proxy::pp::server::HaProxyLayer, + proxy::haproxy::server::HaProxyLayer, rt::Executor, service::service_fn, stream::layer::http::BodyLimitLayer, tcp::server::TcpListener, - tls::backend::boring::server::TlsAcceptorLayer, + tls::boring::server::TlsAcceptorLayer, ua::UserAgentClassifierLayer, utils::backoff::ExponentialBackoff, }; diff --git a/src/cli/args.rs b/src/cli/args.rs index 64220cd8..38878062 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -1,6 +1,5 @@ //! build requests from command line arguments -use rama_utils::macros::match_ignore_ascii_case_str; use crate::{ error::{ErrorContext, OpaqueError}, http::{ @@ -8,6 +7,7 @@ use crate::{ Body, Method, Request, Uri, }, }; +use rama_utils::macros::match_ignore_ascii_case_str; use serde_json::Value; use std::collections::HashMap; diff --git a/src/cli/forward.rs b/src/cli/forward.rs index 90a85e84..e9a37f06 100644 --- a/src/cli/forward.rs +++ b/src/cli/forward.rs @@ -37,7 +37,7 @@ pub enum ForwardKind { TrueClientIp, /// [`HaProxy`] protocol (transport layer). /// - /// [`HaProxy`]: crate::proxy::pp + /// [`HaProxy`]: crate::proxy::haproxy HaProxy, } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 7e8bfcac..560b8955 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,11 +1,14 @@ //! rama cli utilities +#[cfg(feature = "http")] pub mod args; + +#[cfg(all(feature = "http", feature = "net", feature = "haproxy"))] pub mod service; mod forward; #[doc(inline)] pub use forward::ForwardKind; -#[cfg(any(feature = "boring", feature = "rustls"))] +#[cfg(all(feature = "http", any(feature = "boring", feature = "rustls")))] pub mod tls; diff --git a/src/cli/service/echo.rs b/src/cli/service/echo.rs index 377d2d93..a6664b66 100644 --- a/src/cli/service/echo.rs +++ b/src/cli/service/echo.rs @@ -13,19 +13,21 @@ use crate::{ dep::http_body_util::BodyExt, headers::{CFConnectingIp, ClientIp, TrueClientIp, XClientIp, XRealIp}, layer::{ - forwarded::GetForwardedHeadersLayer, required_header::AddRequiredResponseHeadersLayer, + forwarded::GetForwardedHeadersLayer, + required_header::AddRequiredResponseHeadersLayer, trace::TraceLayer, + ua::{UserAgent, UserAgentClassifierLayer}, }, response::Json, server::HttpServer, - IntoResponse, Request, RequestContext, Response, + IntoResponse, Request, Response, }, layer::{limit::policy::ConcurrentPolicy, ConsumeErrLayer, LimitLayer, TimeoutLayer}, net::forwarded::Forwarded, - proxy::pp::server::HaProxyLayer, + net::http::RequestContext, + net::stream::{layer::http::BodyLimitLayer, SocketInfo}, + proxy::haproxy::server::HaProxyLayer, rt::Executor, - stream::{layer::http::BodyLimitLayer, SocketInfo}, - ua::{UserAgent, UserAgentClassifierLayer}, Context, Layer, Service, }; use serde_json::json; @@ -36,14 +38,14 @@ use tokio::net::TcpStream; use crate::{ cli::tls::TlsServerCertKeyPair, error::{ErrorContext, OpaqueError}, - tls::{client::ClientHelloExtension, SecureTransport}, + tls::types::{client::ClientHelloExtension, SecureTransport}, }; #[cfg(feature = "boring")] -use crate::tls::backend::boring::server::TlsAcceptorLayer; +use crate::tls::boring::server::TlsAcceptorLayer; #[cfg(all(feature = "rustls", not(feature = "boring")))] -use crate::tls::backend::rustls::server::{TlsAcceptorLayer, TlsClientConfigHandler}; +use crate::tls::rustls::server::{TlsAcceptorLayer, TlsClientConfigHandler}; #[derive(Debug, Clone)] /// Builder that can be used to run your own echo [`Service`], diff --git a/src/cli/service/ip.rs b/src/cli/service/ip.rs index 1d0d7c6c..68a92ec0 100644 --- a/src/cli/service/ip.rs +++ b/src/cli/service/ip.rs @@ -10,17 +10,16 @@ use crate::{ headers::{CFConnectingIp, ClientIp, TrueClientIp, XClientIp, XRealIp}, layer::{ forwarded::GetForwardedHeadersLayer, required_header::AddRequiredResponseHeadersLayer, - trace::TraceLayer, + trace::TraceLayer, ua::UserAgentClassifierLayer, }, server::HttpServer, IntoResponse, Request, Response, StatusCode, }, layer::{limit::policy::ConcurrentPolicy, ConsumeErrLayer, LimitLayer, TimeoutLayer}, net::forwarded::Forwarded, - proxy::pp::server::HaProxyLayer, + net::stream::{layer::http::BodyLimitLayer, SocketInfo, Stream}, + proxy::haproxy::server::HaProxyLayer, rt::Executor, - stream::{layer::http::BodyLimitLayer, SocketInfo, Stream}, - ua::UserAgentClassifierLayer, Context, Layer, Service, }; use std::{convert::Infallible, marker::PhantomData, time::Duration}; diff --git a/src/cli/tls/boring.rs b/src/cli/tls/boring.rs index 81f60158..e1e961e1 100644 --- a/src/cli/tls/boring.rs +++ b/src/cli/tls/boring.rs @@ -2,11 +2,11 @@ use crate::error::{BoxError, ErrorContext}; use crate::http::Version; -use crate::tls::backend::boring::server::ServerConfig; -use crate::tls::ApplicationProtocol; +use crate::tls::boring::dep::boring::pkey::PKey; +use crate::tls::boring::dep::boring::x509::X509; +use crate::tls::boring::server::ServerConfig; +use crate::tls::types::ApplicationProtocol; use base64::Engine; -use boring::pkey::PKey; -use boring::x509::X509; const BASE64: base64::engine::GeneralPurpose = base64::engine::general_purpose::STANDARD; diff --git a/src/cli/tls/rustls.rs b/src/cli/tls/rustls.rs index 8282ee8a..fcb9971b 100644 --- a/src/cli/tls/rustls.rs +++ b/src/cli/tls/rustls.rs @@ -2,8 +2,8 @@ use crate::error::BoxError; use crate::http::Version; -use crate::tls::backend::rustls::dep::pemfile; -use crate::tls::backend::rustls::dep::rustls::{KeyLogFile, ServerConfig}; +use crate::tls::rustls::dep::pemfile; +use crate::tls::rustls::dep::rustls::{KeyLogFile, ServerConfig}; use base64::Engine; use std::io::BufReader; use std::sync::Arc; diff --git a/src/http.rs b/src/http.rs index fc7ebb35..50113a10 100644 --- a/src/http.rs +++ b/src/http.rs @@ -4,23 +4,20 @@ //! `rama-http` and `rama-http-backend`. pub use ::rama_http::{ - header, + dep, header, headers, io, matcher, response::{self, IntoResponse, Response}, - Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, Method, - Request, Scheme, StatusCode, Uri, Version, - headers, matcher, service, io, dep, RequestContext, + service, Body, BodyDataStream, BodyExtractExt, BodyLimit, HeaderMap, HeaderName, HeaderValue, + Method, Request, Scheme, StatusCode, Uri, Version, }; pub mod layer { - //! Http [`Layer`]s provided by Rama. + //! Http [`Layer`][crate::Layer]s provided by Rama. //! //! mostly contains re-exports from //! `rama-http` and `rama-http-backend`. pub use ::rama_http::layer::*; - pub use ::rama_http_backend::layer::*; + pub use ::rama_http_backend::server::layer::*; } -pub use ::rama_http_backend::{ - server, client, -}; +pub use ::rama_http_backend::{client, server}; diff --git a/src/lib.rs b/src/lib.rs index 208137a4..ecf3073b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,16 +15,16 @@ //! //! | category | support list | //! |-|-| -//! | βœ… [transports](crate::stream) | βœ… [tcp] βΈ± πŸ—οΈ udp (1) βΈ± βœ… [middleware](crate::stream::layer) | +//! | βœ… [transports](crate::net::stream) | βœ… [tcp] βΈ± πŸ—οΈ udp (1) βΈ± βœ… [middleware](crate::net::stream::layer) | //! | βœ… [http] | βœ… [auto](crate::http::server::service::HttpServer::auto) βΈ± βœ… [http/1.1](crate::http::server::service::HttpServer::http1) βΈ± βœ… [h2](crate::http::server::service::HttpServer::h2) βΈ± πŸ—οΈ h3 (1) βΈ± βœ… [middleware](crate::http::layer) | //! | βœ… web server | βœ… [fs](crate::http::service::fs) βΈ± βœ… [redirect](crate::http::service::redirect::Redirect) βΈ± βœ… [dyn router](crate::http::service::web::WebService) βΈ± βœ… [static router](crate::http::service::web::match_service) βΈ± βœ… [handler extractors](crate::http::service::web::extract) βΈ± βœ… [k8s healthcheck](crate::http::service::web::k8s) | -//! | βœ… [http client](crate::http::client) | βœ… [client](crate::http::client::HttpClient) βΈ± βœ… [high level API](crate::http::client::HttpClientExt) βΈ± βœ… [Proxy Connect](crate::proxy::http::client::layer::HttpProxyConnector) βΈ± ❌ [Chromium Http](https://github.com/plabayo/rama/issues/189) (3) | -//! | βœ… [tls] | βœ… [Rustls](crate::tls::backend::rustls) βΈ± βœ… [BoringSSL](crate::tls::backend::boring) βΈ± ❌ NSS (3) | +//! | βœ… [http client](crate::http::client) | βœ… [client](crate::http::client::HttpClient) βΈ± βœ… [high level API](crate::http::service::client::HttpClientExt) βΈ± βœ… [Proxy Connect](crate::http::client::proxy::layer::HttpProxyConnector) βΈ± ❌ [Chromium Http](https://github.com/plabayo/rama/issues/189) (3) | +//! | βœ… [tls] | βœ… [Rustls](crate::tls::rustls) βΈ± βœ… [BoringSSL](crate::tls::boring) βΈ± ❌ NSS (3) | //! | βœ… [dns] | βœ… [DNS Resolver][crate::dns::Dns] | -//! | βœ… [proxy] protocols | βœ… [PROXY protocol](crate::proxy::pp) βΈ± βœ… [http proxy](https://github.com/plabayo/rama/blob/main/examples/http_connect_proxy.rs) βΈ± βœ… [https proxy](https://github.com/plabayo/rama/blob/main/examples/https_connect_proxy.rs) βΈ± πŸ—οΈ SOCKS5 (1) βΈ± πŸ—οΈ SOCKS5H (1) | +//! | βœ… [proxy] protocols | βœ… [PROXY protocol](crate::proxy::haproxy) βΈ± βœ… [http proxy](https://github.com/plabayo/rama/blob/main/examples/http_connect_proxy.rs) βΈ± βœ… [https proxy](https://github.com/plabayo/rama/blob/main/examples/https_connect_proxy.rs) βΈ± πŸ—οΈ SOCKS5 (1) βΈ± πŸ—οΈ SOCKS5H (1) | //! | πŸ—οΈ web protocols | πŸ—οΈ Web Sockets (WS) (2) βΈ± πŸ—οΈ WSS (2) βΈ± ❌ Web Transport (3) βΈ± ❌ gRPC (3) | //! | βœ… [async-method trait](https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html) services | βœ… [Service] βΈ± βœ… [Layer] βΈ± βœ… [context] βΈ± βœ… [dyn dispatch](crate::service::BoxService) βΈ± βœ… [middleware](crate::layer) | -//! | βœ… [telemetry][opentelemetry] | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry] βΈ± βœ… [http metrics](crate::http::layer::opentelemetry) βΈ± βœ… [transport metrics](crate::stream::layer::opentelemetry) | +//! | βœ… [telemetry] | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry][telemetry::opentelemetry] βΈ± βœ… [http metrics](crate::http::layer::opentelemetry) βΈ± βœ… [transport metrics](crate::net::stream::layer::opentelemetry) | //! | βœ… upstream [proxies](proxy) | βœ… [MemoryProxyDB](crate::proxy::MemoryProxyDB) βΈ± βœ… [L4 Username Config] βΈ± βœ… [Proxy Filters](crate::proxy::ProxyFilter) | //! | πŸ—οΈ [User Agent (UA)](https://ramaproxy.org/book/intro/user_agent) | πŸ—οΈ Http Emulation (1) βΈ± πŸ—οΈ Tls Emulation (1) βΈ± βœ… [UA Parsing](crate::ua::UserAgent) | //! | βœ… utilities | βœ… [error handling](crate::error) βΈ± βœ… [graceful shutdown](crate::graceful) βΈ± πŸ—οΈ Connection Pool (2) βΈ± πŸ—οΈ IP2Loc (2) | @@ -277,8 +277,8 @@ #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] pub use ::rama_core::{ - combinators, dns, error, graceful, layer, matcher, net, rt, service, stream, Context, - Layer, Service, + combinators, context, dns, error, graceful, layer, matcher, rt, service, Context, Layer, + Service, }; #[cfg(feature = "tcp")] From 88a1037bbcbac2d355bfa61f6a0105635cb6dd0d Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 21:01:12 +0200 Subject: [PATCH 12/24] sort workspace + add dummy socks5/udp rama crates --- Cargo.lock | 8 +++++ Cargo.toml | 20 +++++++------ rama-http-backend/Cargo.toml | 16 +++++----- rama-http/Cargo.toml | 32 ++++++++++---------- rama-net/Cargo.toml | 8 ++--- rama-proxy/Cargo.toml | 12 ++++---- rama-socks5/Cargo.toml | 25 ++++++++++++++++ rama-socks5/README.md | 49 ++++++++++++++++++++++++++++++ rama-socks5/src/lib.rs | 58 ++++++++++++++++++++++++++++++++++++ rama-tcp/Cargo.toml | 6 ++-- rama-tcp/src/lib.rs | 2 +- rama-tls/Cargo.toml | 12 ++++---- rama-udp/Cargo.toml | 25 ++++++++++++++++ rama-udp/README.md | 49 ++++++++++++++++++++++++++++++ rama-udp/src/lib.rs | 58 ++++++++++++++++++++++++++++++++++++ 15 files changed, 327 insertions(+), 53 deletions(-) create mode 100644 rama-socks5/Cargo.toml create mode 100644 rama-socks5/README.md create mode 100644 rama-socks5/src/lib.rs create mode 100644 rama-udp/Cargo.toml create mode 100644 rama-udp/README.md create mode 100644 rama-udp/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 14b5e655..342130ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1766,6 +1766,10 @@ dependencies = [ "venndb", ] +[[package]] +name = "rama-socks5" +version = "0.2.0-alpha.2" + [[package]] name = "rama-tcp" version = "0.2.0-alpha.2" @@ -1813,6 +1817,10 @@ dependencies = [ "tokio", ] +[[package]] +name = "rama-udp" +version = "0.2.0-alpha.2" + [[package]] name = "rama-utils" version = "0.2.0-alpha.2" diff --git a/Cargo.toml b/Cargo.toml index 68b14da6..319d375d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,16 +5,18 @@ members = [ "rama-cli", "rama-core", "rama-error", - "rama-tcp", + "rama-haproxy", "rama-http", "rama-http-backend", "rama-http-types", "rama-macros", "rama-net", "rama-proxy", - "rama-haproxy", + "rama-socks5", + "rama-tcp", "rama-tls", "rama-ua", + "rama-udp", "rama-utils", ] @@ -161,21 +163,21 @@ rustversion = { workspace = true } base64 = { workspace = true, optional = true } bytes = { workspace = true, optional = true } hex = { workspace = true, optional = true } -serde_json = { workspace = true, optional = true } -serde_html_form = { workspace = true, optional = true } -tracing = { workspace = true, optional = true } -tokio = { workspace = true, features = ["macros", "io-std"], optional = true } rama-core = { version = "0.2.0-alpha.2", path = "rama-core" } -rama-net = { version = "0.2.0-alpha.2", path = "rama-net", optional = true } +rama-haproxy = { version = "0.2.0-alpha.2", path = "rama-haproxy", optional = true } rama-http = { version = "0.2.0-alpha.2", path = "rama-http", optional = true } rama-http-backend = { version = "0.2.0-alpha.2", path = "rama-http-backend", optional = true } rama-macros = { version = "0.2.0-alpha.2", path = "rama-macros" } +rama-net = { version = "0.2.0-alpha.2", path = "rama-net", optional = true } rama-proxy = { version = "0.2.0-alpha.2", path = "rama-proxy", optional = true } -rama-haproxy = { version = "0.2.0-alpha.2", path = "rama-haproxy", optional = true } +rama-tcp = { version = "0.2.0-alpha.2", path = "rama-tcp", optional = true } rama-tls = { version = "0.2.0-alpha.2", path = "rama-tls", optional = true } rama-ua = { version = "0.2.0-alpha.2", path = "rama-ua", optional = true } rama-utils = { version = "0.2.0-alpha.2", path = "rama-utils" } -rama-tcp = { version = "0.2.0-alpha.2", path = "rama-tcp", optional = true } +serde_html_form = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true } +tokio = { workspace = true, features = ["macros", "io-std"], optional = true } +tracing = { workspace = true, optional = true } [dev-dependencies] diff --git a/rama-http-backend/Cargo.toml b/rama-http-backend/Cargo.toml index f7085fc2..a59e596a 100644 --- a/rama-http-backend/Cargo.toml +++ b/rama-http-backend/Cargo.toml @@ -18,17 +18,17 @@ boring = ["tls", "rama-net/boring"] rustls-ring = ["rustls", "rama-tls/rustls-ring"] [dependencies] -rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } -rama-tls = { version = "0.2.0-alpha.2", path = "../rama-tls", optional = true } -rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } -rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } -rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp", features = ["http"] } -rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } +h2 = { workspace = true } hyper = { workspace = true, features = ["http1", "http2", "server", "client"] } hyper-util = { workspace = true, features = ["tokio", "server-auto"] } -h2 = { workspace = true } -tokio = { workspace = true, features = ["macros"] } pin-project-lite = { workspace = true } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } +rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp", features = ["http"] } +rama-tls = { version = "0.2.0-alpha.2", path = "../rama-tls", optional = true } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +tokio = { workspace = true, features = ["macros"] } tracing = { workspace = true } [dev-dependencies] diff --git a/rama-http/Cargo.toml b/rama-http/Cargo.toml index 2c3a754d..6cc45673 100644 --- a/rama-http/Cargo.toml +++ b/rama-http/Cargo.toml @@ -24,6 +24,8 @@ async-compression = { workspace = true, features = [ "gzip", "zstd", ], optional = true } +base64 = { workspace = true } +bitflags = { workspace = true } bytes = { workspace = true } const_format = { workspace = true } futures-core = { workspace = true } @@ -32,43 +34,41 @@ headers = { workspace = true } http = { workspace = true } http-body = { workspace = true } http-body-util = { workspace = true } +http-range-header = { workspace = true } +httpdate = { workspace = true } +iri-string = { workspace = true } mime = { workspace = true } mime_guess = { workspace = true } paste = { workspace = true } +percent-encoding = { workspace = true } pin-project-lite = { workspace = true } -rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } -rama-ua = { version = "0.2.0-alpha.2", path = "../rama-ua" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } +rama-ua = { version = "0.2.0-alpha.2", path = "../rama-ua" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } serde_json = { workspace = true } sync_wrapper = { workspace = true } -tracing = { workspace = true } -regex = { workspace = true } -base64 = { workspace = true } -httpdate = { workspace = true } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } -http-range-header = { workspace = true } -iri-string = { workspace = true } tokio-util = { workspace = true, features = ["io"] } +tracing = { workspace = true } uuid = { workspace = true, features = ["v4"] } -percent-encoding = { workspace = true } -bitflags = { workspace = true } [dev-dependencies] -tokio = { workspace = true, features = ["full"] } -tokio-test = { workspace = true } +brotli = { workspace = true } +flate2 = { workspace = true } itertools = { workspace = true } parking_lot = { workspace = true } -flate2 = { workspace = true } -brotli = { workspace = true } -zstd = { workspace = true } -tempfile = { workspace = true } rama-http-backend = { version = "0.2.0-alpha.2", path = "../rama-http-backend" } rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp" } +tempfile = { workspace = true } +tokio = { workspace = true, features = ["full"] } +tokio-test = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } +zstd = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-net/Cargo.toml b/rama-net/Cargo.toml index c2fcc932..99ce9c78 100644 --- a/rama-net/Cargo.toml +++ b/rama-net/Cargo.toml @@ -22,11 +22,14 @@ telemetry = ["rama-core/telemetry"] [dependencies] base64 = { workspace = true } +boring = { workspace = true, optional = true } bytes = { workspace = true } futures-lite = { workspace = true } headers = { workspace = true } +hex = { workspace = true, optional = true } hickory-resolver = { workspace = true } ipnet = { workspace = true } +nom = { workspace = true, optional = true } opentelemetry = { workspace = true, optional = true } opentelemetry-semantic-conventions = { workspace = true, optional = true } opentelemetry_sdk = { workspace = true, optional = true } @@ -36,15 +39,12 @@ pin-project-lite = { workspace = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +rustls = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } tokio-graceful = { workspace = true } tracing = { workspace = true } venndb = { workspace = true, optional = true } -boring = { workspace = true, optional = true } -rustls = { workspace = true, optional = true } -nom = { workspace = true, optional = true } -hex = { workspace = true, optional = true } [dev-dependencies] itertools = { workspace = true } diff --git a/rama-proxy/Cargo.toml b/rama-proxy/Cargo.toml index aecdaf5e..e168caad 100644 --- a/rama-proxy/Cargo.toml +++ b/rama-proxy/Cargo.toml @@ -20,23 +20,23 @@ csv = ["dep:tokio", "tokio/fs"] [dependencies] arc-swap = { workspace = true, optional = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } -rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } -venndb = { workspace = true, optional = true } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, optional = true } -unicode-normalization = { workspace = true } tracing = { workspace = true } +unicode-normalization = { workspace = true } +venndb = { workspace = true, optional = true } [dev-dependencies] -tokio = { workspace = true, features = ["macros"] } -tokio-test = { workspace = true } itertools = { workspace = true } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp", features = ["http"] } -serde_json = { workspace = true } serde_html_form = { workspace = true } +serde_json = { workspace = true } +tokio = { workspace = true, features = ["macros"] } +tokio-test = { workspace = true } [package.metadata.cargo-public-api-crates] allowed = [] diff --git a/rama-socks5/Cargo.toml b/rama-socks5/Cargo.toml new file mode 100644 index 00000000..fa899666 --- /dev/null +++ b/rama-socks5/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "rama-socks5" +description = "SOCKS5 support for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = [] + +[dependencies] + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-socks5/README.md b/rama-socks5/README.md new file mode 100644 index 00000000..7558a88d --- /dev/null +++ b/rama-socks5/README.md @@ -0,0 +1,49 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-socks5.svg +[crates-url]: https://crates.io/crates/rama-socks5 +[docs-badge]: https://img.shields.io/docsrs/rama-socks5/latest +[docs-url]: https://docs.rs/rama-socks5/latest/rama_socks5/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-socks5 + +SOCKS5 support for rama. + +Crate used by the end-user `rama` crate. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-socks5/src/lib.rs b/rama-socks5/src/lib.rs new file mode 100644 index 00000000..a0be950f --- /dev/null +++ b/rama-socks5/src/lib.rs @@ -0,0 +1,58 @@ +//! SOCKS5 support for Rama. +//! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +/// TODO +pub const PLACEHOLDER: bool = true; diff --git a/rama-tcp/Cargo.toml b/rama-tcp/Cargo.toml index 6b94095d..b6b69278 100644 --- a/rama-tcp/Cargo.toml +++ b/rama-tcp/Cargo.toml @@ -15,11 +15,11 @@ default = [] http = ["dep:rama-http-types", "rama-net/http"] [dependencies] -tokio = { workspace = true, features = ["macros", "net"] } -rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } -rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } +rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } +tokio = { workspace = true, features = ["macros", "net"] } tracing = { workspace = true } [dev-dependencies] diff --git a/rama-tcp/src/lib.rs b/rama-tcp/src/lib.rs index 19ebf68a..7209da83 100644 --- a/rama-tcp/src/lib.rs +++ b/rama-tcp/src/lib.rs @@ -1,4 +1,4 @@ -//! TCP module for Rama. +//! TCP support for Rama. //! //! # Rama //! diff --git a/rama-tls/Cargo.toml b/rama-tls/Cargo.toml index 28bfe627..a952da49 100644 --- a/rama-tls/Cargo.toml +++ b/rama-tls/Cargo.toml @@ -18,23 +18,23 @@ rustls-ring = ["rustls", "tokio-rustls/ring", "rustls/ring", "rama-net/rustls-ri [dependencies] boring = { workspace = true, optional = true } +hex = { workspace = true } +parking_lot = { workspace = true } +pin-project-lite = { workspace = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http", "tls"] } rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } -rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rcgen = { workspace = true } rustls = { workspace = true, optional = true } rustls-native-certs = { workspace = true, optional = true } rustls-pemfile = { workspace = true, optional = true } rustls-pki-types = { workspace = true, optional = true } +tokio = { workspace = true, features = ["macros", "io-std"] } tokio-boring = { workspace = true, optional = true } tokio-rustls = { workspace = true, optional = true } -webpki-roots = { workspace = true, optional = true } -parking_lot = { workspace = true } -tokio = { workspace = true, features = ["macros", "io-std"] } tracing = { workspace = true } -pin-project-lite = { workspace = true } -hex = { workspace = true } +webpki-roots = { workspace = true, optional = true } [dev-dependencies] diff --git a/rama-udp/Cargo.toml b/rama-udp/Cargo.toml new file mode 100644 index 00000000..b0fd4af6 --- /dev/null +++ b/rama-udp/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "rama-udp" +description = "UDP support for rama" +version = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } + +[features] +default = [] + +[dependencies] + +[dev-dependencies] + +[package.metadata.cargo-public-api-crates] +allowed = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rama-udp/README.md b/rama-udp/README.md new file mode 100644 index 00000000..d7fc3739 --- /dev/null +++ b/rama-udp/README.md @@ -0,0 +1,49 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-udp.svg +[crates-url]: https://crates.io/crates/rama-udp +[docs-badge]: https://img.shields.io/docsrs/rama-udp/latest +[docs-url]: https://docs.rs/rama-udp/latest/rama_udp/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-udp + +UDP support for rama. + +Crate used by the end-user `rama` crate. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/rama-udp/src/lib.rs b/rama-udp/src/lib.rs new file mode 100644 index 00000000..4f42db8b --- /dev/null +++ b/rama-udp/src/lib.rs @@ -0,0 +1,58 @@ +//! UDP module for Rama. +//! +//! # Rama +//! +//! Crate used by the end-user `rama` crate and `rama` crate authors alike. +//! +//! Learn more about `rama`: +//! +//! - Github: +//! - Book: + +#![doc( + html_favicon_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png" +)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/plabayo/rama/main/docs/img/old_logo.png")] +#![warn( + clippy::all, + clippy::todo, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::mem_forget, + clippy::unused_self, + clippy::filter_map_next, + clippy::needless_continue, + clippy::needless_borrow, + clippy::match_wildcard_for_single_variants, + clippy::if_let_mutex, + clippy::mismatched_target_os, + clippy::await_holding_lock, + clippy::match_on_vec_items, + clippy::imprecise_flops, + clippy::suboptimal_flops, + clippy::lossy_float_literal, + clippy::rest_pat_in_fully_bound_structs, + clippy::fn_params_excessive_bools, + clippy::exit, + clippy::inefficient_to_string, + clippy::linkedlist, + clippy::macro_use_imports, + clippy::option_option, + clippy::verbose_file_reads, + clippy::unnested_or_patterns, + clippy::str_to_string, + rust_2018_idioms, + future_incompatible, + nonstandard_style, + missing_debug_implementations, + missing_docs +)] +#![deny(unreachable_pub)] +#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![cfg_attr(test, allow(clippy::float_cmp))] +#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] + +/// TODO +pub const PLACEHOLDER: bool = true; From 45a5761dbc678c15392e783846eda5ed1fc992d3 Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 21:12:25 +0200 Subject: [PATCH 13/24] fix more fmt/tests/docs --- Cargo.lock | 16 ---------------- Cargo.toml | 4 ++-- rama-cli/src/cmd/fp/data.rs | 6 +++--- rama-cli/src/cmd/fp/mod.rs | 4 ++-- rama-cli/src/cmd/http/mod.rs | 2 +- rama-cli/src/cmd/proxy/mod.rs | 5 +++-- rama-core/Cargo.toml | 9 --------- rama-core/src/dns/mod.rs | 14 ++++++++++---- rama-http-backend/Cargo.toml | 2 +- rama-http/Cargo.toml | 5 +---- rama-net/Cargo.toml | 9 +-------- rama-proxy/Cargo.toml | 2 +- rama-tls/Cargo.toml | 3 +-- rama-ua/src/info.rs | 2 +- rama-ua/src/lib.rs | 2 +- 15 files changed, 28 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 342130ec..3eb77a8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1561,27 +1561,21 @@ dependencies = [ name = "rama-core" version = "0.2.0-alpha.2" dependencies = [ - "base64 0.22.1", "futures-lite", - "headers", "hickory-resolver", "opentelemetry", "opentelemetry-semantic-conventions", "opentelemetry_sdk", "parking_lot", "paste", - "pin-project-lite", "quickcheck", "rama-error", - "rama-http-types", "rama-macros", "rama-utils", - "serde", "tokio", "tokio-graceful", "tokio-test", "tracing", - "venndb", ] [[package]] @@ -1616,9 +1610,7 @@ dependencies = [ "bitflags", "brotli", "bytes", - "const_format", "flate2", - "futures-core", "futures-lite", "headers", "http", @@ -1645,7 +1637,6 @@ dependencies = [ "serde", "serde_html_form", "serde_json", - "sync_wrapper", "tempfile", "tokio", "tokio-test", @@ -1722,15 +1713,10 @@ dependencies = [ "futures-lite", "headers", "hex", - "hickory-resolver", "ipnet", "itertools 0.13.0", "nom", "opentelemetry", - "opentelemetry-semantic-conventions", - "opentelemetry_sdk", - "parking_lot", - "paste", "pin-project-lite", "quickcheck", "rama-core", @@ -1739,7 +1725,6 @@ dependencies = [ "rustls", "serde", "tokio", - "tokio-graceful", "tokio-test", "tracing", "venndb", @@ -1787,7 +1772,6 @@ name = "rama-tls" version = "0.2.0-alpha.2" dependencies = [ "boring", - "hex", "parking_lot", "pin-project-lite", "rama-core", diff --git a/Cargo.toml b/Cargo.toml index 319d375d..0d674fe7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,12 +146,12 @@ boring = ["tls", "rama-tls/boring", "rama-net/boring", "rama-http-backend/boring cli = ["dep:base64", "dep:bytes", "dep:hex", "dep:serde_json", "dep:serde_html_form", "dep:tracing", "dep:tokio", "http"] net = [] tcp = ["net"] -http = ["net", "dep:rama-http", "net", "ua", "rama-core/http", "rama-net/http", "rama-proxy/http", "rama-tcp/http"] +http = ["net", "dep:rama-http", "net", "ua", "rama-net/http", "rama-proxy/http", "rama-tcp/http"] http-full = ["http", "dep:rama-http-backend"] proxy = ["dep:rama-proxy"] haproxy = ["dep:rama-haproxy"] ua = ["dep:rama-ua"] -proxy-memory-db = ["proxy", "rama-proxy/memory-db", "rama-core/venndb", "rama-net/venndb"] +proxy-memory-db = ["proxy", "rama-proxy/memory-db", "rama-net/venndb"] proxy-live-update = ["proxy", "rama-proxy/live-update"] proxy-csv = ["proxy", "rama-proxy/csv"] proxy-full = ["proxy-memory-db", "proxy-live-update", "proxy-csv", "haproxy"] diff --git a/rama-cli/src/cmd/fp/data.rs b/rama-cli/src/cmd/fp/data.rs index 962e622a..964a15ee 100644 --- a/rama-cli/src/cmd/fp/data.rs +++ b/rama-cli/src/cmd/fp/data.rs @@ -1,9 +1,9 @@ use super::State; use rama::{ error::{BoxError, ErrorContext}, - http::{dep::http::request::Parts, headers::Forwarded, Request, RequestContext}, - stream::SocketInfo, - tls::{ + http::{dep::http::request::Parts, headers::Forwarded, Request}, + net::{stream::SocketInfo, http::RequestContext}, + tls::types::{ client::{ClientHello, ClientHelloExtension}, SecureTransport, }, diff --git a/rama-cli/src/cmd/fp/mod.rs b/rama-cli/src/cmd/fp/mod.rs index c439158c..22853228 100644 --- a/rama-cli/src/cmd/fp/mod.rs +++ b/rama-cli/src/cmd/fp/mod.rs @@ -11,6 +11,7 @@ use rama::{ catch_panic::CatchPanicLayer, compression::CompressionLayer, forwarded::GetForwardedHeadersLayer, required_header::AddRequiredResponseHeadersLayer, set_header::SetResponseHeaderLayer, trace::TraceLayer, + ua::UserAgentClassifierLayer, }, matcher::HttpMatcher, response::Redirect, @@ -25,10 +26,9 @@ use rama::{ proxy::haproxy::server::HaProxyLayer, rt::Executor, service::service_fn, - stream::layer::http::BodyLimitLayer, + net::stream::layer::http::BodyLimitLayer, tcp::server::TcpListener, tls::boring::server::TlsAcceptorLayer, - ua::UserAgentClassifierLayer, utils::backoff::ExponentialBackoff, }; use std::{convert::Infallible, str::FromStr, sync::Arc, time::Duration}; diff --git a/rama-cli/src/cmd/http/mod.rs b/rama-cli/src/cmd/http/mod.rs index aee168a2..7c88a10d 100644 --- a/rama-cli/src/cmd/http/mod.rs +++ b/rama-cli/src/cmd/http/mod.rs @@ -19,7 +19,7 @@ use rama::{ }, layer::{HijackLayer, MapResultLayer}, net::{address::ProxyAddress, user::ProxyCredential}, - proxy::http::client::layer::{HttpProxyAddressLayer, SetProxyAuthHttpHeaderLayer}, + http::client::proxy::layer::{HttpProxyAddressLayer, SetProxyAuthHttpHeaderLayer}, rt::Executor, service::service_fn, Context, Layer, Service, diff --git a/rama-cli/src/cmd/proxy/mod.rs b/rama-cli/src/cmd/proxy/mod.rs index d907e484..ed32f043 100644 --- a/rama-cli/src/cmd/proxy/mod.rs +++ b/rama-cli/src/cmd/proxy/mod.rs @@ -12,12 +12,13 @@ use rama::{ }, matcher::MethodMatcher, server::HttpServer, - Body, IntoResponse, Request, RequestContext, Response, StatusCode, + Body, IntoResponse, Request, Response, StatusCode, }, layer::{limit::policy::ConcurrentPolicy, LimitLayer, TimeoutLayer}, rt::Executor, service::service_fn, - stream::layer::http::BodyLimitLayer, + net::stream::layer::http::BodyLimitLayer, + net::http::RequestContext, tcp::{server::TcpListener, utils::is_connection_error}, Context, Layer, Service, }; diff --git a/rama-core/Cargo.toml b/rama-core/Cargo.toml index 49533994..0a8ad9e6 100644 --- a/rama-core/Cargo.toml +++ b/rama-core/Cargo.toml @@ -12,35 +12,26 @@ rust-version = { workspace = true } [features] default = [] -full = ["telemetry", "venndb", "http"] telemetry = [ "dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-semantic-conventions", ] -venndb = ["dep:venndb"] -http = ["dep:rama-http-types"] [dependencies] -base64 = { workspace = true } futures-lite = { workspace = true } -headers = { workspace = true } hickory-resolver = { workspace = true } opentelemetry = { workspace = true, optional = true } opentelemetry-semantic-conventions = { workspace = true, optional = true } opentelemetry_sdk = { workspace = true, optional = true } parking_lot = { workspace = true } paste = { workspace = true } -pin-project-lite = { workspace = true } rama-error = { version = "0.2.0-alpha.2", path = "../rama-error" } -rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } rama-macros = { version = "0.2.0-alpha.2", path = "../rama-macros" } rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } -serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } tokio-graceful = { workspace = true } tracing = { workspace = true } -venndb = { workspace = true, optional = true } [dev-dependencies] quickcheck = { workspace = true } diff --git a/rama-core/src/dns/mod.rs b/rama-core/src/dns/mod.rs index 1895629a..beec883a 100644 --- a/rama-core/src/dns/mod.rs +++ b/rama-core/src/dns/mod.rs @@ -123,7 +123,11 @@ impl Dns { /// /// Note that this impacts both [`Self::ipv4_lookup`] and [`Self::ipv6_lookup`], /// meaning that no Ipv6 addresses will be returned for the domain. - pub fn insert_overwrite(&mut self, name: impl TryIntoName, addresses: Vec) -> Result<&mut Self, OpaqueError> { + pub fn insert_overwrite( + &mut self, + name: impl TryIntoName, + addresses: Vec, + ) -> Result<&mut Self, OpaqueError> { self.overwrites .get_or_insert_with(HashMap::new) .insert(Name::fqdn_from_domain(name)?, addresses); @@ -135,9 +139,11 @@ impl Dns { /// Existing mappings will be overwritten. /// /// See [`Self::insert_overwrite`] for more information. - pub fn extend_overwrites(&mut self, overwrites: HashMap>) -> Result<&mut Self, OpaqueError> { - let map = self.overwrites - .get_or_insert_with(HashMap::new); + pub fn extend_overwrites( + &mut self, + overwrites: HashMap>, + ) -> Result<&mut Self, OpaqueError> { + let map = self.overwrites.get_or_insert_with(HashMap::new); for (name, addresses) in overwrites.into_iter() { map.insert(Name::fqdn_from_domain(name)?, addresses); } diff --git a/rama-http-backend/Cargo.toml b/rama-http-backend/Cargo.toml index a59e596a..9cf0151c 100644 --- a/rama-http-backend/Cargo.toml +++ b/rama-http-backend/Cargo.toml @@ -22,7 +22,7 @@ h2 = { workspace = true } hyper = { workspace = true, features = ["http1", "http2", "server", "client"] } hyper-util = { workspace = true, features = ["tokio", "server-auto"] } pin-project-lite = { workspace = true } -rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } rama-tcp = { version = "0.2.0-alpha.2", path = "../rama-tcp", features = ["http"] } diff --git a/rama-http/Cargo.toml b/rama-http/Cargo.toml index 6cc45673..e3ea3954 100644 --- a/rama-http/Cargo.toml +++ b/rama-http/Cargo.toml @@ -27,8 +27,6 @@ async-compression = { workspace = true, features = [ base64 = { workspace = true } bitflags = { workspace = true } bytes = { workspace = true } -const_format = { workspace = true } -futures-core = { workspace = true } futures-lite = { workspace = true } headers = { workspace = true } http = { workspace = true } @@ -42,7 +40,7 @@ mime_guess = { workspace = true } paste = { workspace = true } percent-encoding = { workspace = true } pin-project-lite = { workspace = true } -rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } rama-ua = { version = "0.2.0-alpha.2", path = "../rama-ua" } @@ -51,7 +49,6 @@ regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_html_form = { workspace = true } serde_json = { workspace = true } -sync_wrapper = { workspace = true } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } tokio-util = { workspace = true, features = ["io"] } tracing = { workspace = true } diff --git a/rama-net/Cargo.toml b/rama-net/Cargo.toml index 99ce9c78..deef6ca3 100644 --- a/rama-net/Cargo.toml +++ b/rama-net/Cargo.toml @@ -12,8 +12,7 @@ rust-version = { workspace = true } [features] default = [] -full = ["http", "rustls", "boring", "telemetry"] -http = ["dep:rama-http-types", "rama-core/http"] +http = ["dep:rama-http-types"] tls = ["dep:hex"] rustls = ["tls", "dep:rustls"] boring = ["tls", "dep:boring", "dep:nom"] @@ -27,14 +26,9 @@ bytes = { workspace = true } futures-lite = { workspace = true } headers = { workspace = true } hex = { workspace = true, optional = true } -hickory-resolver = { workspace = true } ipnet = { workspace = true } nom = { workspace = true, optional = true } opentelemetry = { workspace = true, optional = true } -opentelemetry-semantic-conventions = { workspace = true, optional = true } -opentelemetry_sdk = { workspace = true, optional = true } -parking_lot = { workspace = true } -paste = { workspace = true } pin-project-lite = { workspace = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types", optional = true } @@ -42,7 +36,6 @@ rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } rustls = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "fs", "io-std"] } -tokio-graceful = { workspace = true } tracing = { workspace = true } venndb = { workspace = true, optional = true } diff --git a/rama-proxy/Cargo.toml b/rama-proxy/Cargo.toml index e168caad..88cc9e76 100644 --- a/rama-proxy/Cargo.toml +++ b/rama-proxy/Cargo.toml @@ -12,7 +12,7 @@ rust-version = { workspace = true } [features] default = ["memory-db", "csv"] -memory-db = ["dep:venndb", "rama-core/venndb", "rama-net/venndb"] +memory-db = ["dep:venndb", "rama-net/venndb"] live-update = ["dep:arc-swap"] http = ["rama-net/http"] csv = ["dep:tokio", "tokio/fs"] diff --git a/rama-tls/Cargo.toml b/rama-tls/Cargo.toml index a952da49..c485a894 100644 --- a/rama-tls/Cargo.toml +++ b/rama-tls/Cargo.toml @@ -18,10 +18,9 @@ rustls-ring = ["rustls", "tokio-rustls/ring", "rustls/ring", "rama-net/rustls-ri [dependencies] boring = { workspace = true, optional = true } -hex = { workspace = true } parking_lot = { workspace = true } pin-project-lite = { workspace = true } -rama-core = { version = "0.2.0-alpha.2", path = "../rama-core", features = ["http"] } +rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } rama-http-types = { version = "0.2.0-alpha.2", path = "../rama-http-types" } rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http", "tls"] } rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } diff --git a/rama-ua/src/info.rs b/rama-ua/src/info.rs index bf1bfc6a..793f82a8 100644 --- a/rama-ua/src/info.rs +++ b/rama-ua/src/info.rs @@ -1,6 +1,6 @@ use super::parse_http_user_agent_header; -use rama_utils::macros::match_ignore_ascii_case_str; use rama_core::error::OpaqueError; +use rama_utils::macros::match_ignore_ascii_case_str; use serde::{Deserialize, Deserializer, Serialize}; use std::{convert::Infallible, fmt, str::FromStr}; diff --git a/rama-ua/src/lib.rs b/rama-ua/src/lib.rs index 65df0759..5251ae8c 100644 --- a/rama-ua/src/lib.rs +++ b/rama-ua/src/lib.rs @@ -92,7 +92,7 @@ #![cfg_attr(test, allow(clippy::float_cmp))] #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; mod info; pub use info::{ From 3bc9105d0ee6fd33b242ce37baf91d041c41ae3f Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 21:21:47 +0200 Subject: [PATCH 14/24] add appropriate feature flags --- Cargo.toml | 2 +- rama-proxy/src/proxydb/mod.rs | 2 ++ src/http.rs | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0d674fe7..b4a7ab70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -145,7 +145,7 @@ rustls-ring = ["tls", "rama-tls/rustls-ring"] boring = ["tls", "rama-tls/boring", "rama-net/boring", "rama-http-backend/boring"] cli = ["dep:base64", "dep:bytes", "dep:hex", "dep:serde_json", "dep:serde_html_form", "dep:tracing", "dep:tokio", "http"] net = [] -tcp = ["net"] +tcp = ["net", "dep:rama-tcp"] http = ["net", "dep:rama-http", "net", "ua", "rama-net/http", "rama-proxy/http", "rama-tcp/http"] http-full = ["http", "dep:rama-http-backend"] proxy = ["dep:rama-proxy"] diff --git a/rama-proxy/src/proxydb/mod.rs b/rama-proxy/src/proxydb/mod.rs index 2c2beef7..eedd07a5 100644 --- a/rama-proxy/src/proxydb/mod.rs +++ b/rama-proxy/src/proxydb/mod.rs @@ -7,7 +7,9 @@ use rama_utils::str::NonEmptyString; use serde::Deserialize; use std::{fmt, future::Future}; +#[cfg(feature = "live-update")] mod update; +#[cfg(feature = "live-update")] #[doc(inline)] pub use update::{proxy_db_updater, LiveUpdateProxyDB, LiveUpdateProxyDBSetter}; diff --git a/src/http.rs b/src/http.rs index 50113a10..73e95c65 100644 --- a/src/http.rs +++ b/src/http.rs @@ -17,7 +17,10 @@ pub mod layer { //! `rama-http` and `rama-http-backend`. pub use ::rama_http::layer::*; + + #[cfg(feature = "http-full")] pub use ::rama_http_backend::server::layer::*; } +#[cfg(feature = "http-full")] pub use ::rama_http_backend::{client, server}; From 44a42c3b726903e8beef7c7afc340dd1bc2be3ab Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 21:22:45 +0200 Subject: [PATCH 15/24] cargo hack: fix more feature combos --- Cargo.toml | 16 +- fuzz/Cargo.toml | 1 + rama-cli/Cargo.toml | 2 +- rama-cli/src/cmd/fp/data.rs | 2 +- rama-cli/src/cmd/fp/mod.rs | 5 +- rama-cli/src/cmd/http/mod.rs | 2 +- rama-cli/src/cmd/proxy/mod.rs | 4 +- rama-http-backend/Cargo.toml | 4 +- rama-proxy/Cargo.toml | 5 +- rama-proxy/src/lib.rs | 1 - rama-proxy/src/proxydb/internal.rs | 3 +- rama-proxy/src/proxydb/mod.rs | 1712 ++++++++++++++-------------- rama-proxy/src/proxydb/str.rs | 1 + rama-tcp/src/client/mod.rs | 1 + 14 files changed, 891 insertions(+), 868 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b4a7ab70..d8b1199d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,16 +137,26 @@ rust-version = { workspace = true } [features] default = [] +full = [ + "telemetry", + "compression", + "rustls", + "boring", + "cli", + "tcp", + "http-full", + "proxy-full", +] telemetry = ["rama-core/telemetry", "rama-net/telemetry", "rama-http/telemetry"] compression = ["http", "rama-http/compression"] -tls = ["net", "rama-net/tls", "rama-http/tls", "rama-http-backend/tls"] +tls = ["net", "dep:rama-tls", "rama-net/tls", "rama-http/tls", "rama-http-backend/tls"] rustls = ["tls", "rama-tls/rustls", "rama-net/rustls", "rama-http-backend/rustls"] rustls-ring = ["tls", "rama-tls/rustls-ring"] boring = ["tls", "rama-tls/boring", "rama-net/boring", "rama-http-backend/boring"] cli = ["dep:base64", "dep:bytes", "dep:hex", "dep:serde_json", "dep:serde_html_form", "dep:tracing", "dep:tokio", "http"] -net = [] +net = ["dep:rama-net"] tcp = ["net", "dep:rama-tcp"] -http = ["net", "dep:rama-http", "net", "ua", "rama-net/http", "rama-proxy/http", "rama-tcp/http"] +http = ["net", "dep:rama-http", "net", "ua", "rama-net/http", "rama-tcp/http"] http-full = ["http", "dep:rama-http-backend"] proxy = ["dep:rama-proxy"] haproxy = ["dep:rama-haproxy"] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index a646b6b6..0bb12d53 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -12,6 +12,7 @@ libfuzzer-sys = "0.4" [dependencies.rama] path = ".." +features = ["ua"] [[bin]] name = "ua_parse" diff --git a/rama-cli/Cargo.toml b/rama-cli/Cargo.toml index 9b288665..dd4ee5e6 100644 --- a/rama-cli/Cargo.toml +++ b/rama-cli/Cargo.toml @@ -15,7 +15,7 @@ default-run = "rama" bytes = { workspace = true } clap = { workspace = true } hex = { workspace = true } -rama = { version = "0.2.0-alpha.2", path = "..", features = ["telemetry", "compression", "boring", "cli"] } +rama = { version = "0.2.0-alpha.2", path = "..", features = ["full"] } serde = { workspace = true } serde_json = { workspace = true } terminal-prompt = { workspace = true } diff --git a/rama-cli/src/cmd/fp/data.rs b/rama-cli/src/cmd/fp/data.rs index 964a15ee..646457c5 100644 --- a/rama-cli/src/cmd/fp/data.rs +++ b/rama-cli/src/cmd/fp/data.rs @@ -2,7 +2,7 @@ use super::State; use rama::{ error::{BoxError, ErrorContext}, http::{dep::http::request::Parts, headers::Forwarded, Request}, - net::{stream::SocketInfo, http::RequestContext}, + net::{http::RequestContext, stream::SocketInfo}, tls::types::{ client::{ClientHello, ClientHelloExtension}, SecureTransport, diff --git a/rama-cli/src/cmd/fp/mod.rs b/rama-cli/src/cmd/fp/mod.rs index 22853228..770c8184 100644 --- a/rama-cli/src/cmd/fp/mod.rs +++ b/rama-cli/src/cmd/fp/mod.rs @@ -10,8 +10,7 @@ use rama::{ layer::{ catch_panic::CatchPanicLayer, compression::CompressionLayer, forwarded::GetForwardedHeadersLayer, required_header::AddRequiredResponseHeadersLayer, - set_header::SetResponseHeaderLayer, trace::TraceLayer, - ua::UserAgentClassifierLayer, + set_header::SetResponseHeaderLayer, trace::TraceLayer, ua::UserAgentClassifierLayer, }, matcher::HttpMatcher, response::Redirect, @@ -23,10 +22,10 @@ use rama::{ limit::policy::ConcurrentPolicy, ConsumeErrLayer, HijackLayer, Layer, LimitLayer, TimeoutLayer, }, + net::stream::layer::http::BodyLimitLayer, proxy::haproxy::server::HaProxyLayer, rt::Executor, service::service_fn, - net::stream::layer::http::BodyLimitLayer, tcp::server::TcpListener, tls::boring::server::TlsAcceptorLayer, utils::backoff::ExponentialBackoff, diff --git a/rama-cli/src/cmd/http/mod.rs b/rama-cli/src/cmd/http/mod.rs index 7c88a10d..203f315e 100644 --- a/rama-cli/src/cmd/http/mod.rs +++ b/rama-cli/src/cmd/http/mod.rs @@ -5,6 +5,7 @@ use rama::{ cli::args::RequestArgsBuilder, error::{error, BoxError, ErrorContext, OpaqueError}, graceful::{self, Shutdown, ShutdownGuard}, + http::client::proxy::layer::{HttpProxyAddressLayer, SetProxyAuthHttpHeaderLayer}, http::{ client::HttpClient, layer::{ @@ -19,7 +20,6 @@ use rama::{ }, layer::{HijackLayer, MapResultLayer}, net::{address::ProxyAddress, user::ProxyCredential}, - http::client::proxy::layer::{HttpProxyAddressLayer, SetProxyAuthHttpHeaderLayer}, rt::Executor, service::service_fn, Context, Layer, Service, diff --git a/rama-cli/src/cmd/proxy/mod.rs b/rama-cli/src/cmd/proxy/mod.rs index ed32f043..52b2cc61 100644 --- a/rama-cli/src/cmd/proxy/mod.rs +++ b/rama-cli/src/cmd/proxy/mod.rs @@ -15,10 +15,10 @@ use rama::{ Body, IntoResponse, Request, Response, StatusCode, }, layer::{limit::policy::ConcurrentPolicy, LimitLayer, TimeoutLayer}, + net::http::RequestContext, + net::stream::layer::http::BodyLimitLayer, rt::Executor, service::service_fn, - net::stream::layer::http::BodyLimitLayer, - net::http::RequestContext, tcp::{server::TcpListener, utils::is_connection_error}, Context, Layer, Service, }; diff --git a/rama-http-backend/Cargo.toml b/rama-http-backend/Cargo.toml index 9cf0151c..aa0ea2dc 100644 --- a/rama-http-backend/Cargo.toml +++ b/rama-http-backend/Cargo.toml @@ -13,8 +13,8 @@ rust-version = { workspace = true } [features] default = [] tls = ["dep:rama-tls", "rama-net/tls"] -rustls = ["tls", "rama-tls/rustls"] -boring = ["tls", "rama-net/boring"] +rustls = ["tls", "rama-net/rustls", "rama-tls/rustls"] +boring = ["tls", "rama-net/boring", "rama-tls/boring"] rustls-ring = ["rustls", "rama-tls/rustls-ring"] [dependencies] diff --git a/rama-proxy/Cargo.toml b/rama-proxy/Cargo.toml index 88cc9e76..a0579bf9 100644 --- a/rama-proxy/Cargo.toml +++ b/rama-proxy/Cargo.toml @@ -11,16 +11,15 @@ authors = { workspace = true } rust-version = { workspace = true } [features] -default = ["memory-db", "csv"] +default = [] memory-db = ["dep:venndb", "rama-net/venndb"] live-update = ["dep:arc-swap"] -http = ["rama-net/http"] csv = ["dep:tokio", "tokio/fs"] [dependencies] arc-swap = { workspace = true, optional = true } rama-core = { version = "0.2.0-alpha.2", path = "../rama-core" } -rama-net = { version = "0.2.0-alpha.2", path = "../rama-net" } +rama-net = { version = "0.2.0-alpha.2", path = "../rama-net", features = ["http"] } rama-utils = { version = "0.2.0-alpha.2", path = "../rama-utils" } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, optional = true } diff --git a/rama-proxy/src/lib.rs b/rama-proxy/src/lib.rs index d16169a1..0ad1c3e2 100644 --- a/rama-proxy/src/lib.rs +++ b/rama-proxy/src/lib.rs @@ -292,7 +292,6 @@ mod proxydb; #[doc(inline)] pub use proxydb::{Proxy, ProxyDB, ProxyFilter, ProxyID, ProxyQueryPredicate, StringFilter}; -#[cfg(feature = "http")] #[doc(inline)] pub use proxydb::layer::{ProxyDBLayer, ProxyDBService, ProxyFilterMode, UsernameFormatter}; diff --git a/rama-proxy/src/proxydb/internal.rs b/rama-proxy/src/proxydb/internal.rs index e437753a..ac0879c0 100644 --- a/rama-proxy/src/proxydb/internal.rs +++ b/rama-proxy/src/proxydb/internal.rs @@ -78,6 +78,7 @@ pub struct Proxy { pub asn: Option, } +#[cfg(feature = "memory-db")] /// Validate the proxy is valid according to rules that are not enforced by the type system. fn proxydb_insert_validator(proxy: &Proxy) -> bool { (proxy.datacenter || proxy.residential || proxy.mobile) @@ -352,7 +353,7 @@ mod tests { let mut reader = ProxyCsvRowReader::raw("id1,1,,,,,,,,,authority,,,,,,,\nid2,,1,,,,,,,,authority,,,,,,,\nid3,,1,1,,,,,,,authority,,,,,,,\nid4,,1,1,,,,,1,,authority,,,,,,,\nid5,,1,1,,,,,1,,authority,,,,,,,"); while let Some(proxy) = reader.next().await.unwrap() { assert_eq!( - ProxyDBErrorKind::InvalidRow, + MemoryProxyDBInsertErrorKind::InvalidRow, db.append(proxy).unwrap_err().kind ); } diff --git a/rama-proxy/src/proxydb/mod.rs b/rama-proxy/src/proxydb/mod.rs index eedd07a5..7392ed39 100644 --- a/rama-proxy/src/proxydb/mod.rs +++ b/rama-proxy/src/proxydb/mod.rs @@ -1,8 +1,5 @@ use rama_core::error::BoxError; -use rama_net::{ - asn::Asn, - transport::{TransportContext, TransportProtocol}, -}; +use rama_net::{asn::Asn, transport::TransportContext}; use rama_utils::str::NonEmptyString; use serde::Deserialize; use std::{fmt, future::Future}; @@ -22,7 +19,6 @@ mod csv; #[cfg(feature = "csv")] pub use csv::{ProxyCsvRowReader, ProxyCsvRowReaderError, ProxyCsvRowReaderErrorKind}; -#[cfg(feature = "http")] pub(super) mod layer; mod str; @@ -239,7 +235,7 @@ where } impl ProxyDB for Proxy { - type Error = MemoryProxyDBQueryError; + type Error = rama_core::error::OpaqueError; async fn get_proxy_if( &self, @@ -249,825 +245,654 @@ impl ProxyDB for Proxy { ) -> Result { (self.is_match(&ctx, &filter) && predicate.execute(self)) .then(|| self.clone()) - .ok_or_else(MemoryProxyDBQueryError::mismatch) + .ok_or_else(|| rama_core::error::OpaqueError::from_display("hardcoded proxy no match")) } } -/// A fast in-memory ProxyDatabase that is the default choice for Rama. -#[derive(Debug)] -pub struct MemoryProxyDB { - data: internal::ProxyDB, -} - -impl MemoryProxyDB { - /// Create a new in-memory proxy database with the given proxies. - pub fn try_from_rows(proxies: Vec) -> Result { - Ok(MemoryProxyDB { - data: internal::ProxyDB::from_rows(proxies).map_err(|err| match err.kind() { - internal::ProxyDBErrorKind::DuplicateKey => { - MemoryProxyDBInsertError::duplicate_key(err.into_input()) - } - internal::ProxyDBErrorKind::InvalidRow => { - MemoryProxyDBInsertError::invalid_proxy(err.into_input()) - } - })?, - }) - } - - /// Create a new in-memory proxy database with the given proxies from an iterator. - pub fn try_from_iter(proxies: I) -> Result - where - I: IntoIterator, - { - Ok(MemoryProxyDB { - data: internal::ProxyDB::from_iter(proxies).map_err(|err| match err.kind() { - internal::ProxyDBErrorKind::DuplicateKey => { - MemoryProxyDBInsertError::duplicate_key(err.into_input()) - } - internal::ProxyDBErrorKind::InvalidRow => { - MemoryProxyDBInsertError::invalid_proxy(err.into_input()) - } - })?, - }) - } - - /// Return the number of proxies in the database. - pub fn len(&self) -> usize { - self.data.len() - } +#[cfg(feature = "memory-db")] +mod memdb { + use super::*; + use crate::proxydb::internal::ProxyDBErrorKind; + use rama_net::transport::TransportProtocol; - /// Rerturns if the database is empty. - pub fn is_empty(&self) -> bool { - self.data.is_empty() + /// A fast in-memory ProxyDatabase that is the default choice for Rama. + #[derive(Debug)] + pub struct MemoryProxyDB { + data: internal::ProxyDB, } - fn query_from_filter( - &self, - ctx: TransportContext, - filter: ProxyFilter, - ) -> internal::ProxyDBQuery { - let mut query = self.data.query(); - - for pool_id in filter.pool_id.into_iter().flatten() { - query.pool_id(pool_id); - } - for continent in filter.continent.into_iter().flatten() { - query.continent(continent); - } - for country in filter.country.into_iter().flatten() { - query.country(country); - } - for state in filter.state.into_iter().flatten() { - query.state(state); - } - for city in filter.city.into_iter().flatten() { - query.city(city); - } - for carrier in filter.carrier.into_iter().flatten() { - query.carrier(carrier); - } - for asn in filter.asn.into_iter().flatten() { - query.asn(asn); + impl MemoryProxyDB { + /// Create a new in-memory proxy database with the given proxies. + pub fn try_from_rows(proxies: Vec) -> Result { + Ok(MemoryProxyDB { + data: internal::ProxyDB::from_rows(proxies).map_err(|err| match err.kind() { + ProxyDBErrorKind::DuplicateKey => { + MemoryProxyDBInsertError::duplicate_key(err.into_input()) + } + ProxyDBErrorKind::InvalidRow => { + MemoryProxyDBInsertError::invalid_proxy(err.into_input()) + } + })?, + }) } - if let Some(value) = filter.datacenter { - query.datacenter(value); - } - if let Some(value) = filter.residential { - query.residential(value); + /// Create a new in-memory proxy database with the given proxies from an iterator. + pub fn try_from_iter(proxies: I) -> Result + where + I: IntoIterator, + { + Ok(MemoryProxyDB { + data: internal::ProxyDB::from_iter(proxies).map_err(|err| match err.kind() { + ProxyDBErrorKind::DuplicateKey => { + MemoryProxyDBInsertError::duplicate_key(err.into_input()) + } + ProxyDBErrorKind::InvalidRow => { + MemoryProxyDBInsertError::invalid_proxy(err.into_input()) + } + })?, + }) } - if let Some(value) = filter.mobile { - query.mobile(value); + + /// Return the number of proxies in the database. + pub fn len(&self) -> usize { + self.data.len() } - match ctx.protocol { - TransportProtocol::Tcp => { - query.tcp(true); - } - TransportProtocol::Udp => { - query.udp(true).socks5(true); - } + /// Rerturns if the database is empty. + pub fn is_empty(&self) -> bool { + self.data.is_empty() } - query - } -} + fn query_from_filter( + &self, + ctx: TransportContext, + filter: ProxyFilter, + ) -> internal::ProxyDBQuery { + let mut query = self.data.query(); -// TODO: custom query filters using ProxyQueryPredicate -// might be a lot faster for cases where we want to filter a big batch of proxies, -// in which case a bitmap could be supported by a future VennDB version... -// -// Would just need to figure out how to allow this to happen. + for pool_id in filter.pool_id.into_iter().flatten() { + query.pool_id(pool_id); + } + for continent in filter.continent.into_iter().flatten() { + query.continent(continent); + } + for country in filter.country.into_iter().flatten() { + query.country(country); + } + for state in filter.state.into_iter().flatten() { + query.state(state); + } + for city in filter.city.into_iter().flatten() { + query.city(city); + } + for carrier in filter.carrier.into_iter().flatten() { + query.carrier(carrier); + } + for asn in filter.asn.into_iter().flatten() { + query.asn(asn); + } -impl ProxyDB for MemoryProxyDB { - type Error = MemoryProxyDBQueryError; + if let Some(value) = filter.datacenter { + query.datacenter(value); + } + if let Some(value) = filter.residential { + query.residential(value); + } + if let Some(value) = filter.mobile { + query.mobile(value); + } - async fn get_proxy_if( - &self, - ctx: TransportContext, - filter: ProxyFilter, - predicate: impl ProxyQueryPredicate, - ) -> Result { - match &filter.id { - Some(id) => match self.data.get_by_id(id) { - None => Err(MemoryProxyDBQueryError::not_found()), - Some(proxy) => { - if proxy.is_match(&ctx, &filter) && predicate.execute(proxy) { - Ok(proxy.clone()) - } else { - Err(MemoryProxyDBQueryError::mismatch()) - } + match ctx.protocol { + TransportProtocol::Tcp => { + query.tcp(true); } - }, - None => { - let query = self.query_from_filter(ctx, filter.clone()); - match query - .execute() - .and_then(|result| result.filter(|proxy| predicate.execute(proxy))) - .map(|result| result.any()) - { - None => Err(MemoryProxyDBQueryError::not_found()), - Some(proxy) => Ok(proxy.clone()), + TransportProtocol::Udp => { + query.udp(true).socks5(true); } } + + query } } -} -/// The error type that can be returned by [`MemoryProxyDB`] when some of the proxies -/// could not be inserted due to a proxy that had a duplicate key or was invalid for some other reason. -#[derive(Debug)] -pub struct MemoryProxyDBInsertError { - kind: MemoryProxyDBInsertErrorKind, - proxies: Vec, -} + // TODO: custom query filters using ProxyQueryPredicate + // might be a lot faster for cases where we want to filter a big batch of proxies, + // in which case a bitmap could be supported by a future VennDB version... + // + // Would just need to figure out how to allow this to happen. -impl std::fmt::Display for MemoryProxyDBInsertError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.kind { - MemoryProxyDBInsertErrorKind::DuplicateKey => write!( - f, - "A proxy with the same key already exists in the database" - ), - MemoryProxyDBInsertErrorKind::InvalidProxy => { - write!(f, "A proxy in the list is invalid for some reason") + impl ProxyDB for MemoryProxyDB { + type Error = MemoryProxyDBQueryError; + + async fn get_proxy_if( + &self, + ctx: TransportContext, + filter: ProxyFilter, + predicate: impl ProxyQueryPredicate, + ) -> Result { + match &filter.id { + Some(id) => match self.data.get_by_id(id) { + None => Err(MemoryProxyDBQueryError::not_found()), + Some(proxy) => { + if proxy.is_match(&ctx, &filter) && predicate.execute(proxy) { + Ok(proxy.clone()) + } else { + Err(MemoryProxyDBQueryError::mismatch()) + } + } + }, + None => { + let query = self.query_from_filter(ctx, filter.clone()); + match query + .execute() + .and_then(|result| result.filter(|proxy| predicate.execute(proxy))) + .map(|result| result.any()) + { + None => Err(MemoryProxyDBQueryError::not_found()), + Some(proxy) => Ok(proxy.clone()), + } + } } } } -} - -impl std::error::Error for MemoryProxyDBInsertError {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -/// The kind of error that [`MemoryProxyDBInsertError`] represents. -pub enum MemoryProxyDBInsertErrorKind { - /// Duplicate key found in the proxies. - DuplicateKey, - /// Invalid proxy found in the proxies. - /// - /// This could be due to a proxy that is not valid for some reason. - /// E.g. a proxy that neither supports http or socks5. - InvalidProxy, -} -impl MemoryProxyDBInsertError { - fn duplicate_key(proxies: Vec) -> Self { - MemoryProxyDBInsertError { - kind: MemoryProxyDBInsertErrorKind::DuplicateKey, - proxies, - } + /// The error type that can be returned by [`MemoryProxyDB`] when some of the proxies + /// could not be inserted due to a proxy that had a duplicate key or was invalid for some other reason. + #[derive(Debug)] + pub struct MemoryProxyDBInsertError { + kind: MemoryProxyDBInsertErrorKind, + proxies: Vec, } - fn invalid_proxy(proxies: Vec) -> Self { - MemoryProxyDBInsertError { - kind: MemoryProxyDBInsertErrorKind::InvalidProxy, - proxies, + impl std::fmt::Display for MemoryProxyDBInsertError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.kind { + MemoryProxyDBInsertErrorKind::DuplicateKey => write!( + f, + "A proxy with the same key already exists in the database" + ), + MemoryProxyDBInsertErrorKind::InvalidProxy => { + write!(f, "A proxy in the list is invalid for some reason") + } + } } } - /// Returns the kind of error that [`MemoryProxyDBInsertError`] represents. - pub fn kind(&self) -> MemoryProxyDBInsertErrorKind { - self.kind + impl std::error::Error for MemoryProxyDBInsertError {} + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + /// The kind of error that [`MemoryProxyDBInsertError`] represents. + pub enum MemoryProxyDBInsertErrorKind { + /// Duplicate key found in the proxies. + DuplicateKey, + /// Invalid proxy found in the proxies. + /// + /// This could be due to a proxy that is not valid for some reason. + /// E.g. a proxy that neither supports http or socks5. + InvalidProxy, } - /// Returns the proxies that were not inserted. - pub fn proxies(&self) -> &[Proxy] { - &self.proxies - } + impl MemoryProxyDBInsertError { + fn duplicate_key(proxies: Vec) -> Self { + MemoryProxyDBInsertError { + kind: MemoryProxyDBInsertErrorKind::DuplicateKey, + proxies, + } + } - /// Consumes the error and returns the proxies that were not inserted. - pub fn into_proxies(self) -> Vec { - self.proxies - } -} + fn invalid_proxy(proxies: Vec) -> Self { + MemoryProxyDBInsertError { + kind: MemoryProxyDBInsertErrorKind::InvalidProxy, + proxies, + } + } -/// The error type that can be returned by [`MemoryProxyDB`] when no proxy could be returned. -#[derive(Debug)] -pub struct MemoryProxyDBQueryError { - kind: MemoryProxyDBQueryErrorKind, -} + /// Returns the kind of error that [`MemoryProxyDBInsertError`] represents. + pub fn kind(&self) -> MemoryProxyDBInsertErrorKind { + self.kind + } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -/// The kind of error that [`MemoryProxyDBQueryError`] represents. -pub enum MemoryProxyDBQueryErrorKind { - /// No proxy match could be found. - NotFound, - /// A proxy looked up by key had a config that did not match the given filters/requirements. - Mismatch, -} + /// Returns the proxies that were not inserted. + pub fn proxies(&self) -> &[Proxy] { + &self.proxies + } -impl std::fmt::Display for MemoryProxyDBQueryError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.kind { - MemoryProxyDBQueryErrorKind::NotFound => write!(f, "No proxy match could be found"), - MemoryProxyDBQueryErrorKind::Mismatch => write!( - f, - "Proxy config did not match the given filters/requirements" - ), + /// Consumes the error and returns the proxies that were not inserted. + pub fn into_proxies(self) -> Vec { + self.proxies } } -} -impl std::error::Error for MemoryProxyDBQueryError {} + /// The error type that can be returned by [`MemoryProxyDB`] when no proxy could be returned. + #[derive(Debug)] + pub struct MemoryProxyDBQueryError { + kind: MemoryProxyDBQueryErrorKind, + } -impl MemoryProxyDBQueryError { - /// Create a new error that indicates no proxy match could be found. - pub fn not_found() -> Self { - MemoryProxyDBQueryError { - kind: MemoryProxyDBQueryErrorKind::NotFound, - } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + /// The kind of error that [`MemoryProxyDBQueryError`] represents. + pub enum MemoryProxyDBQueryErrorKind { + /// No proxy match could be found. + NotFound, + /// A proxy looked up by key had a config that did not match the given filters/requirements. + Mismatch, } - /// Create a new error that indicates a proxy looked up by key had a config that did not match the given filters/requirements. - pub fn mismatch() -> Self { - MemoryProxyDBQueryError { - kind: MemoryProxyDBQueryErrorKind::Mismatch, + impl std::fmt::Display for MemoryProxyDBQueryError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.kind { + MemoryProxyDBQueryErrorKind::NotFound => write!(f, "No proxy match could be found"), + MemoryProxyDBQueryErrorKind::Mismatch => write!( + f, + "Proxy config did not match the given filters/requirements" + ), + } } } - /// Returns the kind of error that [`MemoryProxyDBQueryError`] represents. - pub fn kind(&self) -> MemoryProxyDBQueryErrorKind { - self.kind - } -} + impl std::error::Error for MemoryProxyDBQueryError {} -#[cfg(test)] -mod tests { - use super::*; - use itertools::Itertools; - use rama_net::{address::ProxyAddress, Protocol}; - use rama_utils::str::NonEmptyString; - use std::str::FromStr; - - const RAW_CSV_DATA: &str = include_str!("./test_proxydb_rows.csv"); - - async fn memproxydb() -> MemoryProxyDB { - let mut reader = ProxyCsvRowReader::raw(RAW_CSV_DATA); - let mut rows = Vec::new(); - while let Some(proxy) = reader.next().await.unwrap() { - rows.push(proxy); + impl MemoryProxyDBQueryError { + /// Create a new error that indicates no proxy match could be found. + pub fn not_found() -> Self { + MemoryProxyDBQueryError { + kind: MemoryProxyDBQueryErrorKind::NotFound, + } } - MemoryProxyDB::try_from_rows(rows).unwrap() - } - #[tokio::test] - async fn test_load_memproxydb_from_rows() { - let db = memproxydb().await; - assert_eq!(db.len(), 64); - } + /// Create a new error that indicates a proxy looked up by key had a config that did not match the given filters/requirements. + pub fn mismatch() -> Self { + MemoryProxyDBQueryError { + kind: MemoryProxyDBQueryErrorKind::Mismatch, + } + } - fn h2_transport_context() -> TransportContext { - TransportContext { - protocol: TransportProtocol::Tcp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), + /// Returns the kind of error that [`MemoryProxyDBQueryError`] represents. + pub fn kind(&self) -> MemoryProxyDBQueryErrorKind { + self.kind } } - #[tokio::test] - async fn test_memproxydb_get_proxy_by_id_found() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - ..Default::default() - }; - let proxy = db.get_proxy(ctx, filter).await.unwrap(); - assert_eq!(proxy.id, "3031533634"); - } + #[cfg(test)] + mod tests { + use super::*; + use itertools::Itertools; + use rama_net::{address::ProxyAddress, Protocol}; + use rama_utils::str::NonEmptyString; + use std::str::FromStr; + + const RAW_CSV_DATA: &str = include_str!("./test_proxydb_rows.csv"); + + async fn memproxydb() -> MemoryProxyDB { + let mut reader = ProxyCsvRowReader::raw(RAW_CSV_DATA); + let mut rows = Vec::new(); + while let Some(proxy) = reader.next().await.unwrap() { + rows.push(proxy); + } + MemoryProxyDB::try_from_rows(rows).unwrap() + } - #[tokio::test] - async fn test_memproxydb_get_proxy_by_id_found_correct_filters() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - pool_id: Some(vec![StringFilter::new("poolF")]), - country: Some(vec![StringFilter::new("JP")]), - city: Some(vec![StringFilter::new("Yokohama")]), - datacenter: Some(true), - residential: Some(false), - mobile: Some(true), - carrier: Some(vec![StringFilter::new("Verizon")]), - ..Default::default() - }; - let proxy = db.get_proxy(ctx, filter).await.unwrap(); - assert_eq!(proxy.id, "3031533634"); - } + #[tokio::test] + async fn test_load_memproxydb_from_rows() { + let db = memproxydb().await; + assert_eq!(db.len(), 64); + } - #[tokio::test] - async fn test_memproxydb_get_proxy_by_id_not_found() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter { - id: Some(NonEmptyString::from_static("notfound")), - ..Default::default() - }; - let err = db.get_proxy(ctx, filter).await.unwrap_err(); - assert_eq!(err.kind(), MemoryProxyDBQueryErrorKind::NotFound); - } + fn h2_transport_context() -> TransportContext { + TransportContext { + protocol: TransportProtocol::Tcp, + app_protocol: Some(Protocol::HTTPS), + http_version: None, + authority: "localhost:8443".try_into().unwrap(), + } + } - #[tokio::test] - async fn test_memproxydb_get_proxy_by_id_mismatch_filter() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filters = [ - ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - pool_id: Some(vec![StringFilter::new("poolB")]), - ..Default::default() - }, - ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - country: Some(vec![StringFilter::new("US")]), - ..Default::default() - }, - ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - city: Some(vec![StringFilter::new("New York")]), - ..Default::default() - }, - ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - continent: Some(vec![StringFilter::new("americas")]), - ..Default::default() - }, - ProxyFilter { - id: Some(NonEmptyString::from_static("3732488183")), - state: Some(vec![StringFilter::new("Texas")]), - ..Default::default() - }, - ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - datacenter: Some(false), - ..Default::default() - }, - ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - residential: Some(true), - ..Default::default() - }, - ProxyFilter { + #[tokio::test] + async fn test_memproxydb_get_proxy_by_id_found() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter { id: Some(NonEmptyString::from_static("3031533634")), - mobile: Some(false), ..Default::default() - }, - ProxyFilter { + }; + let proxy = db.get_proxy(ctx, filter).await.unwrap(); + assert_eq!(proxy.id, "3031533634"); + } + + #[tokio::test] + async fn test_memproxydb_get_proxy_by_id_found_correct_filters() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter { id: Some(NonEmptyString::from_static("3031533634")), - carrier: Some(vec![StringFilter::new("AT&T")]), - ..Default::default() - }, - ProxyFilter { - id: Some(NonEmptyString::from_static("292096733")), - asn: Some(vec![Asn::from_static(1)]), + pool_id: Some(vec![StringFilter::new("poolF")]), + country: Some(vec![StringFilter::new("JP")]), + city: Some(vec![StringFilter::new("Yokohama")]), + datacenter: Some(true), + residential: Some(false), + mobile: Some(true), + carrier: Some(vec![StringFilter::new("Verizon")]), ..Default::default() - }, - ]; - for filter in filters.iter() { - let err = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap_err(); - assert_eq!(err.kind(), MemoryProxyDBQueryErrorKind::Mismatch); + }; + let proxy = db.get_proxy(ctx, filter).await.unwrap(); + assert_eq!(proxy.id, "3031533634"); } - } - fn h3_transport_context() -> TransportContext { - TransportContext { - protocol: TransportProtocol::Udp, - app_protocol: Some(Protocol::HTTPS), - http_version: None, - authority: "localhost:8443".try_into().unwrap(), + #[tokio::test] + async fn test_memproxydb_get_proxy_by_id_not_found() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter { + id: Some(NonEmptyString::from_static("notfound")), + ..Default::default() + }; + let err = db.get_proxy(ctx, filter).await.unwrap_err(); + assert_eq!(err.kind(), MemoryProxyDBQueryErrorKind::NotFound); } - } - #[tokio::test] - async fn test_memproxydb_get_proxy_by_id_mismatch_req_context() { - let db = memproxydb().await; - let ctx = h3_transport_context(); - let filter = ProxyFilter { - id: Some(NonEmptyString::from_static("3031533634")), - ..Default::default() - }; - // this proxy does not support socks5 UDP, which is what we need - let err = db.get_proxy(ctx, filter).await.unwrap_err(); - assert_eq!(err.kind(), MemoryProxyDBQueryErrorKind::Mismatch); - } - - #[tokio::test] - async fn test_memorydb_get_h3_capable_proxies() { - let db = memproxydb().await; - let ctx = h3_transport_context(); - let filter = ProxyFilter::default(); - let mut found_ids = Vec::new(); - for _ in 0..5000 { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - if found_ids.contains(&proxy.id) { - continue; + #[tokio::test] + async fn test_memproxydb_get_proxy_by_id_mismatch_filter() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filters = [ + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + pool_id: Some(vec![StringFilter::new("poolB")]), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + country: Some(vec![StringFilter::new("US")]), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + city: Some(vec![StringFilter::new("New York")]), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + continent: Some(vec![StringFilter::new("americas")]), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3732488183")), + state: Some(vec![StringFilter::new("Texas")]), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + datacenter: Some(false), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + residential: Some(true), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + mobile: Some(false), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + carrier: Some(vec![StringFilter::new("AT&T")]), + ..Default::default() + }, + ProxyFilter { + id: Some(NonEmptyString::from_static("292096733")), + asn: Some(vec![Asn::from_static(1)]), + ..Default::default() + }, + ]; + for filter in filters.iter() { + let err = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap_err(); + assert_eq!(err.kind(), MemoryProxyDBQueryErrorKind::Mismatch); } - assert!(proxy.udp); - assert!(proxy.socks5); - found_ids.push(proxy.id); } - assert_eq!(found_ids.len(), 40); - assert_eq!( - found_ids.iter().sorted().join(","), - r##"1125300915,1259341971,1316455915,153202126,1571861931,1684342915,1742367441,1844412609,1916851007,20647117,2107229589,2261612122,2497865606,2521901221,2560727338,2593294918,2596743625,2745456299,2880295577,2909724448,2950022859,2951529660,3187902553,3269411602,3269465574,3269921904,3481200027,3498810974,362091157,3679054656,3732488183,3836943127,39048766,3951672504,3976711563,4187178960,56402588,724884866,738626121,906390012"## - ); - } - #[tokio::test] - async fn test_memorydb_get_h2_capable_proxies() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter::default(); - let mut found_ids = Vec::new(); - for _ in 0..5000 { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - if found_ids.contains(&proxy.id) { - continue; + fn h3_transport_context() -> TransportContext { + TransportContext { + protocol: TransportProtocol::Udp, + app_protocol: Some(Protocol::HTTPS), + http_version: None, + authority: "localhost:8443".try_into().unwrap(), } - assert!(proxy.tcp); - found_ids.push(proxy.id); } - assert_eq!(found_ids.len(), 50); - assert_eq!( - found_ids.iter().sorted().join(","), - r#"1125300915,1259341971,1264821985,129108927,1316455915,1425588737,1571861931,1810781137,1836040682,1844412609,1885107293,2021561518,2079461709,2107229589,2141152822,2438596154,2497865606,2521901221,2551759475,2560727338,2593294918,2798907087,2854473221,2880295577,2909724448,2912880381,292096733,2951529660,3031533634,3187902553,3269411602,3269465574,339020035,3481200027,3498810974,3503691556,362091157,3679054656,371209663,3861736957,39048766,3976711563,4062553709,49590203,56402588,724884866,738626121,767809962,846528631,906390012"#, - ); - } - #[tokio::test] - async fn test_memorydb_get_any_country_proxies() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter { - // there are no explicit BE proxies, - // so these will only match the proxies that have a wildcard country - country: Some(vec!["BE".into()]), - ..Default::default() - }; - let mut found_ids = Vec::new(); - for _ in 0..5000 { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - if found_ids.contains(&proxy.id) { - continue; - } - found_ids.push(proxy.id); + #[tokio::test] + async fn test_memproxydb_get_proxy_by_id_mismatch_req_context() { + let db = memproxydb().await; + let ctx = h3_transport_context(); + let filter = ProxyFilter { + id: Some(NonEmptyString::from_static("3031533634")), + ..Default::default() + }; + // this proxy does not support socks5 UDP, which is what we need + let err = db.get_proxy(ctx, filter).await.unwrap_err(); + assert_eq!(err.kind(), MemoryProxyDBQueryErrorKind::Mismatch); } - assert_eq!(found_ids.len(), 5); - assert_eq!( - found_ids.iter().sorted().join(","), - r#"2141152822,2593294918,2912880381,371209663,767809962"#, - ); - } - #[tokio::test] - async fn test_memorydb_get_illinois_proxies() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter { - // this will also work for proxies that have 'any' state - state: Some(vec!["illinois".into()]), - ..Default::default() - }; - let mut found_ids = Vec::new(); - for _ in 0..5000 { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - if found_ids.contains(&proxy.id) { - continue; + #[tokio::test] + async fn test_memorydb_get_h3_capable_proxies() { + let db = memproxydb().await; + let ctx = h3_transport_context(); + let filter = ProxyFilter::default(); + let mut found_ids = Vec::new(); + for _ in 0..5000 { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + if found_ids.contains(&proxy.id) { + continue; + } + assert!(proxy.udp); + assert!(proxy.socks5); + found_ids.push(proxy.id); } - found_ids.push(proxy.id); + assert_eq!(found_ids.len(), 40); + assert_eq!( + found_ids.iter().sorted().join(","), + r##"1125300915,1259341971,1316455915,153202126,1571861931,1684342915,1742367441,1844412609,1916851007,20647117,2107229589,2261612122,2497865606,2521901221,2560727338,2593294918,2596743625,2745456299,2880295577,2909724448,2950022859,2951529660,3187902553,3269411602,3269465574,3269921904,3481200027,3498810974,362091157,3679054656,3732488183,3836943127,39048766,3951672504,3976711563,4187178960,56402588,724884866,738626121,906390012"## + ); } - assert_eq!(found_ids.len(), 9); - assert_eq!( - found_ids.iter().sorted().join(","), - r#"2141152822,2521901221,2560727338,2593294918,2912880381,292096733,371209663,39048766,767809962"#, - ); - } - #[tokio::test] - async fn test_memorydb_get_asn_proxies() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter { - // this will also work for proxies that have 'any' ASN - asn: Some(vec![Asn::from_static(42)]), - ..Default::default() - }; - let mut found_ids = Vec::new(); - for _ in 0..5000 { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - if found_ids.contains(&proxy.id) { - continue; + #[tokio::test] + async fn test_memorydb_get_h2_capable_proxies() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter::default(); + let mut found_ids = Vec::new(); + for _ in 0..5000 { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + if found_ids.contains(&proxy.id) { + continue; + } + assert!(proxy.tcp); + found_ids.push(proxy.id); } - found_ids.push(proxy.id); - } - assert_eq!(found_ids.len(), 4); - assert_eq!( - found_ids.iter().sorted().join(","), - r#"2141152822,2912880381,292096733,3481200027"#, - ); - } - - #[tokio::test] - async fn test_memorydb_get_h3_capable_mobile_residential_be_asterix_proxies() { - let db = memproxydb().await; - let ctx = h3_transport_context(); - let filter = ProxyFilter { - country: Some(vec!["BE".into()]), - mobile: Some(true), - residential: Some(true), - ..Default::default() - }; - for _ in 0..50 { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - assert_eq!(proxy.id, "2593294918"); + assert_eq!(found_ids.len(), 50); + assert_eq!( + found_ids.iter().sorted().join(","), + r#"1125300915,1259341971,1264821985,129108927,1316455915,1425588737,1571861931,1810781137,1836040682,1844412609,1885107293,2021561518,2079461709,2107229589,2141152822,2438596154,2497865606,2521901221,2551759475,2560727338,2593294918,2798907087,2854473221,2880295577,2909724448,2912880381,292096733,2951529660,3031533634,3187902553,3269411602,3269465574,339020035,3481200027,3498810974,3503691556,362091157,3679054656,371209663,3861736957,39048766,3976711563,4062553709,49590203,56402588,724884866,738626121,767809962,846528631,906390012"#, + ); } - } - - #[tokio::test] - async fn test_memorydb_get_blocked_proxies() { - let db = memproxydb().await; - let ctx = h2_transport_context(); - let filter = ProxyFilter::default(); - - let mut blocked_proxies = vec![ - "1125300915", - "1259341971", - "1264821985", - "129108927", - "1316455915", - "1425588737", - "1571861931", - "1810781137", - "1836040682", - "1844412609", - "1885107293", - "2021561518", - "2079461709", - "2107229589", - "2141152822", - "2438596154", - "2497865606", - "2521901221", - "2551759475", - "2560727338", - "2593294918", - "2798907087", - "2854473221", - "2880295577", - "2909724448", - "2912880381", - "292096733", - "2951529660", - "3031533634", - "3187902553", - "3269411602", - "3269465574", - "339020035", - "3481200027", - "3498810974", - "3503691556", - "362091157", - "3679054656", - "371209663", - "3861736957", - "39048766", - "3976711563", - "4062553709", - "49590203", - "56402588", - "724884866", - "738626121", - "767809962", - "846528631", - "906390012", - ]; - - { - let blocked_proxies = blocked_proxies.clone(); + #[tokio::test] + async fn test_memorydb_get_any_country_proxies() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter { + // there are no explicit BE proxies, + // so these will only match the proxies that have a wildcard country + country: Some(vec!["BE".into()]), + ..Default::default() + }; + let mut found_ids = Vec::new(); + for _ in 0..5000 { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + if found_ids.contains(&proxy.id) { + continue; + } + found_ids.push(proxy.id); + } + assert_eq!(found_ids.len(), 5); assert_eq!( - MemoryProxyDBQueryErrorKind::NotFound, - db.get_proxy_if(ctx.clone(), filter.clone(), move |proxy: &Proxy| { - !blocked_proxies.contains(&proxy.id.as_str()) - }) - .await - .unwrap_err() - .kind() + found_ids.iter().sorted().join(","), + r#"2141152822,2593294918,2912880381,371209663,767809962"#, ); } - let last_proxy_id = blocked_proxies.pop().unwrap(); - - let proxy = db - .get_proxy_if(ctx, filter.clone(), move |proxy: &Proxy| { - !blocked_proxies.contains(&proxy.id.as_str()) - }) - .await - .unwrap(); - assert_eq!(proxy.id, last_proxy_id); - } - - #[tokio::test] - async fn test_db_proxy_filter_any_use_filter_property() { - let db = MemoryProxyDB::try_from_iter([Proxy { - id: NonEmptyString::from_static("1"), - address: ProxyAddress::from_str("example.com").unwrap(), - tcp: true, - udp: true, - http: true, - https: true, - socks5: true, - socks5h: true, - datacenter: true, - residential: true, - mobile: true, - pool_id: Some("*".into()), - continent: Some("*".into()), - country: Some("*".into()), - state: Some("*".into()), - city: Some("*".into()), - carrier: Some("*".into()), - asn: Some(Asn::unspecified()), - }]) - .unwrap(); - - let ctx = h2_transport_context(); - - for filter in [ - ProxyFilter { - id: Some(NonEmptyString::from_static("1")), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("hq")]), - ..Default::default() - }, - ProxyFilter { - country: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - country: Some(vec![StringFilter::new("US")]), - ..Default::default() - }, - ProxyFilter { - city: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - city: Some(vec![StringFilter::new("NY")]), - ..Default::default() - }, - ProxyFilter { - carrier: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - carrier: Some(vec![StringFilter::new("Telenet")]), + #[tokio::test] + async fn test_memorydb_get_illinois_proxies() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter { + // this will also work for proxies that have 'any' state + state: Some(vec!["illinois".into()]), ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("hq")]), - country: Some(vec![StringFilter::new("US")]), - city: Some(vec![StringFilter::new("NY")]), - carrier: Some(vec![StringFilter::new("AT&T")]), - ..Default::default() - }, - ] { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - assert!(filter.id.map(|id| proxy.id == id).unwrap_or(true)); - assert!(filter - .pool_id - .map(|pool_id| pool_id.contains(proxy.pool_id.as_ref().unwrap())) - .unwrap_or(true)); - assert!(filter - .country - .map(|country| country.contains(proxy.country.as_ref().unwrap())) - .unwrap_or(true)); - assert!(filter - .city - .map(|city| city.contains(proxy.city.as_ref().unwrap())) - .unwrap_or(true)); - assert!(filter - .carrier - .map(|carrier| carrier.contains(proxy.carrier.as_ref().unwrap())) - .unwrap_or(true)); + }; + let mut found_ids = Vec::new(); + for _ in 0..5000 { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + if found_ids.contains(&proxy.id) { + continue; + } + found_ids.push(proxy.id); + } + assert_eq!(found_ids.len(), 9); + assert_eq!( + found_ids.iter().sorted().join(","), + r#"2141152822,2521901221,2560727338,2593294918,2912880381,292096733,371209663,39048766,767809962"#, + ); } - } - #[tokio::test] - async fn test_db_proxy_filter_any_only_matches_any_value() { - let db = MemoryProxyDB::try_from_iter([Proxy { - id: NonEmptyString::from_static("1"), - address: ProxyAddress::from_str("example.com").unwrap(), - tcp: true, - udp: true, - http: true, - https: true, - socks5: true, - socks5h: true, - datacenter: true, - residential: true, - mobile: true, - pool_id: Some("hq".into()), - continent: Some("americas".into()), - country: Some("US".into()), - state: Some("NY".into()), - city: Some("NY".into()), - carrier: Some("AT&T".into()), - asn: Some(Asn::from_static(7018)), - }]) - .unwrap(); - - let ctx = h2_transport_context(); - - for filter in [ - ProxyFilter { - pool_id: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - continent: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - country: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - state: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - city: Some(vec![StringFilter::new("*")]), + #[tokio::test] + async fn test_memorydb_get_asn_proxies() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter { + // this will also work for proxies that have 'any' ASN + asn: Some(vec![Asn::from_static(42)]), ..Default::default() - }, - ProxyFilter { - carrier: Some(vec![StringFilter::new("*")]), - ..Default::default() - }, - ProxyFilter { - asn: Some(vec![Asn::unspecified()]), - ..Default::default() - }, - ProxyFilter { - pool_id: Some(vec![StringFilter::new("*")]), - continent: Some(vec![StringFilter::new("*")]), - country: Some(vec![StringFilter::new("*")]), - state: Some(vec![StringFilter::new("*")]), - city: Some(vec![StringFilter::new("*")]), - carrier: Some(vec![StringFilter::new("*")]), - asn: Some(vec![Asn::unspecified()]), - ..Default::default() - }, - ] { - let err = match db.get_proxy(ctx.clone(), filter.clone()).await { - Ok(proxy) => { - panic!( - "expected error for filter {:?}, not found proxy: {:?}", - filter, proxy - ); - } - Err(err) => err, }; + let mut found_ids = Vec::new(); + for _ in 0..5000 { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + if found_ids.contains(&proxy.id) { + continue; + } + found_ids.push(proxy.id); + } + assert_eq!(found_ids.len(), 4); assert_eq!( - MemoryProxyDBQueryErrorKind::NotFound, - err.kind(), - "filter: {:?}", - filter + found_ids.iter().sorted().join(","), + r#"2141152822,2912880381,292096733,3481200027"#, ); } - } - #[tokio::test] - async fn test_search_proxy_for_any_of_given_pools() { - let db = MemoryProxyDB::try_from_iter([ - Proxy { + #[tokio::test] + async fn test_memorydb_get_h3_capable_mobile_residential_be_asterix_proxies() { + let db = memproxydb().await; + let ctx = h3_transport_context(); + let filter = ProxyFilter { + country: Some(vec!["BE".into()]), + mobile: Some(true), + residential: Some(true), + ..Default::default() + }; + for _ in 0..50 { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + assert_eq!(proxy.id, "2593294918"); + } + } + + #[tokio::test] + async fn test_memorydb_get_blocked_proxies() { + let db = memproxydb().await; + let ctx = h2_transport_context(); + let filter = ProxyFilter::default(); + + let mut blocked_proxies = vec![ + "1125300915", + "1259341971", + "1264821985", + "129108927", + "1316455915", + "1425588737", + "1571861931", + "1810781137", + "1836040682", + "1844412609", + "1885107293", + "2021561518", + "2079461709", + "2107229589", + "2141152822", + "2438596154", + "2497865606", + "2521901221", + "2551759475", + "2560727338", + "2593294918", + "2798907087", + "2854473221", + "2880295577", + "2909724448", + "2912880381", + "292096733", + "2951529660", + "3031533634", + "3187902553", + "3269411602", + "3269465574", + "339020035", + "3481200027", + "3498810974", + "3503691556", + "362091157", + "3679054656", + "371209663", + "3861736957", + "39048766", + "3976711563", + "4062553709", + "49590203", + "56402588", + "724884866", + "738626121", + "767809962", + "846528631", + "906390012", + ]; + + { + let blocked_proxies = blocked_proxies.clone(); + + assert_eq!( + MemoryProxyDBQueryErrorKind::NotFound, + db.get_proxy_if(ctx.clone(), filter.clone(), move |proxy: &Proxy| { + !blocked_proxies.contains(&proxy.id.as_str()) + }) + .await + .unwrap_err() + .kind() + ); + } + + let last_proxy_id = blocked_proxies.pop().unwrap(); + + let proxy = db + .get_proxy_if(ctx, filter.clone(), move |proxy: &Proxy| { + !blocked_proxies.contains(&proxy.id.as_str()) + }) + .await + .unwrap(); + assert_eq!(proxy.id, last_proxy_id); + } + + #[tokio::test] + async fn test_db_proxy_filter_any_use_filter_property() { + let db = MemoryProxyDB::try_from_iter([Proxy { id: NonEmptyString::from_static("1"), address: ProxyAddress::from_str("example.com").unwrap(), tcp: true, @@ -1079,56 +904,88 @@ mod tests { datacenter: true, residential: true, mobile: true, - pool_id: Some("a".into()), - continent: Some("americas".into()), - country: Some("US".into()), - state: Some("NY".into()), - city: Some("NY".into()), - carrier: Some("AT&T".into()), - asn: Some(Asn::from_static(7018)), - }, - Proxy { - id: NonEmptyString::from_static("2"), - address: ProxyAddress::from_str("example.com").unwrap(), - tcp: true, - udp: true, - http: true, - https: true, - socks5: true, - socks5h: true, - datacenter: true, - residential: true, - mobile: true, - pool_id: Some("b".into()), - continent: Some("americas".into()), - country: Some("US".into()), - state: Some("NY".into()), - city: Some("NY".into()), - carrier: Some("AT&T".into()), - asn: Some(Asn::from_static(7018)), - }, - Proxy { - id: NonEmptyString::from_static("3"), - address: ProxyAddress::from_str("example.com").unwrap(), - tcp: true, - udp: true, - http: true, - https: true, - socks5: true, - socks5h: true, - datacenter: true, - residential: true, - mobile: true, - pool_id: Some("b".into()), - continent: Some("americas".into()), - country: Some("US".into()), - state: Some("NY".into()), - city: Some("NY".into()), - carrier: Some("AT&T".into()), - asn: Some(Asn::from_static(7018)), - }, - Proxy { - id: NonEmptyString::from_static("4"), + pool_id: Some("*".into()), + continent: Some("*".into()), + country: Some("*".into()), + state: Some("*".into()), + city: Some("*".into()), + carrier: Some("*".into()), + asn: Some(Asn::unspecified()), + }]) + .unwrap(); + + let ctx = h2_transport_context(); + + for filter in [ + ProxyFilter { + id: Some(NonEmptyString::from_static("1")), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("hq")]), + ..Default::default() + }, + ProxyFilter { + country: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + country: Some(vec![StringFilter::new("US")]), + ..Default::default() + }, + ProxyFilter { + city: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + city: Some(vec![StringFilter::new("NY")]), + ..Default::default() + }, + ProxyFilter { + carrier: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + carrier: Some(vec![StringFilter::new("Telenet")]), + ..Default::default() + }, + ProxyFilter { + pool_id: Some(vec![StringFilter::new("hq")]), + country: Some(vec![StringFilter::new("US")]), + city: Some(vec![StringFilter::new("NY")]), + carrier: Some(vec![StringFilter::new("AT&T")]), + ..Default::default() + }, + ] { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + assert!(filter.id.map(|id| proxy.id == id).unwrap_or(true)); + assert!(filter + .pool_id + .map(|pool_id| pool_id.contains(proxy.pool_id.as_ref().unwrap())) + .unwrap_or(true)); + assert!(filter + .country + .map(|country| country.contains(proxy.country.as_ref().unwrap())) + .unwrap_or(true)); + assert!(filter + .city + .map(|city| city.contains(proxy.city.as_ref().unwrap())) + .unwrap_or(true)); + assert!(filter + .carrier + .map(|carrier| carrier.contains(proxy.carrier.as_ref().unwrap())) + .unwrap_or(true)); + } + } + + #[tokio::test] + async fn test_db_proxy_filter_any_only_matches_any_value() { + let db = MemoryProxyDB::try_from_iter([Proxy { + id: NonEmptyString::from_static("1"), address: ProxyAddress::from_str("example.com").unwrap(), tcp: true, udp: true, @@ -1139,101 +996,256 @@ mod tests { datacenter: true, residential: true, mobile: true, - pool_id: Some("c".into()), + pool_id: Some("hq".into()), continent: Some("americas".into()), country: Some("US".into()), state: Some("NY".into()), city: Some("NY".into()), carrier: Some("AT&T".into()), asn: Some(Asn::from_static(7018)), - }, - ]) - .unwrap(); - - let ctx = h2_transport_context(); - - let filter = ProxyFilter { - pool_id: Some(vec![StringFilter::new("a"), StringFilter::new("c")]), - ..Default::default() - }; - - let mut seen_1 = false; - let mut seen_4 = false; - for _ in 0..100 { - let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); - match proxy.id.as_str() { - "1" => seen_1 = true, - "4" => seen_4 = true, - _ => panic!("unexpected pool id"), - } - } - assert!(seen_1); - assert!(seen_4); - } + }]) + .unwrap(); + + let ctx = h2_transport_context(); - #[tokio::test] - async fn test_deserialize_url_proxy_filter() { - for (input, expected_output) in [ - ( - "id=1", + for filter in [ ProxyFilter { - id: Some(NonEmptyString::from_static("1")), + pool_id: Some(vec![StringFilter::new("*")]), ..Default::default() }, - ), - ( - "pool=hq&country=us", ProxyFilter { - pool_id: Some(vec![StringFilter::new("hq")]), - country: Some(vec![StringFilter::new("us")]), + continent: Some(vec![StringFilter::new("*")]), ..Default::default() }, - ), - ( - "pool=hq&country=us&country=be", ProxyFilter { - pool_id: Some(vec![StringFilter::new("hq")]), - country: Some(vec![StringFilter::new("us"), StringFilter::new("be")]), + country: Some(vec![StringFilter::new("*")]), ..Default::default() }, - ), - ( - "pool=a&country=uk&pool=b", ProxyFilter { - pool_id: Some(vec![StringFilter::new("a"), StringFilter::new("b")]), - country: Some(vec![StringFilter::new("uk")]), + state: Some(vec![StringFilter::new("*")]), ..Default::default() }, - ), - ( - "continent=europe&continent=asia", ProxyFilter { - continent: Some(vec![StringFilter::new("europe"), StringFilter::new("asia")]), + city: Some(vec![StringFilter::new("*")]), ..Default::default() }, - ), - ( - "continent=americas&country=us&state=NY&city=buffalo&carrier=AT%26T&asn=7018", ProxyFilter { - continent: Some(vec![StringFilter::new("americas")]), - country: Some(vec![StringFilter::new("us")]), - state: Some(vec![StringFilter::new("ny")]), - city: Some(vec![StringFilter::new("buffalo")]), - carrier: Some(vec![StringFilter::new("at&t")]), - asn: Some(vec![Asn::from_static(7018)]), + carrier: Some(vec![StringFilter::new("*")]), + ..Default::default() + }, + ProxyFilter { + asn: Some(vec![Asn::unspecified()]), ..Default::default() }, - ), - ( - "asn=1&asn=2", ProxyFilter { - asn: Some(vec![Asn::from_static(1), Asn::from_static(2)]), + pool_id: Some(vec![StringFilter::new("*")]), + continent: Some(vec![StringFilter::new("*")]), + country: Some(vec![StringFilter::new("*")]), + state: Some(vec![StringFilter::new("*")]), + city: Some(vec![StringFilter::new("*")]), + carrier: Some(vec![StringFilter::new("*")]), + asn: Some(vec![Asn::unspecified()]), ..Default::default() }, - ), - ] { - let filter: ProxyFilter = serde_html_form::from_str(input).unwrap(); - assert_eq!(filter, expected_output); + ] { + let err = match db.get_proxy(ctx.clone(), filter.clone()).await { + Ok(proxy) => { + panic!( + "expected error for filter {:?}, not found proxy: {:?}", + filter, proxy + ); + } + Err(err) => err, + }; + assert_eq!( + MemoryProxyDBQueryErrorKind::NotFound, + err.kind(), + "filter: {:?}", + filter + ); + } + } + + #[tokio::test] + async fn test_search_proxy_for_any_of_given_pools() { + let db = MemoryProxyDB::try_from_iter([ + Proxy { + id: NonEmptyString::from_static("1"), + address: ProxyAddress::from_str("example.com").unwrap(), + tcp: true, + udp: true, + http: true, + https: true, + socks5: true, + socks5h: true, + datacenter: true, + residential: true, + mobile: true, + pool_id: Some("a".into()), + continent: Some("americas".into()), + country: Some("US".into()), + state: Some("NY".into()), + city: Some("NY".into()), + carrier: Some("AT&T".into()), + asn: Some(Asn::from_static(7018)), + }, + Proxy { + id: NonEmptyString::from_static("2"), + address: ProxyAddress::from_str("example.com").unwrap(), + tcp: true, + udp: true, + http: true, + https: true, + socks5: true, + socks5h: true, + datacenter: true, + residential: true, + mobile: true, + pool_id: Some("b".into()), + continent: Some("americas".into()), + country: Some("US".into()), + state: Some("NY".into()), + city: Some("NY".into()), + carrier: Some("AT&T".into()), + asn: Some(Asn::from_static(7018)), + }, + Proxy { + id: NonEmptyString::from_static("3"), + address: ProxyAddress::from_str("example.com").unwrap(), + tcp: true, + udp: true, + http: true, + https: true, + socks5: true, + socks5h: true, + datacenter: true, + residential: true, + mobile: true, + pool_id: Some("b".into()), + continent: Some("americas".into()), + country: Some("US".into()), + state: Some("NY".into()), + city: Some("NY".into()), + carrier: Some("AT&T".into()), + asn: Some(Asn::from_static(7018)), + }, + Proxy { + id: NonEmptyString::from_static("4"), + address: ProxyAddress::from_str("example.com").unwrap(), + tcp: true, + udp: true, + http: true, + https: true, + socks5: true, + socks5h: true, + datacenter: true, + residential: true, + mobile: true, + pool_id: Some("c".into()), + continent: Some("americas".into()), + country: Some("US".into()), + state: Some("NY".into()), + city: Some("NY".into()), + carrier: Some("AT&T".into()), + asn: Some(Asn::from_static(7018)), + }, + ]) + .unwrap(); + + let ctx = h2_transport_context(); + + let filter = ProxyFilter { + pool_id: Some(vec![StringFilter::new("a"), StringFilter::new("c")]), + ..Default::default() + }; + + let mut seen_1 = false; + let mut seen_4 = false; + for _ in 0..100 { + let proxy = db.get_proxy(ctx.clone(), filter.clone()).await.unwrap(); + match proxy.id.as_str() { + "1" => seen_1 = true, + "4" => seen_4 = true, + _ => panic!("unexpected pool id"), + } + } + assert!(seen_1); + assert!(seen_4); + } + + #[tokio::test] + async fn test_deserialize_url_proxy_filter() { + for (input, expected_output) in [ + ( + "id=1", + ProxyFilter { + id: Some(NonEmptyString::from_static("1")), + ..Default::default() + }, + ), + ( + "pool=hq&country=us", + ProxyFilter { + pool_id: Some(vec![StringFilter::new("hq")]), + country: Some(vec![StringFilter::new("us")]), + ..Default::default() + }, + ), + ( + "pool=hq&country=us&country=be", + ProxyFilter { + pool_id: Some(vec![StringFilter::new("hq")]), + country: Some(vec![StringFilter::new("us"), StringFilter::new("be")]), + ..Default::default() + }, + ), + ( + "pool=a&country=uk&pool=b", + ProxyFilter { + pool_id: Some(vec![StringFilter::new("a"), StringFilter::new("b")]), + country: Some(vec![StringFilter::new("uk")]), + ..Default::default() + }, + ), + ( + "continent=europe&continent=asia", + ProxyFilter { + continent: Some(vec![ + StringFilter::new("europe"), + StringFilter::new("asia"), + ]), + ..Default::default() + }, + ), + ( + "continent=americas&country=us&state=NY&city=buffalo&carrier=AT%26T&asn=7018", + ProxyFilter { + continent: Some(vec![StringFilter::new("americas")]), + country: Some(vec![StringFilter::new("us")]), + state: Some(vec![StringFilter::new("ny")]), + city: Some(vec![StringFilter::new("buffalo")]), + carrier: Some(vec![StringFilter::new("at&t")]), + asn: Some(vec![Asn::from_static(7018)]), + ..Default::default() + }, + ), + ( + "asn=1&asn=2", + ProxyFilter { + asn: Some(vec![Asn::from_static(1), Asn::from_static(2)]), + ..Default::default() + }, + ), + ] { + let filter: ProxyFilter = serde_html_form::from_str(input).unwrap(); + assert_eq!(filter, expected_output); + } } } } + +#[cfg(feature = "memory-db")] +pub use memdb::{ + MemoryProxyDB, MemoryProxyDBInsertError, MemoryProxyDBInsertErrorKind, MemoryProxyDBQueryError, + MemoryProxyDBQueryErrorKind, +}; diff --git a/rama-proxy/src/proxydb/str.rs b/rama-proxy/src/proxydb/str.rs index bbcabf4b..0c2fd919 100644 --- a/rama-proxy/src/proxydb/str.rs +++ b/rama-proxy/src/proxydb/str.rs @@ -119,6 +119,7 @@ impl<'de> Deserialize<'de> for StringFilter { } } +#[cfg(feature = "memory-db")] impl venndb::Any for StringFilter { fn is_any(&self) -> bool { self.0 == "*" diff --git a/rama-tcp/src/client/mod.rs b/rama-tcp/src/client/mod.rs index 7f1aeb27..350cad7f 100644 --- a/rama-tcp/src/client/mod.rs +++ b/rama-tcp/src/client/mod.rs @@ -1,5 +1,6 @@ //! Rama TCP Client module. +#[cfg(feature = "http")] pub mod service; mod connect; From 1d379b3535e418beb6f6b2d469fe62ba32b0c09c Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 21:55:12 +0200 Subject: [PATCH 16/24] fix proxydb feature-gate test --- rama-proxy/src/proxydb/internal.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/rama-proxy/src/proxydb/internal.rs b/rama-proxy/src/proxydb/internal.rs index ac0879c0..cb4de86e 100644 --- a/rama-proxy/src/proxydb/internal.rs +++ b/rama-proxy/src/proxydb/internal.rs @@ -176,11 +176,12 @@ impl Proxy { } } -#[cfg(feature = "csv")] +#[cfg(all(feature = "csv", feature = "memory-db"))] #[cfg(test)] mod tests { use super::*; use crate::proxydb::csv::{parse_csv_row, ProxyCsvRowReader}; + use crate::proxydb::ProxyDB; use itertools::Itertools; #[test] @@ -352,10 +353,7 @@ mod tests { let mut db = ProxyDB::new(); let mut reader = ProxyCsvRowReader::raw("id1,1,,,,,,,,,authority,,,,,,,\nid2,,1,,,,,,,,authority,,,,,,,\nid3,,1,1,,,,,,,authority,,,,,,,\nid4,,1,1,,,,,1,,authority,,,,,,,\nid5,,1,1,,,,,1,,authority,,,,,,,"); while let Some(proxy) = reader.next().await.unwrap() { - assert_eq!( - MemoryProxyDBInsertErrorKind::InvalidRow, - db.append(proxy).unwrap_err().kind - ); + assert_eq!(ProxyDB::InvalidRow, db.append(proxy).unwrap_err().kind); } } } From dc6ecc782c728e9ee05984f5b85db10bcf6eafc5 Mon Sep 17 00:00:00 2001 From: glendc Date: Wed, 4 Sep 2024 22:07:33 +0200 Subject: [PATCH 17/24] fix examples --- Cargo.lock | 2 ++ Cargo.toml | 15 ++++++++++++++- examples/http_conn_state.rs | 2 +- examples/http_connect_proxy.rs | 9 +++++---- src/lib.rs | 2 +- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3eb77a8e..557fe4f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1535,10 +1535,12 @@ dependencies = [ "rama-ua", "rama-utils", "rustversion", + "serde", "serde_html_form", "serde_json", "tokio", "tracing", + "tracing-subscriber", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d8b1199d..840e20d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -157,7 +157,7 @@ cli = ["dep:base64", "dep:bytes", "dep:hex", "dep:serde_json", "dep:serde_html_f net = ["dep:rama-net"] tcp = ["net", "dep:rama-tcp"] http = ["net", "dep:rama-http", "net", "ua", "rama-net/http", "rama-tcp/http"] -http-full = ["http", "dep:rama-http-backend"] +http-full = ["http", "tcp", "dep:rama-http-backend"] proxy = ["dep:rama-proxy"] haproxy = ["dep:rama-haproxy"] ua = ["dep:rama-ua"] @@ -190,6 +190,11 @@ tokio = { workspace = true, features = ["macros", "io-std"], optional = true } tracing = { workspace = true, optional = true } [dev-dependencies] +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +tokio = { workspace = true, features = ["macros"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter"] } [profile.dev.package."*"] opt-level = 3 @@ -206,6 +211,14 @@ rustdoc-args = ["--cfg", "docsrs"] name = "ua_parse" harness = false +[[example]] +name = "http_conn_state" +required-features = ["http-full"] + +[[example]] +name = "http_connect_proxy" +required-features = ["http-full"] + [[example]] name = "http_high_level_client" required-features = ["compression"] diff --git a/examples/http_conn_state.rs b/examples/http_conn_state.rs index 34cc516c..ae969e79 100644 --- a/examples/http_conn_state.rs +++ b/examples/http_conn_state.rs @@ -11,7 +11,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_conn_state +//! cargo run --example http_conn_state --features=http-full //! ``` //! //! # Expected output diff --git a/examples/http_connect_proxy.rs b/examples/http_connect_proxy.rs index 6b6a3382..e3bc51e5 100644 --- a/examples/http_connect_proxy.rs +++ b/examples/http_connect_proxy.rs @@ -6,7 +6,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_connect_proxy +//! cargo run --example http_connect_proxy --features=http-full //! ``` //! //! # Expected output @@ -70,15 +70,16 @@ use rama::{ response::Json, server::HttpServer, service::web::{extract::Path, match_service}, - Body, IntoResponse, Request, RequestContext, Response, StatusCode, + Body, IntoResponse, Request, Response, StatusCode, }, layer::HijackLayer, + net::http::RequestContext, + net::stream::layer::http::BodyLimitLayer, net::{address::Domain, user::Basic}, rt::Executor, service::service_fn, - stream::layer::http::BodyLimitLayer, tcp::{server::TcpListener, utils::is_connection_error}, - utils::username::{ + username::{ UsernameLabelParser, UsernameLabelState, UsernameLabels, UsernameOpaqueLabelParser, }, Context, Layer, Service, diff --git a/src/lib.rs b/src/lib.rs index ecf3073b..7e7e047e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -278,7 +278,7 @@ pub use ::rama_core::{ combinators, context, dns, error, graceful, layer, matcher, rt, service, Context, Layer, - Service, + Service, username, }; #[cfg(feature = "tcp")] From cba79f7a63b08da7b4990f4b3970b7695835a7ea Mon Sep 17 00:00:00 2001 From: glendc Date: Thu, 5 Sep 2024 00:02:04 +0200 Subject: [PATCH 18/24] make examples work again --- Cargo.lock | 252 ++++++++++++++++++++++- Cargo.toml | 70 ++++++- examples/http_form.rs | 2 +- examples/http_health_check.rs | 2 +- examples/http_high_level_client.rs | 5 +- examples/http_k8s_health.rs | 2 +- examples/http_key_value_store.rs | 2 +- examples/http_listener_hello.rs | 2 +- examples/http_mitm_proxy.rs | 13 +- examples/http_rate_limit.rs | 4 +- examples/http_service_fs.rs | 2 +- examples/http_service_hello.rs | 8 +- examples/http_service_match.rs | 4 +- examples/http_telemetry.rs | 4 +- examples/http_user_agent_classifier.rs | 4 +- examples/http_web_service_dir_and_api.rs | 4 +- examples/https_connect_proxy.rs | 13 +- examples/mtls_tunnel_and_service.rs | 15 +- examples/tcp_listener_hello.rs | 7 +- examples/tcp_listener_layers.rs | 4 +- examples/tls_boring_termination.rs | 10 +- examples/tls_termination.rs | 12 +- src/lib.rs | 4 +- 23 files changed, 371 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 557fe4f7..709335c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,6 +114,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "arbitrary" version = "1.3.2" @@ -214,6 +220,53 @@ dependencies = [ "paste", ] +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.1", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.73" @@ -827,13 +880,19 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.5" @@ -1017,6 +1076,19 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-timeout" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.7" @@ -1024,12 +1096,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", + "futures-channel", "futures-util", "http", "http-body", "hyper", "pin-project-lite", + "socket2", "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1052,6 +1129,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.5.0" @@ -1059,7 +1146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -1227,6 +1314,12 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.7.4" @@ -1352,6 +1445,36 @@ dependencies = [ "thiserror", ] +[[package]] +name = "opentelemetry-otlp" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b925a602ffb916fb7421276b86756027b37ee708f9dce2dbdcc51739f07e727" +dependencies = [ + "async-trait", + "futures-core", + "http", + "opentelemetry", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "thiserror", + "tokio", + "tonic", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ee9f20bff9c984511a02f082dc8ede839e4a9bf15cc2487c8d6fea5ad850d9" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", +] + [[package]] name = "opentelemetry-semantic-conventions" version = "0.16.0" @@ -1368,11 +1491,15 @@ dependencies = [ "futures-channel", "futures-executor", "futures-util", + "glob", "once_cell", "opentelemetry", "percent-encoding", "rand", + "serde_json", "thiserror", + "tokio", + "tokio-stream", ] [[package]] @@ -1438,6 +1565,26 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1490,6 +1637,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +dependencies = [ + "anyhow", + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quickcheck" version = "1.0.3" @@ -1523,6 +1693,8 @@ dependencies = [ "base64 0.22.1", "bytes", "hex", + "opentelemetry-otlp", + "opentelemetry_sdk", "rama-core", "rama-haproxy", "rama-http", @@ -1688,7 +1860,7 @@ dependencies = [ "serde", "serde_html_form", "serde_json", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tokio-test", "tracing", @@ -2095,7 +2267,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de514ef58196f1fc96dcaef80fe6170a1ce6215df9687a93fe8300e773fefc5" dependencies = [ "form_urlencoded", - "indexmap", + "indexmap 2.5.0", "itoa", "ryu", "serde", @@ -2211,6 +2383,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.1" @@ -2448,13 +2626,75 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", "winnow", ] +[[package]] +name = "tonic" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "socket2", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.40" @@ -2623,7 +2863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ed0d279917911e77093bb5f6a86870c5420cf288e2393c70bcc3a802f0fa63" dependencies = [ "bitvec", - "hashbrown", + "hashbrown 0.14.5", "rand", "venndb-macros", ] diff --git a/Cargo.toml b/Cargo.toml index 840e20d0..7ad64831 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ nom = "7.1.3" opentelemetry-otlp = { version = "0.17", features = [ "tokio" ] } opentelemetry_sdk = { version = "0.24", default-features = false, features = [ "trace", + "rt-tokio", ] } opentelemetry-semantic-conventions = "0.16" quickcheck = "1.0" @@ -190,6 +191,9 @@ tokio = { workspace = true, features = ["macros", "io-std"], optional = true } tracing = { workspace = true, optional = true } [dev-dependencies] +bytes = { workspace = true } +opentelemetry-otlp = { workspace = true } +opentelemetry_sdk = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros"] } @@ -219,30 +223,82 @@ required-features = ["http-full"] name = "http_connect_proxy" required-features = ["http-full"] +[[example]] +name = "http_form" +required-features = ["http-full"] + +[[example]] +name = "http_health_check" +required-features = ["http-full"] + [[example]] name = "http_high_level_client" -required-features = ["compression"] +required-features = ["compression", "http-full"] + +[[example]] +name = "http_k8s_health" +required-features = ["http-full"] + +[[example]] +name = "http_key_value_store" +required-features = ["compression", "http-full"] + +[[example]] +name = "http_listener_hello" +required-features = ["http-full"] [[example]] name = "http_mitm_proxy" -required-features = ["rustls"] +required-features = ["http-full", "rustls"] + +[[example]] +name = "http_rate_limit" +required-features = ["http-full"] + +[[example]] +name = "http_service_fs" +required-features = ["http-full"] + +[[example]] +name = "http_service_hello" +required-features = ["compression", "http-full"] + +[[example]] +name = "http_service_match" +required-features = ["http-full"] [[example]] name = "http_telemetry" -required-features = ["telemetry"] +required-features = ["http-full", "telemetry"] + +[[example]] +name = "http_user_agent_classifier" +required-features = ["http-full"] + +[[example]] +name = "http_web_service_dir_and_api" +required-features = ["compression", "http-full"] [[example]] name = "https_connect_proxy" -required-features = ["rustls"] +required-features = ["http-full", "rustls"] [[example]] name = "mtls_tunnel_and_service" -required-features = ["rustls"] +required-features = ["http-full", "rustls"] + +[[example]] +name = "tcp_listener_hello" +required-features = ["tcp"] + +[[example]] +name = "tcp_listener_layers" +required-features = ["tcp"] [[example]] name = "tls_boring_termination" -required-features = ["boring"] +required-features = ["boring", "haproxy", "http-full"] [[example]] name = "tls_termination" -required-features = ["rustls"] +required-features = ["haproxy", "http-full", "rustls"] diff --git a/examples/http_form.rs b/examples/http_form.rs index 5add741f..dd6bf33d 100644 --- a/examples/http_form.rs +++ b/examples/http_form.rs @@ -9,7 +9,7 @@ //! # Run the example //! //! ```sh -//! RUST_LOG=trace cargo run --example http_form +//! RUST_LOG=trace cargo run --example http_form --features=http-full //! ``` //! //! # Expected output diff --git a/examples/http_health_check.rs b/examples/http_health_check.rs index 7afcf13e..24cdee27 100644 --- a/examples/http_health_check.rs +++ b/examples/http_health_check.rs @@ -9,7 +9,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_health_check +//! cargo run --example http_health_check --features=http-full //! ``` //! //! # Expected output diff --git a/examples/http_high_level_client.rs b/examples/http_high_level_client.rs index b4aaabc7..0da4f800 100644 --- a/examples/http_high_level_client.rs +++ b/examples/http_high_level_client.rs @@ -2,7 +2,7 @@ //! layer stack in a high level manner using the HttpClientExt. //! //! ```sh -//! cargo run --example http_high_level_client +//! cargo run --example http_high_level_client --features=compression,http-full //! ``` //! //! # Expected output @@ -14,7 +14,7 @@ use rama::{ http::{ - client::{HttpClient, HttpClientExt}, + client::HttpClient, headers::{authorization::Basic, Accept, Authorization, HeaderMapExt}, layer::{ auth::{AddAuthorizationLayer, AsyncRequireAuthorizationLayer}, @@ -25,6 +25,7 @@ use rama::{ }, response::Json, server::HttpServer, + service::client::HttpClientExt, service::web::WebService, Body, BodyExtractExt, IntoResponse, Request, Response, StatusCode, }, diff --git a/examples/http_k8s_health.rs b/examples/http_k8s_health.rs index 9eeafd6e..4630b1e8 100644 --- a/examples/http_k8s_health.rs +++ b/examples/http_k8s_health.rs @@ -9,7 +9,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_k8s_health +//! cargo run --example http_k8s_health --features=http-full //! ``` //! //! # Expected output diff --git a/examples/http_key_value_store.rs b/examples/http_key_value_store.rs index faaabf07..1fc55ba7 100644 --- a/examples/http_key_value_store.rs +++ b/examples/http_key_value_store.rs @@ -19,7 +19,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_key_value_store +//! cargo run --example http_key_value_store --features=compression,http-full //! ``` //! //! # Expected output diff --git a/examples/http_listener_hello.rs b/examples/http_listener_hello.rs index 6e2c9064..9b936af7 100644 --- a/examples/http_listener_hello.rs +++ b/examples/http_listener_hello.rs @@ -4,7 +4,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_listener_hello +//! cargo run --example http_listener_hello --features=http-full //! ``` //! //! # Expected output diff --git a/examples/http_mitm_proxy.rs b/examples/http_mitm_proxy.rs index a58fdaa5..e67451ac 100644 --- a/examples/http_mitm_proxy.rs +++ b/examples/http_mitm_proxy.rs @@ -20,7 +20,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_mitm_proxy --features=rustls +//! cargo run --example http_mitm_proxy --features=http-full,rustls //! ``` //! //! # Expected output @@ -29,7 +29,7 @@ //! //! ```sh //! curl -v -x http://127.0.0.1:62017 --proxy-user 'john:secret' http://www.example.com/ -//! curl -v -x http://127.0.0.1:62017 --proxy-user 'john:secret' https://www.example.com/ +//! curl -k -v -x http://127.0.0.1:62017 --proxy-user 'john:secret' https://www.example.com/ //! ``` use rama::{ @@ -47,23 +47,24 @@ use rama::{ }, matcher::MethodMatcher, server::HttpServer, - Body, IntoResponse, Request, RequestContext, Response, StatusCode, + Body, IntoResponse, Request, Response, StatusCode, }, layer::ConsumeErrLayer, + net::http::RequestContext, + net::stream::layer::http::BodyLimitLayer, net::user::Basic, rt::Executor, service::service_fn, - stream::layer::http::BodyLimitLayer, tcp::server::TcpListener, tls::{ - backend::rustls::{ + dep::rcgen::{self, KeyPair}, + rustls::{ dep::{ pki_types::{CertificateDer, PrivatePkcs8KeyDer}, rustls::ServerConfig, }, server::TlsAcceptorLayer, }, - dep::rcgen::KeyPair, }, Layer, Service, }; diff --git a/examples/http_rate_limit.rs b/examples/http_rate_limit.rs index 1376294b..93093f68 100644 --- a/examples/http_rate_limit.rs +++ b/examples/http_rate_limit.rs @@ -6,7 +6,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_rate_limit +//! cargo run --example http_rate_limit --features=http-full //! ``` //! //! # Expected output @@ -47,9 +47,9 @@ use rama::{ limit::policy::{ConcurrentPolicy, LimitReached}, Layer, LimitLayer, MapResultLayer, TraceErrLayer, }, + net::stream::matcher::SocketMatcher, rt::Executor, service::service_fn, - stream::matcher::SocketMatcher, utils::backoff::ExponentialBackoff, }; use serde_json::json; diff --git a/examples/http_service_fs.rs b/examples/http_service_fs.rs index 093b47df..b7a60099 100644 --- a/examples/http_service_fs.rs +++ b/examples/http_service_fs.rs @@ -3,7 +3,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_service_fs +//! cargo run --example http_service_fs --features=http-full //! ``` //! //! # Expected output diff --git a/examples/http_service_hello.rs b/examples/http_service_hello.rs index c9de1403..fb152318 100644 --- a/examples/http_service_hello.rs +++ b/examples/http_service_hello.rs @@ -5,7 +5,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_service_hello +//! cargo run --example http_service_hello --features=compression,http-full //! ``` //! //! # Expected output @@ -35,12 +35,12 @@ use rama::{ IntoResponse, Request, }, layer::{MapResponseLayer, TimeoutLayer, TraceErrLayer}, - rt::Executor, - service::service_fn, - stream::{ + net::stream::{ layer::{BytesRWTrackerHandle, IncomingBytesTrackerLayer}, SocketInfo, }, + rt::Executor, + service::service_fn, tcp::server::TcpListener, utils::latency::LatencyUnit, Context, Layer, diff --git a/examples/http_service_match.rs b/examples/http_service_match.rs index b75d939e..992bac78 100644 --- a/examples/http_service_match.rs +++ b/examples/http_service_match.rs @@ -4,7 +4,7 @@ //! the [`http_web_service_dir_and_api`] example. //! //! ```sh -//! cargo run --example http_service_match +//! cargo run --example http_service_match --features=http-full //! ``` //! //! # Expected output @@ -33,8 +33,8 @@ use rama::{ Layer, }; -use serde_json::json; /// Everything else we need is provided by the standard library, community crates or tokio. +use serde_json::json; use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; diff --git a/examples/http_telemetry.rs b/examples/http_telemetry.rs index d3fc8f29..f5c75480 100644 --- a/examples/http_telemetry.rs +++ b/examples/http_telemetry.rs @@ -21,7 +21,7 @@ //! # Run the example //! //! ```sh -//! cargo run --features=telemetry --example http_telemetry +//! cargo run --example http_telemetry --features=http-full,telemetry //! ``` //! //! # Expected output @@ -48,8 +48,8 @@ use rama::{ server::HttpServer, service::web::{extract::State, WebService}, }, + net::stream::layer::opentelemetry::NetworkMetricsLayer, rt::Executor, - stream::layer::opentelemetry::NetworkMetricsLayer, tcp::server::TcpListener, telemetry::opentelemetry::{ self, diff --git a/examples/http_user_agent_classifier.rs b/examples/http_user_agent_classifier.rs index 8f1b9547..032d2bd1 100644 --- a/examples/http_user_agent_classifier.rs +++ b/examples/http_user_agent_classifier.rs @@ -3,7 +3,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_user_agent_classifier +//! cargo run --example http_user_agent_classifier --features=http-full //! ``` //! //! # Expected output @@ -17,10 +17,10 @@ //! You should see a response with `HTTP/1.1 200 OK` and a JSON body with the user agent info exposed by Rama. use rama::{ + http::layer::ua::{UserAgent, UserAgentClassifierLayer}, http::{response::Json, server::HttpServer, HeaderName, IntoResponse, Request, Response}, rt::Executor, service::service_fn, - ua::{UserAgent, UserAgentClassifierLayer}, Context, Layer, }; use serde_json::json; diff --git a/examples/http_web_service_dir_and_api.rs b/examples/http_web_service_dir_and_api.rs index 7a619272..24bce34b 100644 --- a/examples/http_web_service_dir_and_api.rs +++ b/examples/http_web_service_dir_and_api.rs @@ -8,7 +8,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example http_web_service_dir_and_api +//! cargo run --example http_web_service_dir_and_api --features=compression,http-full //! ``` //! //! # Expected output @@ -35,8 +35,8 @@ use rama::{ WebService, }, }, + net::stream::{matcher::SocketMatcher, SocketInfo}, rt::Executor, - stream::{matcher::SocketMatcher, SocketInfo}, Layer, }; diff --git a/examples/https_connect_proxy.rs b/examples/https_connect_proxy.rs index 309e1c98..4b00e4f1 100644 --- a/examples/https_connect_proxy.rs +++ b/examples/https_connect_proxy.rs @@ -6,7 +6,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example https_connect_proxy --features=rustls +//! cargo run --example https_connect_proxy --features=http-full,rustls //! ``` //! //! # Expected output @@ -34,23 +34,24 @@ use rama::{ }, matcher::MethodMatcher, server::HttpServer, - Body, IntoResponse, Request, RequestContext, Response, StatusCode, + Body, IntoResponse, Request, Response, StatusCode, }, + net::http::RequestContext, + net::stream::layer::http::BodyLimitLayer, net::user::Basic, rt::Executor, service::service_fn, - stream::layer::http::BodyLimitLayer, tcp::{server::TcpListener, utils::is_connection_error}, tls::{ - backend::rustls::{ + dep::rcgen::{self, KeyPair}, + rustls::{ dep::{ pki_types::{CertificateDer, PrivatePkcs8KeyDer}, rustls::ServerConfig, }, server::{TlsAcceptorLayer, TlsClientConfigHandler}, }, - client::ClientHello, - dep::rcgen::KeyPair, + types::client::ClientHello, }, Context, Layer, Service, }; diff --git a/examples/mtls_tunnel_and_service.rs b/examples/mtls_tunnel_and_service.rs index f9080e3f..0e38452a 100644 --- a/examples/mtls_tunnel_and_service.rs +++ b/examples/mtls_tunnel_and_service.rs @@ -6,7 +6,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example mtls_tunnel_and_service --features=rustls +//! cargo run --example mtls_tunnel_and_service --features=http-full,rustls //! ``` //! //! # Expected output @@ -29,16 +29,14 @@ // as to make it easy to use them and ensure that the versions remain compatible // (given most do not have a stable release yet) use rama::{ - layer::TraceErrLayer, - service::service_fn, - tls::backend::rustls::dep::{ + tls::dep::rcgen::{self, KeyPair}, + tls::rustls::dep::{ pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, ServerName}, rustls::{ server::WebPkiClientVerifier, ClientConfig, KeyLogFile, RootCertStore, ServerConfig, }, tokio_rustls::TlsConnector, }, - Layer, }; // rama provides everything out of the box to build mtls web services and proxies @@ -51,12 +49,13 @@ use rama::{ server::HttpServer, service::web::WebService, }, + layer::TraceErrLayer, rt::Executor, + service::service_fn, tcp::server::TcpListener, - tls::backend::rustls::server::TlsAcceptorLayer, - Context, + tls::rustls::server::TlsAcceptorLayer, + Context, Layer, }; -use rcgen::KeyPair; // everything else is provided by the standard library, community crates or tokio use std::{sync::Arc, time::Duration}; diff --git a/examples/tcp_listener_hello.rs b/examples/tcp_listener_hello.rs index fae5c508..22fc4249 100644 --- a/examples/tcp_listener_hello.rs +++ b/examples/tcp_listener_hello.rs @@ -3,7 +3,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example tcp_listener_hello +//! cargo run --example tcp_listener_hello --features=tcp //! ``` //! //! # Expected output @@ -16,12 +16,11 @@ //! //! You should see a response with `HTTP/1.1 200 OK` and a body with the source code of this example. -use std::convert::Infallible; - use rama::{ - stream::{Socket, Stream}, + net::stream::{Socket, Stream}, tcp::server::TcpListener, }; +use std::convert::Infallible; use tokio::io::AsyncWriteExt; const SRC: &str = include_str!("./tcp_listener_hello.rs"); diff --git a/examples/tcp_listener_layers.rs b/examples/tcp_listener_layers.rs index 32a3572b..a65c9613 100644 --- a/examples/tcp_listener_layers.rs +++ b/examples/tcp_listener_layers.rs @@ -3,7 +3,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example tcp_listener_layers +//! cargo run --example tcp_listener_layers --features=tcp //! ``` //! //! # Expected output @@ -20,8 +20,8 @@ use rama::{ layer::{HijackLayer, TimeoutLayer, TraceErrLayer}, + net::stream::{matcher::SocketMatcher, service::EchoService}, service::service_fn, - stream::{matcher::SocketMatcher, service::EchoService}, tcp::server::TcpListener, Layer, }; diff --git a/examples/tls_boring_termination.rs b/examples/tls_boring_termination.rs index 52de0b29..835d7ac3 100644 --- a/examples/tls_boring_termination.rs +++ b/examples/tls_boring_termination.rs @@ -7,7 +7,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example tls_boring_termination --features=boring +//! cargo run --example tls_boring_termination --features=boring,haproxy,http-full //! ``` //! //! # Expected output @@ -38,17 +38,17 @@ use rama::{ graceful::Shutdown, layer::{ConsumeErrLayer, GetExtensionLayer}, net::forwarded::Forwarded, - proxy::pp::{ + net::stream::{SocketInfo, Stream}, + proxy::haproxy::{ client::HaProxyLayer as HaProxyClientLayer, server::HaProxyLayer as HaProxyServerLayer, }, service::service_fn, - stream::{SocketInfo, Stream}, tcp::{ client::service::{Forwarder, TcpConnector}, server::TcpListener, }, tls::{ - backend::boring::{ + boring::{ dep::boring::{ asn1::Asn1Time, bn::{BigNum, MsbOption}, @@ -62,7 +62,7 @@ use rama::{ }, server::{ServerConfig, TlsAcceptorLayer}, }, - ApplicationProtocol, SecureTransport, + types::{ApplicationProtocol, SecureTransport}, }, Context, Layer, }; diff --git a/examples/tls_termination.rs b/examples/tls_termination.rs index 05c24333..d7b96823 100644 --- a/examples/tls_termination.rs +++ b/examples/tls_termination.rs @@ -16,7 +16,7 @@ //! # Run the example //! //! ```sh -//! cargo run --example tls_termination --features=rustls +//! cargo run --example tls_termination --features=haproxy,http-full,rustls //! ``` //! //! # Expected output @@ -46,25 +46,25 @@ use rama::{ graceful::Shutdown, layer::ConsumeErrLayer, net::forwarded::Forwarded, - proxy::pp::{ + net::stream::{SocketInfo, Stream}, + proxy::haproxy::{ client::HaProxyLayer as HaProxyClientLayer, server::HaProxyLayer as HaProxyServerLayer, }, service::service_fn, - stream::{SocketInfo, Stream}, tcp::{ client::service::{Forwarder, TcpConnector}, server::TcpListener, }, tls::{ - backend::rustls::{ + dep::rcgen::{self, KeyPair}, + rustls::{ dep::{ pki_types::{CertificateDer, PrivatePkcs8KeyDer}, rustls::ServerConfig, }, server::{TlsAcceptorLayer, TlsClientConfigHandler}, }, - client::ClientHello, - dep::rcgen::KeyPair, + types::client::ClientHello, }, Context, Layer, }; diff --git a/src/lib.rs b/src/lib.rs index 7e7e047e..7e1b716f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,8 +277,8 @@ #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] pub use ::rama_core::{ - combinators, context, dns, error, graceful, layer, matcher, rt, service, Context, Layer, - Service, username, + combinators, context, dns, error, graceful, layer, matcher, rt, service, username, Context, + Layer, Service, }; #[cfg(feature = "tcp")] From 0c0780e5d07cc89de4a67475d3361c02307a5b32 Mon Sep 17 00:00:00 2001 From: glendc Date: Thu, 5 Sep 2024 00:27:09 +0200 Subject: [PATCH 19/24] fix integration tests --- Cargo.lock | 15 +++++++++++++++ Cargo.toml | 4 +++- justfile | 2 +- rama-proxy/src/proxydb/internal.rs | 7 +++++-- .../examples/example_tests/http_mitm_proxy.rs | 6 +++--- .../example_tests/http_user_agent_classifier.rs | 2 +- .../examples/example_tests/utils/mod.rs | 9 +++++---- 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 709335c9..81401183 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -659,6 +659,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "escargot" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c000f23e9d459aef148b7267e02b03b94a0aaacf4ec64c65612f67e02f525fb6" +dependencies = [ + "log", + "once_cell", + "serde", + "serde_json", +] + [[package]] name = "fastrand" version = "2.1.1" @@ -1692,7 +1704,9 @@ version = "0.2.0-alpha.2" dependencies = [ "base64 0.22.1", "bytes", + "escargot", "hex", + "itertools 0.13.0", "opentelemetry-otlp", "opentelemetry_sdk", "rama-core", @@ -1706,6 +1720,7 @@ dependencies = [ "rama-tls", "rama-ua", "rama-utils", + "regex", "rustversion", "serde", "serde_html_form", diff --git a/Cargo.toml b/Cargo.toml index 7ad64831..c65fba95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,6 @@ opentelemetry_sdk = { version = "0.24", default-features = false, features = [ opentelemetry-semantic-conventions = "0.16" quickcheck = "1.0" quote = "1.0" -ratatui = "0.26" rcgen = "0.13.0" regex = "1.10.3" rustls = { version = "0.23", default-features = false, features = [ @@ -192,8 +191,11 @@ tracing = { workspace = true, optional = true } [dev-dependencies] bytes = { workspace = true } +escargot = { workspace = true } +itertools = { workspace = true } opentelemetry-otlp = { workspace = true } opentelemetry_sdk = { workspace = true } +regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } tokio = { workspace = true, features = ["macros"] } diff --git a/justfile b/justfile index 58768afd..4249f58d 100644 --- a/justfile +++ b/justfile @@ -31,7 +31,7 @@ test: cargo test --all-features --workspace test-ignored: - cargo test --features=cli,telemetry,compression,rustls --workspace -- --ignored + cargo test --features=cli,telemetry,compression,http-full,proxy-full,tcp,rustls --workspace -- --ignored qa: lint check clippy doc test diff --git a/rama-proxy/src/proxydb/internal.rs b/rama-proxy/src/proxydb/internal.rs index cb4de86e..c27573db 100644 --- a/rama-proxy/src/proxydb/internal.rs +++ b/rama-proxy/src/proxydb/internal.rs @@ -181,7 +181,7 @@ impl Proxy { mod tests { use super::*; use crate::proxydb::csv::{parse_csv_row, ProxyCsvRowReader}; - use crate::proxydb::ProxyDB; + use crate::proxydb::internal::{ProxyDB, ProxyDBErrorKind}; use itertools::Itertools; #[test] @@ -353,7 +353,10 @@ mod tests { let mut db = ProxyDB::new(); let mut reader = ProxyCsvRowReader::raw("id1,1,,,,,,,,,authority,,,,,,,\nid2,,1,,,,,,,,authority,,,,,,,\nid3,,1,1,,,,,,,authority,,,,,,,\nid4,,1,1,,,,,1,,authority,,,,,,,\nid5,,1,1,,,,,1,,authority,,,,,,,"); while let Some(proxy) = reader.next().await.unwrap() { - assert_eq!(ProxyDB::InvalidRow, db.append(proxy).unwrap_err().kind); + assert_eq!( + ProxyDBErrorKind::InvalidRow, + db.append(proxy).unwrap_err().kind + ); } } } diff --git a/tests/integration/examples/example_tests/http_mitm_proxy.rs b/tests/integration/examples/example_tests/http_mitm_proxy.rs index 4ee0a76f..0986881b 100644 --- a/tests/integration/examples/example_tests/http_mitm_proxy.rs +++ b/tests/integration/examples/example_tests/http_mitm_proxy.rs @@ -1,16 +1,16 @@ use super::utils; -use rama::tls::backend::rustls::dep::{ +use rama::tls::dep::rcgen::{self, KeyPair}; +use rama::tls::rustls::dep::{ pki_types::{CertificateDer, PrivatePkcs8KeyDer}, rustls::ServerConfig, }; -use rama::tls::dep::rcgen::KeyPair; use rama::{ http::{response::Json, server::HttpServer, BodyExtractExt, Request}, net::address::ProxyAddress, rt::Executor, service::service_fn, tcp::server::TcpListener, - tls::backend::rustls::server::TlsAcceptorLayer, + tls::rustls::server::TlsAcceptorLayer, Context, Layer, }; use serde_json::{json, Value}; diff --git a/tests/integration/examples/example_tests/http_user_agent_classifier.rs b/tests/integration/examples/example_tests/http_user_agent_classifier.rs index 13c6412a..c870860c 100644 --- a/tests/integration/examples/example_tests/http_user_agent_classifier.rs +++ b/tests/integration/examples/example_tests/http_user_agent_classifier.rs @@ -1,5 +1,5 @@ use super::utils; -use rama::http::BodyExtractExt; +use rama::http::{headers, BodyExtractExt}; use rama::ua::{HttpAgent, TlsAgent, UserAgentOverwrites}; use rama::Context; diff --git a/tests/integration/examples/example_tests/utils/mod.rs b/tests/integration/examples/example_tests/utils/mod.rs index 7e9ff00e..b49504ad 100644 --- a/tests/integration/examples/example_tests/utils/mod.rs +++ b/tests/integration/examples/example_tests/utils/mod.rs @@ -2,8 +2,10 @@ use rama::{ error::{BoxError, OpaqueError}, + http::client::proxy::layer::SetProxyAuthHttpHeaderLayer, + http::service::client::{HttpClientExt, IntoUrl, RequestBuilder}, http::{ - client::{HttpClient, HttpClientExt, IntoUrl, RequestBuilder}, + client::HttpClient, layer::{ decompression::DecompressionLayer, follow_redirect::FollowRedirectLayer, @@ -14,9 +16,8 @@ use rama::{ Request, Response, }, layer::MapResultLayer, - proxy::http::client::layer::SetProxyAuthHttpHeaderLayer, + net::stream::Stream, service::BoxService, - stream::Stream, utils::{backoff::ExponentialBackoff, rng::HasherRng}, Layer, Service, }; @@ -72,7 +73,7 @@ where ) -> Self { let child = escargot::CargoBuild::new() .arg(format!( - "--features=cli,compression,{}", + "--features=cli,compression,tcp,http-full,proxy-full,{}", extra_features.unwrap_or_default() )) .example(example_name.as_ref()) From a67a2b645575c3584ecfeecfd4b2e50ad99ff89e Mon Sep 17 00:00:00 2001 From: glendc Date: Thu, 5 Sep 2024 00:28:38 +0200 Subject: [PATCH 20/24] fix tests (divan) --- Cargo.lock | 145 +++++++++++++++++++++++++++++++++++++++++++++++------ Cargo.toml | 1 + 2 files changed, 131 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81401183..76118c03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -485,6 +485,7 @@ dependencies = [ "anstyle", "clap_lex", "strsim", + "terminal_size", ] [[package]] @@ -520,6 +521,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +[[package]] +name = "condtype" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" + [[package]] name = "const_format" version = "0.2.32" @@ -609,6 +616,31 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "divan" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d567df2c9c2870a43f3f2bd65aaeb18dbce1c18f217c3e564b4fbaeb3ee56c" +dependencies = [ + "cfg-if", + "clap", + "condtype", + "divan-macros", + "libc", + "regex-lite", +] + +[[package]] +name = "divan-macros" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27540baf49be0d484d8f0130d7d8da3011c32a44d4fc873368154f1510e574a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dunce" version = "1.0.5" @@ -1261,7 +1293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1546,7 +1578,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1704,6 +1736,7 @@ version = "0.2.0-alpha.2" dependencies = [ "base64 0.22.1", "bytes", + "divan", "escargot", "hex", "itertools 0.13.0", @@ -2090,6 +2123,12 @@ dependencies = [ "regex-syntax 0.8.4", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.6.29" @@ -2448,6 +2487,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -3029,7 +3078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ "windows-core", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3042,7 +3091,7 @@ dependencies = [ "windows-interface", "windows-result", "windows-strings", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3073,7 +3122,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3083,7 +3132,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -3092,7 +3150,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3101,7 +3159,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -3110,28 +3183,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3144,24 +3235,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index c65fba95..52601d06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -191,6 +191,7 @@ tracing = { workspace = true, optional = true } [dev-dependencies] bytes = { workspace = true } +divan = { workspace = true } escargot = { workspace = true } itertools = { workspace = true } opentelemetry-otlp = { workspace = true } From 114ad7f1195b52ccb524396b1110d88a21a205a7 Mon Sep 17 00:00:00 2001 From: glendc Date: Thu, 5 Sep 2024 00:28:50 +0200 Subject: [PATCH 21/24] update deps: cargo update --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 76118c03..cdb88abf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -430,9 +430,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.15" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "e9d013ecb737093c0e86b151a7b837993cf9ec6c502946cfb44bedc392421e0b" dependencies = [ "jobserver", "libc", @@ -467,9 +467,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -477,9 +477,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -2329,9 +2329,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -2652,9 +2652,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", From 50f4b2f04eb5524ab56033f711380ff3355e89fa Mon Sep 17 00:00:00 2001 From: glendc Date: Thu, 5 Sep 2024 00:39:33 +0200 Subject: [PATCH 22/24] fix last test as well --- rama-macros/Cargo.toml | 2 +- rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rama-macros/Cargo.toml b/rama-macros/Cargo.toml index 8b9214e9..3afb3edc 100644 --- a/rama-macros/Cargo.toml +++ b/rama-macros/Cargo.toml @@ -19,7 +19,7 @@ quote = { workspace = true } syn = { workspace = true, features = ["full", "parsing"] } [dev-dependencies] -rama = { path = ".." } +rama = { path = "..", features = ["full"] } syn = { workspace = true, features = ["full", "extra-traits"] } trybuild = { workspace = true } diff --git a/rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr b/rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr index 351fbcdb..cefa89b6 100644 --- a/rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr +++ b/rama-macros/tests/as_ref/fail/wrap_ambiguity.stderr @@ -1,4 +1,4 @@ -error[E0119]: conflicting implementations of trait `AsRef` for type `ConnState` +error[E0119]: conflicting implementations of trait `AsRef` for type `ConnState` --> tests/as_ref/fail/wrap_ambiguity.rs:15:17 | 14 | app: Arc, From 1daa5cfe78923c31c5693c8756c44d20757ac3c0 Mon Sep 17 00:00:00 2001 From: glendc Date: Thu, 5 Sep 2024 01:03:25 +0200 Subject: [PATCH 23/24] improve docs and code --- README.md | 37 ++++++++++++++++--- docs/book/src/ecosystem.md | 25 +++++++++++++ docs/book/src/http_clients.md | 2 +- docs/book/src/intro/service_branches.md | 4 +- docs/book/src/intro/telemetry.md | 4 +- docs/book/src/preface.md | 10 ++--- rama-http/README.md | 49 +++++++++++++++++++++++++ src/lib.rs | 2 +- 8 files changed, 116 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 20c5a2f2..1b9f3abf 100644 --- a/README.md +++ b/README.md @@ -57,17 +57,17 @@ This framework comes with πŸ”‹ batteries included, giving you the full freedome | category | support list | |-|-| -| βœ… [transports](https://ramaproxy.org/docs/rama/stream/index.html) | βœ… [tcp](https://ramaproxy.org/docs/rama/tcp/index.html) βΈ± πŸ—οΈ udp (2) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/stream/layer/index.html) | +| βœ… [transports](https://ramaproxy.org/docs/rama/net/stream/index.html) | βœ… [tcp](https://ramaproxy.org/docs/rama/tcp/index.html) βΈ± πŸ—οΈ udp (2) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/net/stream/layer/index.html) | | βœ… [http](https://ramaproxy.org/docs/rama/http/index.html) | βœ… [auto](https://ramaproxy.org/docs/rama/http/server/service/struct.HttpServer.html#method.auto) βΈ± βœ… [http/1.1](https://ramaproxy.org/docs/rama/http/server/service/struct.HttpServer.html#method.http1) βΈ± βœ… [h2](https://ramaproxy.org/docs/rama/http/server/service/struct.HttpServer.html#method.h2) βΈ± πŸ—οΈ h3 (2) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/http/layer/index.html) | | βœ… web server | βœ… [fs](https://ramaproxy.org/docs/rama/http/service/fs/index.html) βΈ± βœ… [redirect](https://ramaproxy.org/docs/rama/http/service/redirect/struct.Redirect.html) βΈ± βœ… [dyn router](https://ramaproxy.org/docs/rama/http/service/web/struct.WebService.html) βΈ± βœ… [static router](https://ramaproxy.org/docs/rama/http/service/web/macro.match_service.html) βΈ± βœ… [handler extractors](https://ramaproxy.org/docs/rama/http/service/web/extract/index.html) βΈ± βœ… [k8s healthcheck](https://ramaproxy.org/docs/rama/http/service/web/k8s/index.html) | -| βœ… http [client](https://ramaproxy.org/docs/rama/http/client/index.html) | βœ… [client](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) βΈ± βœ… [high level API](https://ramaproxy.org/docs/rama/http/client/trait.HttpClientExt.html) βΈ± βœ… [Proxy Connect](https://ramaproxy.org/docs/rama/proxy/http/client/layer/struct.HttpProxyConnector.html) βΈ± ❌ [Chromium Http](https://github.com/plabayo/rama/issues/189) (3) | +| βœ… http [client](https://ramaproxy.org/docs/rama/http/client/index.html) | βœ… [client](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) βΈ± βœ… [high level API](https://ramaproxy.org/docs/rama/http/service/client/trait.HttpClientExt.html) βΈ± βœ… [Proxy Connect](https://ramaproxy.org/docs/rama/proxy/http/client/layer/struct.HttpProxyConnector.html) βΈ± ❌ [Chromium Http](https://github.com/plabayo/rama/issues/189) (3) | | βœ… [tls](https://ramaproxy.org/docs/rama/tls/index.html) | βœ… [Rustls](https://ramaproxy.org/docs/rama/tls/backend/rustls/index.html) βΈ± βœ… [BoringSSL](https://ramaproxy.org/docs/rama/tls/backend/boring/index.html) βΈ± ❌ NSS (3) | | βœ… [dns](https://ramaproxy.org/docs/rama/dns/index.html) | βœ… [DNS Resolver](https://ramaproxy.org/docs/rama/dns/struct.Dns.html) | -| βœ… [proxy protocols](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [PROXY protocol](https://ramaproxy.org/docs/rama/proxy/pp/index.html) βΈ± βœ… [http proxy](https://github.com/plabayo/rama/blob/main/examples/http_connect_proxy.rs) βΈ± βœ… [https proxy](https://github.com/plabayo/rama/blob/main/examples/https_connect_proxy.rs) βΈ± πŸ—οΈ SOCKS5 (1) βΈ± πŸ—οΈ SOCKS5H (1) | +| βœ… [proxy protocols](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [PROXY protocol](https://ramaproxy.org/docs/rama/proxy/haproxy/index.html) βΈ± βœ… [http proxy](https://github.com/plabayo/rama/blob/main/examples/http_connect_proxy.rs) βΈ± βœ… [https proxy](https://github.com/plabayo/rama/blob/main/examples/https_connect_proxy.rs) βΈ± πŸ—οΈ SOCKS5 (1) βΈ± πŸ—οΈ SOCKS5H (1) | | πŸ—οΈ web protocols | πŸ—οΈ Web Sockets (WS) (2) βΈ± πŸ—οΈ WSS (2) βΈ± ❌ Web Transport (3) βΈ± ❌ gRPC (3) | | βœ… [async-method trait](https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html) services | βœ… [Service](https://ramaproxy.org/docs/rama/service/trait.Service.html) βΈ± βœ… [Layer](https://ramaproxy.org/docs/rama/layer/trait.Layer.html) βΈ± βœ… [context](https://ramaproxy.org/docs/rama/context/index.html) βΈ± βœ… [dyn dispatch](https://ramaproxy.org/docs/rama/service/struct.BoxService.html) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/layer/index.html) | -| βœ… [telemetry](https://ramaproxy.org/docs/rama/telemetry/index.html) | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry](https://ramaproxy.org/docs/rama/telemetry/opentelemetry/index.html) βΈ± βœ… [http metrics](https://ramaproxy.org/docs/rama/http/layer/opentelemetry/index.html) βΈ± βœ… [transport metrics](https://ramaproxy.org/docs/rama/stream/layer/opentelemetry/index.html) | -| βœ… upstream [proxies](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [MemoryProxyDB](https://ramaproxy.org/docs/rama/proxy/struct.MemoryProxyDB.html) βΈ± βœ… [L4 Username Config](https://ramaproxy.org/docs/rama/utils/username/index.html) βΈ± βœ… [Proxy Filters](https://ramaproxy.org/docs/rama/proxy/struct.ProxyFilter.html) | +| βœ… [telemetry](https://ramaproxy.org/docs/rama/telemetry/index.html) | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry](https://ramaproxy.org/docs/rama/telemetry/opentelemetry/index.html) βΈ± βœ… [http metrics](https://ramaproxy.org/docs/rama/http/layer/opentelemetry/index.html) βΈ± βœ… [transport metrics](https://ramaproxy.org/docs/rama/net/stream/layer/opentelemetry/index.html) | +| βœ… upstream [proxies](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [MemoryProxyDB](https://ramaproxy.org/docs/rama/proxy/struct.MemoryProxyDB.html) βΈ± βœ… [L4 Username Config](https://ramaproxy.org/docs/rama/username/index.html) βΈ± βœ… [Proxy Filters](https://ramaproxy.org/docs/rama/proxy/struct.ProxyFilter.html) | | πŸ—οΈ [User Agent (UA)](https://ramaproxy.org/book/intro/user_agent) | πŸ—οΈ Http Emulation (1) βΈ± πŸ—οΈ Tls Emulation (1) βΈ± βœ… [UA Parsing](https://ramaproxy.org/docs/rama/ua/struct.UserAgent.html) | | βœ… utilities | βœ… [error handling](https://ramaproxy.org/docs/rama/error/index.html) βΈ± βœ… [graceful shutdown](https://ramaproxy.org/docs/rama/graceful/index.html) βΈ± πŸ—οΈ Connection Pool (2) βΈ± πŸ—οΈ IP2Loc (2) | | πŸ—οΈ [TUI](https://ratatui.rs/) | πŸ—οΈ traffic logger (2) βΈ± πŸ—οΈ curl export (2) βΈ± ❌ traffic intercept (3) βΈ± ❌ traffic replay (3) | @@ -173,6 +173,31 @@ and are sufficiently different from "official" rama crates". Once you have such a crate published do let us know it, such that we can list them here. +### πŸ“¦ | Rama Crates + +The `rama` crate can be used as the one and only dependency. +However, as you can also read in the "DIY" chapter of the book +at , you are able +to pick and choose not only what specific parts of `rama` you wish to use, +but also in fact what specific (sub) crates. + +Here is a list of all `rama` crates: + +- [`rama`](https://crates.io/crates/rama): one crate to rule them all +- [`rama-error`](https://crates.io/crates/rama-error): error utilities for rama and its users +- [`rama-macros`]: `rama-macros` contains the procedural macros used by `rama` +- [`rama-core`](https://crates.io/crates/rama-core): core crate containing the service, layer and + context used by all other `rama` code, as well as some other _core_ utilities +- [`rama-net`](https://crates.io/crates/rama-net): rama network types and utilities +- [`rama-tcp`](https://crates.io/crates/rama-tcp): TCP support for rama +- [`rama-tls`](https://crates.io/crates/rama-tls): TLS support for rama (types, `rustls` and `boring`) +- [`rama-proxy`](https://crates.io/crates/rama-proxy): proxy types and utilities for rama +- [`rama-haproxy`](https://crates.io/crates/rama-haproxy): rama HaProxy support +- [`rama-ua`](https://crates.io/crates/rama-ua): User-Agent (UA) support for `rama` +- [`rama-http-types`](https://crates.io/crates/rama-http-types): http types and utilities +- [`rama-http`](https://crates.io/crates/rama-http): rama http services, layers and utilities +- [`rama-http-backend`](https://crates.io/crates/rama-http-backend): default http backend for `rama` + ## 🏒 | Proxy Examples - [/examples/tls_termination.rs](https://github.com/plabayo/rama/tree/main/examples/tls_termination.rs): @@ -253,7 +278,7 @@ It's a powerful concept, originally introduced to Rust by [the Tower ecosystem]( Rama provides an [`HttpClient`](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) which sends your _Http_ `Request` over the network and returns the `Response` if it receives and read one or an `Error` otherwise. Combined with [the many Layers (middleware)](https://ramaproxy.org/docs/rama/http/layer/index.html) that `Rama` provides and perhaps also some developed by you it is possible to create a powerful _Http_ client suited to your needs. -As a πŸ’ cherry on the cake you can import the [`HttpClientExt`](https://ramaproxy.org/docs/rama/http/client/trait.HttpClientExt.html) trait in your Rust module to be able to use your _Http_ Client [`Service`][rama-service] stack using a high level API to build and send requests with ease. +As a πŸ’ cherry on the cake you can import the [`HttpClientExt`](https://ramaproxy.org/docs/rama/http/service/client/trait.HttpClientExt.html) trait in your Rust module to be able to use your _Http_ Client [`Service`][rama-service] stack using a high level API to build and send requests with ease. ### πŸ§‘β€πŸ’» | Http Client Example diff --git a/docs/book/src/ecosystem.md b/docs/book/src/ecosystem.md index 1cc36a9f..80b62151 100644 --- a/docs/book/src/ecosystem.md +++ b/docs/book/src/ecosystem.md @@ -13,3 +13,28 @@ Please prefix all rama community crates with "rama-x", this way the crates are e and are sufficiently different from "official" rama crates". Once you have such a crate published do let us know it, such that we can list them here. + +## πŸ“¦ | Rama Crates + +The `rama` crate can be used as the one and only dependency. +However, as you can also read in the "DIY" chapter of the book +at , you are able +to pick and choose not only what specific parts of `rama` you wish to use, +but also in fact what specific (sub) crates. + +Here is a list of all `rama` crates: + +- [`rama`](https://crates.io/crates/rama): one crate to rule them all +- [`rama-error`](https://crates.io/crates/rama-error): error utilities for rama and its users +- [`rama-macros`]: `rama-macros` contains the procedural macros used by `rama` +- [`rama-core`](https://crates.io/crates/rama-core): core crate containing the service, layer and + context used by all other `rama` code, as well as some other _core_ utilities +- [`rama-net`](https://crates.io/crates/rama-net): rama network types and utilities +- [`rama-tcp`](https://crates.io/crates/rama-tcp): TCP support for rama +- [`rama-tls`](https://crates.io/crates/rama-tls): TLS support for rama (types, `rustls` and `boring`) +- [`rama-proxy`](https://crates.io/crates/rama-proxy): proxy types and utilities for rama +- [`rama-haproxy`](https://crates.io/crates/rama-haproxy): rama HaProxy support +- [`rama-ua`](https://crates.io/crates/rama-ua): User-Agent (UA) support for `rama` +- [`rama-http-types`](https://crates.io/crates/rama-http-types): http types and utilities +- [`rama-http`](https://crates.io/crates/rama-http): rama http services, layers and utilities +- [`rama-http-backend`](https://crates.io/crates/rama-http-backend): default http backend for `rama` diff --git a/docs/book/src/http_clients.md b/docs/book/src/http_clients.md index 14f782aa..0a821491 100644 --- a/docs/book/src/http_clients.md +++ b/docs/book/src/http_clients.md @@ -8,7 +8,7 @@ It's a powerful concept, originally introduced to Rust by [the Tower ecosystem]( Rama provides an [`HttpClient`](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) which sends your _Http_ `Request` over the network and returns the `Response` if it receives and read one or an `Error` otherwise. Combined with [the many Layers (middleware)](https://ramaproxy.org/docs/rama/http/layer/index.html) that `Rama` provides and perhaps also some developed by you it is possible to create a powerful _Http_ client suited to your needs. -As a πŸ’ cherry on the cake you can import the [`HttpClientExt`](https://ramaproxy.org/docs/rama/http/client/trait.HttpClientExt.html) trait in your Rust module to be able to use your _Http_ Client [`Service`][rama-service] stack using a high level API to build and send requests with ease. +As a πŸ’ cherry on the cake you can import the [`HttpClientExt`](https://ramaproxy.org/docs/rama/http/service/client/trait.HttpClientExt.html) trait in your Rust module to be able to use your _Http_ Client [`Service`][rama-service] stack using a high level API to build and send requests with ease. ## Http Client Example diff --git a/docs/book/src/intro/service_branches.md b/docs/book/src/intro/service_branches.md index d5043c3f..78a670fc 100644 --- a/docs/book/src/intro/service_branches.md +++ b/docs/book/src/intro/service_branches.md @@ -18,7 +18,7 @@ In case you need this routing to be done on the web you can make use of: - [`match_service!` macro](https://ramaproxy.org/docs/rama/http/service/web/macro.match_service.html) in case you want/like a static dispatch approach; - or you can use the [`WebService` router](https://ramaproxy.org/docs/rama/http/service/web/struct.WebService.html) if dynamic dispatch is what you prefer. -On the transport layer you could make use of the [`SocketMatcher`](https://ramaproxy.org/docs/rama/stream/matcher/struct.SocketMatcher.html) +On the transport layer you could make use of the [`SocketMatcher`](https://ramaproxy.org/docs/rama/net/stream/matcher/struct.SocketMatcher.html) matcher. And of course for any layer there is always the option to roll out your own `Matcher` implementation or even start from scratch entirely. The tools are there freely to be used directly or as inspiration. @@ -49,7 +49,7 @@ The match concept is pretty powerful, be it by using [the `Matcher` trait](https Take a typical http client for example. As part of its work it needs to establish a connection to the target server. In the case of port `8080` this would be a plain `tcp` connection (for `http/1.1`), but in the case of port `443` that would require the `tcp` stream to be handled by a `Tls` client first (e.g. for `h2`). -Using the tuple matchers you can wrap these two different flows in a two-element tuple with a [`SocketMatcher`](https://ramaproxy.org/docs/rama/stream/matcher/struct.SocketMatcher.html) to match on the port (for example). And in fact that is more or less what [the HttpClient](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) does by default if you do not specify your own "Connection" service. We hope you can make happy use of it yourself. +Using the tuple matchers you can wrap these two different flows in a two-element tuple with a [`SocketMatcher`](https://ramaproxy.org/docs/rama/net/stream/matcher/struct.SocketMatcher.html) to match on the port (for example). And in fact that is more or less what [the HttpClient](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) does by default if you do not specify your own "Connection" service. We hope you can make happy use of it yourself. ## Fallible middleware services diff --git a/docs/book/src/intro/telemetry.md b/docs/book/src/intro/telemetry.md index 87973c4f..f5960c99 100644 --- a/docs/book/src/intro/telemetry.md +++ b/docs/book/src/intro/telemetry.md @@ -24,7 +24,7 @@ Rama re-exports [OpenTelemetry](https://opentelemetry.io/) crates under [the `ra and provides middlewares for collecting metrics on: - the http layer: -- the transport layer: +- the transport layer: Rama does not provide specific exporters or consumers of these metrics. Instead β€” similar to tracing β€” you'll have to add your own dependency for it. @@ -37,7 +37,7 @@ popular ingestion tools such as [Prometheus](https://prometheus.io/). > Source Code: [/examples/http_telemetry.rs](https://github.com/plabayo/rama/tree/main/examples/http_telemetry.rs) -In this example you can see a web service which keeps track of a visitor counter as a custom opentelemetry counter metric. It also makes use of the rama provided [`RequestMetricsLayer`](https://ramaproxy.org/docs/rama/http/layer/opentelemetry/struct.RequestMetricsLayer.html) and [`NetworkMetricsLayer`](https://ramaproxy.org/docs/rama/stream/layer/opentelemetry/struct.NetworkMetricsLayer.html) layers to also some insights in the traffic both on the network- and application (http) layers. These metrics are exported using the dependency. +In this example you can see a web service which keeps track of a visitor counter as a custom opentelemetry counter metric. It also makes use of the rama provided [`RequestMetricsLayer`](https://ramaproxy.org/docs/rama/http/layer/opentelemetry/struct.RequestMetricsLayer.html) and [`NetworkMetricsLayer`](https://ramaproxy.org/docs/rama/net/stream/layer/opentelemetry/struct.NetworkMetricsLayer.html) layers to also some insights in the traffic both on the network- and application (http) layers. These metrics are exported using the dependency. With that example setup you can use a tool like [Grafana](https://grafana.com/) or [Prometheus](https://prometheus.io/) to make a dashboard with your own charts. diff --git a/docs/book/src/preface.md b/docs/book/src/preface.md index bf332a33..fca54b82 100644 --- a/docs/book/src/preface.md +++ b/docs/book/src/preface.md @@ -46,17 +46,17 @@ This framework comes with πŸ”‹ batteries included, giving you the full freedome | category | support list | |-|-| -| βœ… [transports](https://ramaproxy.org/docs/rama/stream/index.html) | βœ… [tcp](https://ramaproxy.org/docs/rama/tcp/index.html) βΈ± πŸ—οΈ udp (2) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/stream/layer/index.html) | +| βœ… [transports](https://ramaproxy.org/docs/rama/net/stream/index.html) | βœ… [tcp](https://ramaproxy.org/docs/rama/tcp/index.html) βΈ± πŸ—οΈ udp (2) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/net/stream/layer/index.html) | | βœ… [http](https://ramaproxy.org/docs/rama/http/index.html) | βœ… [auto](https://ramaproxy.org/docs/rama/http/server/service/struct.HttpServer.html#method.auto) βΈ± βœ… [http/1.1](https://ramaproxy.org/docs/rama/http/server/service/struct.HttpServer.html#method.http1) βΈ± βœ… [h2](https://ramaproxy.org/docs/rama/http/server/service/struct.HttpServer.html#method.h2) βΈ± πŸ—οΈ h3 (2) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/http/layer/index.html) | | βœ… web server | βœ… [fs](https://ramaproxy.org/docs/rama/http/service/fs/index.html) βΈ± βœ… [redirect](https://ramaproxy.org/docs/rama/http/service/redirect/struct.Redirect.html) βΈ± βœ… [dyn router](https://ramaproxy.org/docs/rama/http/service/web/struct.WebService.html) βΈ± βœ… [static router](https://ramaproxy.org/docs/rama/http/service/web/macro.match_service.html) βΈ± βœ… [handler extractors](https://ramaproxy.org/docs/rama/http/service/web/extract/index.html) βΈ± βœ… [k8s healthcheck](https://ramaproxy.org/docs/rama/http/service/web/k8s/index.html) | -| βœ… http [client](https://ramaproxy.org/docs/rama/http/client/index.html) | βœ… [client](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) βΈ± βœ… [high level API](https://ramaproxy.org/docs/rama/http/client/trait.HttpClientExt.html) βΈ± βœ… [Proxy Connect](https://ramaproxy.org/docs/rama/proxy/http/client/layer/struct.HttpProxyConnector.html) βΈ± ❌ [Chromium Http](https://github.com/plabayo/rama/issues/189) (3) | +| βœ… http [client](https://ramaproxy.org/docs/rama/http/client/index.html) | βœ… [client](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) βΈ± βœ… [high level API](https://ramaproxy.org/docs/rama/http/service/client/trait.HttpClientExt.html) βΈ± βœ… [Proxy Connect](https://ramaproxy.org/docs/rama/proxy/http/client/layer/struct.HttpProxyConnector.html) βΈ± ❌ [Chromium Http](https://github.com/plabayo/rama/issues/189) (3) | | βœ… [tls](https://ramaproxy.org/docs/rama/tls/index.html) | βœ… [Rustls](https://ramaproxy.org/docs/rama/tls/backend/rustls/index.html) βΈ± βœ… [BoringSSL](https://ramaproxy.org/docs/rama/tls/backend/boring/index.html) βΈ± ❌ NSS (3) | | βœ… [dns](https://ramaproxy.org/docs/rama/dns/index.html) | βœ… [DNS Resolver](https://ramaproxy.org/docs/rama/dns/struct.Dns.html) | -| βœ… [proxy protocols](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [PROXY protocol](https://ramaproxy.org/docs/rama/proxy/pp/index.html) βΈ± βœ… [http proxy](https://github.com/plabayo/rama/blob/main/examples/http_connect_proxy.rs) βΈ± βœ… [https proxy](https://github.com/plabayo/rama/blob/main/examples/https_connect_proxy.rs) βΈ± πŸ—οΈ SOCKS5 (1) βΈ± πŸ—οΈ SOCKS5H (1) | +| βœ… [proxy protocols](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [PROXY protocol](https://ramaproxy.org/docs/rama/proxy/haproxy/index.html) βΈ± βœ… [http proxy](https://github.com/plabayo/rama/blob/main/examples/http_connect_proxy.rs) βΈ± βœ… [https proxy](https://github.com/plabayo/rama/blob/main/examples/https_connect_proxy.rs) βΈ± πŸ—οΈ SOCKS5 (1) βΈ± πŸ—οΈ SOCKS5H (1) | | πŸ—οΈ web protocols | πŸ—οΈ Web Sockets (WS) (2) βΈ± πŸ—οΈ WSS (2) βΈ± ❌ Web Transport (3) βΈ± ❌ gRPC (3) | | βœ… [async-method trait](https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html) services | βœ… [Service](https://ramaproxy.org/docs/rama/service/trait.Service.html) βΈ± βœ… [Layer](https://ramaproxy.org/docs/rama/layer/trait.Layer.html) βΈ± βœ… [context](https://ramaproxy.org/docs/rama/context/index.html) βΈ± βœ… [dyn dispatch](https://ramaproxy.org/docs/rama/service/struct.BoxService.html) βΈ± βœ… [middleware](https://ramaproxy.org/docs/rama/layer/index.html) | -| βœ… [telemetry](https://ramaproxy.org/docs/rama/telemetry/index.html) | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry](https://ramaproxy.org/docs/rama/telemetry/opentelemetry/index.html) βΈ± βœ… [http metrics](https://ramaproxy.org/docs/rama/http/layer/opentelemetry/index.html) βΈ± βœ… [transport metrics](https://ramaproxy.org/docs/rama/stream/layer/opentelemetry/index.html) | -| βœ… upstream [proxies](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [MemoryProxyDB](https://ramaproxy.org/docs/rama/proxy/struct.MemoryProxyDB.html) βΈ± βœ… [L4 Username Config](https://ramaproxy.org/docs/rama/utils/username/index.html) βΈ± βœ… [Proxy Filters](https://ramaproxy.org/docs/rama/proxy/struct.ProxyFilter.html) | +| βœ… [telemetry](https://ramaproxy.org/docs/rama/telemetry/index.html) | βœ… [tracing](https://tracing.rs/tracing/) βΈ± βœ… [opentelemetry](https://ramaproxy.org/docs/rama/telemetry/opentelemetry/index.html) βΈ± βœ… [http metrics](https://ramaproxy.org/docs/rama/http/layer/opentelemetry/index.html) βΈ± βœ… [transport metrics](https://ramaproxy.org/docs/rama/net/stream/layer/opentelemetry/index.html) | +| βœ… upstream [proxies](https://ramaproxy.org/docs/rama/proxy/index.html) | βœ… [MemoryProxyDB](https://ramaproxy.org/docs/rama/proxy/struct.MemoryProxyDB.html) βΈ± βœ… [L4 Username Config](https://ramaproxy.org/docs/rama/username/index.html) βΈ± βœ… [Proxy Filters](https://ramaproxy.org/docs/rama/proxy/struct.ProxyFilter.html) | | πŸ—οΈ [User Agent (UA)](https://ramaproxy.org/book/intro/user_agent) | πŸ—οΈ Http Emulation (1) βΈ± πŸ—οΈ Tls Emulation (1) βΈ± βœ… [UA Parsing](https://ramaproxy.org/docs/rama/ua/struct.UserAgent.html) | | βœ… utilities | βœ… [error handling](https://ramaproxy.org/docs/rama/error/index.html) βΈ± βœ… [graceful shutdown](https://ramaproxy.org/docs/rama/graceful/index.html) βΈ± πŸ—οΈ Connection Pool (2) βΈ± πŸ—οΈ IP2Loc (2) | | πŸ—οΈ [TUI](https://ratatui.rs/) | πŸ—οΈ traffic logger (2) βΈ± πŸ—οΈ curl export (2) βΈ± ❌ traffic intercept (3) βΈ± ❌ traffic replay (3) | diff --git a/rama-http/README.md b/rama-http/README.md index e69de29b..0b46d406 100644 --- a/rama-http/README.md +++ b/rama-http/README.md @@ -0,0 +1,49 @@ +[![rama banner](../docs/img/rama_banner.jpeg)](https://ramaproxy.org/) + +[![Crates.io][crates-badge]][crates-url] +[![Docs.rs][docs-badge]][docs-url] +[![MIT License][license-mit-badge]][license-mit-url] +[![Apache 2.0 License][license-apache-badge]][license-apache-url] +[![rust version][rust-version-badge]][rust-version-url] +[![Build Status][actions-badge]][actions-url] + +[![Discord][discord-badge]][discord-url] +[![Buy Me A Coffee][bmac-badge]][bmac-url] +[![GitHub Sponsors][ghs-badge]][ghs-url] +[![Paypal Donation][paypal-badge]][paypal-url] + +[crates-badge]: https://img.shields.io/crates/v/rama-http.svg +[crates-url]: https://crates.io/crates/rama-http +[docs-badge]: https://img.shields.io/docsrs/rama-http/latest +[docs-url]: https://docs.rs/rama-http/latest/rama_http/index.html +[license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-mit-url]: https://github.com/plabayo/rama/blob/main/LICENSE-MIT +[license-apache-badge]: https://img.shields.io/badge/license-APACHE-blue.svg +[license-apache-url]: https://github.com/plabayo/rama/blob/main/LICENSE-APACHE +[rust-version-badge]: https://img.shields.io/badge/rustc-1.80+-blue?style=flat-square&logo=rust +[rust-version-url]: https://www.rust-lang.org +[actions-badge]: https://github.com/plabayo/rama/workflows/CI/badge.svg +[actions-url]: https://github.com/plabayo/rama/actions + +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white +[discord-url]: https://discord.gg/29EetaSYCD +[bmac-badge]: https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black +[bmac-url]: https://www.buymeacoffee.com/plabayo +[ghs-badge]: https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA +[ghs-url]: https://github.com/sponsors/plabayo +[paypal-badge]: https://img.shields.io/badge/paypal-contribution?style=for-the-badge&color=blue +[paypal-url]: https://www.paypal.com/donate/?hosted_button_id=P3KCGT2ACBVFE + +πŸ¦™ Rama (γƒ©γƒž) is a modular service framework for the πŸ¦€ Rust language to move and transform your network packets. +The reasons behind the creation of rama can be read in [the "Why Rama" chapter](https://ramaproxy.org/book/why_rama). + +## rama-http + +Rama http services, layers and utilities. + +Crate used by the end-user `rama` crate and `rama` "http" crate authors alike. + +Learn more about `rama`: + +- Github: +- Book: diff --git a/src/lib.rs b/src/lib.rs index 7e1b716f..9536c710 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,7 +189,7 @@ //! //! Rama provides an [`HttpClient`](https://ramaproxy.org/docs/rama/http/client/struct.HttpClient.html) which sends your _Http_ `Request` over the network and returns the `Response` if it receives and read one or an `Error` otherwise. Combined with [the many Layers (middleware)](https://ramaproxy.org/docs/rama/http/layer/index.html) that `Rama` provides and perhaps also some developed by you it is possible to create a powerful _Http_ client suited to your needs. //! -//! As a πŸ’ cherry on the cake you can import the [`HttpClientExt`](https://ramaproxy.org/docs/rama/http/client/trait.HttpClientExt.html) trait in your Rust module to be able to use your _Http_ Client [`Service`][rama-service] stack using a high level API to build and send requests with ease. +//! As a πŸ’ cherry on the cake you can import the [`HttpClientExt`](https://ramaproxy.org/docs/rama/http/service/client/trait.HttpClientExt.html) trait in your Rust module to be able to use your _Http_ Client [`Service`][rama-service] stack using a high level API to build and send requests with ease. //! //! ### πŸ§‘β€πŸ’» | Http Client Example //! From 52ed6983ff77171740e9ce8878657aba5e2df16a Mon Sep 17 00:00:00 2001 From: glendc Date: Thu, 5 Sep 2024 01:08:40 +0200 Subject: [PATCH 24/24] fix minor issues --- .github/workflows/mdbook.yml | 2 -- rama-http/src/service/client/ext.rs | 2 -- .../src/service/web/endpoint/extract/authority.rs | 11 ----------- rama-http/src/service/web/endpoint/extract/host.rs | 11 ----------- 4 files changed, 26 deletions(-) diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml index 2f66f79f..7109b42b 100644 --- a/.github/workflows/mdbook.yml +++ b/.github/workflows/mdbook.yml @@ -11,8 +11,6 @@ env: on: # Runs on pushes targeting the default branch push: - # todo: switch back to "main" once mdbook-graphviz is fixed - # see: https://github.com/dylanowen/mdbook-graphviz/issues/107 branches: ["main"] # Allows you to run this workflow manually from the Actions tab diff --git a/rama-http/src/service/client/ext.rs b/rama-http/src/service/client/ext.rs index e44eae35..a6309fa2 100644 --- a/rama-http/src/service/client/ext.rs +++ b/rama-http/src/service/client/ext.rs @@ -5,8 +5,6 @@ use rama_core::{ }; use std::future::Future; -// TODO: integrate client ext into rama-http, as it is backend agnostic!, can live under service?! - /// Extends an Http Client with high level features, /// to facilitate the creation and sending of http requests, /// in a more ergonomic way. diff --git a/rama-http/src/service/web/endpoint/extract/authority.rs b/rama-http/src/service/web/endpoint/extract/authority.rs index 4d03523c..172d3e38 100644 --- a/rama-http/src/service/web/endpoint/extract/authority.rs +++ b/rama-http/src/service/web/endpoint/extract/authority.rs @@ -7,17 +7,6 @@ use rama_net::http::RequestContext; use rama_utils::macros::impl_deref; /// Extractor that resolves the authority of the request. -/// -/// Host, part authority, is resolved through the following, in order: -/// - `Forwarded` header -/// - `X-Forwarded-Host` header -/// - `Host` header -/// - request target / URI -/// -/// TODO: update the above once we have forwarded better implemented! -/// -/// Note that user agents can set `X-Forwarded-Host` and `Host` headers to arbitrary values so make -/// sure to validate them to avoid security issues. #[derive(Debug, Clone)] pub struct Authority(pub address::Authority); diff --git a/rama-http/src/service/web/endpoint/extract/host.rs b/rama-http/src/service/web/endpoint/extract/host.rs index 8a9ab93c..6b0c72a0 100644 --- a/rama-http/src/service/web/endpoint/extract/host.rs +++ b/rama-http/src/service/web/endpoint/extract/host.rs @@ -7,17 +7,6 @@ use rama_net::http::RequestContext; use rama_utils::macros::impl_deref; /// Extractor that resolves the hostname of the request. -/// -/// Hostname is resolved through the following, in order: -/// - `Forwarded` header -/// - `X-Forwarded-Host` header -/// - `Host` header -/// - request target / URI -/// -/// TODO: update the above once we have forwarded better implemented! -/// -/// Note that user agents can set `X-Forwarded-Host` and `Host` headers to arbitrary values so make -/// sure to validate them to avoid security issues. #[derive(Debug, Clone)] pub struct Host(pub address::Host);