Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit 8990a81

Browse files
committed
Merge pull request #68 from chris-morgan/ssl
SSL client support
2 parents 9a9fbc3 + 222566f commit 8990a81

File tree

14 files changed

+256
-25
lines changed

14 files changed

+256
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ doc/http/
99
doc/src/http/
1010
lib/
1111
.rust/
12+
Makefile

.hgignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
^doc/src/http/
99
^lib/
1010
^.rust/
11+
^Makefile$

.travis.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ before_install:
66
- sudo apt-get update
77
install:
88
- sudo apt-get install rust-nightly
9+
- git clone https://github.com/sfackler/rust-openssl.git
10+
- cd rust-openssl
11+
- ./configure
12+
- make
13+
- cd ..
14+
- mv rust-openssl ../
915
script:
10-
- make check
11-
- make docs
16+
- ./configure
17+
- make all check docs
1218
after_script:
1319
- curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh

Makefile renamed to Makefile.in

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
SSL_LIB ?= %SSL_LIB%
2+
SSL_CFG ?= %SSL_CFG%
13
RUSTC ?= rustc
24
RUSTDOC ?= rustdoc
35
RUSTPKG ?= rustpkg
4-
RUSTFLAGS ?= -O
6+
RUSTFLAGS ?= -O -L $(SSL_LIB) $(SSL_CFG)
57
RUST_REPOSITORY ?= ../rust
68
RUST_CTAGS ?= $(RUST_REPOSITORY)/src/etc/ctags.rust
79
VERSION=0.1-pre
@@ -12,7 +14,7 @@ codegen_files=\
1214
src/codegen/read_method.rs \
1315
src/codegen/status.rs \
1416

15-
libhttp_so=build/libhttp-9296ff29-0.1-pre.so
17+
libhttp_so=build/.libhttp.timestamp
1618
http_files=\
1719
src/http/lib.rs \
1820
src/http/buffer.rs \
@@ -28,9 +30,20 @@ http_files=\
2830

2931
http: $(libhttp_so)
3032

31-
$(libhttp_so): $(http_files)
33+
Makefile: configure Makefile.in
34+
@echo "configure or Makefile.in changed, regenerating Makefile"
35+
@DOING_RECONFIGURE=1 SSL_LIB="$(SSL_LIB)" SSL_CFG="$(SSL_CFG)" ./configure
36+
@echo
37+
@echo ======================
38+
@echo Please run make again!
39+
@echo ======================
40+
@echo
41+
@exit 1
42+
43+
$(libhttp_so): Makefile $(http_files)
3244
mkdir -p build/
3345
$(RUSTC) $(RUSTFLAGS) src/http/lib.rs --out-dir=build
46+
@touch build/.libhttp.timestamp
3447

3548
all: http examples docs
3649

README.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ At present, all of the example servers serve to http://127.0.0.1:8001/.
6868
Don't expect everything to work well. The server claims HTTP/1.1, but is not
6969
in any way compliant yet.
7070

71+
SSL support
72+
-----------
73+
74+
rust-http can be compiled with or without SSL support.
75+
76+
To compile with SSL support, drop rust-openssl_ in a sibling directory of
77+
rust-http (i.e. ``../rust-openssl`` from this file) and run its ``configure``
78+
and ``make``. rust-http's ``configure`` will then automatically detect it and
79+
you will get SSL support enabled.
80+
81+
To compile rust-http without SSL support, just don’t put rust-openssl_ where it
82+
can find it. You'll then get an ``IoError { kind: InvalidInput, .. }`` if you
83+
try to make an SSL request (e.g. HTTPS).
84+
85+
.. _rust-openssl: https://github.com/sfackler/rust-openssl
86+
7187
Roadmap
7288
-------
7389

configure

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/bin/bash
2+
3+
if [ "$1" = --help ]; then
4+
echo "Usage: ./configure"
5+
echo
6+
echo "Sorry, no command line arguments or anything; it's too hard."
7+
echo
8+
echo "You can, however, use environment variables:"
9+
echo
10+
echo "- WITH_OPENSSL=/path/to/rust-openssl"
11+
echo "- WITH_NSS=/path/to/rust-nss"
12+
echo "- WITHOUT_SSL=1"
13+
echo
14+
echo "If you specify nothing, it will try ../rust-openssl and ../rust-nss."
15+
exit
16+
fi
17+
18+
if [ -n "$DOING_RECONFIGURE" ]; then
19+
echo configure: reapplying existing configuration
20+
# Inherit variables
21+
elif [ -n "$WITH_OPENSSL" ]; then
22+
echo configure: OpenSSL specified, using it.
23+
SSL_LIB="$WITH_OPENSSL/build"
24+
SSL_CFG="--cfg openssl"
25+
elif [ -n "$WITH_NSS" ]; then
26+
echo configure: NSS specified, using it.
27+
SSL_LIB="$WITH_NSS/build"
28+
SSL_CFG="--cfg nss"
29+
elif [ -n "$WITHOUT_SSL" ]; then
30+
echo configure: disabling SSL support
31+
SSL_LIB=
32+
SSL_CFG=
33+
elif [ -d ../rust-openssl ]; then
34+
echo configure: no SSL library selected but OpenSSL found at ../rust-openssl, using it.
35+
SSL_LIB=../rust-openssl/build
36+
SSL_CFG="--cfg openssl"
37+
elif [ -d ../rust-nss ]; then
38+
echo configure: no SSL library selected but NSS found at ../rust-nss, using it.
39+
SSL_LIB=../rust-nss/build
40+
SSL_CFG="--cfg nss"
41+
else
42+
echo configure: no SSL library selected or found
43+
echo configure: you will not be able to access HTTPS URLs
44+
echo configure: check the README for instructions on enabling HTTPS
45+
SSL_LIB=
46+
SSL_CFG=
47+
fi
48+
49+
echo configure: writing Makefile
50+
sed -e "s|%SSL_LIB%|$SSL_LIB|" \
51+
-e "s|%SSL_CFG%|$SSL_CFG|" \
52+
Makefile.in > Makefile
53+
echo configure: done!

src/examples/client/main.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ fn main() {
2323
}
2424

2525
fn make_and_print_request(url: ~str) {
26-
let request = RequestWriter::<TcpStream>::new(Get, from_str(url).expect("Invalid URL :-("))
27-
.unwrap();
26+
let request: RequestWriter = RequestWriter::new(Get, from_str(url).expect("Invalid URL :-("))
27+
.unwrap();
2828

2929
println!("Request");
3030
println!("=======");
@@ -51,6 +51,9 @@ fn make_and_print_request(url: ~str) {
5151
println!(" - {}: {}", header.header_name(), header.header_value());
5252
}
5353
println!("Body:");
54-
let body = response.read_to_end().unwrap();
54+
let body = match response.read_to_end() {
55+
Ok(body) => body,
56+
Err(err) => fail!("Reading response failed: {}", err),
57+
};
5558
println(str::from_utf8(body).expect("Uh oh, response wasn't UTF-8"));
5659
}

src/http/client/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ possible, but it's not elegant convenient yet. (Most notably, no transfer-encodi
1717

1818
pub use self::request::RequestWriter;
1919
pub use self::response::ResponseReader;
20+
pub use self::sslclients::NetworkStream;
2021

2122
pub mod request;
2223
pub mod response;
24+
mod sslclients;

src/http/client/request.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ let response = match request.read_response() {
3535
```
3636
3737
*/
38+
3839
use url;
3940
use url::Url;
4041
use method::Method;
@@ -65,8 +66,9 @@ use client::response::ResponseReader;
6566
}
6667
}*/
6768

68-
pub struct RequestWriter<S> {
69-
// The place to write to (typically a TCP stream, io::net::tcp::TcpStream)
69+
pub struct RequestWriter<S = super::NetworkStream> {
70+
// The place to write to (typically a network stream, which is
71+
// io::net::tcp::TcpStream or an SSL wrapper around that)
7072
stream: Option<BufferedStream<S>>,
7173
headers_written: bool,
7274

@@ -86,6 +88,9 @@ pub struct RequestWriter<S> {
8688

8789
/// The URL being requested.
8890
pub url: Url,
91+
92+
/// Should we use SSL?
93+
use_ssl: bool,
8994
}
9095

9196
/// Low-level HTTP request writing support
@@ -94,9 +99,13 @@ pub struct RequestWriter<S> {
9499
/// take place until writing is completed.
95100
///
96101
/// At present, this only supports making one request per connection.
97-
impl<S: Reader + Writer> RequestWriter<S> {
102+
impl<S: Reader + Writer = super::NetworkStream> RequestWriter<S> {
98103
/// Create a `RequestWriter` writing to the specified location
99104
pub fn new(method: Method, url: Url) -> IoResult<RequestWriter<S>> {
105+
RequestWriter::new_request(method, url, false, true)
106+
}
107+
108+
pub fn new_request(method: Method, url: Url, use_ssl: bool, auto_detect_ssl: bool) -> IoResult<RequestWriter<S>> {
100109
let host = match url.port {
101110
None => Host {
102111
name: url.host.to_owned(),
@@ -125,10 +134,12 @@ impl<S: Reader + Writer> RequestWriter<S> {
125134
// TODO: Error handling
126135
let addr = addr.unwrap();
127136

128-
let port = url.port.clone().unwrap_or(~"80");
129-
let port = from_str(port);
130-
// TODO: Error handling
131-
let port = port.unwrap();
137+
// Default to 80, using the port specified or 443 if the protocol is HTTPS.
138+
let port = match url.port {
139+
Some(ref p) => from_str(*p).expect("You didn’t aught to give a bad port!"),
140+
// FIXME: case insensitivity?
141+
None => if url.scheme.as_slice() == "https" { 443 } else { 80 },
142+
};
132143

133144
Ok(SocketAddr {
134145
ip: addr,
@@ -143,13 +154,20 @@ impl<S: Reader + Writer> RequestWriter<S> {
143154
headers: ~HeaderCollection::new(),
144155
method: method,
145156
url: url,
157+
use_ssl: use_ssl,
146158
};
159+
160+
if auto_detect_ssl {
161+
// FIXME: case insensitivity?
162+
request.use_ssl = request.url.scheme.as_slice() == "https";
163+
}
164+
147165
request.headers.host = Some(host);
148166
Ok(request)
149167
}
150168
}
151169

152-
impl<S: Connecter + Reader + Writer> RequestWriter<S> {
170+
impl<S: Connecter + Reader + Writer = super::NetworkStream> RequestWriter<S> {
153171

154172
/// Connect to the remote host if not already connected.
155173
pub fn try_connect(&mut self) -> IoResult<()> {
@@ -169,7 +187,7 @@ impl<S: Connecter + Reader + Writer> RequestWriter<S> {
169187

170188
self.stream = match self.remote_addr {
171189
Some(addr) => {
172-
let stream = try!(Connecter::connect(addr));
190+
let stream = try!(Connecter::connect(addr, self.url.host, self.use_ssl));
173191
Some(BufferedStream::new(stream))
174192
},
175193
None => fail!("connect() called before remote_addr was set"),
@@ -235,7 +253,7 @@ impl<S: Connecter + Reader + Writer> RequestWriter<S> {
235253
}
236254

237255
/// Write the request body. Note that any calls to `write()` will cause the headers to be sent.
238-
impl<S: Reader + Writer + Connecter> Writer for RequestWriter<S> {
256+
impl<S: Reader + Writer + Connecter = super::NetworkStream> Writer for RequestWriter<S> {
239257
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
240258
if !self.headers_written {
241259
try!(self.write_headers());

src/http/client/sslclients/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//! SSL client support.
2+
//!
3+
//! Which particular library is used depends upon the configuration used at
4+
//! compile time; at present it can only be OpenSSL (`--cfg openssl`); without
5+
//! that, you won't be able to use SSL (an attempt to make an HTTPS connection
6+
//! will return an error).
7+
8+
#[cfg(openssl)]
9+
pub use self::openssl::NetworkStream;
10+
#[cfg(not(openssl))]
11+
pub use self::none::NetworkStream;
12+
13+
#[cfg(openssl)]
14+
mod openssl;
15+
#[cfg(not(openssl))]
16+
mod none;

src/http/client/sslclients/none.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//! No SSL support (neither OpenSSL nor NSS were compiled in).
2+
3+
use std::io::net::ip::SocketAddr;
4+
use std::io::net::tcp::TcpStream;
5+
use std::io::{IoResult, IoError, InvalidInput};
6+
use connecter::Connecter;
7+
8+
/// A TCP stream, plain text and with no SSL support.
9+
///
10+
/// This build was made *without* SSL support; if you attempt to make an SSL
11+
/// connection you will receive an `IoError` of the `InvalidInput` kind.
12+
///
13+
/// (To build with SSL support, use ``--cfg openssl`` or ``--cfg nss``.)
14+
pub enum NetworkStream {
15+
priv NormalStream(TcpStream),
16+
}
17+
18+
impl Connecter for NetworkStream {
19+
fn connect(addr: SocketAddr, _host: &str, use_ssl: bool) -> IoResult<NetworkStream> {
20+
if use_ssl {
21+
Err(IoError {
22+
kind: InvalidInput,
23+
desc: "http crate was compiled without SSL support",
24+
detail: None,
25+
})
26+
} else {
27+
let stream = try!(TcpStream::connect(addr));
28+
Ok(NormalStream(stream))
29+
}
30+
}
31+
}
32+
33+
impl Reader for NetworkStream {
34+
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
35+
match *self {
36+
NormalStream(ref mut ns) => ns.read(buf),
37+
}
38+
}
39+
}
40+
41+
impl Writer for NetworkStream {
42+
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
43+
match *self {
44+
NormalStream(ref mut ns) => ns.write(buf),
45+
}
46+
}
47+
48+
fn flush(&mut self) -> IoResult<()> {
49+
match *self {
50+
NormalStream(ref mut ns) => ns.flush(),
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)