Abort support
This commit is contained in:
parent
0f0af9c1a5
commit
8f13b550d8
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1758,7 +1758,7 @@ dependencies = [
|
|||||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||||
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
||||||
"checksum libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "97def9dc7ce1d8e153e693e3a33020bc69972181adb2f871e87e888876feae49"
|
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
|
||||||
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
||||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||||
"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
|
"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
|
||||||
|
@ -97,7 +97,7 @@ impl Fetch {
|
|||||||
self.abort.load(Ordering::Relaxed)
|
self.abort.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
fn mark_aborted(&mut self) -> Next {
|
fn mark_aborted(&mut self) -> Next {
|
||||||
self.result = Some(Err(Error::Aborted));
|
self.result = Some(Err(Error::Aborted.into()));
|
||||||
Next::end()
|
Next::end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
pub mod fetch_file;
|
pub mod fetch_file;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::sync::mpsc;
|
use std::sync::{mpsc, Arc};
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use hyper;
|
use hyper;
|
||||||
@ -62,7 +63,7 @@ impl Client {
|
|||||||
self.https_client.close();
|
self.https_client.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(&mut self, url: String, on_done: Box<Fn() + Send>) -> Result<mpsc::Receiver<FetchResult>, FetchError> {
|
pub fn request(&mut self, url: String, abort: Arc<AtomicBool>, on_done: Box<Fn() + Send>) -> Result<mpsc::Receiver<FetchResult>, FetchError> {
|
||||||
let is_https = url.starts_with("https://");
|
let is_https = url.starts_with("https://");
|
||||||
let url = try!(url.parse().map_err(|_| FetchError::InvalidUrl));
|
let url = try!(url.parse().map_err(|_| FetchError::InvalidUrl));
|
||||||
trace!(target: "dapps", "Fetching from: {:?}", url);
|
trace!(target: "dapps", "Fetching from: {:?}", url);
|
||||||
@ -71,7 +72,7 @@ impl Client {
|
|||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let temp_path = Self::temp_path();
|
let temp_path = Self::temp_path();
|
||||||
let res = self.https_client.fetch_to_file(url, temp_path.clone(), move |result| {
|
let res = self.https_client.fetch_to_file(url, temp_path.clone(), abort, move |result| {
|
||||||
let res = tx.send(
|
let res = tx.send(
|
||||||
result.map(|_| temp_path).map_err(FetchError::Https)
|
result.map(|_| temp_path).map_err(FetchError::Https)
|
||||||
);
|
);
|
||||||
@ -87,7 +88,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let res = self.http_client.request(url, Fetch::new(tx, on_done));
|
let res = self.http_client.request(url, Fetch::new(tx, abort, on_done));
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(_) => Ok(rx),
|
Ok(_) => Ok(rx),
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::{fs, str, thread};
|
use std::{fs, str, thread};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -56,7 +58,7 @@ impl From<TlsClientError> for FetchError {
|
|||||||
pub type FetchResult = Result<(), FetchError>;
|
pub type FetchResult = Result<(), FetchError>;
|
||||||
|
|
||||||
pub enum ClientMessage {
|
pub enum ClientMessage {
|
||||||
Fetch(Url, Box<io::Write + Send>, Box<FnMut(FetchResult) + Send>),
|
Fetch(Url, Box<io::Write + Send>, Arc<AtomicBool>, Box<FnMut(FetchResult) + Send>),
|
||||||
Shutdown,
|
Shutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,9 +95,9 @@ impl Client {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_to_file<F: FnOnce(FetchResult) + Send + 'static>(&self, url: Url, path: PathBuf, callback: F) -> Result<(), FetchError> {
|
pub fn fetch_to_file<F: FnOnce(FetchResult) + Send + 'static>(&self, url: Url, path: PathBuf, abort: Arc<AtomicBool>, callback: F) -> Result<(), FetchError> {
|
||||||
let file = try!(fs::File::create(&path));
|
let file = try!(fs::File::create(&path));
|
||||||
self.fetch(url, Box::new(file), move |result| {
|
self.fetch(url, Box::new(file), abort, move |result| {
|
||||||
if let Err(_) = result {
|
if let Err(_) = result {
|
||||||
// remove temporary file
|
// remove temporary file
|
||||||
let _ = fs::remove_file(&path);
|
let _ = fs::remove_file(&path);
|
||||||
@ -104,9 +106,9 @@ impl Client {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch<F: FnOnce(FetchResult) + Send + 'static>(&self, url: Url, writer: Box<io::Write + Send>, callback: F) -> Result<(), FetchError> {
|
pub fn fetch<F: FnOnce(FetchResult) + Send + 'static>(&self, url: Url, writer: Box<io::Write + Send>, abort: Arc<AtomicBool>, callback: F) -> Result<(), FetchError> {
|
||||||
let cell = RefCell::new(Some(callback));
|
let cell = RefCell::new(Some(callback));
|
||||||
try!(self.channel.send(ClientMessage::Fetch(url, writer, Box::new(move |res| {
|
try!(self.channel.send(ClientMessage::Fetch(url, writer, abort, Box::new(move |res| {
|
||||||
cell.borrow_mut().take().expect("Called only once.")(res);
|
cell.borrow_mut().take().expect("Called only once.")(res);
|
||||||
}))));
|
}))));
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -148,11 +150,11 @@ impl mio::Handler for ClientLoop {
|
|||||||
fn notify(&mut self, event_loop: &mut mio::EventLoop<Self>, msg: Self::Message) {
|
fn notify(&mut self, event_loop: &mut mio::EventLoop<Self>, msg: Self::Message) {
|
||||||
match msg {
|
match msg {
|
||||||
ClientMessage::Shutdown => event_loop.shutdown(),
|
ClientMessage::Shutdown => event_loop.shutdown(),
|
||||||
ClientMessage::Fetch(url, writer, callback) => {
|
ClientMessage::Fetch(url, writer, abort, callback) => {
|
||||||
let token = self.next_token;
|
let token = self.next_token;
|
||||||
self.next_token += 1;
|
self.next_token += 1;
|
||||||
|
|
||||||
if let Ok(mut tlsclient) = TlsClient::new(mio::Token(token), &url, writer, callback) {
|
if let Ok(mut tlsclient) = TlsClient::new(mio::Token(token), &url, writer, abort, callback) {
|
||||||
let httpreq = format!(
|
let httpreq = format!(
|
||||||
"GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\nAccept-Encoding: identity\r\n\r\n",
|
"GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\nAccept-Encoding: identity\r\n\r\n",
|
||||||
url.path(),
|
url.path(),
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::io::{self, Write, Read, Cursor, BufReader};
|
use std::io::{self, Write, Read, Cursor, BufReader};
|
||||||
|
|
||||||
use mio;
|
use mio;
|
||||||
@ -28,6 +29,7 @@ use client::{FetchError, ClientLoop, FetchResult};
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TlsClientError {
|
pub enum TlsClientError {
|
||||||
|
Aborted,
|
||||||
Initialization,
|
Initialization,
|
||||||
UnexpectedEof,
|
UnexpectedEof,
|
||||||
Connection(io::Error),
|
Connection(io::Error),
|
||||||
@ -38,6 +40,7 @@ pub enum TlsClientError {
|
|||||||
/// This encapsulates the TCP-level connection, some connection
|
/// This encapsulates the TCP-level connection, some connection
|
||||||
/// state, and the underlying TLS-level session.
|
/// state, and the underlying TLS-level session.
|
||||||
pub struct TlsClient {
|
pub struct TlsClient {
|
||||||
|
abort: Arc<AtomicBool>,
|
||||||
token: mio::Token,
|
token: mio::Token,
|
||||||
socket: TcpStream,
|
socket: TcpStream,
|
||||||
tls_session: rustls::ClientSession,
|
tls_session: rustls::ClientSession,
|
||||||
@ -81,6 +84,7 @@ impl TlsClient {
|
|||||||
token: mio::Token,
|
token: mio::Token,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
writer: Box<io::Write + Send>,
|
writer: Box<io::Write + Send>,
|
||||||
|
abort: Arc<AtomicBool>,
|
||||||
mut callback: Box<FnMut(FetchResult) + Send>,
|
mut callback: Box<FnMut(FetchResult) + Send>,
|
||||||
) -> Result<Self, FetchError> {
|
) -> Result<Self, FetchError> {
|
||||||
let res = TlsClient::make_config().and_then(|cfg| {
|
let res = TlsClient::make_config().and_then(|cfg| {
|
||||||
@ -91,6 +95,7 @@ impl TlsClient {
|
|||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok((cfg, sock)) => Ok(TlsClient {
|
Ok((cfg, sock)) => Ok(TlsClient {
|
||||||
|
abort: abort,
|
||||||
token: token,
|
token: token,
|
||||||
writer: HttpProcessor::new(writer),
|
writer: HttpProcessor::new(writer),
|
||||||
socket: sock,
|
socket: sock,
|
||||||
@ -111,6 +116,13 @@ impl TlsClient {
|
|||||||
pub fn ready(&mut self, event_loop: &mut mio::EventLoop<ClientLoop>, token: mio::Token, events: mio::EventSet) -> bool {
|
pub fn ready(&mut self, event_loop: &mut mio::EventLoop<ClientLoop>, token: mio::Token, events: mio::EventSet) -> bool {
|
||||||
assert_eq!(token, self.token);
|
assert_eq!(token, self.token);
|
||||||
|
|
||||||
|
let aborted = self.is_aborted();
|
||||||
|
if aborted {
|
||||||
|
// do_write needs to be invoked after that
|
||||||
|
self.tls_session.send_close_notify();
|
||||||
|
self.error = Some(TlsClientError::Aborted);
|
||||||
|
}
|
||||||
|
|
||||||
if events.is_readable() {
|
if events.is_readable() {
|
||||||
self.do_read();
|
self.do_read();
|
||||||
}
|
}
|
||||||
@ -119,7 +131,7 @@ impl TlsClient {
|
|||||||
self.do_write();
|
self.do_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_closed() {
|
if self.is_closed() || aborted {
|
||||||
trace!("Connection closed");
|
trace!("Connection closed");
|
||||||
let callback = &mut self.callback;
|
let callback = &mut self.callback;
|
||||||
callback(match self.error.take() {
|
callback(match self.error.take() {
|
||||||
@ -226,5 +238,9 @@ impl TlsClient {
|
|||||||
fn is_closed(&self) -> bool {
|
fn is_closed(&self) -> bool {
|
||||||
self.closing
|
self.closing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_aborted(&self) -> bool {
|
||||||
|
self.abort.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user