Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return errors instead of panicking for Endpoint::set_endpoint #1496

Closed
Tracked by #1692
mfelsche opened this issue Jun 24, 2022 · 6 comments · Fixed by #1984
Closed
Tracked by #1692

Return errors instead of panicking for Endpoint::set_endpoint #1496

mfelsche opened this issue Jun 24, 2022 · 6 comments · Fixed by #1984
Assignees
Labels
Milestone

Comments

@mfelsche
Copy link

We are happy users of the rust aws_sdk but just recently found out that its underlying libraries use .expect("...") in several places and thus will panic under some conditions. One such condition would be e.g. setting a custom endpoint with a slightly invalid URL: https://github.com/awslabs/smithy-rs/blob/e1e9a29d5db1330eb51c1e84e5c6c3acb9b4f65e/rust-runtime/aws-smithy-http/src/endpoint.rs#L84-L105

There are many more places where smithy code could panic. Some of those might be legit as they might never be triggered, but some of those are actually dangerous.

In our codebase we take great care to avoid panicking constructs and we would love to have the rust aws_sdk do the same. We are ready to bite the bullet of handling additional Result<..., ...> return types in sdk code.

@jdisanti
Copy link
Collaborator

Hello! We appreciate the concern and definitely want to keep these cases to a minimum for the reasons you outlined. I'll briefly dive into each of these below to see if we have any issues that need fixing.

smithy-rs/rust-runtime/aws-smithy-http/src/endpoint.rs

I think the idea for this one was that the passed in Uri must be valid, so everything should succeed. However, I think it actually does fail in the case where a Uri without an authority is passed in, in which case the authority will be empty string, which will fail on Authority::from_str. I haven't confirmed this, but we should dig into it and fix it if true.

smithy-rs/aws/rust-runtime/aws-inlineable/src/glacier_checksums.rs

The complete_hash is a string representation of a hex value (characters ^[0-9A-Fa-f]+$) which will always be a valid HeaderValue. This one is safe.

smithy-rs/rust-runtime/aws-smithy-xml/src/escape.rs

In this case, there will always be a next character due to the nature of string splitting. This one is safe, and there's also a proptest in this file that tests it against random inputs. This test has been passing since its creation over a year ago.

smithy-rs/rust-runtime/aws-smithy-client/src/dvr/replay.rs
smithy-rs/rust-runtime/aws-smithy-client/src/test_connection.rs

Both of these are only used for tests, so it doesn't matter if we unwrap in them.

Action items from this:

Thanks!

@mfelsche mfelsche changed the title Return errors instead of panicking Return errors instead of panicking for Endpoint::set_endpoint Jun 28, 2022
@mfelsche
Copy link
Author

I did get the panic when doing the following:

const MINIO_ROOT_USER: &str = "tremor";
const MINIO_ROOT_PASSWORD: &str = "snot_badger";
const MINIO_REGION: &str = "eu-central-1";

use aws_sdk_s3::{CLient, Config, Credentials, Region, Endpoint};
let s3_config = Config::builder()
        .credentials_provider(Credentials::new(
            MINIO_ROOT_USER,
            MINIO_ROOT_PASSWORD,
            None,
            None,
            "Environment",
        ))
        .region(Region::new(MINIO_REGION))
        .endpoint_resolver(Endpoint::immutable(
            format!("localhost:{http_port}").parse().unwrap(), // adding http:// does not make it panic anymore
        ))
        .build();

let client = Client::from_conf(s3_config)
client.list_buckets().send().await?; // panic

Here is a backtrace of the panic, so you can follow the call-graph:

thread 'connectors::tests::s3::reader::connector_s3_no_region' panicked at 'scheme must be provided', /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-http-0.44.0/src/endpoint.rs:97:50
stack backtrace:
   0: rust_begin_unwind
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/panicking.rs:143:14
   2: core::panicking::panic_display
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/panicking.rs:72:5
   3: core::panicking::panic_str
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/panicking.rs:56:5
   4: core::option::expect_failed
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/option.rs:1874:5
   5: core::option::Option<T>::expect
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/option.rs:718:21
   6: aws_smithy_http::endpoint::Endpoint::set_endpoint
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-http-0.44.0/src/endpoint.rs:97:23
   7: aws_types::endpoint::AwsEndpoint::set_endpoint
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-types-0.14.0/src/endpoint.rs:47:9
   8: <aws_endpoint::AwsEndpointStage as aws_smithy_http::middleware::MapRequest>::apply::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-endpoint-0.14.0/src/lib.rs:84:13
   9: aws_smithy_http::operation::Request::augment
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-http-0.44.0/src/operation.rs:273:13
  10: <aws_endpoint::AwsEndpointStage as aws_smithy_http::middleware::MapRequest>::apply
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-endpoint-0.14.0/src/lib.rs:65:9
  11: <aws_smithy_http_tower::map_request::MapRequestService<S,M> as tower_service::Service<aws_smithy_http::operation::Request>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-http-tower-0.44.0/src/map_request.rs:141:15
  12: <aws_smithy_client::erase::boxclone::Boxed<S> as tower_service::Service<Request>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-client-0.44.0/src/erase/boxclone.rs:171:18
  13: <alloc::boxed::Box<S> as tower_service::Service<Request>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/tower-service-0.3.2/src/lib.rs:387:9
  14: <aws_smithy_client::erase::boxclone::BoxCloneService<T,U,E> as tower_service::Service<T>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-client-0.44.0/src/erase/boxclone.rs:145:9
  15: <aws_smithy_http_tower::parse_response::ParseResponseService<InnerService,ResponseHandler,RetryPolicy> as tower_service::Service<aws_smithy_http::operation::Operation<ResponseHandler,RetryPolicy>>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-http-tower-0.44.0/src/parse_response.rs:107:20
  16: <aws_smithy_client::timeout::TimeoutService<InnerService> as tower_service::Service<aws_smithy_http::operation::Operation<H,R>>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-client-0.44.0/src/timeout.rs:229:22
  17: <tower::retry::Retry<P,S> as tower_service::Service<Request>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/tower-0.4.13/src/retry/mod.rs:70:22
  18: <aws_smithy_client::timeout::TimeoutService<InnerService> as tower_service::Service<aws_smithy_http::operation::Operation<H,R>>>::call
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-client-0.44.0/src/timeout.rs:229:22
  19: aws_smithy_client::Client<C,M,R>::call_raw::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-client-0.44.0/src/lib.rs:269:9
  20: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/future/mod.rs:91:19
  21: aws_smithy_client::Client<C,M,R>::call::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-smithy-client-0.44.0/src/lib.rs:216:29
  22: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/future/mod.rs:91:19
  23: aws_sdk_s3::client::fluent_builders::ListBuckets::send::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/aws-sdk-s3-0.14.0/src/client.rs:8109:40
  24: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/future/mod.rs:91:19
  25: tremor_runtime::connectors::tests::s3::wait_for_s3::{{closure}}
             at ./src/connectors/tests/s3.rs:37:55
  26: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/future/mod.rs:91:19
  27: tremor_runtime::connectors::tests::s3::reader::connector_s3_no_region::{{closure}}::{{closure}}
             at ./src/connectors/tests/s3/reader.rs:110:27
  28: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/future/mod.rs:91:19
  29: <async_std::task::builder::SupportTaskLocals<F> as core::future::future::Future>::poll::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/builder.rs:199:17
  30: async_std::task::task_locals_wrapper::TaskLocalsWrapper::set_current::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/task_locals_wrapper.rs:60:13
  31: std::thread::local::LocalKey<T>::try_with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:442:16
  32: std::thread::local::LocalKey<T>::with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:418:9
  33: async_std::task::task_locals_wrapper::TaskLocalsWrapper::set_current
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/task_locals_wrapper.rs:55:9
  34: <async_std::task::builder::SupportTaskLocals<F> as core::future::future::Future>::poll
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/builder.rs:197:13
  35: <futures_lite::future::Or<F1,F2> as core::future::future::Future>::poll
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/futures-lite-1.12.0/src/future.rs:526:33
  36: async_executor::Executor::run::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-executor-1.4.1/src/lib.rs:242:31
  37: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/future/mod.rs:91:19
  38: async_executor::LocalExecutor::run::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-executor-1.4.1/src/lib.rs:447:33
  39: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/future/mod.rs:91:19
  40: async_io::driver::block_on
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-io-1.7.0/src/driver.rs:142:33
  41: async_global_executor::reactor::block_on::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-global-executor-2.2.0/src/reactor.rs:3:18
  42: async_global_executor::reactor::block_on
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-global-executor-2.2.0/src/reactor.rs:12:5
  43: async_global_executor::executor::block_on::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-global-executor-2.2.0/src/executor.rs:26:36
  44: std::thread::local::LocalKey<T>::try_with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:442:16
  45: std::thread::local::LocalKey<T>::with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:418:9
  46: async_global_executor::executor::block_on
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-global-executor-2.2.0/src/executor.rs:26:5
  47: async_std::task::builder::Builder::blocking::{{closure}}::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/builder.rs:171:25
  48: async_std::task::task_locals_wrapper::TaskLocalsWrapper::set_current::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/task_locals_wrapper.rs:60:13
  49: std::thread::local::LocalKey<T>::try_with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:442:16
  50: std::thread::local::LocalKey<T>::with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:418:9
  51: async_std::task::task_locals_wrapper::TaskLocalsWrapper::set_current
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/task_locals_wrapper.rs:55:9
  52: async_std::task::builder::Builder::blocking::{{closure}}
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/builder.rs:168:17
  53: std::thread::local::LocalKey<T>::try_with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:442:16
  54: std::thread::local::LocalKey<T>::with
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/std/src/thread/local.rs:418:9
  55: async_std::task::builder::Builder::blocking
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/builder.rs:161:9
  56: async_std::task::block_on::block_on
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/async-std-1.12.0/src/task/block_on.rs:33:5
  57: tremor_runtime::connectors::tests::s3::reader::connector_s3_no_region::{{closure}}
             at ./src/connectors/tests/s3/reader.rs:99:1
  58: core::ops::function::FnOnce::call_once
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/ops/function.rs:227:5
  59: serial_test::serial_code_lock::local_serial_core_with_return
             at /home/mat/.cargo/registry/src/github.aaakk.us.kg-1ecc6299db9ec823/serial_test-0.8.0/src/serial_code_lock.rs:16:5
  60: tremor_runtime::connectors::tests::s3::reader::connector_s3_no_region
             at ./src/connectors/tests/s3/reader.rs:100:1
  61: tremor_runtime::connectors::tests::s3::reader::connector_s3_no_region::{{closure}}
             at ./src/connectors/tests/s3/reader.rs:99:1
  62: core::ops::function::FnOnce::call_once
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/ops/function.rs:227:5
  63: core::ops::function::FnOnce::call_once
             at /rustc/fe5b13d681f25ee6474be29d748c65adcd91f69e/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

@mfelsche
Copy link
Author

Another small reproducer:

use aws_smithy_http::endpoint::Endpoint;

fn main() -> anyhow::Result<()> {
    let mut uri = "localhost:12345".parse::<http::Uri>()?;
    let endpoint = Endpoint::immutable(uri.clone()); // all good
    endpoint.set_endpoint(&mut uri, None); // panic!
    println!("Endpoint: {:?}", &endpoint);
    Ok(())
}

@jdisanti
Copy link
Collaborator

Thanks for digging into that! You're welcome to contribute a fix if you want to. Otherwise, we'll get to this at some point in the near future.

@jdisanti jdisanti added the bug Something isn't working label Jun 28, 2022
@mfelsche
Copy link
Author

I would be up for fixing that.

What would a fix look like for you? Should the constructors Endpoint::mutable, Endpoint::immutable behave the same as set_endpoint and should both return a Result<...>? I guess this will make ripples throughout the whole aws_sdk codebase, so any ideas/requirements from your side would help a lot.

@rcoh
Copy link
Collaborator

rcoh commented Jun 29, 2022

I think Endpoint::mutable and Endpoint::immutable should probably both return Result–I did a quick audit, I don't expect it will ripple, these are mostly only invoked by customers.

While we're at it, it might be worth adding a constructor that accepts impl Into<String> and doing the parsing / validation on that since that will be more convenient.

In places where these constructors are invoked, you can just panic in your PR and we can deal with the ripples if handling the error isn't obvious in-situ.

@jdisanti jdisanti mentioned this issue Aug 31, 2022
28 tasks
@jdisanti jdisanti added this to the SDK GA milestone Sep 30, 2022
@jdisanti jdisanti added the sdk label Sep 30, 2022
@jdisanti jdisanti self-assigned this Nov 14, 2022
@jdisanti jdisanti moved this to In Progress in AWS Rust SDK Public Roadmap Nov 15, 2022
Repository owner moved this from In Progress to Done in AWS Rust SDK Public Roadmap Nov 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants