diff --git a/dapps/src/api/api.rs b/dapps/src/api/api.rs
index 84db93f63..9a8dfef95 100644
--- a/dapps/src/api/api.rs
+++ b/dapps/src/api/api.rs
@@ -15,23 +15,26 @@
// along with Parity. If not, see .
use std::sync::Arc;
-use hyper::{server, net, Decoder, Encoder, Next};
+use hyper::{server, net, Decoder, Encoder, Next, Control};
use api::types::{App, ApiError};
use api::response::{as_json, as_json_error, ping_response};
use handlers::extract_url;
use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
+use apps::fetcher::ContentFetcher;
#[derive(Clone)]
pub struct RestApi {
local_domain: String,
endpoints: Arc,
+ fetcher: Arc,
}
impl RestApi {
- pub fn new(local_domain: String, endpoints: Arc) -> Box {
+ pub fn new(local_domain: String, endpoints: Arc, fetcher: Arc) -> Box {
Box::new(RestApi {
local_domain: local_domain,
endpoints: endpoints,
+ fetcher: fetcher,
})
}
@@ -43,23 +46,42 @@ impl RestApi {
}
impl Endpoint for RestApi {
- fn to_handler(&self, _path: EndpointPath) -> Box {
- Box::new(RestApiRouter {
- api: self.clone(),
- handler: as_json_error(&ApiError {
- code: "404".into(),
- title: "Not Found".into(),
- detail: "Resource you requested has not been found.".into(),
- }),
- })
+ fn to_async_handler(&self, path: EndpointPath, control: Control) -> Box {
+ Box::new(RestApiRouter::new(self.clone(), path, control))
}
}
struct RestApiRouter {
api: RestApi,
+ path: Option,
+ control: Option,
handler: Box,
}
+impl RestApiRouter {
+ fn new(api: RestApi, path: EndpointPath, control: Control) -> Self {
+ RestApiRouter {
+ path: Some(path),
+ control: Some(control),
+ api: api,
+ handler: as_json_error(&ApiError {
+ code: "404".into(),
+ title: "Not Found".into(),
+ detail: "Resource you requested has not been found.".into(),
+ }),
+ }
+ }
+
+ fn resolve_content(&self, hash: Option<&str>, path: EndpointPath, control: Control) -> Option> {
+ match hash {
+ Some(hash) if self.api.fetcher.contains(hash) => {
+ Some(self.api.fetcher.to_async_handler(path, control))
+ },
+ _ => None
+ }
+ }
+}
+
impl server::Handler for RestApiRouter {
fn on_request(&mut self, request: server::Request) -> Next {
@@ -69,13 +91,18 @@ impl server::Handler for RestApiRouter {
return Next::write();
}
- let url = url.expect("Check for None is above; qed");
+ let url = url.expect("Check for None early-exists above; qed");
+ let path = self.path.take().expect("on_request called only once, and path is always defined in new; qed");
+ let control = self.control.take().expect("on_request called only once, and control is always defined in new; qed");
+
let endpoint = url.path.get(1).map(|v| v.as_str());
+ let hash = url.path.get(2).map(|v| v.as_str());
let handler = endpoint.and_then(|v| match v {
"apps" => Some(as_json(&self.api.list_apps())),
"ping" => Some(ping_response(&self.api.local_domain)),
- _ => None,
+ "content" => self.resolve_content(hash, path, control),
+ _ => None
});
// Overwrite default
diff --git a/dapps/src/endpoint.rs b/dapps/src/endpoint.rs
index 51e863f19..eea7a872f 100644
--- a/dapps/src/endpoint.rs
+++ b/dapps/src/endpoint.rs
@@ -42,7 +42,9 @@ pub type Handler = server::Handler + Send;
pub trait Endpoint : Send + Sync {
fn info(&self) -> Option<&EndpointInfo> { None }
- fn to_handler(&self, path: EndpointPath) -> Box;
+ fn to_handler(&self, _path: EndpointPath) -> Box {
+ panic!("This Endpoint is asynchronous and requires Control object.");
+ }
fn to_async_handler(&self, path: EndpointPath, _control: hyper::Control) -> Box {
self.to_handler(path)
diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs
index 4dcf53a44..edc0bebe5 100644
--- a/dapps/src/lib.rs
+++ b/dapps/src/lib.rs
@@ -196,8 +196,11 @@ impl Server {
let special = Arc::new({
let mut special = HashMap::new();
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone()));
- special.insert(router::SpecialEndpoint::Api, api::RestApi::new(format!("{}", addr), endpoints.clone()));
special.insert(router::SpecialEndpoint::Utils, apps::utils());
+ special.insert(
+ router::SpecialEndpoint::Api,
+ api::RestApi::new(format!("{}", addr), endpoints.clone(), content_fetcher.clone())
+ );
special
});
let hosts = Self::allowed_hosts(hosts, format!("{}", addr));
diff --git a/dapps/src/router/mod.rs b/dapps/src/router/mod.rs
index f54d6bf3d..e3ff6e64f 100644
--- a/dapps/src/router/mod.rs
+++ b/dapps/src/router/mod.rs
@@ -91,7 +91,7 @@ impl server::Handler for Router {
(Some(ref path), _) if self.fetch.contains(&path.app_id) => {
self.fetch.to_async_handler(path.clone(), control)
},
- // Redirection to main page (maybe 404 instead?)
+ // 404 for non-existent content
(Some(ref path), _) if *req.method() == hyper::method::Method::Get => {
let address = apps::redirection_address(path.using_dapps_domains, self.main_page);
Box::new(ContentHandler::error(
@@ -143,7 +143,7 @@ impl Router {
allowed_hosts: Option>,
) -> Self {
- let handler = special.get(&SpecialEndpoint::Api).unwrap().to_handler(EndpointPath::default());
+ let handler = special.get(&SpecialEndpoint::Utils).unwrap().to_handler(EndpointPath::default());
Router {
control: Some(control),
main_page: main_page,
diff --git a/dapps/src/rpc.rs b/dapps/src/rpc.rs
index 4fbc37772..649d283ce 100644
--- a/dapps/src/rpc.rs
+++ b/dapps/src/rpc.rs
@@ -38,10 +38,6 @@ struct RpcEndpoint {
}
impl Endpoint for RpcEndpoint {
- fn to_handler(&self, _path: EndpointPath) -> Box {
- panic!("RPC Endpoint is asynchronous and requires Control object.");
- }
-
fn to_async_handler(&self, _path: EndpointPath, control: hyper::Control) -> Box {
let panic_handler = PanicHandler { handler: self.panic_handler.clone() };
Box::new(ServerHandler::new(
diff --git a/dapps/src/tests/api.rs b/dapps/src/tests/api.rs
index ab0d33726..fc255ec20 100644
--- a/dapps/src/tests/api.rs
+++ b/dapps/src/tests/api.rs
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use tests::helpers::{serve, request};
+use tests::helpers::{serve, serve_with_registrar, request};
#[test]
fn should_return_error() {
@@ -82,3 +82,24 @@ fn should_handle_ping() {
assert_eq!(response.body, "0\n\n".to_owned());
}
+
+#[test]
+fn should_try_to_resolve_dapp() {
+ // given
+ let (server, registrar) = serve_with_registrar();
+
+ // when
+ let response = request(server,
+ "\
+ GET /api/content/1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d HTTP/1.1\r\n\
+ Host: home.parity\r\n\
+ Connection: close\r\n\
+ \r\n\
+ "
+ );
+
+ // then
+ assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
+ assert_eq!(registrar.calls.lock().len(), 2);
+}
+