1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-03 09:36:36 +02:00

Compare commits

..

8 Commits

Author SHA1 Message Date
a342b1289d prep awc release 2019-06-05 08:14:00 +06:00
38f04b75a7 update deps 2019-06-04 22:36:10 +06:00
a771540b16 prepare actix-web-codegen release 2019-06-04 22:33:43 +06:00
cf217d35a8 Added HEAD, CONNECT, OPTIONS and TRACE to the codegen (#886)
* Added HEAD, CONNECT, OPTIONS and TRACE to the codegen

* Add new macros to use statement

* Add patch to supported codegen http methods

* Update CHANGES.md

Added head, options, trace, connect and patch codegen changes to CHANGES.md
2019-06-04 22:30:43 +06:00
0e138e111f add external resource support on scope level 2019-06-03 23:41:32 +06:00
1fce4876f3 Scope configuration (#880)
* WIP: Scope configuarion

* Extensions: Fix into_iter()

* Scope: Fix tests

* Add ScopeConfig to web

Committing from mobile, if this doesn't look good it's because I haven't tested it...

* Scope Config: Use ServiceConfig instead

* Scope: Switch to ServiceConfig in doc

* ScopeConfig: Remove unnecessary changes, handle the case when data is empty

* ScopeConfig: Remove changes from actix-http
2019-06-03 23:12:37 +06:00
4a179d1ae1 prepare actix-session release 2019-06-03 10:52:43 +06:00
a780ea10e9 Guard cookie mod by cookie-session feature (#883)
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2019-06-03 10:30:30 +06:00
15 changed files with 278 additions and 18 deletions

View File

@ -1,14 +1,18 @@
# Changes
## [1.0.0] - 2019-05-xx
## [1.0.0] - 2019-06-xx
### Add
* Add `Scope::configure()` method.
* Add `ServiceRequest::set_payload()` method.
* Add `test::TestRequest::set_json()` convenience method to automatically
serialize data and set header in test requests.
* Add macros for head, options, trace, connect and patch http methods
### Changes
* Drop an unnecessary `Option<_>` indirection around `ServerBuilder` from `HttpServer`. #863

View File

@ -72,11 +72,11 @@ actix-service = "0.4.0"
actix-utils = "0.4.1"
actix-router = "0.1.5"
actix-rt = "0.2.2"
actix-web-codegen = "0.1.1"
actix-http = "0.2.2"
actix-web-codegen = "0.1.2"
actix-http = "0.2.3"
actix-server = "0.5.1"
actix-server-config = "0.1.1"
actix-threadpool = "0.1.0"
actix-threadpool = "0.1.1"
awc = { version = "0.2.0", optional = true }
bytes = "0.4"
@ -100,9 +100,9 @@ openssl = { version="0.10", optional = true }
rustls = { version = "0.15", optional = true }
[dev-dependencies]
actix-http = { version = "0.2.2", features=["ssl", "brotli", "flate2-zlib"] }
actix-http = { version = "0.2.3", features=["ssl", "brotli", "flate2-zlib"] }
actix-http-test = { version = "0.2.0", features=["ssl"] }
actix-files = { version = "0.1.0" }
actix-files = { version = "0.1.1" }
rand = "0.6"
env_logger = "0.6"
serde_derive = "1.0"

View File

@ -1,5 +1,9 @@
# Changes
## [0.1.1] - 2019-06-03
* Fix optional cookie session support
## [0.1.0] - 2019-05-18
* Use actix-web 1.0.0-rc

View File

@ -1,6 +1,6 @@
[package]
name = "actix-session"
version = "0.1.0"
version = "0.1.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Session for actix web framework."
readme = "README.md"

View File

@ -52,7 +52,9 @@ use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json;
#[cfg(feature = "cookie-session")]
mod cookie;
#[cfg(feature = "cookie-session")]
pub use crate::cookie::CookieSession;
/// The high-level interface you use to modify session data.

View File

@ -1,5 +1,9 @@
# Changes
## [0.1.2] - 2019-06-04
* Add macros for head, options, trace, connect and patch http methods
## [0.1.1] - 2019-06-01
* Add syn "extra-traits" feature

View File

@ -1,6 +1,6 @@
[package]
name = "actix-web-codegen"
version = "0.1.1"
version = "0.1.2"
description = "Actix web proc macros"
readme = "README.md"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]

View File

@ -11,6 +11,11 @@
//! - [post](attr.post.html)
//! - [put](attr.put.html)
//! - [delete](attr.delete.html)
//! - [head](attr.head.html)
//! - [connect](attr.connect.html)
//! - [options](attr.options.html)
//! - [trace](attr.trace.html)
//! - [patch](attr.patch.html)
//!
//! ### Attributes:
//!
@ -92,3 +97,63 @@ pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
let gen = route::Args::new(&args, input, route::GuardType::Delete);
gen.generate()
}
/// Creates route handler with `HEAD` method guard.
///
/// Syntax: `#[head("path"[, attributes])]`
///
/// Attributes are the same as in [head](attr.head.html)
#[proc_macro_attribute]
pub fn head(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as syn::AttributeArgs);
let gen = route::Args::new(&args, input, route::GuardType::Head);
gen.generate()
}
/// Creates route handler with `CONNECT` method guard.
///
/// Syntax: `#[connect("path"[, attributes])]`
///
/// Attributes are the same as in [connect](attr.connect.html)
#[proc_macro_attribute]
pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as syn::AttributeArgs);
let gen = route::Args::new(&args, input, route::GuardType::Connect);
gen.generate()
}
/// Creates route handler with `OPTIONS` method guard.
///
/// Syntax: `#[options("path"[, attributes])]`
///
/// Attributes are the same as in [options](attr.options.html)
#[proc_macro_attribute]
pub fn options(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as syn::AttributeArgs);
let gen = route::Args::new(&args, input, route::GuardType::Options);
gen.generate()
}
/// Creates route handler with `TRACE` method guard.
///
/// Syntax: `#[trace("path"[, attributes])]`
///
/// Attributes are the same as in [trace](attr.trace.html)
#[proc_macro_attribute]
pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as syn::AttributeArgs);
let gen = route::Args::new(&args, input, route::GuardType::Trace);
gen.generate()
}
/// Creates route handler with `PATCH` method guard.
///
/// Syntax: `#[patch("path"[, attributes])]`
///
/// Attributes are the same as in [patch](attr.patch.html)
#[proc_macro_attribute]
pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as syn::AttributeArgs);
let gen = route::Args::new(&args, input, route::GuardType::Patch);
gen.generate()
}

View File

@ -25,6 +25,11 @@ pub enum GuardType {
Post,
Put,
Delete,
Head,
Connect,
Options,
Trace,
Patch
}
impl fmt::Display for GuardType {
@ -34,6 +39,11 @@ impl fmt::Display for GuardType {
&GuardType::Post => write!(f, "Post"),
&GuardType::Put => write!(f, "Put"),
&GuardType::Delete => write!(f, "Delete"),
&GuardType::Head => write!(f, "Head"),
&GuardType::Connect => write!(f, "Connect"),
&GuardType::Options => write!(f, "Options"),
&GuardType::Trace => write!(f, "Trace"),
&GuardType::Patch => write!(f, "Patch"),
}
}
}

View File

@ -1,7 +1,7 @@
use actix_http::HttpService;
use actix_http_test::TestServer;
use actix_web::{http, web::Path, App, HttpResponse, Responder};
use actix_web_codegen::{delete, get, post, put};
use actix_web_codegen::{delete, get, post, put, patch, head, connect, options, trace};
use futures::{future, Future};
#[get("/test")]
@ -14,11 +14,36 @@ fn put_test() -> impl Responder {
HttpResponse::Created()
}
#[patch("/test")]
fn patch_test() -> impl Responder {
HttpResponse::Ok()
}
#[post("/test")]
fn post_test() -> impl Responder {
HttpResponse::NoContent()
}
#[head("/test")]
fn head_test() -> impl Responder {
HttpResponse::Ok()
}
#[connect("/test")]
fn connect_test() -> impl Responder {
HttpResponse::Ok()
}
#[options("/test")]
fn options_test() -> impl Responder {
HttpResponse::Ok()
}
#[trace("/test")]
fn trace_test() -> impl Responder {
HttpResponse::Ok()
}
#[get("/test")]
fn auto_async() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
future::ok(HttpResponse::Ok().finish())
@ -75,6 +100,11 @@ fn test_body() {
App::new()
.service(post_test)
.service(put_test)
.service(head_test)
.service(connect_test)
.service(options_test)
.service(trace_test)
.service(patch_test)
.service(test),
)
});
@ -82,6 +112,26 @@ fn test_body() {
let response = srv.block_on(request.send()).unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::HEAD, srv.url("/test"));
let response = srv.block_on(request.send()).unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::CONNECT, srv.url("/test"));
let response = srv.block_on(request.send()).unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::OPTIONS, srv.url("/test"));
let response = srv.block_on(request.send()).unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::TRACE, srv.url("/test"));
let response = srv.block_on(request.send()).unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::PATCH, srv.url("/test"));
let response = srv.block_on(request.send()).unwrap();
assert!(response.status().is_success());
let request = srv.request(http::Method::PUT, srv.url("/test"));
let response = srv.block_on(request.send()).unwrap();
assert!(response.status().is_success());

View File

@ -1,5 +1,11 @@
# Changes
## [0.2.1] - 2019-06-05
### Added
* Add license files
## [0.2.0] - 2019-05-12
### Added

View File

@ -1,6 +1,6 @@
[package]
name = "awc"
version = "0.2.0"
version = "0.2.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix http client."
readme = "README.md"
@ -41,7 +41,7 @@ flate2-rust = ["actix-http/flate2-rust"]
[dependencies]
actix-codec = "0.1.2"
actix-service = "0.4.0"
actix-http = "0.2.0"
actix-http = "0.2.3"
base64 = "0.10.1"
bytes = "0.4"
derive_more = "0.14"
@ -58,11 +58,11 @@ openssl = { version="0.10", optional = true }
[dev-dependencies]
actix-rt = "0.2.2"
actix-web = { version = "1.0.0-beta.4", features=["ssl"] }
actix-http = { version = "0.2.0", features=["ssl"] }
actix-web = { version = "1.0.0-rc", features=["ssl"] }
actix-http = { version = "0.2.3", features=["ssl"] }
actix-http-test = { version = "0.2.0", features=["ssl"] }
actix-utils = "0.4.0"
actix-server = { version = "0.5.0", features=["ssl"] }
actix-utils = "0.4.1"
actix-server = { version = "0.5.1", features=["ssl"] }
brotli2 = { version="0.3.2" }
flate2 = { version="1.0.2" }
env_logger = "0.6"

View File

@ -188,7 +188,7 @@ impl ServiceConfig {
}
}
/// Set application data. Applicatin data could be accessed
/// Set application data. Application data could be accessed
/// by using `Data<T>` extractor where `T` is data type.
///
/// This is same as `App::data()` method.

View File

@ -122,7 +122,9 @@ impl ResourceMap {
I: AsRef<str>,
{
if let Some(pattern) = self.named.get(name) {
self.fill_root(path, elements)?;
if pattern.pattern().starts_with("/") {
self.fill_root(path, elements)?;
}
if pattern.resource_path(path, elements) {
Ok(Some(()))
} else {

View File

@ -11,6 +11,7 @@ use actix_service::{
use futures::future::{ok, Either, Future, FutureResult};
use futures::{Async, IntoFuture, Poll};
use crate::config::ServiceConfig;
use crate::data::Data;
use crate::dev::{AppService, HttpServiceFactory};
use crate::error::Error;
@ -66,6 +67,7 @@ pub struct Scope<T = ScopeEndpoint> {
services: Vec<Box<ServiceFactory>>,
guards: Vec<Box<Guard>>,
default: Rc<RefCell<Option<Rc<HttpNewService>>>>,
external: Vec<ResourceDef>,
factory_ref: Rc<RefCell<Option<ScopeFactory>>>,
}
@ -80,6 +82,7 @@ impl Scope {
guards: Vec::new(),
services: Vec::new(),
default: Rc::new(RefCell::new(None)),
external: Vec::new(),
factory_ref: fref,
}
}
@ -153,6 +156,56 @@ where
self
}
/// Run external configuration as part of the scope building
/// process
///
/// This function is useful for moving parts of configuration to a
/// different module or even library. For example,
/// some of the resource's configuration could be moved to different module.
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::{web, middleware, App, HttpResponse};
///
/// // this function could be located in different module
/// fn config(cfg: &mut web::ServiceConfig) {
/// cfg.service(web::resource("/test")
/// .route(web::get().to(|| HttpResponse::Ok()))
/// .route(web::head().to(|| HttpResponse::MethodNotAllowed()))
/// );
/// }
///
/// fn main() {
/// let app = App::new()
/// .wrap(middleware::Logger::default())
/// .service(
/// web::scope("/api")
/// .configure(config)
/// )
/// .route("/index.html", web::get().to(|| HttpResponse::Ok()));
/// }
/// ```
pub fn configure<F>(mut self, f: F) -> Self
where
F: FnOnce(&mut ServiceConfig),
{
let mut cfg = ServiceConfig::new();
f(&mut cfg);
self.services.extend(cfg.services);
self.external.extend(cfg.external);
if !cfg.data.is_empty() {
let mut data = self.data.unwrap_or_else(|| Extensions::new());
for value in cfg.data.iter() {
value.create(&mut data);
}
self.data = Some(data);
}
self
}
/// Register http service.
///
/// This is similar to `App's` service registration.
@ -281,6 +334,7 @@ where
guards: self.guards,
services: self.services,
default: self.default,
external: self.external,
factory_ref: self.factory_ref,
}
}
@ -359,6 +413,11 @@ where
let mut rmap = ResourceMap::new(ResourceDef::root_prefix(&self.rdef));
// external resources
for mut rdef in std::mem::replace(&mut self.external, Vec::new()) {
rmap.add(&mut rdef, None);
}
// custom app data storage
if let Some(ref mut ext) = self.data {
config.set_service_data(ext);
@ -594,7 +653,7 @@ mod tests {
use crate::dev::{Body, ResponseBody};
use crate::http::{header, HeaderValue, Method, StatusCode};
use crate::service::{ServiceRequest, ServiceResponse};
use crate::test::{block_on, call_service, init_service, TestRequest};
use crate::test::{block_on, call_service, init_service, read_body, TestRequest};
use crate::{guard, web, App, Error, HttpRequest, HttpResponse};
#[test]
@ -1022,4 +1081,58 @@ mod tests {
let resp = call_service(&mut srv, req);
assert_eq!(resp.status(), StatusCode::OK);
}
#[test]
fn test_scope_config() {
let mut srv =
init_service(App::new().service(web::scope("/app").configure(|s| {
s.route("/path1", web::get().to(|| HttpResponse::Ok()));
})));
let req = TestRequest::with_uri("/app/path1").to_request();
let resp = block_on(srv.call(req)).unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[test]
fn test_scope_config_2() {
let mut srv =
init_service(App::new().service(web::scope("/app").configure(|s| {
s.service(web::scope("/v1").configure(|s| {
s.route("/", web::get().to(|| HttpResponse::Ok()));
}));
})));
let req = TestRequest::with_uri("/app/v1/").to_request();
let resp = block_on(srv.call(req)).unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[test]
fn test_url_for_external() {
let mut srv =
init_service(App::new().service(web::scope("/app").configure(|s| {
s.service(web::scope("/v1").configure(|s| {
s.external_resource(
"youtube",
"https://youtube.com/watch/{video_id}",
);
s.route(
"/",
web::get().to(|req: HttpRequest| {
HttpResponse::Ok().body(format!(
"{}",
req.url_for("youtube", &["xxxxxx"]).unwrap().as_str()
))
}),
);
}));
})));
let req = TestRequest::with_uri("/app/v1/").to_request();
let resp = block_on(srv.call(req)).unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let body = read_body(resp);
assert_eq!(body, &b"https://youtube.com/watch/xxxxxx"[..]);
}
}