// Copyright 2015-2017 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity. If not, see <http://www.gnu.org/licenses/>. use page::{handler, PageCache}; use std::sync::Arc; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; use parity_dapps::{WebApp, File, Info}; pub struct PageEndpoint<T : WebApp + 'static> { /// Content of the files pub app: Arc<T>, /// Prefix to strip from the path (when `None` deducted from `app_id`) pub prefix: Option<String>, /// Safe to be loaded in frame by other origin. (use wisely!) safe_to_embed_on: Option<(String, u16)>, info: EndpointInfo, } impl<T: WebApp + 'static> PageEndpoint<T> { /// Creates new `PageEndpoint` for builtin (compile time) Dapp. pub fn new(app: T) -> Self { let info = app.info(); PageEndpoint { app: Arc::new(app), prefix: None, safe_to_embed_on: None, info: EndpointInfo::from(info), } } /// Create new `PageEndpoint` and specify prefix that should be removed before looking for a file. /// It's used only for special endpoints (i.e. `/parity-utils/`) /// So `/parity-utils/inject.js` will be resolved to `/inject.js` is prefix is set. pub fn with_prefix(app: T, prefix: String) -> Self { let info = app.info(); PageEndpoint { app: Arc::new(app), prefix: Some(prefix), safe_to_embed_on: None, info: EndpointInfo::from(info), } } /// Creates new `PageEndpoint` which can be safely used in iframe /// even from different origin. It might be dangerous (clickjacking). /// Use wisely! pub fn new_safe_to_embed(app: T, address: Option<(String, u16)>) -> Self { let info = app.info(); PageEndpoint { app: Arc::new(app), prefix: None, safe_to_embed_on: address, info: EndpointInfo::from(info), } } } impl<T: WebApp> Endpoint for PageEndpoint<T> { fn info(&self) -> Option<&EndpointInfo> { Some(&self.info) } fn to_handler(&self, path: EndpointPath) -> Box<Handler> { Box::new(handler::PageHandler { app: BuiltinDapp::new(self.app.clone()), prefix: self.prefix.clone(), path: path, file: handler::ServedFile::new(self.safe_to_embed_on.clone()), cache: PageCache::Disabled, safe_to_embed_on: self.safe_to_embed_on.clone(), }) } } impl From<Info> for EndpointInfo { fn from(info: Info) -> Self { EndpointInfo { name: info.name.into(), description: info.description.into(), author: info.author.into(), icon_url: info.icon_url.into(), version: info.version.into(), } } } struct BuiltinDapp<T: WebApp + 'static> { app: Arc<T>, } impl<T: WebApp + 'static> BuiltinDapp<T> { fn new(app: Arc<T>) -> Self { BuiltinDapp { app: app, } } } impl<T: WebApp + 'static> handler::Dapp for BuiltinDapp<T> { type DappFile = BuiltinDappFile<T>; fn file(&self, path: &str) -> Option<Self::DappFile> { self.app.file(path).map(|_| { BuiltinDappFile { app: self.app.clone(), path: path.into(), write_pos: 0, } }) } } struct BuiltinDappFile<T: WebApp + 'static> { app: Arc<T>, path: String, write_pos: usize, } impl<T: WebApp + 'static> BuiltinDappFile<T> { fn file(&self) -> &File { self.app.file(&self.path).expect("Check is done when structure is created.") } } impl<T: WebApp + 'static> handler::DappFile for BuiltinDappFile<T> { fn content_type(&self) -> &str { self.file().content_type } fn is_drained(&self) -> bool { self.write_pos == self.file().content.len() } fn next_chunk(&mut self) -> &[u8] { &self.file().content[self.write_pos..] } fn bytes_written(&mut self, bytes: usize) { self.write_pos += bytes; } }