mirror of
https://github.com/fafhrd91/actix-web
synced 2025-08-31 00:50:20 +02:00
add rustfmt config
This commit is contained in:
203
src/ws/client.rs
203
src/ws/client.rs
@@ -1,67 +1,65 @@
|
||||
//! Http client request
|
||||
use std::{fmt, io, str};
|
||||
use std::rc::Rc;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
use std::{fmt, io, str};
|
||||
|
||||
use base64;
|
||||
use rand;
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
use bytes::Bytes;
|
||||
use cookie::Cookie;
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
use http::{HttpTryFrom, StatusCode, Error as HttpError};
|
||||
use http::header::{self, HeaderName, HeaderValue};
|
||||
use sha1::Sha1;
|
||||
use futures::{Async, Future, Poll, Stream};
|
||||
use futures::unsync::mpsc::{unbounded, UnboundedSender};
|
||||
use futures::{Async, Future, Poll, Stream};
|
||||
use http::header::{self, HeaderName, HeaderValue};
|
||||
use http::{Error as HttpError, HttpTryFrom, StatusCode};
|
||||
use rand;
|
||||
use sha1::Sha1;
|
||||
|
||||
use actix::prelude::*;
|
||||
|
||||
use body::{Body, Binary};
|
||||
use body::{Binary, Body};
|
||||
use error::{Error, UrlParseError};
|
||||
use header::IntoHeaderValue;
|
||||
use payload::PayloadHelper;
|
||||
use httpmessage::HttpMessage;
|
||||
use payload::PayloadHelper;
|
||||
|
||||
use client::{ClientRequest, ClientRequestBuilder, ClientResponse,
|
||||
ClientConnector, SendRequest, SendRequestError,
|
||||
HttpResponseParserError};
|
||||
use client::{ClientConnector, ClientRequest, ClientRequestBuilder, ClientResponse,
|
||||
HttpResponseParserError, SendRequest, SendRequestError};
|
||||
|
||||
use super::{Message, ProtocolError};
|
||||
use super::frame::Frame;
|
||||
use super::proto::{CloseCode, OpCode};
|
||||
|
||||
use super::{Message, ProtocolError};
|
||||
|
||||
/// Websocket client error
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum ClientError {
|
||||
#[fail(display="Invalid url")]
|
||||
#[fail(display = "Invalid url")]
|
||||
InvalidUrl,
|
||||
#[fail(display="Invalid response status")]
|
||||
#[fail(display = "Invalid response status")]
|
||||
InvalidResponseStatus(StatusCode),
|
||||
#[fail(display="Invalid upgrade header")]
|
||||
#[fail(display = "Invalid upgrade header")]
|
||||
InvalidUpgradeHeader,
|
||||
#[fail(display="Invalid connection header")]
|
||||
#[fail(display = "Invalid connection header")]
|
||||
InvalidConnectionHeader(HeaderValue),
|
||||
#[fail(display="Missing CONNECTION header")]
|
||||
#[fail(display = "Missing CONNECTION header")]
|
||||
MissingConnectionHeader,
|
||||
#[fail(display="Missing SEC-WEBSOCKET-ACCEPT header")]
|
||||
#[fail(display = "Missing SEC-WEBSOCKET-ACCEPT header")]
|
||||
MissingWebSocketAcceptHeader,
|
||||
#[fail(display="Invalid challenge response")]
|
||||
#[fail(display = "Invalid challenge response")]
|
||||
InvalidChallengeResponse(String, HeaderValue),
|
||||
#[fail(display="Http parsing error")]
|
||||
#[fail(display = "Http parsing error")]
|
||||
Http(Error),
|
||||
#[fail(display="Url parsing error")]
|
||||
#[fail(display = "Url parsing error")]
|
||||
Url(UrlParseError),
|
||||
#[fail(display="Response parsing error")]
|
||||
#[fail(display = "Response parsing error")]
|
||||
ResponseParseError(HttpResponseParserError),
|
||||
#[fail(display="{}", _0)]
|
||||
#[fail(display = "{}", _0)]
|
||||
SendRequest(SendRequestError),
|
||||
#[fail(display="{}", _0)]
|
||||
#[fail(display = "{}", _0)]
|
||||
Protocol(#[cause] ProtocolError),
|
||||
#[fail(display="{}", _0)]
|
||||
#[fail(display = "{}", _0)]
|
||||
Io(io::Error),
|
||||
#[fail(display="Disconnected")]
|
||||
#[fail(display = "Disconnected")]
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
@@ -117,14 +115,15 @@ pub struct Client {
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
||||
/// Create new websocket connection
|
||||
pub fn new<S: AsRef<str>>(uri: S) -> Client {
|
||||
Client::with_connector(uri, ClientConnector::from_registry())
|
||||
}
|
||||
|
||||
/// Create new websocket connection with custom `ClientConnector`
|
||||
pub fn with_connector<S: AsRef<str>>(uri: S, conn: Addr<Unsync, ClientConnector>) -> Client {
|
||||
pub fn with_connector<S: AsRef<str>>(
|
||||
uri: S, conn: Addr<Unsync, ClientConnector>
|
||||
) -> Client {
|
||||
let mut cl = Client {
|
||||
request: ClientRequest::build(),
|
||||
err: None,
|
||||
@@ -140,11 +139,13 @@ impl Client {
|
||||
|
||||
/// Set supported websocket protocols
|
||||
pub fn protocols<U, V>(mut self, protos: U) -> Self
|
||||
where U: IntoIterator<Item=V> + 'static,
|
||||
V: AsRef<str>
|
||||
where
|
||||
U: IntoIterator<Item = V> + 'static,
|
||||
V: AsRef<str>,
|
||||
{
|
||||
let mut protos = protos.into_iter()
|
||||
.fold(String::new(), |acc, s| {acc + s.as_ref() + ","});
|
||||
let mut protos = protos
|
||||
.into_iter()
|
||||
.fold(String::new(), |acc, s| acc + s.as_ref() + ",");
|
||||
protos.pop();
|
||||
self.protocols = Some(protos);
|
||||
self
|
||||
@@ -158,7 +159,8 @@ impl Client {
|
||||
|
||||
/// Set request Origin
|
||||
pub fn origin<V>(mut self, origin: V) -> Self
|
||||
where HeaderValue: HttpTryFrom<V>
|
||||
where
|
||||
HeaderValue: HttpTryFrom<V>,
|
||||
{
|
||||
match HeaderValue::try_from(origin) {
|
||||
Ok(value) => self.origin = Some(value),
|
||||
@@ -185,7 +187,9 @@ impl Client {
|
||||
|
||||
/// Set request header
|
||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where HeaderName: HttpTryFrom<K>, V: IntoHeaderValue
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
self.request.header(key, value);
|
||||
self
|
||||
@@ -204,8 +208,7 @@ impl Client {
|
||||
pub fn connect(&mut self) -> ClientHandshake {
|
||||
if let Some(e) = self.err.take() {
|
||||
ClientHandshake::error(e)
|
||||
}
|
||||
else if let Some(e) = self.http_err.take() {
|
||||
} else if let Some(e) = self.http_err.take() {
|
||||
ClientHandshake::error(Error::from(e).into())
|
||||
} else {
|
||||
// origin
|
||||
@@ -216,11 +219,13 @@ impl Client {
|
||||
self.request.upgrade();
|
||||
self.request.set_header(header::UPGRADE, "websocket");
|
||||
self.request.set_header(header::CONNECTION, "upgrade");
|
||||
self.request.set_header(header::SEC_WEBSOCKET_VERSION, "13");
|
||||
self.request
|
||||
.set_header(header::SEC_WEBSOCKET_VERSION, "13");
|
||||
self.request.with_connector(self.conn.clone());
|
||||
|
||||
if let Some(protocols) = self.protocols.take() {
|
||||
self.request.set_header(header::SEC_WEBSOCKET_PROTOCOL, protocols.as_str());
|
||||
self.request
|
||||
.set_header(header::SEC_WEBSOCKET_PROTOCOL, protocols.as_str());
|
||||
}
|
||||
let request = match self.request.finish() {
|
||||
Ok(req) => req,
|
||||
@@ -228,14 +233,16 @@ impl Client {
|
||||
};
|
||||
|
||||
if request.uri().host().is_none() {
|
||||
return ClientHandshake::error(ClientError::InvalidUrl)
|
||||
return ClientHandshake::error(ClientError::InvalidUrl);
|
||||
}
|
||||
if let Some(scheme) = request.uri().scheme_part() {
|
||||
if scheme != "http" && scheme != "https" && scheme != "ws" && scheme != "wss" {
|
||||
return ClientHandshake::error(ClientError::InvalidUrl)
|
||||
if scheme != "http" && scheme != "https" && scheme != "ws"
|
||||
&& scheme != "wss"
|
||||
{
|
||||
return ClientHandshake::error(ClientError::InvalidUrl);
|
||||
}
|
||||
} else {
|
||||
return ClientHandshake::error(ClientError::InvalidUrl)
|
||||
return ClientHandshake::error(ClientError::InvalidUrl);
|
||||
}
|
||||
|
||||
// start handshake
|
||||
@@ -263,8 +270,7 @@ pub struct ClientHandshake {
|
||||
}
|
||||
|
||||
impl ClientHandshake {
|
||||
fn new(mut request: ClientRequest, max_size: usize) -> ClientHandshake
|
||||
{
|
||||
fn new(mut request: ClientRequest, max_size: usize) -> ClientHandshake {
|
||||
// Generate a random key for the `Sec-WebSocket-Key` header.
|
||||
// a base64-encoded (see Section 4 of [RFC4648]) value that,
|
||||
// when decoded, is 16 bytes in length (RFC 6455)
|
||||
@@ -273,12 +279,13 @@ impl ClientHandshake {
|
||||
|
||||
request.headers_mut().insert(
|
||||
header::SEC_WEBSOCKET_KEY,
|
||||
HeaderValue::try_from(key.as_str()).unwrap());
|
||||
HeaderValue::try_from(key.as_str()).unwrap(),
|
||||
);
|
||||
|
||||
let (tx, rx) = unbounded();
|
||||
request.set_body(Body::Streaming(
|
||||
Box::new(rx.map_err(|_| io::Error::new(
|
||||
io::ErrorKind::Other, "disconnected").into()))));
|
||||
request.set_body(Body::Streaming(Box::new(rx.map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::Other, "disconnected").into()
|
||||
}))));
|
||||
|
||||
ClientHandshake {
|
||||
key,
|
||||
@@ -329,20 +336,20 @@ impl Future for ClientHandshake {
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Some(err) = self.error.take() {
|
||||
return Err(err)
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let resp = match self.request.as_mut().unwrap().poll()? {
|
||||
Async::Ready(response) => {
|
||||
self.request.take();
|
||||
response
|
||||
},
|
||||
Async::NotReady => return Ok(Async::NotReady)
|
||||
}
|
||||
Async::NotReady => return Ok(Async::NotReady),
|
||||
};
|
||||
|
||||
// verify response
|
||||
if resp.status() != StatusCode::SWITCHING_PROTOCOLS {
|
||||
return Err(ClientError::InvalidResponseStatus(resp.status()))
|
||||
return Err(ClientError::InvalidResponseStatus(resp.status()));
|
||||
}
|
||||
// Check for "UPGRADE" to websocket header
|
||||
let has_hdr = if let Some(hdr) = resp.headers().get(header::UPGRADE) {
|
||||
@@ -356,26 +363,25 @@ impl Future for ClientHandshake {
|
||||
};
|
||||
if !has_hdr {
|
||||
trace!("Invalid upgrade header");
|
||||
return Err(ClientError::InvalidUpgradeHeader)
|
||||
return Err(ClientError::InvalidUpgradeHeader);
|
||||
}
|
||||
// Check for "CONNECTION" header
|
||||
if let Some(conn) = resp.headers().get(header::CONNECTION) {
|
||||
if let Ok(s) = conn.to_str() {
|
||||
if !s.to_lowercase().contains("upgrade") {
|
||||
trace!("Invalid connection header: {}", s);
|
||||
return Err(ClientError::InvalidConnectionHeader(conn.clone()))
|
||||
return Err(ClientError::InvalidConnectionHeader(conn.clone()));
|
||||
}
|
||||
} else {
|
||||
trace!("Invalid connection header: {:?}", conn);
|
||||
return Err(ClientError::InvalidConnectionHeader(conn.clone()))
|
||||
return Err(ClientError::InvalidConnectionHeader(conn.clone()));
|
||||
}
|
||||
} else {
|
||||
trace!("Missing connection header");
|
||||
return Err(ClientError::MissingConnectionHeader)
|
||||
return Err(ClientError::MissingConnectionHeader);
|
||||
}
|
||||
|
||||
if let Some(key) = resp.headers().get(header::SEC_WEBSOCKET_ACCEPT)
|
||||
{
|
||||
if let Some(key) = resp.headers().get(header::SEC_WEBSOCKET_ACCEPT) {
|
||||
// field is constructed by concatenating /key/
|
||||
// with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (RFC 6455)
|
||||
const WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
@@ -386,12 +392,17 @@ impl Future for ClientHandshake {
|
||||
if key.as_bytes() != encoded.as_bytes() {
|
||||
trace!(
|
||||
"Invalid challenge response: expected: {} received: {:?}",
|
||||
encoded, key);
|
||||
return Err(ClientError::InvalidChallengeResponse(encoded, key.clone()));
|
||||
encoded,
|
||||
key
|
||||
);
|
||||
return Err(ClientError::InvalidChallengeResponse(
|
||||
encoded,
|
||||
key.clone(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
trace!("Missing SEC-WEBSOCKET-ACCEPT header");
|
||||
return Err(ClientError::MissingWebSocketAcceptHeader)
|
||||
return Err(ClientError::MissingWebSocketAcceptHeader);
|
||||
};
|
||||
|
||||
let inner = Inner {
|
||||
@@ -401,13 +412,16 @@ impl Future for ClientHandshake {
|
||||
};
|
||||
|
||||
let inner = Rc::new(UnsafeCell::new(inner));
|
||||
Ok(Async::Ready(
|
||||
(ClientReader{inner: Rc::clone(&inner), max_size: self.max_size},
|
||||
ClientWriter{inner})))
|
||||
Ok(Async::Ready((
|
||||
ClientReader {
|
||||
inner: Rc::clone(&inner),
|
||||
max_size: self.max_size,
|
||||
},
|
||||
ClientWriter { inner },
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct ClientReader {
|
||||
inner: Rc<UnsafeCell<Inner>>,
|
||||
max_size: usize,
|
||||
@@ -422,7 +436,7 @@ impl fmt::Debug for ClientReader {
|
||||
impl ClientReader {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut Inner {
|
||||
unsafe{ &mut *self.inner.get() }
|
||||
unsafe { &mut *self.inner.get() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +448,7 @@ impl Stream for ClientReader {
|
||||
let max_size = self.max_size;
|
||||
let inner = self.as_mut();
|
||||
if inner.closed {
|
||||
return Ok(Async::Ready(None))
|
||||
return Ok(Async::Ready(None));
|
||||
}
|
||||
|
||||
// read
|
||||
@@ -447,31 +461,29 @@ impl Stream for ClientReader {
|
||||
OpCode::Continue => {
|
||||
inner.closed = true;
|
||||
Err(ProtocolError::NoContinuation)
|
||||
},
|
||||
}
|
||||
OpCode::Bad => {
|
||||
inner.closed = true;
|
||||
Err(ProtocolError::BadOpCode)
|
||||
},
|
||||
}
|
||||
OpCode::Close => {
|
||||
inner.closed = true;
|
||||
let code = NetworkEndian::read_uint(payload.as_ref(), 2) as u16;
|
||||
Ok(Async::Ready(Some(Message::Close(CloseCode::from(code)))))
|
||||
},
|
||||
OpCode::Ping =>
|
||||
Ok(Async::Ready(Some(
|
||||
Message::Ping(
|
||||
String::from_utf8_lossy(payload.as_ref()).into())))),
|
||||
OpCode::Pong =>
|
||||
Ok(Async::Ready(Some(
|
||||
Message::Pong(
|
||||
String::from_utf8_lossy(payload.as_ref()).into())))),
|
||||
OpCode::Binary =>
|
||||
Ok(Async::Ready(Some(Message::Binary(payload)))),
|
||||
Ok(Async::Ready(Some(Message::Close(CloseCode::from(
|
||||
code,
|
||||
)))))
|
||||
}
|
||||
OpCode::Ping => Ok(Async::Ready(Some(Message::Ping(
|
||||
String::from_utf8_lossy(payload.as_ref()).into(),
|
||||
)))),
|
||||
OpCode::Pong => Ok(Async::Ready(Some(Message::Pong(
|
||||
String::from_utf8_lossy(payload.as_ref()).into(),
|
||||
)))),
|
||||
OpCode::Binary => Ok(Async::Ready(Some(Message::Binary(payload)))),
|
||||
OpCode::Text => {
|
||||
let tmp = Vec::from(payload.as_ref());
|
||||
match String::from_utf8(tmp) {
|
||||
Ok(s) =>
|
||||
Ok(Async::Ready(Some(Message::Text(s)))),
|
||||
Ok(s) => Ok(Async::Ready(Some(Message::Text(s)))),
|
||||
Err(_) => {
|
||||
inner.closed = true;
|
||||
Err(ProtocolError::BadEncoding)
|
||||
@@ -491,18 +503,17 @@ impl Stream for ClientReader {
|
||||
}
|
||||
|
||||
pub struct ClientWriter {
|
||||
inner: Rc<UnsafeCell<Inner>>
|
||||
inner: Rc<UnsafeCell<Inner>>,
|
||||
}
|
||||
|
||||
impl ClientWriter {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut Inner {
|
||||
unsafe{ &mut *self.inner.get() }
|
||||
unsafe { &mut *self.inner.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientWriter {
|
||||
|
||||
/// Write payload
|
||||
#[inline]
|
||||
fn write(&mut self, mut data: Binary) {
|
||||
@@ -528,13 +539,23 @@ impl ClientWriter {
|
||||
/// Send ping frame
|
||||
#[inline]
|
||||
pub fn ping(&mut self, message: &str) {
|
||||
self.write(Frame::message(Vec::from(message), OpCode::Ping, true, true));
|
||||
self.write(Frame::message(
|
||||
Vec::from(message),
|
||||
OpCode::Ping,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
/// Send pong frame
|
||||
#[inline]
|
||||
pub fn pong(&mut self, message: &str) {
|
||||
self.write(Frame::message(Vec::from(message), OpCode::Pong, true, true));
|
||||
self.write(Frame::message(
|
||||
Vec::from(message),
|
||||
OpCode::Pong,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
/// Send close frame
|
||||
|
Reference in New Issue
Block a user