Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 36 additions & 19 deletions examples/server.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,55 @@
#![feature(macro_rules)]

extern crate hyper;
extern crate debug;

use std::io::{IoResult};
use std::io::util::copy;
use std::io::net::ip::Ipv4Addr;

use hyper::{Get, Post};
use hyper::server::{Server, Handler, Request, Response};
use hyper::server::{Server, Handler, Incoming};
use hyper::header::ContentLength;

struct Echo;

macro_rules! try_continue(
($e:expr) => {{
match $e {
Ok(v) => v,
Err(e) => { println!("Error: {}", e); continue; }
}
}}
)

impl Handler for Echo {
fn handle(&mut self, mut req: Request, mut res: Response) -> IoResult<()> {
match req.uri {
hyper::uri::AbsolutePath(ref path) => match (&req.method, path.as_slice()) {
(&Get, "/") | (&Get, "/echo") => {
let out = b"Try POST /echo";

res.headers.set(ContentLength(out.len()));
try!(res.write(out));
return res.end();
fn handle(self, mut incoming: Incoming) {
for (mut req, mut res) in incoming {
match req.uri {
hyper::uri::AbsolutePath(ref path) => match (&req.method, path.as_slice()) {
(&Get, "/") | (&Get, "/echo") => {
let out = b"Try POST /echo";

res.headers.set(ContentLength(out.len()));
try_continue!(res.write(out));
try_continue!(res.end());
continue;
},
(&Post, "/echo") => (), // fall through, fighting mutable borrows
_ => {
res.status = hyper::status::NotFound;
try_continue!(res.end());
continue;
}
},
(&Post, "/echo") => (), // fall through, fighting mutable borrows
_ => {
res.status = hyper::status::NotFound;
return res.end();
try_continue!(res.end());
continue;
}
},
_ => return res.end()
};
};

try!(copy(&mut req, &mut res));
res.end()
try_continue!(copy(&mut req, &mut res));
try_continue!(res.end());
}
}
}

Expand Down
77 changes: 43 additions & 34 deletions src/server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! HTTP Server
use std::io::net::tcp::{TcpListener, TcpAcceptor};
use std::io::{Acceptor, Listener, IoResult, EndOfFile};
use std::io::{Acceptor, Listener, IoResult, EndOfFile, IncomingConnections};
use std::io::net::ip::{IpAddr, Port, SocketAddr};

pub use self::request::Request;
Expand Down Expand Up @@ -30,42 +30,15 @@ impl Server {
}

/// Binds to a socket, and starts handling connections.
pub fn listen<H: Handler + 'static>(self, mut handler: H) -> IoResult<Listening> {
pub fn listen<H: Handler + 'static>(self, handler: H) -> IoResult<Listening> {
let mut listener = try!(TcpListener::bind(self.ip.to_string().as_slice(), self.port));
let socket = try!(listener.socket_name());
let acceptor = try!(listener.listen());
let worker = acceptor.clone();

spawn(proc() {
let mut acceptor = worker;
for conn in acceptor.incoming() {
match conn {
Ok(stream) => {
debug!("Incoming stream");
let clone = stream.clone();
let req = match Request::new(stream) {
Ok(r) => r,
Err(err) => {
error!("creating Request: {}", err);
continue;
}
};
let mut res = Response::new(clone);
res.version = req.version;
match handler.handle(req, res) {
Ok(..) => debug!("Stream handled"),
Err(e) => {
error!("Error from handler: {}", e)
//TODO try to send a status code
}
}
},
Err(ref e) if e.kind == EndOfFile => break, // server closed
Err(e) => {
error!("Connection failed: {}", e);
}
}
}
handler.handle(Incoming { from: acceptor.incoming() });
});

Ok(Listening {
Expand All @@ -76,6 +49,41 @@ impl Server {

}

/// An iterator over incoming connections, represented as pairs of
/// hyper Requests and Responses.
pub struct Incoming<'a> {
from: IncomingConnections<'a, TcpAcceptor>
}

impl<'a> Iterator<(Request, Response)> for Incoming<'a> {
fn next(&mut self) -> Option<(Request, Response)> {
for conn in self.from {
match conn {
Ok(stream) => {
debug!("Incoming stream");
let clone = stream.clone();
let req = match Request::new(stream) {
Ok(r) => r,
Err(err) => {
error!("creating Request: {}", err);
continue;
}
};
let mut res = Response::new(clone);
res.version = req.version;
return Some((req, res))
},
Err(ref e) if e.kind == EndOfFile => return None, // server closed
Err(e) => {
error!("Connection failed: {}", e);
continue;
}
}
}
None
}
}

/// A listening server, which can later be closed.
pub struct Listening {
acceptor: TcpAcceptor,
Expand All @@ -96,11 +104,12 @@ pub trait Handler: Send {
/// Receives a `Request`/`Response` pair, and should perform some action on them.
///
/// This could reading from the request, and writing to the response.
fn handle(&mut self, req: Request, res: Response) -> IoResult<()>;
fn handle(self, Incoming);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why consume the handler here?

}

impl Handler for fn(Request, Response) -> IoResult<()> {
fn handle(&mut self, req: Request, res: Response) -> IoResult<()> {
(*self)(req, res)
impl Handler for fn(Incoming) {
fn handle(self, incoming: Incoming) {
(self)(incoming)
}
}