Skip to content

Commit 2720aec

Browse files
committed
Use generic cloneable stream
This should allow for wss:// to work
1 parent 36c2fee commit 2720aec

File tree

8 files changed

+89
-110
lines changed

8 files changed

+89
-110
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
name = "websocket"
4-
version = "0.5.0"
4+
version = "0.6.0"
55
authors = ["cyderize <[email protected]>"]
66

77
description = "A WebSocket (RFC6455) library for Rust."
@@ -17,5 +17,5 @@ keywords = ["websocket", "websockets", "rfc6455"]
1717
license = "MIT"
1818

1919
[dependencies]
20-
url = "~0.2.1"
20+
url = "~0.2.2"
2121
sha1 = "~0.0.3"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Rust-WebSocket attempts to provide a framework for WebSocket connections (both c
1010
To add a library release version from [crates.io](https://crates.io/crates/websocket) to a Cargo project, add this to the 'dependencies' section of your Cargo.toml:
1111

1212
```INI
13-
websocket = "~0.5.0"
13+
websocket = "~0.6.0"
1414
```
1515

1616
To add the library's Git repository to a Cargo project, add this to your Cargo.toml:

src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! with the capability to send and receive fragmented messages.
88
//!
99
//! Rust-WebSocket does not provide a 'listener' object, since the WebSocket protocol utilises a TcpStream.
10-
//! To implement a WebSocket server, use a normal TcpListener, and the WebSocketClient::from_stream() function
10+
//! To implement a WebSocket server, use a normal TcpListener, and the WebSocketClient::new() function
1111
//! on an accepted stream. You will then need to read the handshake from the client and send a response.
1212
//!
1313
//! ```no_run
@@ -26,18 +26,18 @@
2626
//! spawn(proc() {
2727
//! // Get a WebSocketClient from this stream
2828
//! // The mask argument is false as messages sent by the server are always unmasked
29-
//! let mut client = WebSocketClient::from_stream(stream, false);
29+
//! let mut client = WebSocketClient::new(stream, false);
3030
//!
3131
//! // Read the handshake from the client
3232
//! let request = client.receive_handshake_request().unwrap();
3333
//!
34-
//! // Get the headers we need to respond
34+
//! // Get the Sec-WebSocket-Key from the request
3535
//! let key = request.key().unwrap();
3636
//!
3737
//! // Form a response from the key
38-
//! /* In this example, we don't deal with the requested protocol
39-
//! Because of this, however, we need to a type annotation,
40-
//! which would usually not be required. */
38+
//! /* In this example, we don't deal with the requested Sec-WebSocket-Protocol.
39+
//! Because of this, however, we need a type annotation, which would
40+
//! not usually be required. */
4141
//! let response = WebSocketResponse::new::<String>(key.as_slice(), None);
4242
//!
4343
//! // Send the response to the client

src/ws/client.rs

Lines changed: 27 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@ use super::handshake::request::{WebSocketRequest, ReadWebSocketRequest, WriteWeb
22
use super::handshake::response::{WebSocketResponse, ReadWebSocketResponse, WriteWebSocketResponse};
33
use super::message::send::{WebSocketSender, new_sender};
44
use super::message::receive::{WebSocketReceiver, new_receiver};
5-
use std::io::net::tcp::TcpStream;
6-
use std::io::net::ip::SocketAddr;
7-
use std::io::{IoResult, IoError, IoErrorKind};
5+
use std::io::{Stream, IoResult};
86
use std::clone::Clone;
97

108
/// Represents a WebSocket client.
11-
/// To use WebSocketClient, you must create one using either WebSocketClient::connect(),
12-
/// which is used for writing clients, or WebSocketClient::from_stream(), which creates
13-
/// a WebSocketClient from a TcpStream (typically used in a server).
9+
/// To use WebSocketClient, you must create one using either WebSocketClient::new().
10+
/// For a client, you can use TcpStream::connect() to connect to the server, then call
11+
/// WebSocketClient::new() passing the resultant stream.
1412
///
1513
/// ```no_run
14+
/// use std::io::TcpStream;
1615
/// use websocket::WebSocketClient;
1716
/// use websocket::handshake::WebSocketRequest;
1817
///
1918
/// let request = WebSocketRequest::new("ws://127.0.0.1:1234", ["myProtocol"].as_slice()).unwrap();
2019
/// let key = request.key().unwrap();
21-
/// let mut client = WebSocketClient::connect(&request).unwrap();
20+
///
21+
/// // We can get the hostname from the request
22+
/// let stream = TcpStream::connect(request.host().unwrap().as_slice()).unwrap();
23+
///
24+
/// let mut client = WebSocketClient::new(stream, true);
2225
/// let response = client.receive_handshake_response().unwrap();
2326
///
2427
/// if !response.is_successful(key) {
@@ -31,62 +34,31 @@ use std::clone::Clone;
3134
///
3235
/// // ...
3336
/// ```
34-
pub struct WebSocketClient {
35-
stream: TcpStream,
37+
pub struct WebSocketClient<S: Stream + Clone> {
38+
stream: S,
3639
mask: bool,
3740
}
3841

39-
impl WebSocketClient {
40-
/// Connect to the WebSocket server using the given request.
41-
/// Use WebSocketRequest::new() to create a request for use with this function.
42-
pub fn connect(request: &WebSocketRequest) -> IoResult<WebSocketClient> {
43-
let host = try!(request.headers.get("Host").ok_or(
44-
IoError {
45-
kind: IoErrorKind::InvalidInput,
46-
desc: "No host specified",
47-
detail: None,
48-
}
49-
));
50-
//Connect to the server
51-
let mut stream = try!(TcpStream::connect(host.as_slice()));
52-
//Send the opening handshake
53-
try!(stream.write_websocket_request(request));
54-
55-
Ok(WebSocketClient{
56-
stream: stream,
57-
mask: true,
58-
})
59-
}
60-
61-
/// Creates a new WebSocketClient from a given TcpStream.
42+
impl<S: Stream + Clone> WebSocketClient<S> {
43+
/// Creates a new WebSocketClient from a given cloneable stream.
6244
/// The mask parameter determines whether or not messages send to the remote endpoint will be masked.
6345
/// If the client is connecting to a remote endpoint, set mask to true. If the client is the remote
6446
/// endpoint (and therefore, the server is the local endpoint), set mask to false.
6547
///
6648
/// Nothing is sent to or read from the stream during the conversion.
67-
pub fn from_stream(stream: TcpStream, mask: bool) -> WebSocketClient {
49+
pub fn new(stream: S, mask: bool) -> WebSocketClient<S> {
6850
WebSocketClient {
6951
stream: stream,
7052
mask: mask,
7153
}
7254
}
7355

74-
/// Returns a copy of the underlying TcpStream for this WebSocketClient.
56+
/// Returns a copy of the underlying S for this WebSocketClient.
7557
/// Note that writing to this stream will likely invalidate the WebSocket data stream.
76-
pub fn stream(&self) -> TcpStream {
58+
pub fn stream(&self) -> S {
7759
self.stream.clone()
7860
}
7961

80-
/// Returns the socket address of the remote peer of this TCP connection.
81-
pub fn peer_name(&mut self) -> IoResult<SocketAddr> {
82-
self.stream.peer_name()
83-
}
84-
85-
/// Returns the socket address of the local half of this TCP connection.
86-
pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
87-
self.stream.socket_name()
88-
}
89-
9062
/// Reads a request from this client. Only to be used if the server is the local endpoint and
9163
/// the client is the remote endpoint.
9264
pub fn receive_handshake_request(&mut self) -> IoResult<WebSocketRequest> {
@@ -99,6 +71,12 @@ impl WebSocketClient {
9971
self.stream.read_websocket_response()
10072
}
10173

74+
/// Sends the specified WebSocketRequest to the remote endpoint. Only to be used if the server is
75+
/// the remote endpoint and the client is the local endpoint.
76+
pub fn send_handshake_request(&mut self, request: WebSocketRequest) -> IoResult<()> {
77+
self.stream.write_websocket_request(&request)
78+
}
79+
10280
/// Sends the specified WebSocketResponse to this client. Only to be used if the server is
10381
/// the local endpoint and the client is the remote endpoint.
10482
pub fn send_handshake_response(&mut self, response: WebSocketResponse) -> IoResult<()> {
@@ -107,37 +85,19 @@ impl WebSocketClient {
10785

10886
/// Returns a WebSocketSender from this client. Used to transmit data to the remote endpoint,
10987
/// that is, to the server if WebSocketClient::connect() has been used, or to this client otherwise.
110-
pub fn sender(&self) -> WebSocketSender {
88+
pub fn sender(&self) -> WebSocketSender<S> {
11189
new_sender(self.stream.clone(), self.mask)
11290
}
11391

114-
/// Closes the sender for this WebSocketClient.
115-
/// This method will close the message sending portion of this client, causing all pending and future sends to immediately return with an error.
116-
/// This affects all WebSocketSenders for the client, and any copies of the underlying stream will be unable to write.
117-
///
118-
/// Note that you should send a WebSocketMessage:Close message to the remote endpoint before calling this method.
119-
pub fn close_send(&mut self) -> IoResult<()> {
120-
self.stream.close_write()
121-
}
122-
12392
/// Returns a WebSocketReceiver from this client. Used to receive data from the remote endpoint,
12493
/// that is, from the server if WebSocketClient::connect() has been used, or from this client otherwise.
125-
pub fn receiver(&self) -> WebSocketReceiver {
94+
pub fn receiver(&self) -> WebSocketReceiver<S> {
12695
new_receiver(self.stream.clone())
12796
}
128-
129-
/// Closes the receiver for this WebSocketClient.
130-
/// This method will close the message receiving portion of this client, causing all pending and future receives to immediately return with an error.
131-
/// This affects all WebSocketReceivers for the client, and any copies of the underlying stream will be unable to read.
132-
///
133-
/// Note that you should send a WebSocketMessage:Close message to the remote endpoint before calling this method.
134-
pub fn close_receive(&mut self) -> IoResult<()> {
135-
self.stream.close_read()
136-
}
13797
}
13898

139-
impl Clone for WebSocketClient {
140-
fn clone(&self) -> WebSocketClient {
99+
impl<S: Stream + Clone> Clone for WebSocketClient<S> {
100+
fn clone(&self) -> WebSocketClient<S> {
141101
WebSocketClient {
142102
stream: self.stream.clone(),
143103
mask: self.mask,

src/ws/handshake/request.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ impl WebSocketRequest {
4747
};
4848

4949
match ws_uri.scheme.as_slice() {
50-
"ws" => { }
51-
/* "wss" => {
52-
// Don't know how to handle secure WebSocket
53-
} */
50+
"ws" | "wss" => { }
5451
_ => { return Err(ParseError::InvalidScheme); }
5552
}
5653

src/ws/handshake/response.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,18 @@ static MAGIC_GUID: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2323
///
2424
/// assert_eq!(response.accept().unwrap().as_slice(), "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
2525
/// assert_eq!(response.upgrade().unwrap().as_slice(), "websocket");
26-
/// //...
26+
/// // ...
27+
/// ```
28+
/// Note that we can also send WebSocket failure responses.
29+
///
30+
/// ```
31+
/// use websocket::handshake::WebSocketResponse;
32+
///
33+
/// let response = WebSocketResponse::failure(403, "Forbidden");
34+
/// assert_eq!(response.status_code, 403);
35+
/// assert_eq!(response.reason_phrase.as_slice(), "Forbidden");
36+
///
37+
/// // ...
2738
/// ```
2839
pub struct WebSocketResponse {
2940
/// The HTTP version of this request
@@ -62,6 +73,17 @@ impl WebSocketResponse {
6273
}
6374
}
6475

76+
/// Create a WebSocket response with a particular status code and reason phrase - generally
77+
/// used to indicate a handshake failure.
78+
pub fn failure<A: ToString>(status_code: uint, reason_phrase: A) -> WebSocketResponse {
79+
WebSocketResponse {
80+
http_version: HttpVersion::new(1u8, Some(1u8)),
81+
status_code: status_code,
82+
reason_phrase: reason_phrase.to_string(),
83+
headers: HeaderCollection::new(),
84+
}
85+
}
86+
6587
/// Short-cut to get the Upgrade field value of this request
6688
pub fn upgrade(&self) -> Option<String> {
6789
self.headers.get("Upgrade")

src/ws/message/receive.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use super::dataframe::{WebSocketOpcode, ReadWebSocketDataFrame};
22
use super::WebSocketMessage;
33
use super::mask::mask_data;
44
use std::iter::Iterator;
5-
use std::io::net::tcp::TcpStream;
6-
use std::io::{IoResult, IoError, IoErrorKind};
5+
use std::io::{Stream, IoResult, IoError, IoErrorKind};
76
use std::option::Option;
87
use std::str::from_utf8;
8+
use std::clone::Clone;
99

1010
/// Represents a WebSocket receiver which can receive data from the remote endpoint.
1111
/// All methods are task blocking (but not stream blocking, so you can send and receive concurrently).
@@ -14,11 +14,11 @@ use std::str::from_utf8;
1414
/// ```no_run
1515
/// use websocket::message::WebSocketMessage;
1616
/// # use websocket::WebSocketClient;
17-
/// # use websocket::handshake::WebSocketRequest;
17+
/// # use std::io::TcpStream;
1818
/// # #[allow(unused_must_use)]
1919
/// # fn foo() {
20-
/// # let request = WebSocketRequest::new("ws://127.0.0.1:1234", ["None"].as_slice()).unwrap();
21-
/// # let mut client = WebSocketClient::connect(&request).unwrap();
20+
/// # let stream = TcpStream::connect("127.0.0.1:1234").unwrap();
21+
/// # let mut client = WebSocketClient::new(stream, true);
2222
///
2323
/// let receiver = client.receiver();
2424
///
@@ -46,13 +46,13 @@ use std::str::from_utf8;
4646
/// });
4747
/// # }
4848
/// ```
49-
pub struct WebSocketReceiver {
50-
stream: TcpStream,
49+
pub struct WebSocketReceiver<S: Stream + Clone> {
50+
stream: S,
5151
opcode: Option<WebSocketOpcode>,
5252
data: Vec<u8>,
5353
}
5454

55-
impl WebSocketReceiver {
55+
impl<S: Stream + Clone> WebSocketReceiver<S> {
5656
/// Wait for and accept a message (subjected to the underlying stream timeout).
5757
/// If the received message is fragmented, this function will not return
5858
/// until the final fragment has been received.
@@ -163,14 +163,14 @@ impl WebSocketReceiver {
163163
}
164164

165165
/// Returns an iterator over the incoming messages for/from this client
166-
pub fn incoming(self) -> IncomingMessages {
166+
pub fn incoming(self) -> IncomingMessages<S> {
167167
IncomingMessages {
168168
inc: self,
169169
}
170170
}
171171
}
172172

173-
pub fn new_receiver(stream: TcpStream) -> WebSocketReceiver {
173+
pub fn new_receiver<S: Stream + Clone>(stream: S) -> WebSocketReceiver<S> {
174174
WebSocketReceiver {
175175
stream: stream,
176176
opcode: None,
@@ -179,11 +179,11 @@ pub fn new_receiver(stream: TcpStream) -> WebSocketReceiver {
179179
}
180180

181181
/// An iterator over incoming messages. Blocks the task and always returns Some.
182-
pub struct IncomingMessages {
183-
inc: WebSocketReceiver,
182+
pub struct IncomingMessages<S: Stream + Clone> {
183+
inc: WebSocketReceiver<S>,
184184
}
185185

186-
impl Iterator<IoResult<WebSocketMessage>> for IncomingMessages {
186+
impl<S: Stream + Clone> Iterator<IoResult<WebSocketMessage>> for IncomingMessages<S> {
187187
fn next(&mut self) -> Option<IoResult<WebSocketMessage>> {
188188
Some(self.inc.receive_message())
189189
}

0 commit comments

Comments
 (0)