X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-block-sync%2Fsrc%2Fhttp.rs;h=aa0d840adb0a168088e6e1d08d52a6ce22f7cf44;hb=ac6d4cb9ad45189e963bd906e9da971502dff129;hp=89eb95dcff84a5165b5dcfdf27f54d71d69f57a4;hpb=8e7b5905fd84999318bdcf9cbcb9cfecbf58f532;p=rust-lightning diff --git a/lightning-block-sync/src/http.rs b/lightning-block-sync/src/http.rs index 89eb95dc..aa0d840a 100644 --- a/lightning-block-sync/src/http.rs +++ b/lightning-block-sync/src/http.rs @@ -8,7 +8,7 @@ use std::convert::TryFrom; use std::fmt; #[cfg(not(feature = "tokio"))] use std::io::Write; -use std::net::ToSocketAddrs; +use std::net::{SocketAddr, ToSocketAddrs}; use std::time::Duration; #[cfg(feature = "tokio")] @@ -27,9 +27,10 @@ const TCP_STREAM_TIMEOUT: Duration = Duration::from_secs(5); /// Timeout for reading the first byte of a response. This is separate from the general read /// timeout as it is not uncommon for Bitcoin Core to be blocked waiting on UTXO cache flushes for -/// upwards of a minute or more. Note that we always retry once when we time out, so the maximum -/// time we allow Bitcoin Core to block for is twice this value. -const TCP_STREAM_RESPONSE_TIMEOUT: Duration = Duration::from_secs(120); +/// upwards of 10 minutes on slow devices (e.g. RPis with SSDs over USB). Note that we always retry +/// once when we time out, so the maximum time we allow Bitcoin Core to block for is twice this +/// value. +const TCP_STREAM_RESPONSE_TIMEOUT: Duration = Duration::from_secs(300); /// Maximum HTTP message header size in bytes. const MAX_HTTP_MESSAGE_HEADER_SIZE: usize = 8192; @@ -97,6 +98,7 @@ impl<'a> std::net::ToSocketAddrs for &'a HttpEndpoint { /// Client for making HTTP requests. pub(crate) struct HttpClient { + address: SocketAddr, stream: TcpStream, } @@ -119,7 +121,7 @@ impl HttpClient { TcpStream::from_std(stream)? }; - Ok(Self { stream }) + Ok(Self { address, stream }) } /// Sends a `GET` request for a resource identified by `uri` at the `host`. @@ -162,7 +164,6 @@ impl HttpClient { /// Sends an HTTP request message and reads the response, returning its body. Attempts to /// reconnect and retry if the connection has been closed. async fn send_request_with_retry(&mut self, request: &str) -> std::io::Result> { - let endpoint = self.stream.peer_addr().unwrap(); match self.send_request(request).await { Ok(bytes) => Ok(bytes), Err(_) => { @@ -176,7 +177,7 @@ impl HttpClient { tokio::time::sleep(Duration::from_millis(100)).await; #[cfg(not(feature = "tokio"))] std::thread::sleep(Duration::from_millis(100)); - *self = Self::connect(endpoint)?; + *self = Self::connect(self.address)?; self.send_request(request).await }, } @@ -287,7 +288,7 @@ impl HttpClient { HttpMessageLength::Empty => { Vec::new() }, HttpMessageLength::ContentLength(length) => { if length == 0 || length > MAX_HTTP_MESSAGE_BODY_SIZE { - return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "out of range")) + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("invalid response length: {} bytes", length))); } else { let mut content = vec![0; length]; #[cfg(feature = "tokio")] @@ -510,21 +511,19 @@ mod endpoint_tests { #[test] fn convert_to_socket_addrs() { - let endpoint = HttpEndpoint::for_host("foo.com".into()); + let endpoint = HttpEndpoint::for_host("localhost".into()); let host = endpoint.host(); let port = endpoint.port(); use std::net::ToSocketAddrs; match (&endpoint).to_socket_addrs() { Err(e) => panic!("Unexpected error: {:?}", e), - Ok(mut socket_addrs) => { - match socket_addrs.next() { - None => panic!("Expected socket address"), - Some(addr) => { - assert_eq!(addr, (host, port).to_socket_addrs().unwrap().next().unwrap()); - assert!(socket_addrs.next().is_none()); - } + Ok(socket_addrs) => { + let mut std_addrs = (host, port).to_socket_addrs().unwrap(); + for addr in socket_addrs { + assert_eq!(addr, std_addrs.next().unwrap()); } + assert!(std_addrs.next().is_none()); } } } @@ -636,7 +635,10 @@ pub(crate) mod client_tests { #[test] fn connect_to_unresolvable_host() { match HttpClient::connect(("example.invalid", 80)) { - Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::Other), + Err(e) => { + assert!(e.to_string().contains("failed to lookup address information") || + e.to_string().contains("No such host"), "{:?}", e); + }, Ok(_) => panic!("Expected error"), } } @@ -725,7 +727,7 @@ pub(crate) mod client_tests { match client.get::("/foo", "foo.com").await { Err(e) => { assert_eq!(e.kind(), std::io::ErrorKind::InvalidData); - assert_eq!(e.get_ref().unwrap().to_string(), "out of range"); + assert_eq!(e.get_ref().unwrap().to_string(), "invalid response length: 8032001 bytes"); }, Ok(_) => panic!("Expected error"), }