Skip to content

Commit

Permalink
Merge branch 'master' into feature/mtls
Browse files Browse the repository at this point in the history
  • Loading branch information
akuanti committed Jul 17, 2018
2 parents 7c54ce3 + 19d8569 commit 932f5da
Show file tree
Hide file tree
Showing 51 changed files with 562 additions and 140 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Version 0.3.15 (Jul 16, 2018)

## Codegen

* The `#[catch]` decorator and `catchers!` macro were introduced, replacing
`#[error]` and `errors!`.
* The `#[error]` decorator and `errors!` macro were deprecated.
* Codegen was updated for `2018-07-15` nightly.
* Minimum required `rustc` is `1.29.0-nightly 2018-07-15`.

# Version 0.3.14 (Jun 22, 2018)

## Codegen
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ members = [
"examples/content_types",
"examples/ranking",
"examples/testing",
"examples/request_local_state",
"examples/request_guard",
"examples/stream",
"examples/json",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,4 @@ Rocket is licensed under either of the following, at your option:
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT License ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

The Rocket website source is licensed under [separate terms](site/README.md#license).
The Rocket website source is licensed under [separate terms](site#license).
3 changes: 3 additions & 0 deletions contrib/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,8 @@ handlebars = { version = "0.32", optional = true }
glob = { version = "^0.2", optional = true }
tera = { version = "0.11", optional = true }

[dev-dependencies]
rocket_codegen = { version = "0.4.0-dev", path = "../../core/codegen" }

[package.metadata.docs.rs]
all-features = true
17 changes: 14 additions & 3 deletions contrib/lib/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ use rocket::data::{self, Data, FromData};
use rocket::response::{self, Responder, content};
use rocket::http::Status;

use serde::Serialize;
use serde::de::DeserializeOwned;

use serde::{Serialize, Serializer};
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
use serde_json;

pub use serde_json::error::Error as SerdeError;
Expand Down Expand Up @@ -186,6 +185,18 @@ impl<T> DerefMut for Json<T> {
#[derive(Debug, Clone, PartialEq, Default)]
pub struct JsonValue(pub serde_json::Value);

impl Serialize for JsonValue {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}

impl<'de> Deserialize<'de> for JsonValue {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
serde_json::Value::deserialize(deserializer).map(JsonValue)
}
}

impl JsonValue {
#[inline(always)]
fn into_inner(self) -> serde_json::Value {
Expand Down
2 changes: 1 addition & 1 deletion contrib/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub use msgpack::{MsgPack, MsgPackError};
mod templates;

#[cfg(feature = "templates")]
pub use templates::{Template, Engines};
pub use templates::{Engines, Template, TemplateMetadata};

#[cfg(feature = "uuid")]
mod uuid;
Expand Down
41 changes: 29 additions & 12 deletions contrib/lib/src/msgpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,28 @@ pub use self::rmp_serde::decode::Error as MsgPackError;
/// [Serde](https://github.com/serde-rs/serde). The data is parsed from the HTTP
/// request body.
///
/// ```rust,ignore
/// #[post("/users/", format = "application/msgpack", data = "<user>")]
/// ```rust
/// # #![feature(plugin, decl_macro)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// # extern crate rocket_contrib;
/// # type User = usize;
/// # fn main() { }
/// #
/// use rocket_contrib::MsgPack;
///
/// #[post("/users", format = "msgpack", data = "<user>")]
/// fn new_user(user: MsgPack<User>) {
/// ...
/// /* ... */
/// }
/// ```
///
/// You don't _need_ to use `format = "application/msgpack"`, but it _may_ be
/// what you want. Using `format = application/msgpack` means that any request
/// that doesn't specify "application/msgpack" as its first `Content-Type:`
/// header parameter will not be routed to this handler. By default, Rocket will
/// accept a Content Type of any of the following for MessagePack data:
/// `application/msgpack`, `application/x-msgpack`, `bin/msgpack`, or
/// `bin/x-msgpack`.
/// You don't _need_ to use `format = "msgpack"`, but it _may_ be what you want.
/// Using `format = msgpack` means that any request that doesn't specify
/// "application/msgpack" as its first `Content-Type:` header parameter will not
/// be routed to this handler. By default, Rocket will accept a Content-Type of
/// any of the following for MessagePack data: `application/msgpack`,
/// `application/x-msgpack`, `bin/msgpack`, or `bin/x-msgpack`.
///
/// ## Sending MessagePack
///
Expand All @@ -48,11 +56,20 @@ pub use self::rmp_serde::decode::Error as MsgPackError;
/// [Serde](https://github.com/serde-rs/serde). The content type of the response
/// is set to `application/msgpack` automatically.
///
/// ```rust,ignore
/// ```rust
/// # #![feature(plugin, decl_macro)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// # extern crate rocket_contrib;
/// # type User = usize;
/// # fn main() { }
/// #
/// use rocket_contrib::MsgPack;
///
/// #[get("/users/<id>")]
/// fn user(id: usize) -> MsgPack<User> {
/// let user_from_id = User::from(id);
/// ...
/// /* ... */
/// MsgPack(user_from_id)
/// }
/// ```
Expand Down
89 changes: 89 additions & 0 deletions contrib/lib/src/templates/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use rocket::{Request, State, Outcome};
use rocket::http::Status;
use rocket::request::{self, FromRequest};

use templates::Context;

/// The `TemplateMetadata` type: implements `FromRequest`, allowing dynamic
/// queries about template metadata.
///
/// # Usage
///
/// First, ensure that the template [fairing](`rocket::fairing`) is attached to
/// your Rocket application:
///
/// ```rust
/// # extern crate rocket;
/// # extern crate rocket_contrib;
/// #
/// use rocket_contrib::Template;
///
/// fn main() {
/// rocket::ignite()
/// .attach(Template::fairing())
/// // ...
/// # ;
/// }
/// ```
///
/// The `TemplateMetadata` type implements Rocket's `FromRequest` trait, so it can
/// be used as a request guard in any request handler.
///
/// ```rust
/// # #![feature(plugin, decl_macro)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// # #[macro_use] extern crate rocket_contrib;
/// # fn main() { }
/// #
/// use rocket_contrib::{Template, TemplateMetadata};
///
/// #[get("/")]
/// fn homepage(metadata: TemplateMetadata) -> Template {
/// // Conditionally render a template if it's available.
/// if metadata.contains_template("some-template") {
/// Template::render("some-template", json!({ /* .. */ }))
/// } else {
/// Template::render("fallback", json!({ /* .. */ }))
/// }
/// }
/// ```
pub struct TemplateMetadata<'a>(&'a Context);

impl<'a> TemplateMetadata<'a> {
/// Returns `true` if the template with name `name` was loaded at start-up
/// time. Otherwise, returns `false`.
///
/// # Example
///
/// ```rust
/// use rocket_contrib::TemplateMetadata;
///
/// fn handler(metadata: TemplateMetadata) {
/// // Returns `true` if the template with name `"name"` was loaded.
/// let loaded = metadata.contains_template("name");
/// }
/// ```
pub fn contains_template(&self, name: &str) -> bool {
self.0.templates.contains_key(name)
}
}

/// Retrieves the template metadata. If a template fairing hasn't been attached,
/// an error is printed and an empty `Err` with status `InternalServerError`
/// (`500`) is returned.
impl<'a, 'r> FromRequest<'a, 'r> for TemplateMetadata<'a> {
type Error = ();

fn from_request(request: &'a Request) -> request::Outcome<Self, ()> {
request.guard::<State<Context>>()
.succeeded()
.and_then(|ctxt| Some(Outcome::Success(TemplateMetadata(ctxt.inner()))))
.unwrap_or_else(|| {
error_!("Uninitialized template context: missing fairing.");
info_!("To use templates, you must attach `Template::fairing()`.");
info_!("See the `Template` documentation for more information.");
Outcome::Failure((Status::InternalServerError, ()))
})
}
}
18 changes: 9 additions & 9 deletions contrib/lib/src/templates/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ extern crate glob;
#[cfg(feature = "handlebars_templates")] mod handlebars_templates;
mod engine;
mod context;
mod metadata;

pub use self::engine::Engines;
pub use self::metadata::TemplateMetadata;

use self::engine::Engine;
use self::context::Context;
Expand Down Expand Up @@ -287,15 +289,13 @@ impl Template {
pub fn show<S, C>(rocket: &Rocket, name: S, context: C) -> Option<String>
where S: Into<Cow<'static, str>>, C: Serialize
{
let ctxt = match rocket.state::<Context>() {
Some(ctxt) => ctxt,
None => {
warn!("Uninitialized template context: missing fairing.");
info!("To use templates, you must attach `Template::fairing()`.");
info!("See the `Template` documentation for more information.");
return None;
}
};
let ctxt = rocket.state::<Context>().or_else(|| {
warn!("Uninitialized template context: missing fairing.");
info!("To use templates, you must attach `Template::fairing()`.");
info!("See the `Template` documentation for more information.");
None
})?;

Template::render(name, context).finalize(&ctxt).ok().map(|v| v.0)
}

Expand Down
53 changes: 50 additions & 3 deletions contrib/lib/tests/templates.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#![feature(plugin, decl_macro)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate rocket_contrib;

Expand All @@ -6,9 +9,17 @@ mod templates_tests {
use std::env;
use std::path::PathBuf;

use rocket::Rocket;
use rocket::{Rocket, http::RawStr};
use rocket::config::{Config, Environment};
use rocket_contrib::Template;
use rocket_contrib::{Template, TemplateMetadata};

#[get("/<engine>/<name>")]
fn template_check(md: TemplateMetadata, engine: &RawStr, name: &RawStr) -> Option<()> {
match md.contains_template(&format!("{}/{}", engine, name)) {
true => Some(()),
false => None
}
}

fn template_root() -> PathBuf {
let cwd = env::current_dir().expect("current working directory");
Expand All @@ -20,13 +31,16 @@ mod templates_tests {
.extra("template_dir", template_root().to_str().expect("template directory"))
.expect("valid configuration");

::rocket::custom(config, true).attach(Template::fairing())
::rocket::custom(config).attach(Template::fairing())
.mount("/", routes![template_check])
}

#[cfg(feature = "tera_templates")]
mod tera_tests {
use super::*;
use std::collections::HashMap;
use rocket::http::Status;
use rocket::local::Client;

const UNESCAPED_EXPECTED: &'static str
= "\nh_start\ntitle: _test_\nh_end\n\n\n<script />\n\nfoot\n";
Expand All @@ -48,12 +62,31 @@ mod templates_tests {
let template = Template::show(&rocket, "tera/html_test", &map);
assert_eq!(template, Some(ESCAPED_EXPECTED.into()));
}

#[test]
fn test_template_metadata_with_tera() {
let client = Client::new(rocket()).unwrap();

let response = client.get("/tera/txt_test").dispatch();
assert_eq!(response.status(), Status::Ok);

let response = client.get("/tera/html_test").dispatch();
assert_eq!(response.status(), Status::Ok);

let response = client.get("/tera/not_existing").dispatch();
assert_eq!(response.status(), Status::NotFound);

let response = client.get("/hbs/txt_test").dispatch();
assert_eq!(response.status(), Status::NotFound);
}
}

#[cfg(feature = "handlebars_templates")]
mod handlebars_tests {
use super::*;
use std::collections::HashMap;
use rocket::http::Status;
use rocket::local::Client;

const EXPECTED: &'static str
= "Hello _test_!\n\n<main> &lt;script /&gt; hi </main>\nDone.\n\n";
Expand All @@ -69,5 +102,19 @@ mod templates_tests {
let template = Template::show(&rocket, "hbs/test", &map);
assert_eq!(template, Some(EXPECTED.into()));
}

#[test]
fn test_template_metadata_with_handlebars() {
let client = Client::new(rocket()).unwrap();

let response = client.get("/hbs/test").dispatch();
assert_eq!(response.status(), Status::Ok);

let response = client.get("/hbs/not_existing").dispatch();
assert_eq!(response.status(), Status::NotFound);

let response = client.get("/tera/test").dispatch();
assert_eq!(response.status(), Status::NotFound);
}
}
}
4 changes: 2 additions & 2 deletions core/codegen/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use yansi::Color::{Red, Yellow, Blue, White};
use version_check::{supports_features, is_min_version, is_min_date};

// Specifies the minimum nightly version needed to compile Rocket's codegen.
const MIN_DATE: &'static str = "2018-06-22";
const MIN_VERSION: &'static str = "1.28.0-nightly";
const MIN_DATE: &'static str = "2018-07-16";
const MIN_VERSION: &'static str = "1.29.0-nightly";

fn main() {
let ok_channel = supports_features();
Expand Down
4 changes: 2 additions & 2 deletions core/codegen/src/decorators/derive_form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use syntax_ext::deriving::generic::MethodDef;
use syntax_ext::deriving::generic::{StaticStruct, Substructure, TraitDef, ty};
use syntax_ext::deriving::generic::combine_substructure as c_s;

use utils::{strip_ty_lifetimes, is_valid_ident, SpanExt};
use utils::{strip_ty_lifetimes, is_valid_ident, SpanExt, GenericParamExt};

static ONLY_STRUCTS_ERR: &'static str = "`FromForm` can only be derived for \
structures with named fields.";
Expand All @@ -26,7 +26,7 @@ fn struct_lifetime(ecx: &mut ExtCtxt, item: &Annotatable, sp: Span) -> Option<St
Annotatable::Item(ref item) => match item.node {
ItemKind::Struct(_, ref generics) => {
let mut lifetimes = generics.params.iter()
.filter(|p| p.kind == GenericParamKind::Lifetime)
.filter(|p| p.is_lifetime())
.map(|p| p.ident.to_string());

let lifetime = lifetimes.next();
Expand Down
4 changes: 4 additions & 0 deletions core/codegen/src/macros/uri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ pub fn uri_internal(
// Building <$T as ::rocket::http::uri::FromUriParam<_>>::from_uri_param($e).
for (i, &(mut ident, ref ty)) in internal.fn_args.iter().enumerate() {
let (span, mut expr) = (exprs[i].span, exprs[i].clone());

// Format argument names cannot begin with `_`, but a function parameter
// might, so we prefix each parameter with the letters `fmt`.
ident.name = Symbol::intern(&format!("fmt{}", ident.name));
ident.span = span;

// path for call: <T as FromUriParam<_>>::from_uri_param
Expand Down
Loading

0 comments on commit 932f5da

Please sign in to comment.