Refactoring dapps to support API endpoints. (#1542)
* Refactoring dapps to support API endpoints. * Using ContentHandler for unauthorized requests
This commit is contained in:
parent
bcb63bce12
commit
a8b26e2cb5
@ -25,8 +25,8 @@ mod inner {
|
|||||||
pub fn main() {
|
pub fn main() {
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
let src = Path::new("./src/api/mod.rs.in");
|
let src = Path::new("./src/api/types.rs.in");
|
||||||
let dst = Path::new(&out_dir).join("mod.rs");
|
let dst = Path::new(&out_dir).join("types.rs");
|
||||||
|
|
||||||
let mut registry = syntex::Registry::new();
|
let mut registry = syntex::Registry::new();
|
||||||
|
|
||||||
|
@ -15,38 +15,16 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use endpoint::{Endpoint, Endpoints, EndpointInfo, Handler, EndpointPath};
|
use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
|
||||||
|
use api::types::{App, ApiError};
|
||||||
use api::response::as_json;
|
use api::response::{as_json, as_json_error};
|
||||||
|
use hyper::{server, net, Decoder, Encoder, Next};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct RestApi {
|
pub struct RestApi {
|
||||||
endpoints: Arc<Endpoints>,
|
endpoints: Arc<Endpoints>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct App {
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub version: String,
|
|
||||||
pub author: String,
|
|
||||||
#[serde(rename="iconUrl")]
|
|
||||||
pub icon_url: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {
|
|
||||||
fn from_info(id: &str, info: &EndpointInfo) -> Self {
|
|
||||||
App {
|
|
||||||
id: id.to_owned(),
|
|
||||||
name: info.name.to_owned(),
|
|
||||||
description: info.description.to_owned(),
|
|
||||||
version: info.version.to_owned(),
|
|
||||||
author: info.author.to_owned(),
|
|
||||||
icon_url: info.icon_url.to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RestApi {
|
impl RestApi {
|
||||||
pub fn new(endpoints: Arc<Endpoints>) -> Box<Endpoint> {
|
pub fn new(endpoints: Arc<Endpoints>) -> Box<Endpoint> {
|
||||||
Box::new(RestApi {
|
Box::new(RestApi {
|
||||||
@ -63,7 +41,39 @@ impl RestApi {
|
|||||||
|
|
||||||
impl Endpoint for RestApi {
|
impl Endpoint for RestApi {
|
||||||
fn to_handler(&self, _path: EndpointPath) -> Box<Handler> {
|
fn to_handler(&self, _path: EndpointPath) -> Box<Handler> {
|
||||||
as_json(&self.list_apps())
|
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(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RestApiRouter {
|
||||||
|
api: RestApi,
|
||||||
|
handler: Box<Handler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl server::Handler<net::HttpStream> for RestApiRouter {
|
||||||
|
|
||||||
|
fn on_request(&mut self, _request: server::Request<net::HttpStream>) -> Next {
|
||||||
|
self.handler = as_json(&self.api.list_apps());
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_request_readable(&mut self, decoder: &mut Decoder<net::HttpStream>) -> Next {
|
||||||
|
self.handler.on_request_readable(decoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
||||||
|
self.handler.on_response(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response_writable(&mut self, encoder: &mut Encoder<net::HttpStream>) -> Next {
|
||||||
|
self.handler.on_response_writable(encoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -16,13 +16,12 @@
|
|||||||
|
|
||||||
//! REST API
|
//! REST API
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
|
||||||
#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))]
|
#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))]
|
||||||
#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))]
|
#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))]
|
||||||
|
|
||||||
#[cfg(feature = "serde_macros")]
|
mod api;
|
||||||
include!("mod.rs.in");
|
mod response;
|
||||||
|
mod types;
|
||||||
#[cfg(not(feature = "serde_macros"))]
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/mod.rs"));
|
|
||||||
|
|
||||||
|
pub use self::api::RestApi;
|
||||||
|
pub use self::types::App;
|
||||||
|
@ -16,8 +16,13 @@
|
|||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use endpoint::{ContentHandler, Handler};
|
use endpoint::Handler;
|
||||||
|
use handlers::ContentHandler;
|
||||||
|
|
||||||
pub fn as_json<T : Serialize>(val: &T) -> Box<Handler> {
|
pub fn as_json<T : Serialize>(val: &T) -> Box<Handler> {
|
||||||
Box::new(ContentHandler::new(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
|
Box::new(ContentHandler::ok(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_json_error<T : Serialize>(val: &T) -> Box<Handler> {
|
||||||
|
Box::new(ContentHandler::not_found(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mod api;
|
#[cfg(feature = "serde_macros")]
|
||||||
mod response;
|
include!("types.rs.in");
|
||||||
|
|
||||||
|
#[cfg(not(feature = "serde_macros"))]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/types.rs"));
|
||||||
|
|
||||||
|
|
||||||
pub use self::api::RestApi;
|
|
||||||
pub use self::api::App;
|
|
51
dapps/src/api/types.rs.in
Normal file
51
dapps/src/api/types.rs.in
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 endpoint::EndpointInfo;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct App {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub version: String,
|
||||||
|
pub author: String,
|
||||||
|
#[serde(rename="iconUrl")]
|
||||||
|
pub icon_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
/// Creates `App` instance from `EndpointInfo` and `id`.
|
||||||
|
pub fn from_info(id: &str, info: &EndpointInfo) -> Self {
|
||||||
|
App {
|
||||||
|
id: id.to_owned(),
|
||||||
|
name: info.name.to_owned(),
|
||||||
|
description: info.description.to_owned(),
|
||||||
|
version: info.version.to_owned(),
|
||||||
|
author: info.author.to_owned(),
|
||||||
|
icon_url: info.icon_url.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct ApiError {
|
||||||
|
pub code: String,
|
||||||
|
pub title: String,
|
||||||
|
pub detail: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -16,11 +16,7 @@
|
|||||||
|
|
||||||
//! URL Endpoint traits
|
//! URL Endpoint traits
|
||||||
|
|
||||||
use hyper::status::StatusCode;
|
use hyper::{server, net};
|
||||||
use hyper::{header, server, Decoder, Encoder, Next};
|
|
||||||
use hyper::net::HttpStream;
|
|
||||||
|
|
||||||
use std::io::Write;
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default, Clone)]
|
#[derive(Debug, PartialEq, Default, Clone)]
|
||||||
@ -42,58 +38,8 @@ pub struct EndpointInfo {
|
|||||||
pub trait Endpoint : Send + Sync {
|
pub trait Endpoint : Send + Sync {
|
||||||
fn info(&self) -> Option<&EndpointInfo> { None }
|
fn info(&self) -> Option<&EndpointInfo> { None }
|
||||||
|
|
||||||
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream> + Send>;
|
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<net::HttpStream> + Send>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
|
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
|
||||||
pub type Handler = server::Handler<HttpStream> + Send;
|
pub type Handler = server::Handler<net::HttpStream> + Send;
|
||||||
|
|
||||||
pub struct ContentHandler {
|
|
||||||
content: String,
|
|
||||||
mimetype: String,
|
|
||||||
write_pos: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContentHandler {
|
|
||||||
pub fn new(content: String, mimetype: String) -> Self {
|
|
||||||
ContentHandler {
|
|
||||||
content: content,
|
|
||||||
mimetype: mimetype,
|
|
||||||
write_pos: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for ContentHandler {
|
|
||||||
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
|
||||||
res.set_status(StatusCode::Ok);
|
|
||||||
res.headers_mut().set(header::ContentType(self.mimetype.parse().unwrap()));
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
|
||||||
let bytes = self.content.as_bytes();
|
|
||||||
if self.write_pos == bytes.len() {
|
|
||||||
return Next::end();
|
|
||||||
}
|
|
||||||
|
|
||||||
match encoder.write(&bytes[self.write_pos..]) {
|
|
||||||
Ok(bytes) => {
|
|
||||||
self.write_pos += bytes;
|
|
||||||
Next::write()
|
|
||||||
},
|
|
||||||
Err(e) => match e.kind() {
|
|
||||||
::std::io::ErrorKind::WouldBlock => Next::write(),
|
|
||||||
_ => Next::end()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
44
dapps/src/handlers/auth.rs
Normal file
44
dapps/src/handlers/auth.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
//! Authorization Handlers
|
||||||
|
|
||||||
|
use hyper::{server, Decoder, Encoder, Next};
|
||||||
|
use hyper::net::HttpStream;
|
||||||
|
use hyper::status::StatusCode;
|
||||||
|
|
||||||
|
pub struct AuthRequiredHandler;
|
||||||
|
|
||||||
|
impl server::Handler<HttpStream> for AuthRequiredHandler {
|
||||||
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
||||||
|
res.set_status(StatusCode::Unauthorized);
|
||||||
|
res.headers_mut().set_raw("WWW-Authenticate", vec![b"Basic realm=\"Parity\"".to_vec()]);
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response_writable(&mut self, _encoder: &mut Encoder<HttpStream>) -> Next {
|
||||||
|
Next::end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
92
dapps/src/handlers/content.rs
Normal file
92
dapps/src/handlers/content.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
//! Simple Content Handler
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
use hyper::{header, server, Decoder, Encoder, Next};
|
||||||
|
use hyper::net::HttpStream;
|
||||||
|
use hyper::status::StatusCode;
|
||||||
|
|
||||||
|
pub struct ContentHandler {
|
||||||
|
code: StatusCode,
|
||||||
|
content: String,
|
||||||
|
mimetype: String,
|
||||||
|
write_pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContentHandler {
|
||||||
|
pub fn ok(content: String, mimetype: String) -> Self {
|
||||||
|
ContentHandler {
|
||||||
|
code: StatusCode::Ok,
|
||||||
|
content: content,
|
||||||
|
mimetype: mimetype,
|
||||||
|
write_pos: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn not_found(content: String, mimetype: String) -> Self {
|
||||||
|
ContentHandler {
|
||||||
|
code: StatusCode::NotFound,
|
||||||
|
content: content,
|
||||||
|
mimetype: mimetype,
|
||||||
|
write_pos: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(code: StatusCode, content: String, mimetype: String) -> Self {
|
||||||
|
ContentHandler {
|
||||||
|
code: code,
|
||||||
|
content: content,
|
||||||
|
mimetype: mimetype,
|
||||||
|
write_pos: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl server::Handler<HttpStream> for ContentHandler {
|
||||||
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
||||||
|
res.set_status(self.code);
|
||||||
|
res.headers_mut().set(header::ContentType(self.mimetype.parse().unwrap()));
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
||||||
|
let bytes = self.content.as_bytes();
|
||||||
|
if self.write_pos == bytes.len() {
|
||||||
|
return Next::end();
|
||||||
|
}
|
||||||
|
|
||||||
|
match encoder.write(&bytes[self.write_pos..]) {
|
||||||
|
Ok(bytes) => {
|
||||||
|
self.write_pos += bytes;
|
||||||
|
Next::write()
|
||||||
|
},
|
||||||
|
Err(e) => match e.kind() {
|
||||||
|
::std::io::ErrorKind::WouldBlock => Next::write(),
|
||||||
|
_ => Next::end()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
dapps/src/handlers/mod.rs
Normal file
25
dapps/src/handlers/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
//! Hyper handlers implementations.
|
||||||
|
|
||||||
|
mod auth;
|
||||||
|
mod content;
|
||||||
|
mod redirect;
|
||||||
|
|
||||||
|
pub use self::auth::AuthRequiredHandler;
|
||||||
|
pub use self::content::ContentHandler;
|
||||||
|
pub use self::redirect::Redirection;
|
@ -59,6 +59,7 @@ mod endpoint;
|
|||||||
mod apps;
|
mod apps;
|
||||||
mod page;
|
mod page;
|
||||||
mod router;
|
mod router;
|
||||||
|
mod handlers;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
mod api;
|
mod api;
|
||||||
mod proxypac;
|
mod proxypac;
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
//! Serving ProxyPac file
|
//! Serving ProxyPac file
|
||||||
|
|
||||||
use endpoint::{Endpoint, Handler, ContentHandler, EndpointPath};
|
use endpoint::{Endpoint, Handler, EndpointPath};
|
||||||
|
use handlers::ContentHandler;
|
||||||
use apps::DAPPS_DOMAIN;
|
use apps::DAPPS_DOMAIN;
|
||||||
|
|
||||||
pub struct ProxyPac;
|
pub struct ProxyPac;
|
||||||
@ -41,7 +42,7 @@ function FindProxyForURL(url, host) {{
|
|||||||
}}
|
}}
|
||||||
"#,
|
"#,
|
||||||
DAPPS_DOMAIN, path.host, path.port);
|
DAPPS_DOMAIN, path.host, path.port);
|
||||||
Box::new(ContentHandler::new(content, "application/javascript".to_owned()))
|
Box::new(ContentHandler::ok(content, "application/javascript".to_owned()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,24 +16,23 @@
|
|||||||
|
|
||||||
//! HTTP Authorization implementations
|
//! HTTP Authorization implementations
|
||||||
|
|
||||||
use std::io::Write;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use hyper::{header, server, Decoder, Encoder, Next};
|
use hyper::{server, net, header, status};
|
||||||
use hyper::net::HttpStream;
|
use endpoint::Handler;
|
||||||
use hyper::status::StatusCode;
|
use handlers::{AuthRequiredHandler, ContentHandler};
|
||||||
|
|
||||||
/// Authorization result
|
/// Authorization result
|
||||||
pub enum Authorized {
|
pub enum Authorized {
|
||||||
/// Authorization was successful.
|
/// Authorization was successful.
|
||||||
Yes,
|
Yes,
|
||||||
/// Unsuccessful authorization. Handler for further work is returned.
|
/// Unsuccessful authorization. Handler for further work is returned.
|
||||||
No(Box<server::Handler<HttpStream> + Send>),
|
No(Box<Handler>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authorization interface
|
/// Authorization interface
|
||||||
pub trait Authorization : Send + Sync {
|
pub trait Authorization : Send + Sync {
|
||||||
/// Checks if authorization is valid.
|
/// Checks if authorization is valid.
|
||||||
fn is_authorized(&self, req: &server::Request<HttpStream>)-> Authorized;
|
fn is_authorized(&self, req: &server::Request<net::HttpStream>)-> Authorized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HTTP Basic Authorization handler
|
/// HTTP Basic Authorization handler
|
||||||
@ -45,18 +44,22 @@ pub struct HttpBasicAuth {
|
|||||||
pub struct NoAuth;
|
pub struct NoAuth;
|
||||||
|
|
||||||
impl Authorization for NoAuth {
|
impl Authorization for NoAuth {
|
||||||
fn is_authorized(&self, _req: &server::Request<HttpStream>)-> Authorized {
|
fn is_authorized(&self, _req: &server::Request<net::HttpStream>)-> Authorized {
|
||||||
Authorized::Yes
|
Authorized::Yes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Authorization for HttpBasicAuth {
|
impl Authorization for HttpBasicAuth {
|
||||||
fn is_authorized(&self, req: &server::Request<HttpStream>) -> Authorized {
|
fn is_authorized(&self, req: &server::Request<net::HttpStream>) -> Authorized {
|
||||||
let auth = self.check_auth(&req);
|
let auth = self.check_auth(&req);
|
||||||
|
|
||||||
match auth {
|
match auth {
|
||||||
Access::Denied => {
|
Access::Denied => {
|
||||||
Authorized::No(Box::new(UnauthorizedHandler { write_pos: 0 }))
|
Authorized::No(Box::new(ContentHandler::new(
|
||||||
|
status::StatusCode::Unauthorized,
|
||||||
|
"<h1>Unauthorized</h1>".into(),
|
||||||
|
"text/html".into(),
|
||||||
|
)))
|
||||||
},
|
},
|
||||||
Access::AuthRequired => {
|
Access::AuthRequired => {
|
||||||
Authorized::No(Box::new(AuthRequiredHandler))
|
Authorized::No(Box::new(AuthRequiredHandler))
|
||||||
@ -89,7 +92,7 @@ impl HttpBasicAuth {
|
|||||||
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
|
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_auth(&self, req: &server::Request<HttpStream>) -> Access {
|
fn check_auth(&self, req: &server::Request<net::HttpStream>) -> Access {
|
||||||
match req.headers().get::<header::Authorization<header::Basic>>() {
|
match req.headers().get::<header::Authorization<header::Basic>>() {
|
||||||
Some(&header::Authorization(
|
Some(&header::Authorization(
|
||||||
header::Basic { ref username, password: Some(ref password) }
|
header::Basic { ref username, password: Some(ref password) }
|
||||||
@ -99,63 +102,3 @@ impl HttpBasicAuth {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UnauthorizedHandler {
|
|
||||||
write_pos: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for UnauthorizedHandler {
|
|
||||||
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
|
||||||
res.set_status(StatusCode::Unauthorized);
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
|
||||||
let response = "Unauthorized".as_bytes();
|
|
||||||
|
|
||||||
if self.write_pos == response.len() {
|
|
||||||
return Next::end();
|
|
||||||
}
|
|
||||||
|
|
||||||
match encoder.write(&response[self.write_pos..]) {
|
|
||||||
Ok(bytes) => {
|
|
||||||
self.write_pos += bytes;
|
|
||||||
Next::write()
|
|
||||||
},
|
|
||||||
Err(e) => match e.kind() {
|
|
||||||
::std::io::ErrorKind::WouldBlock => Next::write(),
|
|
||||||
_ => Next::end()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AuthRequiredHandler;
|
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for AuthRequiredHandler {
|
|
||||||
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
|
||||||
res.set_status(StatusCode::Unauthorized);
|
|
||||||
res.headers_mut().set_raw("WWW-Authenticate", vec![b"Basic realm=\"Parity\"".to_vec()]);
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response_writable(&mut self, _encoder: &mut Encoder<HttpStream>) -> Next {
|
|
||||||
Next::end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
//! Processes request handling authorization and dispatching it to proper application.
|
//! Processes request handling authorization and dispatching it to proper application.
|
||||||
|
|
||||||
mod url;
|
mod url;
|
||||||
mod redirect;
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
|
||||||
use DAPPS_DOMAIN;
|
use DAPPS_DOMAIN;
|
||||||
@ -33,7 +32,7 @@ use apps;
|
|||||||
use endpoint::{Endpoint, Endpoints, EndpointPath};
|
use endpoint::{Endpoint, Endpoints, EndpointPath};
|
||||||
use self::url::Url;
|
use self::url::Url;
|
||||||
use self::auth::{Authorization, Authorized};
|
use self::auth::{Authorization, Authorized};
|
||||||
use self::redirect::Redirection;
|
use handlers::Redirection;
|
||||||
|
|
||||||
/// Special endpoints are accessible on every domain (every dapp)
|
/// Special endpoints are accessible on every domain (every dapp)
|
||||||
#[derive(Debug, PartialEq, Hash, Eq)]
|
#[derive(Debug, PartialEq, Hash, Eq)]
|
||||||
|
Loading…
Reference in New Issue
Block a user