-
-
Notifications
You must be signed in to change notification settings - Fork 45
http: Implement callbacks to configure the sockets used as listeners #407
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
base: main
Are you sure you want to change the base?
Changes from 9 commits
b3ac7a4
5d488ad
710788a
9dd70fb
d929ed1
a7d66e7
890d7ef
202a9d1
f6cd705
64e2f8f
e6efd14
0e3b2a7
9609aca
79ce58f
1b9ea7e
97cc48e
8b8dc97
c48e43f
0f484c8
358c557
0739b17
08559d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| [[scuffle-http]] | ||
| category = "feat" | ||
| description = "add ability to configure sockets using callbacks" | ||
| authors = ["@DrSloth", "@lennartkloock"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ use scuffle_context::ContextFutExt; | |
| use tracing::Instrument; | ||
|
|
||
| use crate::error::Error; | ||
| use crate::server::ConfigureSocketCallback; | ||
| use crate::service::{HttpService, HttpServiceFactory}; | ||
|
|
||
| mod handler; | ||
|
|
@@ -33,6 +34,8 @@ pub struct HyperBackend<F> { | |
| /// Use `[::]` for a dual-stack listener. | ||
| /// For example, use `[::]:80` to bind to port 80 on both IPv4 and IPv6. | ||
| bind: SocketAddr, | ||
| /// Callback to configure socket | ||
| configure_sock: Option<ConfigureSocketCallback>, | ||
| /// rustls config. | ||
| /// | ||
| /// Use this field to set the server into TLS mode. | ||
|
|
@@ -79,7 +82,27 @@ where | |
| } | ||
|
|
||
| // We have to create an std listener first because the tokio listener isn't clonable | ||
| let listener = tokio::net::TcpListener::bind(self.bind).await?.into_std()?; | ||
| let listener = { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect this might not work on windows. Previously when adding windows support we found that if the listener was constructed outside of tokio it would block the eventloop even if non-blocking was set to true. We didnt investigate this further than that, but perhaps this might be a good time to understand why this behaviour was the case when using
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have run just fmt now. I haven't had this problem on windows yet at least when using the socket2 crate but my time spent in windows is not a lot. |
||
| let mut sock = socket2::Socket::new( | ||
| match self.bind { | ||
| SocketAddr::V4(_) => socket2::Domain::IPV4, | ||
| SocketAddr::V6(_) => socket2::Domain::IPV6, | ||
| }, | ||
| socket2::Type::STREAM, | ||
| Some(socket2::Protocol::TCP), | ||
| )?; | ||
|
|
||
| sock.set_nonblocking(true)?; | ||
|
|
||
| if let Some(cfg_fn) = self.configure_sock.as_ref() { | ||
|
philipch07 marked this conversation as resolved.
Outdated
|
||
| sock = cfg_fn.call(sock)?; | ||
| } | ||
|
|
||
| sock.bind(&socket2::SockAddr::from(self.bind))?; | ||
| sock.listen(128)?; | ||
|
|
||
| std::net::TcpListener::from(sock) | ||
| }; | ||
|
|
||
| #[cfg(feature = "tls-rustls")] | ||
| let tls_acceptor = self | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| use std::fmt::Debug; | ||
| use std::net::SocketAddr; | ||
| use std::sync::Arc; | ||
|
|
||
| use crate::error::Error; | ||
| use crate::service::{HttpService, HttpServiceFactory}; | ||
|
|
@@ -40,6 +41,14 @@ pub struct HttpServer<F> { | |
| #[cfg(feature = "http3")] | ||
| #[cfg_attr(docsrs, doc(cfg(feature = "http3")))] | ||
| enable_http3: bool, | ||
| /// Callback to configure socket used for http1 and http2 | ||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||
| #[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))] | ||
| configure_h12_sock: Option<ConfigureSocketCallback>, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we make bon use an |
||
| /// Callback to configure socket used for http3 | ||
| #[cfg(feature = "http3")] | ||
| #[cfg_attr(docsrs, doc(cfg(feature = "http3")))] | ||
| configure_h3_sock: Option<ConfigureSocketCallback>, | ||
| /// rustls config. | ||
| /// | ||
| /// Use this field to set the server into TLS mode. | ||
|
|
@@ -213,6 +222,7 @@ where | |
| .service_factory(self.service_factory) | ||
| .bind(self.bind) | ||
| .rustls_config(_rustls_config) | ||
| .maybe_configure_sock(self.configure_h3_sock.clone()) | ||
| .build(); | ||
|
|
||
| return backend.run().await; | ||
|
|
@@ -224,6 +234,7 @@ where | |
| .worker_tasks(self.worker_tasks) | ||
| .service_factory(self.service_factory) | ||
| .bind(self.bind) | ||
| .maybe_configure_sock(self.configure_h12_sock.clone()) | ||
| .rustls_config(_rustls_config); | ||
|
|
||
| #[cfg(feature = "http1")] | ||
|
|
@@ -241,6 +252,7 @@ where | |
| .worker_tasks(self.worker_tasks) | ||
| .service_factory(self.service_factory.clone()) | ||
| .bind(self.bind) | ||
| .maybe_configure_sock(self.configure_h12_sock.clone()) | ||
| .rustls_config(_rustls_config.clone()); | ||
|
|
||
| #[cfg(feature = "http1")] | ||
|
|
@@ -256,6 +268,7 @@ where | |
| .worker_tasks(self.worker_tasks) | ||
| .service_factory(self.service_factory) | ||
| .bind(self.bind) | ||
| .maybe_configure_sock(self.configure_h3_sock.clone()) | ||
| .rustls_config(_rustls_config) | ||
| .build() | ||
| .run(); | ||
|
|
@@ -283,6 +296,7 @@ where | |
| .ctx(self.ctx) | ||
| .worker_tasks(self.worker_tasks) | ||
| .service_factory(self.service_factory) | ||
| .maybe_configure_sock(self.configure_h12_sock.clone()) | ||
| .bind(self.bind); | ||
|
|
||
| #[cfg(feature = "http1")] | ||
|
|
@@ -297,3 +311,27 @@ where | |
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| /// A callback used to configure a socket2 instance. | ||
| /// | ||
| /// This can be used to tweak options on the TCP/UDP layer | ||
| #[derive(Clone)] | ||
| pub struct ConfigureSocketCallback(Arc<dyn Fn(socket2::Socket) -> std::io::Result<socket2::Socket> + Send + Sync>); | ||
|
|
||
| impl ConfigureSocketCallback { | ||
| /// Create a new `ConfigureSocketCallback` from the given callback function. | ||
| pub fn new<F: Fn(socket2::Socket) -> std::io::Result<socket2::Socket> + 'static + Send + Sync>(f: F) -> Self { | ||
| Self(Arc::new(f)) | ||
| } | ||
|
|
||
| /// Create a new `ConfigureSocketCallback` from the given callback function. | ||
| pub fn call(&self, sock: socket2::Socket) -> std::io::Result<socket2::Socket> { | ||
| (self.0)(sock) | ||
| } | ||
| } | ||
|
|
||
| impl std::fmt::Debug for ConfigureSocketCallback { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
| write!(f, "ConfigureSocketCallback ") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extra space here |
||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.