Skip to content

Commit

Permalink
Implement as a Hyper 0.11 service.
Browse files Browse the repository at this point in the history
  • Loading branch information
Stéphan Kochen committed Aug 7, 2017
1 parent c73c830 commit a8808b2
Show file tree
Hide file tree
Showing 13 changed files with 541 additions and 673 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
language: rust
rust: nightly
after_success: 'curl https://raw.githubusercontent.com/iron/build-doc/master/build-doc.sh | sh '
rust:
- stable
- nightly
26 changes: 0 additions & 26 deletions CONTRIBUTING.md

This file was deleted.

34 changes: 14 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
[package]

name = "staticfile"
version = "0.4.0"
authors = ["Zach Pomerantz <[email protected]>", "Jonathan Reem <[email protected]>"]
description = "Static file serving for Iron."
repository = "https://github.com/iron/staticfile"
name = "hyper-staticfile"
version = "0.1.0"
authors = [
"Zach Pomerantz <[email protected]>",
"Jonathan Reem <[email protected]>",
"Stéphan Kochen <[email protected]>",
]
description = "Static file serving for Hyper 0.11"
repository = "https://github.com/stephank/hyper-staticfile"
license = "MIT"
keywords = ["iron", "web", "http", "file"]

[features]
cache = ["filetime"]
keywords = ["hyper", "web", "http", "file"]

[dependencies]
iron = "0.5"
mount = "0.3"
time = "0.1"
futures = "0.1"
hyper = "0.11"
tokio-core = "0.1"
url = "1.1"

[dependencies.filetime]
version = "0.1"
optional = true

[dev-dependencies]
hyper = "0.10"
router = "0.5"
iron-test = "0.5"
tempdir = "0.3"
10 changes: 7 additions & 3 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
The MIT License (MIT)
Copyright (c) 2017 Stéphan Kochen

Copyright (c) 2014 iron
Based on the `staticfile` crate from the Iron webframework:

> Copyright (c) 2014 iron

All code is covered by the MIT license:

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -18,4 +22,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
52 changes: 3 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,7 @@
staticfile [![Build Status](https://secure.travis-ci.org/iron/staticfile.png?branch=master)](https://travis-ci.org/iron/staticfile)
====
# hyper-staticfile [![Build Status](https://secure.travis-ci.org/stephank/hyper-staticfile.png?branch=master)](https://travis-ci.org/stephank/hyper-staticfile)

> Static file-serving handler for the [Iron](https://github.com/iron/iron) web framework.
## Example

This example uses the [mounting handler][mounting-handler] to serve files from several directories.

```rust
let mut mount = Mount::new();

// Serve the shared JS/CSS at /
mount.mount("/", Static::new(Path::new("target/doc/")));
// Serve the static file docs at /doc/
mount.mount("/doc/", Static::new(Path::new("target/doc/staticfile/")));
// Serve the source code at /src/
mount.mount("/src/", Static::new(Path::new("target/doc/src/staticfile/lib.rs.html")));

Iron::new(mount).http("127.0.0.1:3000").unwrap();
```
Static file-serving for [Hyper 0.11](https://github.com/hyperium/hyper).

See [`examples/doc_server.rs`](examples/doc_server.rs) for a complete example that you can compile.

## Overview

- Serve static files from a given path.

It works well in combination with the [mounting handler][mounting-handler].

## Installation

If you're using a `Cargo.toml` to manage dependencies, just add the `staticfile` package to the `[dependencies]` section of the toml:

```toml
staticfile = "*"
```

Otherwise, `cargo build`, and the rlib will be in your `target` directory.

## [Documentation](http://ironframework.io/doc/staticfile)

Along with the [online documentation](http://ironframework.io/doc/staticfile),
you can build a local copy with `cargo doc`.

## Get Help

One of us ([@reem](https://github.com/reem/), [@zzmp](https://github.com/zzmp/),
[@theptrk](https://github.com/theptrk/), [@mcreinhard](https://github.com/mcreinhard))
is usually on `#iron` on the mozilla irc. Come say hi and ask any questions you might have.
We are also usually on `#rust` and `#rust-webdev`.

[mounting-handler]: https://github.com/iron/mount
## [Documentation](http://docs.rs/hyper-staticfile)
67 changes: 51 additions & 16 deletions examples/doc_server.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,64 @@
extern crate iron;
extern crate staticfile;
extern crate mount;
extern crate futures;
extern crate hyper;
extern crate hyper_staticfile;
extern crate tokio_core;

// This example serves the docs from target/doc/staticfile at /doc/
//
// Run `cargo doc && cargo run --example doc_server`, then
// point your browser to http://127.0.0.1:3000/doc/
// point your browser to http://localhost:3000/

use futures::{Future, BoxFuture, Stream, future};
use hyper::server::{Http, Request, Response, Service};
use hyper_staticfile::Static;
use std::path::Path;
use tokio_core::reactor::{Core, Handle};
use tokio_core::net::{TcpListener};

use iron::Iron;
use staticfile::Static;
use mount::Mount;
struct MainService {
static_: Static,
}

impl MainService {
fn new(handle: &Handle) -> MainService {
MainService {
static_: Static::new(handle, Path::new("target/doc/")),
}
}
}

impl Service for MainService {
type Request = Request;
type Response = Response;
type Error = hyper::Error;
type Future = BoxFuture<Self::Response, Self::Error>;

fn call(&self, req: Request) -> Self::Future {
if req.path() == "/" {
let res = Response::new()
.with_status(hyper::StatusCode::MovedPermanently)
.with_header(hyper::header::Location::new("/hyper_staticfile/"));
future::ok(res).boxed()
} else {
Service::call(&self.static_, req)
}
}
}

fn main() {
let mut mount = Mount::new();
let mut core = Core::new().unwrap();
let handle = core.handle();

// Serve the shared JS/CSS at /
mount.mount("/", Static::new(Path::new("target/doc/")));
// Serve the static file docs at /doc/
mount.mount("/doc/", Static::new(Path::new("target/doc/staticfile/")));
// Serve the source code at /src/
mount.mount("/src/", Static::new(Path::new("target/doc/src/staticfile/lib.rs.html")));
let addr = "127.0.0.1:3000".parse().unwrap();
let listener = TcpListener::bind(&addr, &handle).unwrap();

println!("Doc server running on http://localhost:3000/doc/");
let http = Http::new();
let server = listener.incoming().for_each(|(sock, addr)| {
let s = MainService::new(&handle);
http.bind_connection(&handle, sock, addr, s);
Ok(())
});

Iron::new(mount).http("127.0.0.1:3000").unwrap();
println!("Doc server running on http://localhost:3000/");
core.run(server).unwrap();
}
45 changes: 0 additions & 45 deletions examples/router.rs

This file was deleted.

22 changes: 8 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
#![crate_name = "staticfile"]
#![crate_name = "hyper_staticfile"]
#![deny(missing_docs)]
#![deny(warnings)]

//! Static file-serving handler.
//! Static file-serving for [Hyper 0.11](https://github.com/hyperium/hyper).
extern crate time;

#[cfg(feature = "cache")]
extern crate filetime;

extern crate iron;
extern crate mount;
extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate url;

pub use static_handler::Static;
#[cfg(feature = "cache")]
pub use static_handler::Cache;

mod requested_path;
mod static_handler;
mod static_service;

pub use static_service::Static;
23 changes: 8 additions & 15 deletions src/requested_path.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use iron::Request;
use std::iter::FromIterator;
use hyper::server::Request;
use std::path::{Component, PathBuf, Path};
use std::fs::{self, Metadata};
use std::convert::AsRef;
Expand All @@ -10,7 +9,7 @@ pub struct RequestedPath {
}

#[inline]
fn decode_percents(string: &&str) -> String {
fn decode_percents(string: &str) -> String {
percent_decode(string.as_bytes()).decode_utf8().unwrap().into_owned()
}

Expand All @@ -32,7 +31,7 @@ fn normalize_path(path: &Path) -> PathBuf {

impl RequestedPath {
pub fn new<P: AsRef<Path>>(root_path: P, request: &Request) -> RequestedPath {
let decoded_req_path = PathBuf::from_iter(request.url.path().iter().map(decode_percents));
let decoded_req_path = PathBuf::from(decode_percents(request.path()));
let mut result = root_path.as_ref().to_path_buf();
result.extend(&normalize_path(&decoded_req_path));
RequestedPath { path: result }
Expand All @@ -45,28 +44,22 @@ impl RequestedPath {
// to URLs like http://example.com
// Some middleware may mutate the URL's path to violate this property,
// so the empty list case is handled as a redirect.
let has_trailing_slash = match request.url.path().last() {
Some(&"") => true,
let has_trailing_slash = match request.path().as_bytes().last() {
Some(&b'/') => true,
_ => false,
};

metadata.is_dir() && !has_trailing_slash
}

pub fn get_file(self, metadata: &Metadata) -> Option<PathBuf> {
pub fn get_file(self, metadata: Metadata) -> Option<(PathBuf, Metadata)> {
if metadata.is_file() {
return Some(self.path);
return Some((self.path, metadata));
}

let index_path = self.path.join("index.html");

match fs::metadata(&index_path) {
Ok(m) =>
if m.is_file() {
Some(index_path)
} else {
None
},
Ok(m) => if m.is_file() { Some((index_path, m)) } else { None },
Err(_) => None,
}
}
Expand Down
Loading

0 comments on commit a8808b2

Please sign in to comment.