├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── contrib ├── codegen │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── database.rs │ │ └── lib.rs └── lib │ ├── Cargo.toml │ ├── src │ ├── databases.rs │ ├── helmet │ │ ├── helmet.rs │ │ ├── mod.rs │ │ └── policy.rs │ ├── json.rs │ ├── lib.rs │ ├── msgpack.rs │ ├── serve.rs │ ├── templates │ │ ├── context.rs │ │ ├── engine.rs │ │ ├── fairing.rs │ │ ├── handlebars_templates.rs │ │ ├── metadata.rs │ │ ├── mod.rs │ │ └── tera_templates.rs │ └── uuid.rs │ └── tests │ ├── databases.rs │ ├── helmet.rs │ ├── static │ ├── .hidden │ ├── index.html │ ├── inner │ │ ├── .hideme │ │ ├── goodbye │ │ └── index.html │ └── other │ │ └── hello.txt │ ├── static_files.rs │ ├── templates.rs │ └── templates │ ├── hbs │ ├── common │ │ ├── footer.html.hbs │ │ └── header.html.hbs │ ├── reload.txt.hbs │ └── test.html.hbs │ └── tera │ ├── base.txt.tera │ ├── html_test.html.tera │ └── txt_test.txt.tera ├── core ├── codegen │ ├── Cargo.toml │ ├── build.rs │ ├── src │ │ ├── attribute │ │ │ ├── catch.rs │ │ │ ├── mod.rs │ │ │ ├── route.rs │ │ │ └── segments.rs │ │ ├── bang │ │ │ ├── mod.rs │ │ │ ├── uri.rs │ │ │ └── uri_parsing.rs │ │ ├── derive │ │ │ ├── from_form.rs │ │ │ ├── from_form_value.rs │ │ │ ├── mod.rs │ │ │ ├── responder.rs │ │ │ └── uri_display.rs │ │ ├── http_codegen.rs │ │ ├── lib.rs │ │ ├── proc_macro_ext.rs │ │ └── syn_ext.rs │ └── tests │ │ ├── compile-test.rs │ │ ├── expansion.rs │ │ ├── from_form.rs │ │ ├── from_form_value.rs │ │ ├── responder.rs │ │ ├── route-data.rs │ │ ├── route-format.rs │ │ ├── route-params.rs │ │ ├── route-ranking.rs │ │ ├── route.rs │ │ ├── typed-uris.rs │ │ ├── ui-fail │ │ ├── catch.rs │ │ ├── catch.stderr │ │ ├── catch_type_errors.rs │ │ ├── catch_type_errors.stderr │ │ ├── catchers.rs │ │ ├── catchers.stderr │ │ ├── from_form.rs │ │ ├── from_form.stderr │ │ ├── from_form_type_errors.rs │ │ ├── from_form_type_errors.stderr │ │ ├── from_form_value.rs │ │ ├── from_form_value.stderr │ │ ├── responder-types.rs │ │ ├── responder-types.stderr │ │ ├── responder.stderr │ │ ├── route-attribute-general-syntax.rs │ │ ├── route-attribute-general-syntax.stderr │ │ ├── route-path-bad-syntax.rs │ │ ├── route-path-bad-syntax.stderr │ │ ├── route-type-errors.rs │ │ ├── route-type-errors.stderr │ │ ├── route-warnings.rs │ │ ├── route-warnings.stderr │ │ ├── routes.rs │ │ ├── routes.stderr │ │ ├── typed-uri-bad-type.rs │ │ ├── typed-uri-bad-type.stderr │ │ ├── typed-uris-bad-params.rs │ │ ├── typed-uris-bad-params.stderr │ │ ├── typed-uris-invalid-syntax.rs │ │ ├── typed-uris-invalid-syntax.stderr │ │ ├── update-references.sh │ │ ├── uri_display.rs │ │ ├── uri_display.stderr │ │ ├── uri_display_type_errors.rs │ │ └── uri_display_type_errors.stderr │ │ └── uri_display.rs ├── http │ ├── Cargo.toml │ └── src │ │ ├── accept.rs │ │ ├── content_type.rs │ │ ├── cookies.rs │ │ ├── docify.rs │ │ ├── ext.rs │ │ ├── header.rs │ │ ├── hyper.rs │ │ ├── known_media_types.rs │ │ ├── lib.rs │ │ ├── media_type.rs │ │ ├── method.rs │ │ ├── parse │ │ ├── accept.rs │ │ ├── checkers.rs │ │ ├── indexed.rs │ │ ├── media_type.rs │ │ ├── mod.rs │ │ └── uri │ │ │ ├── error.rs │ │ │ ├── mod.rs │ │ │ ├── parser.rs │ │ │ ├── spec.txt │ │ │ ├── tables.rs │ │ │ └── tests.rs │ │ ├── raw_str.rs │ │ ├── route.rs │ │ ├── status.rs │ │ ├── tls.rs │ │ ├── uncased.rs │ │ └── uri │ │ ├── absolute.rs │ │ ├── authority.rs │ │ ├── formatter.rs │ │ ├── from_uri_param.rs │ │ ├── mod.rs │ │ ├── origin.rs │ │ ├── segments.rs │ │ ├── uri.rs │ │ └── uri_display.rs └── lib │ ├── Cargo.toml │ ├── benches │ ├── format-routing.rs │ ├── ranked-routing.rs │ └── simple-routing.rs │ ├── build.rs │ ├── src │ ├── catcher.rs │ ├── codegen.rs │ ├── config │ │ ├── builder.rs │ │ ├── config.rs │ │ ├── custom_values.rs │ │ ├── environment.rs │ │ ├── error.rs │ │ ├── mod.rs │ │ └── toml_ext.rs │ ├── data │ │ ├── data.rs │ │ ├── data_stream.rs │ │ ├── from_data.rs │ │ ├── mod.rs │ │ └── net_stream.rs │ ├── error.rs │ ├── ext.rs │ ├── fairing │ │ ├── ad_hoc.rs │ │ ├── fairings.rs │ │ ├── info_kind.rs │ │ └── mod.rs │ ├── handler.rs │ ├── lib.rs │ ├── local │ │ ├── client.rs │ │ ├── mod.rs │ │ └── request.rs │ ├── logger.rs │ ├── outcome.rs │ ├── request │ │ ├── form │ │ │ ├── error.rs │ │ │ ├── form.rs │ │ │ ├── form_items.rs │ │ │ ├── from_form.rs │ │ │ ├── from_form_value.rs │ │ │ ├── lenient.rs │ │ │ └── mod.rs │ │ ├── from_request.rs │ │ ├── mod.rs │ │ ├── param.rs │ │ ├── query.rs │ │ ├── request.rs │ │ ├── state.rs │ │ └── tests.rs │ ├── response │ │ ├── content.rs │ │ ├── flash.rs │ │ ├── mod.rs │ │ ├── named_file.rs │ │ ├── redirect.rs │ │ ├── responder.rs │ │ ├── response.rs │ │ ├── status.rs │ │ └── stream.rs │ ├── rocket.rs │ └── router │ │ ├── collider.rs │ │ ├── mod.rs │ │ └── route.rs │ └── tests │ ├── absolute-uris-okay-issue-443.rs │ ├── fairing_before_head_strip-issue-546.rs │ ├── flash-lazy-removes-issue-466.rs │ ├── form_method-issue-45.rs │ ├── form_value_decoding-issue-82.rs │ ├── head_handling.rs │ ├── limits.rs │ ├── local-request-content-type-issue-505.rs │ ├── local_request_private_cookie-issue-368.rs │ ├── mount_point.rs │ ├── nested-fairing-attaches.rs │ ├── precise-content-type-matching.rs │ ├── redirect_from_catcher-issue-113.rs │ ├── responder_lifetime-issue-345.rs │ ├── route_guard.rs │ ├── segments-issues-41-86.rs │ ├── strict_and_lenient_forms.rs │ └── uri-percent-encoding-issue-808.rs ├── examples ├── config │ ├── Cargo.toml │ ├── Rocket.toml │ ├── src │ │ └── main.rs │ └── tests │ │ ├── common │ │ └── mod.rs │ │ ├── development.rs │ │ ├── production.rs │ │ └── staging.rs ├── content_types │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── cookies │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── templates │ │ └── index.html.hbs ├── errors │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── fairings │ ├── Cargo.toml │ ├── Rocket.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── form_kitchen_sink │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── static │ │ └── index.html ├── form_validation │ ├── Cargo.toml │ ├── src │ │ ├── files.rs │ │ ├── main.rs │ │ └── tests.rs │ └── static │ │ └── index.html ├── handlebars_templates │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── templates │ │ ├── about.hbs │ │ ├── error │ │ └── 404.hbs │ │ ├── footer.hbs │ │ ├── index.hbs │ │ ├── layout.hbs │ │ └── nav.hbs ├── hello_2018 │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── hello_person │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── hello_world │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── json │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── managed_queue │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── manual_routes │ ├── Cargo.toml │ ├── Rocket.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── msgpack │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── optional_redirect │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── pastebin │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── paste_id.rs │ │ └── tests.rs ├── query_params │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── ranking │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── raw_sqlite │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── raw_upload │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── redirect │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── request_guard │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── request_local_state │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── session │ ├── Cargo.toml │ ├── Rocket.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── templates │ │ ├── index.html.hbs │ │ └── login.html.hbs ├── state │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── static_files │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── static │ │ ├── hidden │ │ └── hi.txt │ │ ├── index.html │ │ └── rocket-icon.jpg ├── stream │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── tera_templates │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── templates │ │ ├── base.html.tera │ │ ├── error │ │ └── 404.html.tera │ │ └── index.html.tera ├── testing │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── tls │ ├── Cargo.toml │ ├── Rocket.toml │ ├── private │ │ ├── ca_cert.pem │ │ ├── ca_key.pem │ │ ├── cert.pem │ │ ├── gen_cert.sh │ │ └── key.pem │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── todo │ ├── Cargo.toml │ ├── README.md │ ├── Rocket.toml │ ├── bootstrap.sh │ ├── db │ │ └── DB_LIVES_HERE │ ├── migrations │ │ ├── .gitkeep │ │ └── 20160720150332_create_tasks_table │ │ │ ├── down.sql │ │ │ └── up.sql │ ├── src │ │ ├── main.rs │ │ ├── task.rs │ │ └── tests.rs │ └── static │ │ ├── css │ │ ├── normalize.css │ │ ├── skeleton.css │ │ └── style.css │ │ ├── images │ │ └── favicon.png │ │ └── index.html.tera └── uuid │ ├── Cargo.toml │ └── src │ ├── main.rs │ └── tests.rs ├── logo.png ├── scripts ├── bump_version.sh ├── config.sh ├── mk-docs.sh ├── publish.sh └── test.sh └── site ├── LICENSE ├── README.md ├── guide ├── 0-introduction.md ├── 1-quickstart.md ├── 10-pastebin.md ├── 11-conclusion.md ├── 2-getting-started.md ├── 3-overview.md ├── 4-requests.md ├── 5-responses.md ├── 6-state.md ├── 7-fairings.md ├── 8-testing.md ├── 9-configuration.md └── index.md ├── index.toml ├── news ├── 2017-02-06-version-0.2.md ├── 2017-07-14-version-0.3.md ├── 2018-10-31-version-0.4-rc.md ├── 2018-11-30-version-0.4-rc-2.md └── index.toml └── overview.toml /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Hello, and thanks for opening a new issue about Rocket! 2 | 3 | Before opening your issue, we ask that you search through existing issues and 4 | pull requests to see if your bug report, concern, request, or comment has 5 | already been addressed. Ensure to search through both open and closed issues and 6 | pull requests. If this is a question, feature request, or general comment, 7 | please ensure that you have read the relevant sections of the documentation 8 | before posting your issue. Finally, consider asking questions on IRC or Matrix 9 | before opening an issue. 10 | 11 | If you feel confident that your issue is unique, please include the following 12 | information, selecting the category that best describes your issue: 13 | 14 | ## Bug Reports 15 | 16 | Bug reports _must_ include: 17 | 18 | 1. The version of Rocket you're using. Ensure it's the latest, if possible. 19 | 20 | 2. The operating system (distribution and version) where the issue occurs. 21 | 22 | 3. A brief description of the bug that includes: 23 | * The nature of the bug. 24 | * When the bug occurs. 25 | * What you expected vs. what actually happened. 26 | 27 | 4. How you uncovered the bug. Short, reproducible tests are especially useful. 28 | 29 | 5. Ideas, if any, about what Rocket is doing incorrectly. 30 | 31 | ## Questions 32 | 33 | Any questions _must_ include: 34 | 35 | 1. The version of Rocket this question is based on, if any. 36 | 37 | 2. What steps you've taken to answer the question yourself. 38 | 39 | 3. What documentation you believe should include an answer to this question. 40 | 41 | ## Feature Requests 42 | 43 | Feature requests _must_ include: 44 | 45 | 1. Why you believe this feature is necessary. 46 | 47 | 2. A convincing use-case for this feature. 48 | 49 | 3. Why this feature can't or shouldn't exist outside of Rocket. 50 | 51 | ## General Comments 52 | 53 | Feel free to comment at will. We simply ask that your comments are well 54 | constructed and actionable. Consider whether IRC or Matrix would be a better 55 | venue for discussion. 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.o 3 | *.so 4 | *.rlib 5 | *.dll 6 | 7 | # Executables 8 | *.exe 9 | 10 | # Generated by Cargo 11 | target 12 | 13 | # Generated databases 14 | db.sqlite 15 | 16 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 17 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 18 | Cargo.lock 19 | 20 | # The upload script, for now. 21 | scripts/upload-docs.sh 22 | scripts/redirect.html 23 | 24 | # Backup files. 25 | *.bak 26 | 27 | # Uploads in pastebin example. 28 | examples/pastebin/upload/* 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: required # so we get a VM with higher specs 3 | dist: trusty # so we get a VM with higher specs 4 | cache: cargo 5 | env: 6 | - TEST_FLAGS= 7 | - TEST_FLAGS=--release 8 | - TEST_FLAGS=--contrib 9 | - TEST_FLAGS=--core 10 | rust: 11 | - nightly 12 | script: ./scripts/test.sh $TEST_FLAGS 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [profile.dev] 2 | codegen-units = 4 3 | 4 | [workspace] 5 | members = [ 6 | "core/lib/", 7 | "core/codegen/", 8 | "core/http/", 9 | "contrib/lib", 10 | "contrib/codegen", 11 | "examples/cookies", 12 | "examples/errors", 13 | "examples/form_validation", 14 | "examples/hello_person", 15 | "examples/query_params", 16 | "examples/hello_world", 17 | "examples/manual_routes", 18 | "examples/optional_redirect", 19 | "examples/redirect", 20 | "examples/static_files", 21 | "examples/todo", 22 | "examples/content_types", 23 | "examples/ranking", 24 | "examples/testing", 25 | "examples/request_local_state", 26 | "examples/request_guard", 27 | "examples/stream", 28 | "examples/json", 29 | "examples/msgpack", 30 | "examples/handlebars_templates", 31 | "examples/tera_templates", 32 | "examples/form_kitchen_sink", 33 | "examples/config", 34 | "examples/raw_upload", 35 | "examples/pastebin", 36 | "examples/state", 37 | "examples/managed_queue", 38 | "examples/uuid", 39 | "examples/session", 40 | "examples/raw_sqlite", 41 | "examples/tls", 42 | "examples/fairings", 43 | "examples/hello_2018", 44 | ] 45 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016-2018 Sergio Benitez 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /contrib/codegen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_contrib_codegen" 3 | version = "0.4.0" 4 | authors = ["Sergio Benitez "] 5 | description = "Procedural macros for the Rocket contrib libraries." 6 | documentation = "https://api.rocket.rs/v0.4/rocket_contrib/" 7 | homepage = "https://rocket.rs" 8 | repository = "https://github.com/SergioBenitez/Rocket" 9 | readme = "../../README.md" 10 | keywords = ["rocket", "contrib", "code", "generation", "proc-macro"] 11 | license = "MIT/Apache-2.0" 12 | build = "build.rs" 13 | 14 | [features] 15 | database_attribute = [] 16 | 17 | [lib] 18 | proc-macro = true 19 | 20 | [dependencies] 21 | devise = "0.2" 22 | quote = "0.6" 23 | 24 | [build-dependencies] 25 | yansi = "0.5" 26 | version_check = "0.1.3" 27 | -------------------------------------------------------------------------------- /contrib/codegen/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_span, proc_macro_diagnostic)] 2 | #![feature(crate_visibility_modifier)] 3 | #![recursion_limit="256"] 4 | 5 | //! # Rocket Contrib - Code Generation 6 | //! This crate implements the code generation portion of the Rocket Contrib 7 | //! crate. This is for officially sanctioned contributor libraries that require 8 | //! code generation of some kind. 9 | //! 10 | //! This crate includes custom derives and procedural macros and will expand 11 | //! as-needed if future `rocket_contrib` features require code generation 12 | //! facilities. 13 | //! 14 | //! ## Procedural Macros 15 | //! 16 | //! This crate implements the following procedural macros: 17 | //! 18 | //! * **databases** 19 | //! 20 | //! The syntax for the `databases` macro is: 21 | //! 22 | //!
23 | //! macro := database(DATABASE_NAME)
24 | //! DATABASE_NAME := (string literal)
25 | //! 
26 | 27 | extern crate devise; 28 | extern crate proc_macro; 29 | 30 | #[allow(unused_imports)] 31 | #[macro_use] extern crate quote; 32 | 33 | #[allow(unused_imports)] 34 | crate use devise::{syn, proc_macro2}; 35 | 36 | #[cfg(feature = "database_attribute")] 37 | mod database; 38 | 39 | #[allow(unused_imports)] 40 | use proc_macro::TokenStream; 41 | 42 | /// The procedural macro for the `databases` annotation. 43 | #[cfg(feature = "database_attribute")] 44 | #[proc_macro_attribute] 45 | pub fn database(attr: TokenStream, input: TokenStream) -> TokenStream { 46 | ::database::database_attr(attr, input).unwrap_or_else(|diag| { 47 | diag.emit(); 48 | TokenStream::new() 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /contrib/lib/src/templates/handlebars_templates.rs: -------------------------------------------------------------------------------- 1 | use templates::serde::Serialize; 2 | use templates::{Engine, TemplateInfo}; 3 | 4 | pub use templates::handlebars::Handlebars; 5 | 6 | impl Engine for Handlebars { 7 | const EXT: &'static str = "hbs"; 8 | 9 | fn init(templates: &[(&str, &TemplateInfo)]) -> Option { 10 | let mut hb = Handlebars::new(); 11 | for &(name, info) in templates { 12 | let path = &info.path; 13 | if let Err(e) = hb.register_template_file(name, path) { 14 | error!("Error in Handlebars template '{}'.", name); 15 | info_!("{}", e); 16 | info_!("Template path: '{}'.", path.to_string_lossy()); 17 | return None; 18 | } 19 | } 20 | 21 | Some(hb) 22 | } 23 | 24 | fn render(&self, name: &str, context: C) -> Option { 25 | if self.get_template(name).is_none() { 26 | error_!("Handlebars template '{}' does not exist.", name); 27 | return None; 28 | } 29 | 30 | match Handlebars::render(self, name, &context) { 31 | Ok(string) => Some(string), 32 | Err(e) => { 33 | error_!("Error rendering Handlebars template '{}': {}", name, e); 34 | None 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contrib/lib/src/templates/tera_templates.rs: -------------------------------------------------------------------------------- 1 | use templates::serde::Serialize; 2 | use templates::{Engine, TemplateInfo}; 3 | 4 | pub use templates::tera::Tera; 5 | 6 | impl Engine for Tera { 7 | const EXT: &'static str = "tera"; 8 | 9 | fn init(templates: &[(&str, &TemplateInfo)]) -> Option { 10 | // Create the Tera instance. 11 | let mut tera = Tera::default(); 12 | let ext = [".html.tera", ".htm.tera", ".xml.tera", ".html", ".htm", ".xml"]; 13 | tera.autoescape_on(ext.to_vec()); 14 | 15 | // Collect into a tuple of (name, path) for Tera. 16 | let tera_templates = templates.iter() 17 | .map(|&(name, info)| (&info.path, Some(name))) 18 | .collect::>(); 19 | 20 | // Finally try to tell Tera about all of the templates. 21 | if let Err(e) = tera.add_template_files(tera_templates) { 22 | error!("Failed to initialize Tera templating."); 23 | for error in e.iter() { 24 | info_!("{}", error); 25 | } 26 | 27 | None 28 | } else { 29 | Some(tera) 30 | } 31 | } 32 | 33 | fn render(&self, name: &str, context: C) -> Option { 34 | if self.get_template(name).is_err() { 35 | error_!("Tera template '{}' does not exist.", name); 36 | return None; 37 | }; 38 | 39 | match Tera::render(self, name, &context) { 40 | Ok(string) => Some(string), 41 | Err(e) => { 42 | error_!("Error rendering Tera template '{}'.", name); 43 | for error in e.iter() { 44 | error_!("{}", error); 45 | } 46 | 47 | None 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contrib/lib/tests/databases.rs: -------------------------------------------------------------------------------- 1 | extern crate rocket; 2 | extern crate rocket_contrib; 3 | 4 | #[cfg(all(feature = "diesel_sqlite_pool", feature = "diesel_postgres_pool"))] 5 | mod databases_tests { 6 | use rocket_contrib::databases::{database, diesel}; 7 | 8 | #[database("foo")] 9 | struct TempStorage(diesel::SqliteConnection); 10 | 11 | #[database("bar")] 12 | struct PrimaryDb(diesel::PgConnection); 13 | } 14 | -------------------------------------------------------------------------------- /contrib/lib/tests/static/.hidden: -------------------------------------------------------------------------------- 1 | Peek-a-boo. 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/static/index.html: -------------------------------------------------------------------------------- 1 | Just a file here: index.html. 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/static/inner/.hideme: -------------------------------------------------------------------------------- 1 | Oh no! 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/static/inner/goodbye: -------------------------------------------------------------------------------- 1 | Thanks for coming! 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/static/inner/index.html: -------------------------------------------------------------------------------- 1 | Inner index. 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/static/other/hello.txt: -------------------------------------------------------------------------------- 1 | Hi! 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/templates/hbs/common/footer.html.hbs: -------------------------------------------------------------------------------- 1 | Done. 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/templates/hbs/common/header.html.hbs: -------------------------------------------------------------------------------- 1 | Hello {{ title }}! 2 | -------------------------------------------------------------------------------- /contrib/lib/tests/templates/hbs/reload.txt.hbs: -------------------------------------------------------------------------------- 1 | initial -------------------------------------------------------------------------------- /contrib/lib/tests/templates/hbs/test.html.hbs: -------------------------------------------------------------------------------- 1 | {{> hbs/common/header }} 2 |
{{ content }}
3 | {{> hbs/common/footer }} 4 | -------------------------------------------------------------------------------- /contrib/lib/tests/templates/tera/base.txt.tera: -------------------------------------------------------------------------------- 1 | {% block head %} 2 | h_start 3 | title: {% block title %}{% endblock title %} 4 | h_end 5 | {% endblock head %} 6 | {% block content %}{% endblock content %} 7 | {% block footer %}foot{% endblock footer %} 8 | -------------------------------------------------------------------------------- /contrib/lib/tests/templates/tera/html_test.html.tera: -------------------------------------------------------------------------------- 1 | {% extends "tera/base" %} 2 | {% block title %}{{ title }}{% endblock title %} 3 | {% block content %} 4 | {{ content }} 5 | {% endblock content %} 6 | -------------------------------------------------------------------------------- /contrib/lib/tests/templates/tera/txt_test.txt.tera: -------------------------------------------------------------------------------- 1 | {% extends "tera/base" %} 2 | {% block title %}{{ title }}{% endblock title %} 3 | {% block content %} 4 | {{ content }} 5 | {% endblock content %} 6 | -------------------------------------------------------------------------------- /core/codegen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_codegen" 3 | version = "0.4.0" 4 | authors = ["Sergio Benitez "] 5 | description = "Procedural macros for the Rocket web framework." 6 | documentation = "https://api.rocket.rs/v0.4/rocket_codegen/" 7 | homepage = "https://rocket.rs" 8 | repository = "https://github.com/SergioBenitez/Rocket" 9 | readme = "../../README.md" 10 | keywords = ["rocket", "web", "framework", "code", "generation"] 11 | license = "MIT/Apache-2.0" 12 | build = "build.rs" 13 | 14 | [lib] 15 | proc-macro = true 16 | 17 | [dependencies] 18 | indexmap = "1.0" 19 | quote = "0.6.1" 20 | rocket_http = { version = "0.4.0", path = "../http/" } 21 | devise = "0.2" 22 | 23 | [build-dependencies] 24 | yansi = "0.5" 25 | version_check = "0.1.3" 26 | 27 | [dev-dependencies] 28 | rocket = { version = "0.4.0", path = "../lib" } 29 | compiletest_rs = { version = "0.3", features = ["stable"] } 30 | -------------------------------------------------------------------------------- /core/codegen/src/attribute/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod catch; 2 | pub mod route; 3 | pub mod segments; 4 | -------------------------------------------------------------------------------- /core/codegen/src/bang/mod.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use proc_macro2::TokenStream as TokenStream2; 3 | 4 | use devise::{syn, Spanned, Result}; 5 | use self::syn::{Path, punctuated::Punctuated, parse::Parser, token::Comma}; 6 | use syn_ext::{IdentExt, syn_to_diag}; 7 | use {ROUTE_STRUCT_PREFIX, CATCH_STRUCT_PREFIX}; 8 | 9 | mod uri; 10 | mod uri_parsing; 11 | 12 | crate fn prefix_last_segment(path: &mut Path, prefix: &str) { 13 | let mut last_seg = path.segments.last_mut().expect("syn::Path has segments"); 14 | last_seg.value_mut().ident = last_seg.value().ident.prepend(prefix); 15 | } 16 | 17 | fn _prefixed_vec( 18 | prefix: &str, 19 | input: TokenStream, 20 | ty: &TokenStream2 21 | ) -> Result { 22 | // Parse a comma-separated list of paths. 23 | let mut paths = >::parse_terminated 24 | .parse(input) 25 | .map_err(syn_to_diag)?; 26 | 27 | // Prefix the last segment in each path with `prefix`. 28 | paths.iter_mut().for_each(|p| prefix_last_segment(p, prefix)); 29 | 30 | // Return a `vec!` of the prefixed, mapped paths. 31 | let prefixed_mapped_paths = paths.iter() 32 | .map(|path| quote_spanned!(path.span().into() => #ty::from(&#path))); 33 | 34 | Ok(quote!(vec![#(#prefixed_mapped_paths),*])) 35 | } 36 | 37 | fn prefixed_vec(prefix: &str, input: TokenStream, ty: TokenStream2) -> TokenStream { 38 | let vec = _prefixed_vec(prefix, input, &ty) 39 | .map_err(|diag| diag.emit()) 40 | .unwrap_or_else(|_| quote!(vec![])); 41 | 42 | quote!({ 43 | let __vector: Vec<#ty> = #vec; 44 | __vector 45 | }).into() 46 | } 47 | 48 | pub fn routes_macro(input: TokenStream) -> TokenStream { 49 | prefixed_vec(ROUTE_STRUCT_PREFIX, input, quote!(::rocket::Route)) 50 | } 51 | 52 | pub fn catchers_macro(input: TokenStream) -> TokenStream { 53 | prefixed_vec(CATCH_STRUCT_PREFIX, input, quote!(::rocket::Catcher)) 54 | } 55 | 56 | pub fn uri_macro(input: TokenStream) -> TokenStream { 57 | uri::_uri_macro(input) 58 | .map_err(|diag| diag.emit()) 59 | .unwrap_or_else(|_| quote!(()).into()) 60 | } 61 | 62 | pub fn uri_internal_macro(input: TokenStream) -> TokenStream { 63 | uri::_uri_internal_macro(input) 64 | .map_err(|diag| diag.emit()) 65 | .unwrap_or_else(|_| quote!(()).into()) 66 | } 67 | -------------------------------------------------------------------------------- /core/codegen/src/derive/from_form_value.rs: -------------------------------------------------------------------------------- 1 | use devise::*; 2 | use proc_macro::TokenStream; 3 | 4 | #[derive(FromMeta)] 5 | struct Form { 6 | value: String, 7 | } 8 | 9 | pub fn derive_from_form_value(input: TokenStream) -> TokenStream { 10 | DeriveGenerator::build_for(input, quote!(impl<'__v> ::rocket::request::FromFormValue<'__v>)) 11 | .generic_support(GenericSupport::None) 12 | .data_support(DataSupport::Enum) 13 | .validate_enum(|generator, data| { 14 | // This derive only works for variants that are nullary. 15 | for variant in data.variants() { 16 | if !variant.fields().is_empty() { 17 | return Err(variant.span().error("variants cannot have fields")); 18 | } 19 | } 20 | 21 | // Emit a warning if the enum is empty. 22 | if data.variants.is_empty() { 23 | generator.input.span().warning("deriving for empty enum").emit(); 24 | } 25 | 26 | Ok(()) 27 | }) 28 | .function(|_, inner| quote! { 29 | type Error = &'__v ::rocket::http::RawStr; 30 | 31 | fn from_form_value( 32 | value: &'__v ::rocket::http::RawStr 33 | ) -> ::std::result::Result { 34 | let uncased = value.as_uncased_str(); 35 | #inner 36 | ::std::result::Result::Err(value) 37 | } 38 | }) 39 | .try_map_enum(null_enum_mapper) 40 | .try_map_variant(|_, variant| { 41 | let variant_str = Form::from_attrs("form", &variant.attrs) 42 | .unwrap_or_else(|| Ok(Form { value: variant.ident.to_string() }))? 43 | .value; 44 | 45 | let builder = variant.builder(|_| unreachable!()); 46 | Ok(quote! { 47 | if uncased == #variant_str { 48 | return ::std::result::Result::Ok(#builder); 49 | } 50 | }) 51 | }) 52 | .to_tokens() 53 | } 54 | -------------------------------------------------------------------------------- /core/codegen/src/derive/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod from_form; 2 | pub mod from_form_value; 3 | pub mod responder; 4 | pub mod uri_display; 5 | -------------------------------------------------------------------------------- /core/codegen/src/proc_macro_ext.rs: -------------------------------------------------------------------------------- 1 | use std::ops::RangeBounds; 2 | 3 | use proc_macro::{Span, Diagnostic, Literal}; 4 | 5 | pub type PResult = ::std::result::Result; 6 | 7 | pub type DResult = ::std::result::Result; 8 | 9 | // An experiment. 10 | pub struct Diagnostics(Vec); 11 | 12 | impl Diagnostics { 13 | pub fn new() -> Self { 14 | Diagnostics(vec![]) 15 | } 16 | 17 | pub fn push(&mut self, diag: Diagnostic) { 18 | self.0.push(diag); 19 | } 20 | 21 | pub fn join(mut self, mut diags: Diagnostics) -> Self { 22 | self.0.append(&mut diags.0); 23 | self 24 | } 25 | 26 | pub fn emit_head(self) -> Diagnostic { 27 | let mut iter = self.0.into_iter(); 28 | let mut last = iter.next().expect("Diagnostic::emit_head empty"); 29 | for diag in iter { 30 | last.emit(); 31 | last = diag; 32 | } 33 | 34 | last 35 | } 36 | 37 | pub fn head_err_or(self, ok: T) -> PResult { 38 | match self.0.is_empty() { 39 | true => Ok(ok), 40 | false => Err(self.emit_head()) 41 | } 42 | } 43 | 44 | pub fn err_or(self, ok: T) -> DResult { 45 | match self.0.is_empty() { 46 | true => Ok(ok), 47 | false => Err(self) 48 | } 49 | } 50 | } 51 | 52 | impl From for Diagnostics { 53 | fn from(diag: Diagnostic) -> Self { 54 | Diagnostics(vec![diag]) 55 | } 56 | } 57 | 58 | impl From> for Diagnostics { 59 | fn from(diags: Vec) -> Self { 60 | Diagnostics(diags) 61 | } 62 | } 63 | 64 | use std::ops::Deref; 65 | 66 | pub struct StringLit(crate String, crate Literal); 67 | 68 | impl Deref for StringLit { 69 | type Target = str; 70 | 71 | fn deref(&self) -> &str { 72 | &self.0 73 | } 74 | } 75 | 76 | impl StringLit { 77 | pub fn new>(string: S, span: Span) -> Self { 78 | let string = string.into(); 79 | let mut lit = Literal::string(&string); 80 | lit.set_span(span); 81 | StringLit(string, lit) 82 | } 83 | 84 | pub fn span(&self) -> Span { 85 | self.1.span() 86 | } 87 | 88 | pub fn subspan>(&self, range: R) -> Option { 89 | self.1.subspan(range) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /core/codegen/src/syn_ext.rs: -------------------------------------------------------------------------------- 1 | //! Extensions to `syn` types. 2 | 3 | use devise::syn; 4 | use proc_macro::Diagnostic; 5 | 6 | pub fn syn_to_diag(error: syn::parse::Error) -> Diagnostic { 7 | error.span().unstable().error(error.to_string()) 8 | } 9 | 10 | pub trait IdentExt { 11 | fn prepend(&self, string: &str) -> syn::Ident; 12 | } 13 | 14 | impl IdentExt for syn::Ident { 15 | fn prepend(&self, string: &str) -> syn::Ident { 16 | syn::Ident::new(&format!("{}{}", string, self), self.span()) 17 | } 18 | } 19 | 20 | pub trait ReturnTypeExt { 21 | fn ty(&self) -> Option<&syn::Type>; 22 | } 23 | 24 | impl ReturnTypeExt for syn::ReturnType { 25 | fn ty(&self) -> Option<&syn::Type> { 26 | match self { 27 | syn::ReturnType::Default => None, 28 | syn::ReturnType::Type(_, ty) => Some(ty), 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/codegen/tests/expansion.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::local::Client; 6 | 7 | #[get("/easy/")] 8 | fn easy(id: i32) -> String { 9 | format!("easy id: {}", id) 10 | } 11 | 12 | macro_rules! make_handler { 13 | () => { 14 | #[get("/hard/")] 15 | fn hard(id: i32) -> String { 16 | format!("hard id: {}", id) 17 | } 18 | } 19 | } 20 | 21 | make_handler!(); 22 | 23 | #[test] 24 | fn test_reexpansion() { 25 | let rocket = rocket::ignite().mount("/", routes![easy, hard]); 26 | let client = Client::new(rocket).unwrap(); 27 | 28 | let mut response = client.get("/easy/327").dispatch(); 29 | assert_eq!(response.body_string().unwrap(), "easy id: 327"); 30 | 31 | let mut response = client.get("/hard/72").dispatch(); 32 | assert_eq!(response.body_string().unwrap(), "hard id: 72"); 33 | } 34 | 35 | macro_rules! index { 36 | ($type:ty) => { 37 | #[get("/")] 38 | fn index(thing: rocket::State<$type>) -> String { 39 | format!("Thing: {}", *thing) 40 | } 41 | } 42 | } 43 | 44 | index!(i32); 45 | 46 | #[test] 47 | fn test_index() { 48 | let rocket = rocket::ignite().mount("/", routes![index]).manage(100i32); 49 | let client = Client::new(rocket).unwrap(); 50 | 51 | let mut response = client.get("/").dispatch(); 52 | assert_eq!(response.body_string().unwrap(), "Thing: 100"); 53 | } 54 | -------------------------------------------------------------------------------- /core/codegen/tests/from_form_value.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::request::FromFormValue; 4 | 5 | macro_rules! assert_parse { 6 | ($($string:expr),* => $item:ident :: $variant:ident) => ($( 7 | match $item::from_form_value($string.into()) { 8 | Ok($item::$variant) => { /* okay */ }, 9 | Ok(item) => panic!("Failed to parse {} as {:?}. Got {:?} instead.", 10 | $string, $item::$variant, item), 11 | Err(e) => panic!("Failed to parse {} as {}: {:?}", 12 | $string, stringify!($item), e), 13 | 14 | } 15 | )*) 16 | } 17 | 18 | macro_rules! assert_no_parse { 19 | ($($string:expr),* => $item:ident) => ($( 20 | match $item::from_form_value($string.into()) { 21 | Err(_) => { /* okay */ }, 22 | Ok(item) => panic!("Unexpectedly parsed {} as {:?}", $string, item) 23 | } 24 | )*) 25 | } 26 | 27 | #[test] 28 | fn from_form_value_simple() { 29 | #[derive(Debug, FromFormValue)] 30 | enum Foo { A, B, C, } 31 | 32 | assert_parse!("a", "A" => Foo::A); 33 | assert_parse!("b", "B" => Foo::B); 34 | assert_parse!("c", "C" => Foo::C); 35 | } 36 | 37 | #[test] 38 | fn from_form_value_weirder() { 39 | #[allow(non_camel_case_types)] 40 | #[derive(Debug, FromFormValue)] 41 | enum Foo { Ab_Cd, OtherA } 42 | 43 | assert_parse!("ab_cd", "ab_CD", "Ab_CD" => Foo::Ab_Cd); 44 | assert_parse!("othera", "OTHERA", "otherA", "OtherA" => Foo::OtherA); 45 | } 46 | 47 | #[test] 48 | fn from_form_value_no_parse() { 49 | #[derive(Debug, FromFormValue)] 50 | enum Foo { A, B, C, } 51 | 52 | assert_no_parse!("abc", "ab", "bc", "ca" => Foo); 53 | assert_no_parse!("b ", "a ", "c ", "a b" => Foo); 54 | } 55 | 56 | #[test] 57 | fn from_form_value_renames() { 58 | #[derive(Debug, FromFormValue)] 59 | enum Foo { 60 | #[form(value = "foo")] 61 | Bar, 62 | #[form(value = ":book")] 63 | Book 64 | } 65 | 66 | assert_parse!("foo", "FOO", "FoO" => Foo::Bar); 67 | assert_parse!(":book", ":BOOK", ":bOOk", ":booK" => Foo::Book); 68 | assert_no_parse!("book", "bar" => Foo); 69 | } 70 | -------------------------------------------------------------------------------- /core/codegen/tests/route-data.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use std::io::Read; 6 | 7 | use rocket::{Request, Data, Outcome::*}; 8 | use rocket::local::Client; 9 | use rocket::request::Form; 10 | use rocket::data::{self, FromDataSimple}; 11 | use rocket::http::{RawStr, ContentType, Status}; 12 | 13 | // Test that the data parameters works as expected. 14 | 15 | #[derive(FromForm)] 16 | struct Inner<'r> { 17 | field: &'r RawStr 18 | } 19 | 20 | struct Simple(String); 21 | 22 | impl FromDataSimple for Simple { 23 | type Error = (); 24 | 25 | fn from_data(_: &Request, data: Data) -> data::Outcome { 26 | let mut string = String::new(); 27 | if let Err(_) = data.open().take(64).read_to_string(&mut string) { 28 | return Failure((Status::InternalServerError, ())); 29 | } 30 | 31 | Success(Simple(string)) 32 | } 33 | } 34 | 35 | #[post("/f", data = "
")] 36 | fn form(form: Form) -> String { form.field.url_decode_lossy() } 37 | 38 | #[post("/s", data = "")] 39 | fn simple(simple: Simple) -> String { simple.0 } 40 | 41 | #[test] 42 | fn test_data() { 43 | let rocket = rocket::ignite().mount("/", routes![form, simple]); 44 | let client = Client::new(rocket).unwrap(); 45 | 46 | let mut response = client.post("/f") 47 | .header(ContentType::Form) 48 | .body("field=this%20is%20here") 49 | .dispatch(); 50 | 51 | assert_eq!(response.body_string().unwrap(), "this is here"); 52 | 53 | let mut response = client.post("/s").body("this is here").dispatch(); 54 | assert_eq!(response.body_string().unwrap(), "this is here"); 55 | 56 | let mut response = client.post("/s").body("this%20is%20here").dispatch(); 57 | assert_eq!(response.body_string().unwrap(), "this%20is%20here"); 58 | } 59 | -------------------------------------------------------------------------------- /core/codegen/tests/route-params.rs: -------------------------------------------------------------------------------- 1 | // #[post("/<_name>?<_query>", format = "application/json", data = "", rank = 2)] 2 | // fn get( 3 | // _name: &RawStr, 4 | // _query: User, 5 | // user: Form, 6 | // _cookies: Cookies 7 | // ) -> String { 8 | // format!("{}:{}", user.name, user.nickname) 9 | // } 10 | 11 | -------------------------------------------------------------------------------- /core/codegen/tests/route-ranking.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::local::Client; 6 | 7 | // Test that manual/auto ranking works as expected. 8 | 9 | #[get("/<_number>")] 10 | fn get0(_number: u8) -> &'static str { "0" } 11 | 12 | #[get("/<_number>", rank = 1)] 13 | fn get1(_number: u16) -> &'static str { "1" } 14 | 15 | #[get("/<_number>", rank = 2)] 16 | fn get2(_number: u32) -> &'static str { "2" } 17 | 18 | #[get("/<_number>", rank = 3)] 19 | fn get3(_number: u64) -> &'static str { "3" } 20 | 21 | #[test] 22 | fn test_ranking() { 23 | let rocket = rocket::ignite().mount("/", routes![get0, get1, get2, get3]); 24 | let client = Client::new(rocket).unwrap(); 25 | 26 | let mut response = client.get("/0").dispatch(); 27 | assert_eq!(response.body_string().unwrap(), "0"); 28 | 29 | let mut response = client.get(format!("/{}", 1 << 8)).dispatch(); 30 | assert_eq!(response.body_string().unwrap(), "1"); 31 | 32 | let mut response = client.get(format!("/{}", 1 << 16)).dispatch(); 33 | assert_eq!(response.body_string().unwrap(), "2"); 34 | 35 | let mut response = client.get(format!("/{}", 1u64 << 32)).dispatch(); 36 | assert_eq!(response.body_string().unwrap(), "3"); 37 | } 38 | 39 | // Test a collision due to same auto rank. 40 | 41 | #[get("/<_n>")] 42 | fn get0b(_n: u8) { } 43 | 44 | #[test] 45 | fn test_rank_collision() { 46 | use rocket::error::LaunchErrorKind; 47 | 48 | let rocket = rocket::ignite().mount("/", routes![get0, get0b]); 49 | let client_result = Client::new(rocket); 50 | match client_result.as_ref().map_err(|e| e.kind()) { 51 | Err(LaunchErrorKind::Collision(..)) => { /* o.k. */ }, 52 | Ok(_) => panic!("client succeeded unexpectedly"), 53 | Err(e) => panic!("expected collision, got {}", e) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/catch.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::Request; 4 | 5 | #[catch(404)] 6 | struct Catcher(String); 7 | //~^ ERROR expected `fn` 8 | //~^^ HELP on functions 9 | 10 | #[catch(404)] 11 | const CATCH: &str = "Catcher"; 12 | //~^ ERROR expected `fn` 13 | //~^^ HELP on functions 14 | 15 | #[catch("404")] //~ ERROR expected unsigned integer literal 16 | //~^ HELP #[catch(404)] 17 | fn e1(_request: &Request) { } 18 | 19 | #[catch(code = "404")] //~ ERROR unexpected keyed parameter 20 | //~^ HELP #[catch(404)] 21 | fn e2(_request: &Request) { } 22 | 23 | #[catch(code = 404)] //~ ERROR unexpected keyed parameter 24 | //~^ HELP #[catch(404)] 25 | fn e3(_request: &Request) { } 26 | 27 | #[catch(99)] //~ ERROR in range [100, 599] 28 | //~^ HELP #[catch(404)] 29 | fn e4(_request: &Request) { } 30 | 31 | #[catch(600)] //~ ERROR in range [100, 599] 32 | //~^ HELP #[catch(404)] 33 | fn e5(_request: &Request) { } 34 | 35 | #[catch(400, message = "foo")] //~ ERROR unexpected attribute parameter: `message` 36 | //~^ HELP #[catch(404)] 37 | fn e5(_request: &Request) { } 38 | 39 | #[catch(404)] 40 | fn f3(_request: &Request, other: bool) { 41 | //~^ ERROR invalid number of arguments 42 | //~^^ HELP optionally take an argument 43 | } 44 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/catch.stderr: -------------------------------------------------------------------------------- 1 | error: expected `fn` 2 | --> $DIR/catch.rs:6:1 3 | | 4 | 6 | struct Catcher(String); 5 | | ^^^^^^ 6 | | 7 | = help: `#[catch]` can only be used on functions 8 | 9 | error: expected `fn` 10 | --> $DIR/catch.rs:11:7 11 | | 12 | 11 | const CATCH: &str = "Catcher"; 13 | | ^^^^^ 14 | | 15 | = help: `#[catch]` can only be used on functions 16 | 17 | error: invalid value: expected unsigned integer literal 18 | --> $DIR/catch.rs:15:9 19 | | 20 | 15 | #[catch("404")] //~ ERROR expected unsigned integer literal 21 | | ^^^^^ 22 | | 23 | = help: `#[catch]` expects a single status integer, e.g.: #[catch(404)] 24 | 25 | error: unexpected keyed parameter: expected literal or identifier 26 | --> $DIR/catch.rs:19:9 27 | | 28 | 19 | #[catch(code = "404")] //~ ERROR unexpected keyed parameter 29 | | ^^^^^^^^^^^^ 30 | | 31 | = help: `#[catch]` expects a single status integer, e.g.: #[catch(404)] 32 | 33 | error: unexpected keyed parameter: expected literal or identifier 34 | --> $DIR/catch.rs:23:9 35 | | 36 | 23 | #[catch(code = 404)] //~ ERROR unexpected keyed parameter 37 | | ^^^^^^^^^^ 38 | | 39 | = help: `#[catch]` expects a single status integer, e.g.: #[catch(404)] 40 | 41 | error: status must be in range [100, 599] 42 | --> $DIR/catch.rs:27:9 43 | | 44 | 27 | #[catch(99)] //~ ERROR in range [100, 599] 45 | | ^^ 46 | | 47 | = help: `#[catch]` expects a single status integer, e.g.: #[catch(404)] 48 | 49 | error: status must be in range [100, 599] 50 | --> $DIR/catch.rs:31:9 51 | | 52 | 31 | #[catch(600)] //~ ERROR in range [100, 599] 53 | | ^^^ 54 | | 55 | = help: `#[catch]` expects a single status integer, e.g.: #[catch(404)] 56 | 57 | error: unexpected attribute parameter: `message` 58 | --> $DIR/catch.rs:35:14 59 | | 60 | 35 | #[catch(400, message = "foo")] //~ ERROR unexpected attribute parameter: `message` 61 | | ^^^^^^^^^^^^^^^ 62 | | 63 | = help: `#[catch]` expects a single status integer, e.g.: #[catch(404)] 64 | 65 | error: invalid number of arguments: must be zero or one 66 | --> $DIR/catch.rs:40:7 67 | | 68 | 40 | fn f3(_request: &Request, other: bool) { 69 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 70 | | 71 | = help: catchers may optionally take an argument of type `&Request` 72 | 73 | error: aborting due to 9 previous errors 74 | 75 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/catch_type_errors.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::Request; 4 | 5 | #[catch(404)] 6 | fn f1(_request: &Request) -> usize { 7 | //~^ ERROR usize: rocket::response::Responder 8 | 10 9 | } 10 | 11 | #[catch(404)] 12 | fn f2(_request: &Request) -> bool { 13 | //~^ ERROR bool: rocket::response::Responder 14 | false 15 | } 16 | 17 | #[catch(404)] 18 | fn f3(_request: bool) -> usize { 19 | //~^ ERROR mismatched types 20 | 10 21 | } 22 | 23 | #[catch(404)] 24 | fn f4() -> usize { 25 | //~^ ERROR usize: rocket::response::Responder 26 | 10 27 | } 28 | 29 | fn main() { } 30 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/catch_type_errors.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `usize: rocket::response::Responder<'_>` is not satisfied 2 | --> $DIR/catch_type_errors.rs:6:30 3 | | 4 | 6 | fn f1(_request: &Request) -> usize { 5 | | ^^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `usize` 6 | | 7 | = note: required by `rocket::response::Responder::respond_to` 8 | 9 | error[E0277]: the trait bound `bool: rocket::response::Responder<'_>` is not satisfied 10 | --> $DIR/catch_type_errors.rs:12:30 11 | | 12 | 12 | fn f2(_request: &Request) -> bool { 13 | | ^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `bool` 14 | | 15 | = note: required by `rocket::response::Responder::respond_to` 16 | 17 | error[E0308]: mismatched types 18 | --> $DIR/catch_type_errors.rs:18:7 19 | | 20 | 18 | fn f3(_request: bool) -> usize { 21 | | ^^^^^^^^^^^^^^ expected reference, found bool 22 | | 23 | = note: expected type `for<'r, 's> fn(&'r rocket::Request<'s>) -> _` 24 | found type `fn(bool) -> usize {f3}` 25 | 26 | error[E0277]: the trait bound `usize: rocket::response::Responder<'_>` is not satisfied 27 | --> $DIR/catch_type_errors.rs:24:12 28 | | 29 | 24 | fn f4() -> usize { 30 | | ^^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `usize` 31 | | 32 | = note: required by `rocket::response::Responder::respond_to` 33 | 34 | error: aborting due to 4 previous errors 35 | 36 | Some errors occurred: E0277, E0308. 37 | For more information about an error, try `rustc --explain E0277`. 38 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/catchers.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | fn main() { 6 | let _ = catchers![a b]; //~ ERROR expected 7 | let _ = catchers![]; 8 | let _ = catchers![a::, ]; //~ ERROR expected identifier 9 | let _ = catchers![a::]; //~ ERROR expected identifier 10 | } 11 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/catchers.stderr: -------------------------------------------------------------------------------- 1 | error: expected `,` 2 | --> $DIR/catchers.rs:6:25 3 | | 4 | 6 | let _ = catchers![a b]; //~ ERROR expected 5 | | ^ 6 | 7 | error: expected identifier 8 | --> $DIR/catchers.rs:8:26 9 | | 10 | 8 | let _ = catchers![a::, ]; //~ ERROR expected identifier 11 | | ^ 12 | 13 | error: unexpected end of input, expected identifier 14 | --> $DIR/catchers.rs:9:13 15 | | 16 | 9 | let _ = catchers![a::]; //~ ERROR expected identifier 17 | | ^^^^^^^^^^^^^^ 18 | 19 | error: aborting due to 3 previous errors 20 | 21 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/from_form_type_errors.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | struct Unknown; 4 | 5 | #[derive(FromForm)] 6 | struct BadType3 { 7 | field: Unknown, 8 | //~^ rocket::request::FromFormValue 9 | } 10 | 11 | struct Foo(T); 12 | 13 | #[derive(FromForm)] 14 | struct Other { 15 | field: Foo, 16 | //~^ rocket::request::FromFormValue 17 | } 18 | 19 | fn main() { } 20 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/from_form_type_errors.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `Unknown: rocket::request::FromFormValue<'_>` is not satisfied 2 | --> $DIR/from_form_type_errors.rs:7:5 3 | | 4 | 7 | field: Unknown, 5 | | ^^^^^^^^^^^^^^ the trait `rocket::request::FromFormValue<'_>` is not implemented for `Unknown` 6 | 7 | error[E0277]: the trait bound `Foo: rocket::request::FromFormValue<'_>` is not satisfied 8 | --> $DIR/from_form_type_errors.rs:15:5 9 | | 10 | 15 | field: Foo, 11 | | ^^^^^^^^^^^^^^^^^ the trait `rocket::request::FromFormValue<'_>` is not implemented for `Foo` 12 | 13 | error: aborting due to 2 previous errors 14 | 15 | For more information about this error, try `rustc --explain E0277`. 16 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/from_form_value.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[derive(FromFormValue)] 4 | struct Foo1; 5 | //~^ ERROR not supported 6 | 7 | #[derive(FromFormValue)] 8 | struct Foo2(usize); 9 | //~^ ERROR not supported 10 | 11 | #[derive(FromFormValue)] 12 | struct Foo3 { 13 | //~^ ERROR not supported 14 | foo: usize, 15 | } 16 | 17 | #[derive(FromFormValue)] 18 | enum Foo4 { 19 | A(usize), 20 | //~^ ERROR cannot have fields 21 | } 22 | 23 | #[derive(FromFormValue)] 24 | enum Foo5 { } 25 | //~^ WARNING empty enum 26 | 27 | #[derive(FromFormValue)] 28 | enum Foo6 { 29 | //~^ ERROR type generics are not supported 30 | A(T), 31 | } 32 | 33 | #[derive(FromFormValue)] 34 | enum Bar1 { 35 | #[form(value = 123)] 36 | //~^ ERROR invalid value: expected string 37 | A, 38 | } 39 | 40 | #[derive(FromFormValue)] 41 | enum Bar2 { 42 | #[form(value)] 43 | //~^ ERROR expected literal or key/value 44 | A, 45 | } 46 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/responder-types.rs: -------------------------------------------------------------------------------- 1 | // normalize-stderr-test: "<(.*) as (.*)>" -> "$1 as $$TRAIT" 2 | // normalize-stderr-test: "and \d+ others" -> "and $$N others" 3 | 4 | #[macro_use] extern crate rocket; 5 | 6 | #[derive(Responder)] 7 | struct Thing1 { 8 | thing: u8, 9 | //~^ ERROR Responder 10 | } 11 | 12 | #[derive(Responder)] 13 | struct Thing2 { 14 | thing: String, 15 | other: u8, 16 | //~^ ERROR Header 17 | } 18 | 19 | #[derive(Responder)] 20 | struct Thing3 { 21 | thing: u8, 22 | //~^ ERROR Responder 23 | other: u8, 24 | //~^ ERROR Header 25 | } 26 | 27 | #[derive(Responder)] 28 | struct Thing4 { 29 | thing: String, 30 | other: ::rocket::http::ContentType, 31 | then: String, 32 | //~^ ERROR Header 33 | } 34 | 35 | fn main() { } 36 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/route-type-errors.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | struct Q; 6 | 7 | #[get("/")] 8 | fn f0(foo: Q) {} //~ ERROR FromParam 9 | 10 | #[get("/")] 11 | fn f1(foo: Q) {} //~ ERROR FromSegments 12 | 13 | #[get("/?")] 14 | fn f2(foo: Q) {} //~ ERROR FromFormValue 15 | 16 | #[get("/?")] 17 | fn f3(foo: Q) {} //~ ERROR FromQuery 18 | 19 | #[post("/", data = "")] 20 | fn f4(foo: Q) {} //~ ERROR FromData 21 | 22 | #[get("/")] 23 | fn f5(a: Q, foo: Q) {} 24 | //~^ ERROR FromParam 25 | //~^^ ERROR FromRequest 26 | 27 | #[get("//other///okay")] 28 | fn f6(a: Q, foo: Q, good: usize, bar: Q) {} 29 | //~^ ERROR FromParam 30 | //~^^ ERROR FromParam 31 | //~^^^ ERROR FromRequest 32 | 33 | fn main() { } 34 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/route-warnings.rs: -------------------------------------------------------------------------------- 1 | // must-compile-successfully 2 | 3 | #![feature(proc_macro_hygiene, decl_macro)] 4 | 5 | #[macro_use] extern crate rocket; 6 | 7 | // Check for unknown media types. 8 | 9 | #[get("/", format = "application/x-custom")] //~ WARNING not a known media type 10 | fn f0() {} 11 | 12 | #[get("/", format = "x-custom/plain")] //~ WARNING not a known media type 13 | fn f1() {} 14 | 15 | #[get("/", format = "x-custom/x-custom")] //~ WARNING not a known media type 16 | fn f2() {} 17 | 18 | // Check if a data argument is used with a usually non-payload bearing method. 19 | 20 | #[get("/", data = "<_foo>")] //~ WARNING used with non-payload-supporting method 21 | fn g0(_foo: rocket::Data) {} 22 | 23 | #[head("/", data = "<_foo>")] //~ WARNING used with non-payload-supporting method 24 | fn g1(_foo: rocket::Data) {} 25 | 26 | fn main() { } 27 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/route-warnings.stderr: -------------------------------------------------------------------------------- 1 | warning: 'application/x-custom' is not a known media type 2 | --> $DIR/route-warnings.rs:9:21 3 | | 4 | 9 | #[get("/", format = "application/x-custom")] //~ WARNING not a known media type 5 | | ^^^^^^^^^^^^^^^^^^^^^^ 6 | 7 | warning: 'x-custom/plain' is not a known media type 8 | --> $DIR/route-warnings.rs:12:21 9 | | 10 | 12 | #[get("/", format = "x-custom/plain")] //~ WARNING not a known media type 11 | | ^^^^^^^^^^^^^^^^ 12 | 13 | warning: 'x-custom/x-custom' is not a known media type 14 | --> $DIR/route-warnings.rs:15:21 15 | | 16 | 15 | #[get("/", format = "x-custom/x-custom")] //~ WARNING not a known media type 17 | | ^^^^^^^^^^^^^^^^^^^ 18 | 19 | warning: `data` used with non-payload-supporting method 20 | --> $DIR/route-warnings.rs:20:12 21 | | 22 | 20 | #[get("/", data = "<_foo>")] //~ WARNING used with non-payload-supporting method 23 | | ^^^^^^^^^^^^^^^ 24 | | 25 | note: 'GET' does not typically support payloads 26 | --> $DIR/route-warnings.rs:20:3 27 | | 28 | 20 | #[get("/", data = "<_foo>")] //~ WARNING used with non-payload-supporting method 29 | | ^^^ 30 | 31 | warning: `data` used with non-payload-supporting method 32 | --> $DIR/route-warnings.rs:23:13 33 | | 34 | 23 | #[head("/", data = "<_foo>")] //~ WARNING used with non-payload-supporting method 35 | | ^^^^^^^^^^^^^^^ 36 | | 37 | note: 'HEAD' does not typically support payloads 38 | --> $DIR/route-warnings.rs:23:3 39 | | 40 | 23 | #[head("/", data = "<_foo>")] //~ WARNING used with non-payload-supporting method 41 | | ^^^^ 42 | 43 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/routes.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | fn main() { 6 | let _ = routes![a b]; //~ ERROR expected `,` 7 | let _ = routes![]; 8 | let _ = routes![a::, ]; //~ ERROR expected identifier 9 | let _ = routes![a::]; //~ ERROR expected identifier 10 | } 11 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/routes.stderr: -------------------------------------------------------------------------------- 1 | error: expected `,` 2 | --> $DIR/routes.rs:6:23 3 | | 4 | 6 | let _ = routes![a b]; //~ ERROR expected `,` 5 | | ^ 6 | 7 | error: expected identifier 8 | --> $DIR/routes.rs:8:24 9 | | 10 | 8 | let _ = routes![a::, ]; //~ ERROR expected identifier 11 | | ^ 12 | 13 | error: unexpected end of input, expected identifier 14 | --> $DIR/routes.rs:9:13 15 | | 16 | 9 | let _ = routes![a::]; //~ ERROR expected identifier 17 | | ^^^^^^^^^^^^ 18 | 19 | error: aborting due to 3 previous errors 20 | 21 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/typed-uris-invalid-syntax.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[post("//")] 6 | fn simple(id: i32, name: String) -> &'static str { "" } 7 | 8 | fn main() { 9 | uri!(simple: id = 100, "Hello"); //~ ERROR named and unnamed 10 | uri!(simple: "Hello", id = 100); //~ ERROR named and unnamed 11 | uri!(simple,); //~ ERROR expected `:` 12 | uri!(simple:); //~ ERROR argument list 13 | uri!("/mount"); //~ ERROR route path 14 | uri!("/mount",); //~ ERROR expected identifier 15 | uri!("mount", simple); //~ invalid mount point 16 | uri!("/mount/", simple); //~ invalid mount point 17 | uri!(); //~ unexpected end of input 18 | uri!(simple: id = ); //~ expected expression 19 | } 20 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/typed-uris-invalid-syntax.stderr: -------------------------------------------------------------------------------- 1 | error: named and unnamed parameters cannot be mixed 2 | --> $DIR/typed-uris-invalid-syntax.rs:9:18 3 | | 4 | 9 | uri!(simple: id = 100, "Hello"); //~ ERROR named and unnamed 5 | | ^^^^^^^^^^^^^^^^^ 6 | 7 | error: named and unnamed parameters cannot be mixed 8 | --> $DIR/typed-uris-invalid-syntax.rs:10:18 9 | | 10 | 10 | uri!(simple: "Hello", id = 100); //~ ERROR named and unnamed 11 | | ^^^^^^^^^^^^^^^^^ 12 | 13 | error: expected `:` 14 | --> $DIR/typed-uris-invalid-syntax.rs:11:16 15 | | 16 | 11 | uri!(simple,); //~ ERROR expected `:` 17 | | ^ 18 | 19 | error: expected argument list after `:` 20 | --> $DIR/typed-uris-invalid-syntax.rs:12:16 21 | | 22 | 12 | uri!(simple:); //~ ERROR argument list 23 | | ^ 24 | 25 | error: unexpected end of input: expected ',' followed by route path 26 | --> $DIR/typed-uris-invalid-syntax.rs:13:10 27 | | 28 | 13 | uri!("/mount"); //~ ERROR route path 29 | | ^^^^^^^^ 30 | 31 | error: unexpected end of input, expected identifier 32 | --> $DIR/typed-uris-invalid-syntax.rs:14:5 33 | | 34 | 14 | uri!("/mount",); //~ ERROR expected identifier 35 | | ^^^^^^^^^^^^^^^^ 36 | 37 | error: invalid mount point; mount points must be static, absolute URIs: `/example` 38 | --> $DIR/typed-uris-invalid-syntax.rs:15:10 39 | | 40 | 15 | uri!("mount", simple); //~ invalid mount point 41 | | ^^^^^^^ 42 | 43 | error: invalid mount point; mount points must be static, absolute URIs: `/example` 44 | --> $DIR/typed-uris-invalid-syntax.rs:16:10 45 | | 46 | 16 | uri!("/mount/", simple); //~ invalid mount point 47 | | ^^^^^^^^^^^^^ 48 | 49 | error: unexpected end of input, call to `uri!` cannot be empty 50 | --> $DIR/typed-uris-invalid-syntax.rs:17:5 51 | | 52 | 17 | uri!(); //~ unexpected end of input 53 | | ^^^^^^^ 54 | 55 | error: unexpected end of input, expected expression 56 | --> $DIR/typed-uris-invalid-syntax.rs:18:5 57 | | 58 | 18 | uri!(simple: id = ); //~ expected expression 59 | | ^^^^^^^^^^^^^^^^^^^^ 60 | 61 | error: aborting due to 10 previous errors 62 | 63 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/update-references.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright 2015 The Rust Project Developers. See the COPYRIGHT 4 | # file at the top-level directory of this distribution and at 5 | # http://rust-lang.org/COPYRIGHT. 6 | # 7 | # Licensed under the Apache License, Version 2.0 or the MIT license 9 | # , at your 10 | # option. This file may not be copied, modified, or distributed 11 | # except according to those terms. 12 | 13 | # A script to update the references for particular tests. The idea is 14 | # that you do a run, which will generate files in the build directory 15 | # containing the (normalized) actual output of the compiler. This 16 | # script will then copy that output and replace the "expected output" 17 | # files. You can then commit the changes. 18 | # 19 | # If you find yourself manually editing a foo.stderr file, you're 20 | # doing it wrong. 21 | 22 | if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then 23 | echo "usage: $0 " 24 | echo "" 25 | echo "For example:" 26 | echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" 27 | fi 28 | 29 | MYDIR=$(dirname $0) 30 | 31 | BUILD_DIR="$1" 32 | shift 33 | 34 | shopt -s nullglob 35 | 36 | while [[ "$1" != "" ]]; do 37 | for EXT in "stderr" "fixed"; do 38 | for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do 39 | OUT_DIR=`dirname "$1"` 40 | OUT_BASE=`basename "$OUT_NAME"` 41 | if ! (diff $OUT_NAME $MYDIR/$OUT_DIR/$OUT_BASE >& /dev/null); then 42 | echo updating $MYDIR/$OUT_DIR/$OUT_BASE 43 | cp $OUT_NAME $MYDIR/$OUT_DIR 44 | fi 45 | done 46 | done 47 | shift 48 | done 49 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/uri_display.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[derive(UriDisplayQuery)] 4 | struct Foo1; 5 | //~^ ERROR not supported 6 | 7 | #[derive(UriDisplayQuery)] 8 | struct Foo2(); 9 | //~^ ERROR not supported 10 | 11 | #[derive(UriDisplayQuery)] 12 | enum Foo3 { } 13 | //~^ ERROR not supported 14 | 15 | #[derive(UriDisplayQuery)] 16 | enum Foo4 { 17 | Variant, 18 | //~^ ERROR not supported 19 | } 20 | 21 | #[derive(UriDisplayQuery)] 22 | struct Foo5(String, String); 23 | //~^ ERROR exactly one 24 | 25 | #[derive(UriDisplayQuery)] 26 | struct Foo6 { 27 | #[form(field = 123)] 28 | //~^ ERROR invalid value: expected string 29 | field: String, 30 | } 31 | 32 | #[derive(UriDisplayPath)] 33 | struct Foo7(String, usize); 34 | //~^ ERROR exactly one 35 | 36 | #[derive(UriDisplayPath)] 37 | struct Foo8; 38 | //~^ ERROR exactly one 39 | 40 | #[derive(UriDisplayPath)] 41 | enum Foo9 { } 42 | //~^ ERROR not supported 43 | 44 | #[derive(UriDisplayPath)] 45 | struct Foo10 { 46 | //~^ ERROR not supported 47 | named: usize 48 | } 49 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/uri_display_type_errors.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | struct BadType; 4 | 5 | #[derive(UriDisplayQuery)] 6 | struct Bar1(BadType); 7 | //~^ ERROR UriDisplay 8 | 9 | #[derive(UriDisplayQuery)] 10 | struct Bar2 { 11 | field: BadType, 12 | //~^ ERROR UriDisplay 13 | } 14 | 15 | #[derive(UriDisplayQuery)] 16 | struct Bar3 { 17 | field: String, 18 | bad: BadType, 19 | //~^ ERROR UriDisplay 20 | } 21 | 22 | #[derive(UriDisplayQuery)] 23 | enum Bar4 { 24 | Inner(BadType), 25 | //~^ ERROR UriDisplay 26 | } 27 | 28 | #[derive(UriDisplayQuery)] 29 | enum Bar5 { 30 | Inner { 31 | field: BadType, 32 | //~^ ERROR UriDisplay 33 | }, 34 | } 35 | 36 | #[derive(UriDisplayQuery)] 37 | enum Bar6 { 38 | Inner { 39 | field: String, 40 | other: BadType, 41 | //~^ ERROR UriDisplay 42 | }, 43 | } 44 | 45 | #[derive(UriDisplayPath)] 46 | struct Baz(BadType); 47 | //~^ ERROR UriDisplay 48 | 49 | fn main() { } 50 | -------------------------------------------------------------------------------- /core/http/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_http" 3 | version = "0.4.0" 4 | authors = ["Sergio Benitez "] 5 | description = """ 6 | Types, traits, and parsers for HTTP requests, responses, and headers. 7 | """ 8 | documentation = "https://api.rocket.rs/v0.4/rocket_http/" 9 | homepage = "https://rocket.rs" 10 | repository = "https://github.com/SergioBenitez/Rocket" 11 | readme = "../../README.md" 12 | keywords = ["rocket", "web", "framework", "http"] 13 | license = "MIT/Apache-2.0" 14 | categories = ["web-programming"] 15 | 16 | [features] 17 | default = [] 18 | tls = ["rustls", "hyper-sync-rustls"] 19 | private-cookies = ["cookie/secure"] 20 | 21 | [dependencies] 22 | smallvec = "0.6" 23 | percent-encoding = "1" 24 | hyper = { version = "0.10.13", default-features = false } 25 | time = "0.1" 26 | indexmap = "1.0" 27 | rustls = { version = "0.14", optional = true } 28 | state = "0.4" 29 | cookie = { version = "0.11", features = ["percent-encode"] } 30 | pear = "0.1" 31 | unicode-xid = "0.1" 32 | 33 | [dependencies.hyper-sync-rustls] 34 | version = "=0.3.0-rc.4" 35 | features = ["server"] 36 | optional = true 37 | 38 | [dev-dependencies] 39 | rocket = { version = "0.4.0", path = "../lib" } 40 | -------------------------------------------------------------------------------- /core/http/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(specialization)] 2 | #![feature(proc_macro_hygiene)] 3 | #![feature(try_from)] 4 | #![feature(crate_visibility_modifier)] 5 | #![feature(doc_cfg)] 6 | #![recursion_limit="512"] 7 | 8 | //! Types that map to concepts in HTTP. 9 | //! 10 | //! This module exports types that map to HTTP concepts or to the underlying 11 | //! HTTP library when needed. Because the underlying HTTP library is likely to 12 | //! change (see [#17]), types in [`hyper`] should be considered unstable. 13 | //! 14 | //! [#17]: https://github.com/SergioBenitez/Rocket/issues/17 15 | 16 | #[macro_use] extern crate pear; 17 | #[macro_use] extern crate percent_encoding; 18 | extern crate smallvec; 19 | extern crate cookie; 20 | extern crate time; 21 | extern crate indexmap; 22 | extern crate state; 23 | extern crate unicode_xid; 24 | 25 | pub mod hyper; 26 | pub mod uri; 27 | pub mod ext; 28 | 29 | #[doc(hidden)] 30 | #[cfg(feature = "tls")] 31 | pub mod tls; 32 | 33 | #[doc(hidden)] 34 | pub mod route; 35 | 36 | #[macro_use] 37 | mod docify; 38 | #[macro_use] 39 | mod known_media_types; 40 | mod cookies; 41 | mod method; 42 | mod media_type; 43 | mod content_type; 44 | mod status; 45 | mod header; 46 | mod accept; 47 | mod raw_str; 48 | 49 | crate mod parse; 50 | 51 | pub mod uncased; 52 | 53 | #[doc(hidden)] 54 | pub mod private { 55 | // We need to export these for codegen, but otherwise it's unnecessary. 56 | // TODO: Expose a `const fn` from ContentType when possible. (see RFC#1817) 57 | // FIXME(rustc): These show up in the rexported module. 58 | pub use parse::Indexed; 59 | pub use media_type::{MediaParams, Source}; 60 | pub use smallvec::{SmallVec, Array}; 61 | 62 | // This one we need to expose for core. 63 | pub use cookies::{Key, CookieJar}; 64 | } 65 | 66 | pub use method::Method; 67 | pub use content_type::ContentType; 68 | pub use accept::{Accept, QMediaType}; 69 | pub use status::{Status, StatusClass}; 70 | pub use header::{Header, HeaderMap}; 71 | pub use raw_str::RawStr; 72 | 73 | pub use media_type::MediaType; 74 | pub use cookies::{Cookie, SameSite, Cookies}; 75 | -------------------------------------------------------------------------------- /core/http/src/parse/checkers.rs: -------------------------------------------------------------------------------- 1 | #[inline(always)] 2 | pub fn is_whitespace(byte: char) -> bool { 3 | byte == ' ' || byte == '\t' 4 | } 5 | 6 | #[inline] 7 | pub fn is_valid_token(c: char) -> bool { 8 | match c { 9 | '0'...'9' | 'A'...'Z' | '^'...'~' | '#'...'\'' 10 | | '!' | '*' | '+' | '-' | '.' => true, 11 | _ => false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/http/src/parse/mod.rs: -------------------------------------------------------------------------------- 1 | mod media_type; 2 | mod accept; 3 | mod checkers; 4 | mod indexed; 5 | 6 | pub use self::media_type::*; 7 | pub use self::accept::*; 8 | 9 | pub mod uri; 10 | 11 | // Exposed for codegen. 12 | #[doc(hidden)] pub use self::indexed::*; 13 | -------------------------------------------------------------------------------- /core/http/src/parse/uri/mod.rs: -------------------------------------------------------------------------------- 1 | mod parser; 2 | mod error; 3 | mod tables; 4 | #[cfg(test)] 5 | mod tests; 6 | 7 | use uri::{Uri, Origin, Absolute, Authority}; 8 | use parse::indexed::IndexedInput; 9 | use self::parser::{uri, origin, authority_only, absolute_only, rocket_route_origin}; 10 | 11 | pub use self::error::Error; 12 | 13 | type RawInput<'a> = IndexedInput<'a, [u8]>; 14 | 15 | #[inline] 16 | pub fn from_str(string: &str) -> Result { 17 | parse!(uri: &mut RawInput::from(string.as_bytes())) 18 | .map_err(|e| Error::from(string, e)) 19 | } 20 | 21 | #[inline] 22 | pub fn origin_from_str(string: &str) -> Result { 23 | parse!(origin: &mut RawInput::from(string.as_bytes())) 24 | .map_err(|e| Error::from(string, e)) 25 | } 26 | 27 | #[inline] 28 | pub fn route_origin_from_str(string: &str) -> Result { 29 | parse!(rocket_route_origin: &mut RawInput::from(string.as_bytes())) 30 | .map_err(|e| Error::from(string, e)) 31 | } 32 | 33 | #[inline] 34 | pub fn authority_from_str(string: &str) -> Result { 35 | parse!(authority_only: &mut RawInput::from(string.as_bytes())) 36 | .map_err(|e| Error::from(string, e)) 37 | } 38 | 39 | #[inline] 40 | pub fn absolute_from_str(string: &str) -> Result { 41 | parse!(absolute_only: &mut RawInput::from(string.as_bytes())) 42 | .map_err(|e| Error::from(string, e)) 43 | } 44 | -------------------------------------------------------------------------------- /core/http/src/tls.rs: -------------------------------------------------------------------------------- 1 | extern crate rustls; 2 | extern crate hyper_sync_rustls; 3 | 4 | pub use self::hyper_sync_rustls::{util, WrappedStream, ServerSession, TlsServer}; 5 | pub use self::rustls::{Certificate, PrivateKey}; 6 | -------------------------------------------------------------------------------- /core/lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket" 3 | version = "0.4.0" 4 | authors = ["Sergio Benitez "] 5 | description = """ 6 | Web framework for nightly with a focus on ease-of-use, expressibility, and speed. 7 | """ 8 | documentation = "https://api.rocket.rs/v0.4/rocket/" 9 | homepage = "https://rocket.rs" 10 | repository = "https://github.com/SergioBenitez/Rocket" 11 | readme = "../../README.md" 12 | keywords = ["rocket", "web", "framework", "server"] 13 | license = "MIT/Apache-2.0" 14 | build = "build.rs" 15 | categories = ["web-programming::http-server"] 16 | 17 | [package.metadata.docs.rs] 18 | all-features = true 19 | 20 | [features] 21 | default = ["private-cookies"] 22 | tls = ["rocket_http/tls"] 23 | private-cookies = ["rocket_http/private-cookies"] 24 | 25 | [dependencies] 26 | rocket_codegen = { version = "0.4.0", path = "../codegen" } 27 | rocket_http = { version = "0.4.0", path = "../http" } 28 | yansi = "0.5" 29 | log = "0.4" 30 | toml = "0.4.7" 31 | num_cpus = "1.0" 32 | state = "0.4.1" 33 | time = "0.1" 34 | memchr = "2" # TODO: Use pear instead. 35 | base64 = "0.10" 36 | pear = "0.1" 37 | isatty = "0.1" 38 | 39 | [build-dependencies] 40 | yansi = "0.5" 41 | version_check = "0.1.3" 42 | 43 | [dev-dependencies] 44 | # TODO: Find a way to not depend on this. 45 | lazy_static = "1.0" 46 | -------------------------------------------------------------------------------- /core/lib/benches/format-routing.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::config::{Environment, Config, LoggingLevel}; 6 | 7 | #[get("/", format = "application/json")] 8 | fn get() -> &'static str { "get" } 9 | 10 | #[post("/", format = "application/json")] 11 | fn post() -> &'static str { "post" } 12 | 13 | fn rocket() -> rocket::Rocket { 14 | let config = Config::build(Environment::Production).log_level(LoggingLevel::Off); 15 | rocket::custom(config.unwrap()).mount("/", routes![get, post]) 16 | } 17 | 18 | mod benches { 19 | extern crate test; 20 | 21 | use super::rocket; 22 | use self::test::Bencher; 23 | use rocket::local::Client; 24 | use rocket::http::{Accept, ContentType}; 25 | 26 | #[bench] 27 | fn accept_format(b: &mut Bencher) { 28 | let client = Client::new(rocket()).unwrap(); 29 | let mut request = client.get("/").header(Accept::JSON); 30 | b.iter(|| { request.mut_dispatch(); }); 31 | } 32 | 33 | #[bench] 34 | fn wrong_accept_format(b: &mut Bencher) { 35 | let client = Client::new(rocket()).unwrap(); 36 | let mut request = client.get("/").header(Accept::HTML); 37 | b.iter(|| { request.mut_dispatch(); }); 38 | } 39 | 40 | #[bench] 41 | fn content_type_format(b: &mut Bencher) { 42 | let client = Client::new(rocket()).unwrap(); 43 | let mut request = client.post("/").header(ContentType::JSON); 44 | b.iter(|| { request.mut_dispatch(); }); 45 | } 46 | 47 | #[bench] 48 | fn wrong_content_type_format(b: &mut Bencher) { 49 | let client = Client::new(rocket()).unwrap(); 50 | let mut request = client.post("/").header(ContentType::Plain); 51 | b.iter(|| { request.mut_dispatch(); }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/lib/benches/ranked-routing.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::config::{Environment, Config, LoggingLevel}; 6 | 7 | #[get("/", format = "application/json")] 8 | fn get() -> &'static str { "json" } 9 | 10 | #[get("/", format = "text/html")] 11 | fn get2() -> &'static str { "html" } 12 | 13 | #[get("/", format = "text/plain")] 14 | fn get3() -> &'static str { "plain" } 15 | 16 | #[post("/", format = "application/json")] 17 | fn post() -> &'static str { "json" } 18 | 19 | #[post("/", format = "text/html")] 20 | fn post2() -> &'static str { "html" } 21 | 22 | #[post("/", format = "text/plain")] 23 | fn post3() -> &'static str { "plain" } 24 | 25 | fn rocket() -> rocket::Rocket { 26 | let config = Config::build(Environment::Production).log_level(LoggingLevel::Off); 27 | rocket::custom(config.unwrap()) 28 | .mount("/", routes![get, get2, get3]) 29 | .mount("/", routes![post, post2, post3]) 30 | } 31 | 32 | mod benches { 33 | extern crate test; 34 | 35 | use super::rocket; 36 | use self::test::Bencher; 37 | use rocket::local::Client; 38 | use rocket::http::{Accept, ContentType}; 39 | 40 | #[bench] 41 | fn accept_format(b: &mut Bencher) { 42 | let client = Client::new(rocket()).unwrap(); 43 | let mut requests = vec![]; 44 | requests.push(client.get("/").header(Accept::JSON)); 45 | requests.push(client.get("/").header(Accept::HTML)); 46 | requests.push(client.get("/").header(Accept::Plain)); 47 | 48 | b.iter(|| { 49 | for request in requests.iter_mut() { 50 | request.mut_dispatch(); 51 | } 52 | }); 53 | } 54 | 55 | #[bench] 56 | fn content_type_format(b: &mut Bencher) { 57 | let client = Client::new(rocket()).unwrap(); 58 | let mut requests = vec![]; 59 | requests.push(client.post("/").header(ContentType::JSON)); 60 | requests.push(client.post("/").header(ContentType::HTML)); 61 | requests.push(client.post("/").header(ContentType::Plain)); 62 | 63 | b.iter(|| { 64 | for request in requests.iter_mut() { 65 | request.mut_dispatch(); 66 | } 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/lib/build.rs: -------------------------------------------------------------------------------- 1 | //! This tiny build script ensures that rocket is not compiled with an 2 | //! incompatible version of rust. 3 | 4 | extern crate yansi; 5 | extern crate version_check; 6 | 7 | use yansi::Color::{Red, Yellow, Blue}; 8 | use version_check::{supports_features, is_min_version, is_min_date}; 9 | 10 | // Specifies the minimum nightly version needed to compile Rocket. 11 | const MIN_DATE: &'static str = "2018-10-05"; 12 | const MIN_VERSION: &'static str = "1.31.0-nightly"; 13 | 14 | fn main() { 15 | let ok_channel = supports_features(); 16 | let ok_version = is_min_version(MIN_VERSION); 17 | let ok_date = is_min_date(MIN_DATE); 18 | let triple = (ok_channel, ok_version, ok_date); 19 | 20 | let print_version_err = |version: &str, date: &str| { 21 | eprintln!("{} {}. {} {}.", 22 | "Installed version is:", 23 | Yellow.paint(format!("{} ({})", version, date)), 24 | "Minimum required:", 25 | Yellow.paint(format!("{} ({})", MIN_VERSION, MIN_DATE))); 26 | }; 27 | 28 | if let (Some(ok_channel), Some((ok_version, version)), Some((ok_date, date))) = triple { 29 | if !ok_channel { 30 | eprintln!("{} {}", 31 | Red.paint("Error:").bold(), 32 | "Rocket requires a nightly or dev version of Rust."); 33 | print_version_err(&*version, &*date); 34 | eprintln!("{}{}{}", 35 | Blue.paint("See the getting started guide ("), 36 | "https://rocket.rs/v0.4/guide/getting-started/", 37 | Blue.paint(") for more information.")); 38 | panic!("Aborting compilation due to incompatible compiler.") 39 | } 40 | 41 | if !ok_version || !ok_date { 42 | eprintln!("{} {}", 43 | Red.paint("Error:").bold(), 44 | "Rocket requires a more recent version of rustc."); 45 | eprintln!("{}{}{}", 46 | Blue.paint("Use `"), "rustup update", 47 | Blue.paint("` or your preferred method to update Rust.")); 48 | print_version_err(&*version, &*date); 49 | panic!("Aborting compilation due to incompatible compiler.") 50 | } 51 | } else { 52 | println!("cargo:warning={}", "Rocket was unable to check rustc compatibility."); 53 | println!("cargo:warning={}", "Build may fail due to incompatible rustc version."); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/lib/src/codegen.rs: -------------------------------------------------------------------------------- 1 | use {Request, Data}; 2 | use handler::{Outcome, ErrorHandler}; 3 | use http::{Method, MediaType}; 4 | 5 | /// Type of a static handler, which users annotate with Rocket's attribute. 6 | pub type StaticHandler = for<'r> fn(&'r Request, Data) -> Outcome<'r>; 7 | 8 | /// Information generated by the `route` attribute during codegen. 9 | pub struct StaticRouteInfo { 10 | /// The route's name, i.e, the name of the function. 11 | pub name: &'static str, 12 | /// The route's method. 13 | pub method: Method, 14 | /// The route's path, without the base mount point. 15 | pub path: &'static str, 16 | /// The route's format, if any. 17 | pub format: Option, 18 | /// The route's handler, i.e, the annotated function. 19 | pub handler: StaticHandler, 20 | /// The route's rank, if any. 21 | pub rank: Option, 22 | } 23 | 24 | /// Information generated by the `catch` attribute during codegen. 25 | pub struct StaticCatchInfo { 26 | /// The catcher's status code. 27 | pub code: u16, 28 | /// The catcher's handler, i.e, the annotated function. 29 | pub handler: ErrorHandler, 30 | } 31 | -------------------------------------------------------------------------------- /core/lib/src/data/data_stream.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Read, Cursor, Chain}; 2 | use std::net::Shutdown; 3 | 4 | use super::data::BodyReader; 5 | use http::hyper::net::NetworkStream; 6 | use http::hyper::h1::HttpReader; 7 | 8 | // |-- peek buf --| 9 | pub type InnerStream = Chain>, BodyReader>; 10 | 11 | /// Raw data stream of a request body. 12 | /// 13 | /// This stream can only be obtained by calling 14 | /// [`Data::open()`](::data::Data::open()). The stream contains all of the data 15 | /// in the body of the request. It exposes no methods directly. Instead, it must 16 | /// be used as an opaque [`Read`] structure. 17 | pub struct DataStream(crate InnerStream); 18 | 19 | // TODO: Have a `BufRead` impl for `DataStream`. At the moment, this isn't 20 | // possible since Hyper's `HttpReader` doesn't implement `BufRead`. 21 | impl Read for DataStream { 22 | #[inline(always)] 23 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 24 | trace_!("DataStream::read()"); 25 | self.0.read(buf) 26 | } 27 | } 28 | 29 | pub fn kill_stream(stream: &mut BodyReader) { 30 | // Only do the expensive reading if we're not sure we're done. 31 | use self::HttpReader::*; 32 | match *stream { 33 | SizedReader(_, n) | ChunkedReader(_, Some(n)) if n > 0 => { /* continue */ }, 34 | _ => return 35 | }; 36 | 37 | // Take <= 1k from the stream. If there might be more data, force close. 38 | const FLUSH_LEN: u64 = 1024; 39 | match io::copy(&mut stream.take(FLUSH_LEN), &mut io::sink()) { 40 | Ok(FLUSH_LEN) | Err(_) => { 41 | warn_!("Data left unread. Force closing network stream."); 42 | let (_, network) = stream.get_mut().get_mut(); 43 | if let Err(e) = network.close(Shutdown::Read) { 44 | error_!("Failed to close network stream: {:?}", e); 45 | } 46 | } 47 | Ok(n) => debug!("flushed {} unread bytes", n) 48 | } 49 | } 50 | 51 | impl Drop for DataStream { 52 | fn drop(&mut self) { 53 | kill_stream(&mut self.0.get_mut().1); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/lib/src/data/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and traits for handling incoming body data. 2 | 3 | mod data; 4 | mod data_stream; 5 | mod net_stream; 6 | mod from_data; 7 | 8 | pub use self::data::Data; 9 | pub use self::data_stream::DataStream; 10 | pub use self::from_data::{FromData, FromDataSimple, Outcome, Transform, Transformed}; 11 | -------------------------------------------------------------------------------- /core/lib/src/ext.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | pub trait ReadExt: io::Read { 4 | fn read_max(&mut self, mut buf: &mut [u8]) -> io::Result { 5 | let start_len = buf.len(); 6 | while !buf.is_empty() { 7 | match self.read(buf) { 8 | Ok(0) => break, 9 | Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; } 10 | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} 11 | Err(e) => return Err(e), 12 | } 13 | } 14 | 15 | Ok(start_len - buf.len()) 16 | } 17 | } 18 | 19 | impl ReadExt for T { } 20 | -------------------------------------------------------------------------------- /core/lib/src/request/form/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and traits for form processing. 2 | 3 | mod form_items; 4 | mod from_form; 5 | mod from_form_value; 6 | mod lenient; 7 | mod error; 8 | mod form; 9 | 10 | pub use self::form_items::{FormItems, FormItem}; 11 | pub use self::from_form::FromForm; 12 | pub use self::from_form_value::FromFormValue; 13 | pub use self::form::Form; 14 | pub use self::lenient::LenientForm; 15 | pub use self::error::{FormError, FormParseError, FormDataError}; 16 | -------------------------------------------------------------------------------- /core/lib/src/request/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and traits for request parsing and handling. 2 | 3 | mod request; 4 | mod param; 5 | mod form; 6 | mod from_request; 7 | mod state; 8 | mod query; 9 | 10 | #[cfg(test)] 11 | mod tests; 12 | 13 | pub use self::request::Request; 14 | pub use self::from_request::{FromRequest, Outcome}; 15 | pub use self::param::{FromParam, FromSegments}; 16 | pub use self::form::{FromForm, FromFormValue}; 17 | pub use self::form::{Form, LenientForm, FormItems, FormItem}; 18 | pub use self::form::{FormError, FormParseError, FormDataError}; 19 | pub use self::state::State; 20 | pub use self::query::{Query, FromQuery}; 21 | 22 | #[doc(inline)] 23 | pub use response::flash::FlashMessage; 24 | -------------------------------------------------------------------------------- /core/lib/src/request/tests.rs: -------------------------------------------------------------------------------- 1 | use std::net::{IpAddr, Ipv4Addr, SocketAddr}; 2 | use std::collections::HashMap; 3 | 4 | use {Rocket, Request, Config}; 5 | use http::hyper; 6 | 7 | macro_rules! assert_headers { 8 | ($($key:expr => [$($value:expr),+]),+) => ({ 9 | // Set up the parameters to the hyper request object. 10 | let h_method = hyper::Method::Get; 11 | let h_uri = hyper::RequestUri::AbsolutePath("/test".to_string()); 12 | let h_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000); 13 | let mut h_headers = hyper::header::Headers::new(); 14 | 15 | // Add all of the passed in headers to the request. 16 | $($(h_headers.append_raw($key.to_string(), $value.as_bytes().into());)+)+ 17 | 18 | // Build up what we expect the headers to actually be. 19 | let mut expected = HashMap::new(); 20 | $(expected.entry($key).or_insert(vec![]).append(&mut vec![$($value),+]);)+ 21 | 22 | // Dispatch the request and check that the headers are what we expect. 23 | let config = Config::development(); 24 | let r = Rocket::custom(config); 25 | let req = Request::from_hyp(&r, h_method, h_headers, h_uri, h_addr).unwrap(); 26 | let actual_headers = req.headers(); 27 | for (key, values) in expected.iter() { 28 | let actual: Vec<_> = actual_headers.get(key).collect(); 29 | assert_eq!(*values, actual); 30 | } 31 | }) 32 | } 33 | 34 | #[test] 35 | fn test_multiple_headers_from_hyp() { 36 | assert_headers!("friends" => ["alice"]); 37 | assert_headers!("friends" => ["alice", "bob"]); 38 | assert_headers!("friends" => ["alice", "bob, carol"]); 39 | assert_headers!("friends" => ["alice, david", "bob, carol", "eric, frank"]); 40 | assert_headers!("friends" => ["alice"], "enemies" => ["victor"]); 41 | assert_headers!("friends" => ["alice", "bob"], "enemies" => ["david", "emily"]); 42 | } 43 | 44 | #[test] 45 | fn test_multiple_headers_merge_into_one_from_hyp() { 46 | assert_headers!("friend" => ["alice"], "friend" => ["bob"]); 47 | assert_headers!("friend" => ["alice"], "friend" => ["bob"], "friend" => ["carol"]); 48 | assert_headers!("friend" => ["alice"], "friend" => ["bob"], "enemy" => ["carol"]); 49 | } 50 | -------------------------------------------------------------------------------- /core/lib/src/response/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and traits to build and send responses. 2 | //! 3 | //! The return type of a Rocket handler can be any type that implements the 4 | //! [`Responder`](::response::Responder) trait, which means that the type knows 5 | //! how to generate a [`Response`]. Among other things, this module contains 6 | //! several such types. 7 | //! 8 | //! # Composing 9 | //! 10 | //! Many of the built-in `Responder` types _chain_ responses: they take in 11 | //! another `Responder` and add, remove, or change information in the response. 12 | //! In other words, many `Responder` types are built to compose well. As a 13 | //! result, you'll often have types of the form `A>` consisting of three 14 | //! `Responder`s `A`, `B`, and `C`. This is normal and encouraged as the type 15 | //! names typically illustrate the intended response. 16 | //! 17 | //! # Contrib 18 | //! 19 | //! The [`contrib` crate](rocket_contrib) contains several useful `Responder`s 20 | //! including [`Template`](rocket_contrib::Template) and 21 | //! [`Json`](rocket_contrib::Json). 22 | 23 | mod responder; 24 | mod redirect; 25 | mod named_file; 26 | mod stream; 27 | mod response; 28 | 29 | crate mod flash; 30 | 31 | pub mod content; 32 | pub mod status; 33 | 34 | pub use self::response::{Response, ResponseBuilder, Body, DEFAULT_CHUNK_SIZE}; 35 | pub use self::responder::Responder; 36 | pub use self::redirect::Redirect; 37 | pub use self::flash::Flash; 38 | pub use self::named_file::NamedFile; 39 | pub use self::stream::Stream; 40 | #[doc(inline)] pub use self::content::Content; 41 | 42 | /// Type alias for the `Result` of a `Responder::respond` call. 43 | pub type Result<'r> = ::std::result::Result, ::http::Status>; 44 | -------------------------------------------------------------------------------- /core/lib/tests/absolute-uris-okay-issue-443.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::response::Redirect; 6 | 7 | #[get("/google")] 8 | fn google() -> Redirect { 9 | Redirect::to("https://www.google.com") 10 | } 11 | 12 | #[get("/rocket")] 13 | fn rocket() -> Redirect { 14 | Redirect::to("https://rocket.rs:80") 15 | } 16 | 17 | mod test_absolute_uris_okay { 18 | use super::*; 19 | use rocket::local::Client; 20 | 21 | #[test] 22 | fn redirect_works() { 23 | let rocket = rocket::ignite().mount("/", routes![google, rocket]); 24 | let client = Client::new(rocket).unwrap(); 25 | 26 | let response = client.get("/google").dispatch(); 27 | let location = response.headers().get_one("Location"); 28 | assert_eq!(location, Some("https://www.google.com")); 29 | 30 | let response = client.get("/rocket").dispatch(); 31 | let location = response.headers().get_one("Location"); 32 | assert_eq!(location, Some("https://rocket.rs:80")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/lib/tests/flash-lazy-removes-issue-466.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::request::FlashMessage; 6 | use rocket::response::Flash; 7 | 8 | const FLASH_MESSAGE: &str = "Hey! I'm a flash message. :)"; 9 | 10 | #[post("/")] 11 | fn set() -> Flash<&'static str> { 12 | Flash::success("This is the page.", FLASH_MESSAGE) 13 | } 14 | 15 | #[get("/unused")] 16 | fn unused(flash: Option) -> Option<()> { 17 | flash.map(|_| ()) 18 | } 19 | 20 | #[get("/use")] 21 | fn used(flash: Option) -> Option { 22 | flash.map(|flash| flash.msg().into()) 23 | } 24 | 25 | mod flash_lazy_remove_tests { 26 | use rocket::local::Client; 27 | use rocket::http::Status; 28 | 29 | #[test] 30 | fn test() { 31 | use super::*; 32 | let r = rocket::ignite().mount("/", routes![set, unused, used]); 33 | let client = Client::new(r).unwrap(); 34 | 35 | // Ensure the cookie's not there at first. 36 | let response = client.get("/unused").dispatch(); 37 | assert_eq!(response.status(), Status::NotFound); 38 | 39 | // Set the flash cookie. 40 | client.post("/").dispatch(); 41 | 42 | // Try once. 43 | let response = client.get("/unused").dispatch(); 44 | assert_eq!(response.status(), Status::Ok); 45 | 46 | // Try again; should still be there. 47 | let response = client.get("/unused").dispatch(); 48 | assert_eq!(response.status(), Status::Ok); 49 | 50 | // Now use it. 51 | let mut response = client.get("/use").dispatch(); 52 | assert_eq!(response.body_string(), Some(FLASH_MESSAGE.into())); 53 | 54 | // Now it should be gone. 55 | let response = client.get("/unused").dispatch(); 56 | assert_eq!(response.status(), Status::NotFound); 57 | 58 | // Still gone. 59 | let response = client.get("/use").dispatch(); 60 | assert_eq!(response.status(), Status::NotFound); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /core/lib/tests/form_method-issue-45.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::request::Form; 6 | 7 | #[derive(FromForm)] 8 | struct FormData { 9 | form_data: String, 10 | } 11 | 12 | #[patch("/", data = "")] 13 | fn bug(form_data: Form) -> &'static str { 14 | assert_eq!("Form data", form_data.form_data); 15 | "OK" 16 | } 17 | 18 | mod tests { 19 | use super::*; 20 | use rocket::local::Client; 21 | use rocket::http::{Status, ContentType}; 22 | 23 | #[test] 24 | fn method_eval() { 25 | let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap(); 26 | let mut response = client.post("/") 27 | .header(ContentType::Form) 28 | .body("_method=patch&form_data=Form+data") 29 | .dispatch(); 30 | 31 | assert_eq!(response.body_string(), Some("OK".into())); 32 | } 33 | 34 | #[test] 35 | fn get_passes_through() { 36 | let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap(); 37 | let response = client.get("/") 38 | .header(ContentType::Form) 39 | .body("_method=patch&form_data=Form+data") 40 | .dispatch(); 41 | 42 | assert_eq!(response.status(), Status::NotFound); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/lib/tests/form_value_decoding-issue-82.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::request::Form; 6 | 7 | #[derive(FromForm)] 8 | struct FormData { 9 | form_data: String, 10 | } 11 | 12 | #[post("/", data = "")] 13 | fn bug(form_data: Form) -> String { 14 | form_data.into_inner().form_data 15 | } 16 | 17 | mod tests { 18 | use super::*; 19 | use rocket::local::Client; 20 | use rocket::http::ContentType; 21 | use rocket::http::Status; 22 | 23 | fn check_decoding(raw: &str, decoded: &str) { 24 | let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap(); 25 | let mut response = client.post("/") 26 | .header(ContentType::Form) 27 | .body(format!("form_data={}", raw)) 28 | .dispatch(); 29 | 30 | assert_eq!(response.status(), Status::Ok); 31 | assert_eq!(Some(decoded.to_string()), response.body_string()); 32 | } 33 | 34 | #[test] 35 | fn test_proper_decoding() { 36 | check_decoding("password", "password"); 37 | check_decoding("", ""); 38 | check_decoding("+", " "); 39 | check_decoding("%2B", "+"); 40 | check_decoding("1+1", "1 1"); 41 | check_decoding("1%2B1", "1+1"); 42 | check_decoding("%3Fa%3D1%26b%3D2", "?a=1&b=2"); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/lib/tests/head_handling.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::{http::Status, response::content}; 6 | 7 | #[get("/empty")] 8 | fn empty() -> Status { 9 | Status::NoContent 10 | } 11 | 12 | #[get("/")] 13 | fn index() -> &'static str { 14 | "Hello, world!" 15 | } 16 | 17 | #[head("/other")] 18 | fn other() -> content::Json<&'static str> { 19 | content::Json("{ 'hi': 'hello' }") 20 | } 21 | 22 | mod head_handling_tests { 23 | use super::*; 24 | 25 | use std::io::Read; 26 | 27 | use rocket::Route; 28 | use rocket::local::Client; 29 | use rocket::http::{Status, ContentType}; 30 | use rocket::response::Body; 31 | 32 | fn routes() -> Vec { 33 | routes![index, empty, other] 34 | } 35 | 36 | fn assert_empty_sized_body(body: Body, expected_size: u64) { 37 | match body { 38 | Body::Sized(mut body, size) => { 39 | let mut buffer = vec![]; 40 | let n = body.read_to_end(&mut buffer).unwrap(); 41 | assert_eq!(size, expected_size); 42 | assert_eq!(n, 0); 43 | } 44 | _ => panic!("Expected a sized body.") 45 | } 46 | } 47 | 48 | #[test] 49 | fn auto_head() { 50 | let client = Client::new(rocket::ignite().mount("/", routes())).unwrap(); 51 | let mut response = client.head("/").dispatch(); 52 | assert_eq!(response.status(), Status::Ok); 53 | assert_empty_sized_body(response.body().unwrap(), 13); 54 | 55 | let content_type: Vec<_> = response.headers().get("Content-Type").collect(); 56 | assert_eq!(content_type, vec![ContentType::Plain.to_string()]); 57 | 58 | let mut response = client.head("/empty").dispatch(); 59 | assert_eq!(response.status(), Status::NoContent); 60 | assert!(response.body_bytes().is_none()); 61 | } 62 | 63 | #[test] 64 | fn user_head() { 65 | let client = Client::new(rocket::ignite().mount("/", routes())).unwrap(); 66 | let mut response = client.head("/other").dispatch(); 67 | assert_eq!(response.status(), Status::Ok); 68 | assert_empty_sized_body(response.body().unwrap(), 17); 69 | 70 | let content_type: Vec<_> = response.headers().get("Content-Type").collect(); 71 | assert_eq!(content_type, vec![ContentType::JSON.to_string()]); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /core/lib/tests/limits.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::request::Form; 6 | 7 | #[derive(FromForm)] 8 | struct Simple { 9 | value: String 10 | } 11 | 12 | #[post("/", data = "")] 13 | fn index(form: Form) -> String { 14 | form.into_inner().value 15 | } 16 | 17 | mod limits_tests { 18 | use rocket; 19 | use rocket::config::{Environment, Config, Limits}; 20 | use rocket::local::Client; 21 | use rocket::http::{Status, ContentType}; 22 | 23 | fn rocket_with_forms_limit(limit: u64) -> rocket::Rocket { 24 | let config = Config::build(Environment::Development) 25 | .limits(Limits::default().limit("forms", limit)) 26 | .unwrap(); 27 | 28 | rocket::custom(config).mount("/", routes![super::index]) 29 | } 30 | 31 | #[test] 32 | fn large_enough() { 33 | let client = Client::new(rocket_with_forms_limit(128)).unwrap(); 34 | let mut response = client.post("/") 35 | .body("value=Hello+world") 36 | .header(ContentType::Form) 37 | .dispatch(); 38 | 39 | assert_eq!(response.body_string(), Some("Hello world".into())); 40 | } 41 | 42 | #[test] 43 | fn just_large_enough() { 44 | let client = Client::new(rocket_with_forms_limit(17)).unwrap(); 45 | let mut response = client.post("/") 46 | .body("value=Hello+world") 47 | .header(ContentType::Form) 48 | .dispatch(); 49 | 50 | assert_eq!(response.body_string(), Some("Hello world".into())); 51 | } 52 | 53 | #[test] 54 | fn much_too_small() { 55 | let client = Client::new(rocket_with_forms_limit(4)).unwrap(); 56 | let response = client.post("/") 57 | .body("value=Hello+world") 58 | .header(ContentType::Form) 59 | .dispatch(); 60 | 61 | assert_eq!(response.status(), Status::UnprocessableEntity); 62 | } 63 | 64 | #[test] 65 | fn contracted() { 66 | let client = Client::new(rocket_with_forms_limit(10)).unwrap(); 67 | let mut response = client.post("/") 68 | .body("value=Hello+world") 69 | .header(ContentType::Form) 70 | .dispatch(); 71 | 72 | assert_eq!(response.body_string(), Some("Hell".into())); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /core/lib/tests/local_request_private_cookie-issue-368.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] 4 | #[cfg(feature = "private-cookies")] 5 | extern crate rocket; 6 | 7 | #[cfg(feature = "private-cookies")] 8 | mod private_cookie_test { 9 | use rocket::http::Cookies; 10 | 11 | #[get("/")] 12 | fn return_private_cookie(mut cookies: Cookies) -> Option { 13 | match cookies.get_private("cookie_name") { 14 | Some(cookie) => Some(cookie.value().into()), 15 | None => None, 16 | } 17 | } 18 | 19 | mod tests { 20 | use super::*; 21 | use rocket::local::Client; 22 | use rocket::http::Cookie; 23 | use rocket::http::Status; 24 | 25 | #[test] 26 | fn private_cookie_is_returned() { 27 | let rocket = rocket::ignite().mount("/", routes![return_private_cookie]); 28 | 29 | let client = Client::new(rocket).unwrap(); 30 | let req = client.get("/").private_cookie(Cookie::new("cookie_name", "cookie_value")); 31 | let mut response = req.dispatch(); 32 | 33 | assert_eq!(response.body_string(), Some("cookie_value".into())); 34 | assert_eq!(response.headers().get_one("Set-Cookie"), None); 35 | } 36 | 37 | #[test] 38 | fn regular_cookie_is_not_returned() { 39 | let rocket = rocket::ignite().mount("/", routes![return_private_cookie]); 40 | 41 | let client = Client::new(rocket).unwrap(); 42 | let req = client.get("/").cookie(Cookie::new("cookie_name", "cookie_value")); 43 | let response = req.dispatch(); 44 | 45 | assert_eq!(response.status(), Status::NotFound); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/lib/tests/mount_point.rs: -------------------------------------------------------------------------------- 1 | extern crate rocket; 2 | 3 | #[test] 4 | #[should_panic] 5 | fn bad_dynamic_mount() { 6 | rocket::ignite().mount("", vec![]); 7 | } 8 | 9 | #[test] 10 | fn good_static_mount() { 11 | rocket::ignite().mount("/abcdefghijkl_mno", vec![]); 12 | } 13 | -------------------------------------------------------------------------------- /core/lib/tests/nested-fairing-attaches.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use std::sync::atomic::{AtomicUsize, Ordering}; 6 | 7 | use rocket::State; 8 | use rocket::fairing::AdHoc; 9 | use rocket::http::Method; 10 | 11 | #[derive(Default)] 12 | struct Counter { 13 | attach: AtomicUsize, 14 | get: AtomicUsize, 15 | } 16 | 17 | #[get("/")] 18 | fn index(counter: State) -> String { 19 | let attaches = counter.attach.load(Ordering::Relaxed); 20 | let gets = counter.get.load(Ordering::Acquire); 21 | format!("{}, {}", attaches, gets) 22 | } 23 | 24 | fn rocket() -> rocket::Rocket { 25 | rocket::ignite() 26 | .mount("/", routes![index]) 27 | .attach(AdHoc::on_attach("Outer", |rocket| { 28 | let counter = Counter::default(); 29 | counter.attach.fetch_add(1, Ordering::Relaxed); 30 | let rocket = rocket.manage(counter) 31 | .attach(AdHoc::on_request("Inner", |req, _| { 32 | if req.method() == Method::Get { 33 | let counter = req.guard::>().unwrap(); 34 | counter.get.fetch_add(1, Ordering::Release); 35 | } 36 | })); 37 | 38 | Ok(rocket) 39 | })) 40 | } 41 | 42 | mod nested_fairing_attaches_tests { 43 | use super::*; 44 | use rocket::local::Client; 45 | 46 | #[test] 47 | fn test_counts() { 48 | let client = Client::new(rocket()).unwrap(); 49 | let mut response = client.get("/").dispatch(); 50 | assert_eq!(response.body_string(), Some("1, 1".into())); 51 | 52 | let mut response = client.get("/").dispatch(); 53 | assert_eq!(response.body_string(), Some("1, 2".into())); 54 | 55 | client.get("/").dispatch(); 56 | client.get("/").dispatch(); 57 | let mut response = client.get("/").dispatch(); 58 | assert_eq!(response.body_string(), Some("1, 5".into())); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /core/lib/tests/precise-content-type-matching.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[post("/", format = "application/json")] 6 | fn specified() -> &'static str { 7 | "specified" 8 | } 9 | 10 | #[post("/", rank = 2)] 11 | fn unspecified() -> &'static str { 12 | "unspecified" 13 | } 14 | 15 | #[post("/", format = "application/json")] 16 | fn specified_json() -> &'static str { 17 | "specified_json" 18 | } 19 | 20 | #[post("/", format = "text/html")] 21 | fn specified_html() -> &'static str { 22 | "specified_html" 23 | } 24 | 25 | mod tests { 26 | use super::*; 27 | 28 | use rocket::Rocket; 29 | use rocket::local::Client; 30 | use rocket::http::{Status, ContentType}; 31 | 32 | fn rocket() -> Rocket { 33 | rocket::ignite() 34 | .mount("/first", routes![specified, unspecified]) 35 | .mount("/second", routes![specified_json, specified_html]) 36 | } 37 | 38 | macro_rules! check_dispatch { 39 | ($mount:expr, $ct:expr, $body:expr) => ( 40 | let client = Client::new(rocket()).unwrap(); 41 | let mut req = client.post($mount); 42 | let ct: Option = $ct; 43 | if let Some(ct) = ct { 44 | req.add_header(ct); 45 | } 46 | 47 | let mut response = req.dispatch(); 48 | let body_str = response.body_string(); 49 | let body: Option<&'static str> = $body; 50 | match body { 51 | Some(string) => assert_eq!(body_str, Some(string.to_string())), 52 | None => assert_eq!(response.status(), Status::NotFound) 53 | } 54 | ) 55 | } 56 | 57 | #[test] 58 | fn exact_match_or_forward() { 59 | check_dispatch!("/first", Some(ContentType::JSON), Some("specified")); 60 | check_dispatch!("/first", None, Some("unspecified")); 61 | check_dispatch!("/first", Some(ContentType::HTML), Some("unspecified")); 62 | } 63 | 64 | #[test] 65 | fn exact_match_or_none() { 66 | check_dispatch!("/second", Some(ContentType::JSON), Some("specified_json")); 67 | check_dispatch!("/second", Some(ContentType::HTML), Some("specified_html")); 68 | check_dispatch!("/second", Some(ContentType::CSV), None); 69 | check_dispatch!("/second", None, None); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /core/lib/tests/redirect_from_catcher-issue-113.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::response::Redirect; 6 | 7 | #[catch(404)] 8 | fn not_found() -> Redirect { 9 | Redirect::to("/") 10 | } 11 | 12 | mod tests { 13 | use super::*; 14 | use rocket::local::Client; 15 | use rocket::http::Status; 16 | 17 | #[test] 18 | fn error_catcher_redirect() { 19 | let client = Client::new(rocket::ignite().register(catchers![not_found])).unwrap(); 20 | let response = client.get("/unknown").dispatch(); 21 | println!("Response:\n{:?}", response); 22 | 23 | let location: Vec<_> = response.headers().get("location").collect(); 24 | assert_eq!(response.status(), Status::SeeOther); 25 | assert_eq!(location, vec!["/"]); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/lib/tests/responder_lifetime-issue-345.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | #![allow(dead_code)] // This test is only here so that we can ensure it compiles. 3 | 4 | #[macro_use] extern crate rocket; 5 | 6 | use rocket::State; 7 | use rocket::response::{self, Responder}; 8 | 9 | struct SomeState; 10 | 11 | pub struct CustomResponder<'r, R> { 12 | responder: R, 13 | state: &'r SomeState, 14 | } 15 | 16 | impl<'r, R: Responder<'r>> Responder<'r> for CustomResponder<'r, R> { 17 | fn respond_to(self, _: &rocket::Request) -> response::Result<'r> { 18 | unimplemented!() 19 | } 20 | } 21 | 22 | #[get("/unit_state")] 23 | fn unit_state(state: State) -> CustomResponder<()> { 24 | CustomResponder { responder: (), state: state.inner() } 25 | } 26 | 27 | #[get("/string_state")] 28 | fn string_state(state: State) -> CustomResponder { 29 | CustomResponder { responder: "".to_string(), state: state.inner() } 30 | } 31 | -------------------------------------------------------------------------------- /core/lib/tests/route_guard.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use std::path::{Path, PathBuf}; 6 | use rocket::http::ext::Normalize; 7 | use rocket::Route; 8 | 9 | #[get("/")] 10 | fn files(route: &Route, path: PathBuf) -> String { 11 | Path::new(route.base()).join(path).normalized_str().to_string() 12 | } 13 | 14 | mod route_guard_tests { 15 | use super::*; 16 | use rocket::local::Client; 17 | 18 | fn assert_path(client: &Client, path: &str) { 19 | let mut res = client.get(path).dispatch(); 20 | assert_eq!(res.body_string(), Some(path.into())); 21 | } 22 | 23 | #[test] 24 | fn check_mount_path() { 25 | let rocket = rocket::ignite() 26 | .mount("/first", routes![files]) 27 | .mount("/second", routes![files]); 28 | 29 | let client = Client::new(rocket).unwrap(); 30 | assert_path(&client, "/first/some/path"); 31 | assert_path(&client, "/second/some/path"); 32 | assert_path(&client, "/first/second/b/c"); 33 | assert_path(&client, "/second/a/b/c"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/lib/tests/segments-issues-41-86.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::http::uri::Segments; 6 | 7 | #[get("/test/")] 8 | fn test(path: Segments) -> String { 9 | path.collect::>().join("/") 10 | } 11 | 12 | #[get("/two/")] 13 | fn two(path: Segments) -> String { 14 | path.collect::>().join("/") 15 | } 16 | 17 | #[get("/one/two/")] 18 | fn one_two(path: Segments) -> String { 19 | path.collect::>().join("/") 20 | } 21 | 22 | #[get("/", rank = 2)] 23 | fn none(path: Segments) -> String { 24 | path.collect::>().join("/") 25 | } 26 | 27 | #[get("/static//is/")] 28 | fn dual(user: String, path: Segments) -> String { 29 | user + "/is/" + &path.collect::>().join("/") 30 | } 31 | 32 | mod tests { 33 | use super::*; 34 | use rocket::local::Client; 35 | 36 | #[test] 37 | fn segments_works() { 38 | let rocket = rocket::ignite() 39 | .mount("/", routes![test, two, one_two, none, dual]) 40 | .mount("/point", routes![test, two, one_two, dual]); 41 | let client = Client::new(rocket).unwrap(); 42 | 43 | // We construct a path that matches each of the routes above. We ensure the 44 | // prefix is stripped, confirming that dynamic segments are working. 45 | for prefix in &["", "/test", "/two", "/one/two", 46 | "/point/test", "/point/two", "/point/one/two", 47 | "/static", "/point/static"] 48 | { 49 | let path = "this/is/the/path/we/want"; 50 | let mut response = client.get(format!("{}/{}", prefix, path)).dispatch(); 51 | assert_eq!(response.body_string(), Some(path.into())); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/lib/tests/strict_and_lenient_forms.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::request::{Form, LenientForm}; 6 | use rocket::http::RawStr; 7 | 8 | #[derive(FromForm)] 9 | struct MyForm<'r> { 10 | field: &'r RawStr, 11 | } 12 | 13 | #[post("/strict", data = "")] 14 | fn strict<'r>(form: Form>) -> String { 15 | form.field.as_str().into() 16 | } 17 | 18 | #[post("/lenient", data = "")] 19 | fn lenient<'r>(form: LenientForm>) -> String { 20 | form.field.as_str().into() 21 | } 22 | 23 | mod strict_and_lenient_forms_tests { 24 | use super::*; 25 | use rocket::local::Client; 26 | use rocket::http::{Status, ContentType}; 27 | 28 | const FIELD_VALUE: &str = "just_some_value"; 29 | 30 | fn client() -> Client { 31 | Client::new(rocket::ignite().mount("/", routes![strict, lenient])).unwrap() 32 | } 33 | 34 | #[test] 35 | fn test_strict_form() { 36 | let client = client(); 37 | let mut response = client.post("/strict") 38 | .header(ContentType::Form) 39 | .body(format!("field={}", FIELD_VALUE)) 40 | .dispatch(); 41 | 42 | assert_eq!(response.status(), Status::Ok); 43 | assert_eq!(response.body_string(), Some(FIELD_VALUE.into())); 44 | 45 | let response = client.post("/strict") 46 | .header(ContentType::Form) 47 | .body(format!("field={}&extra=whoops", FIELD_VALUE)) 48 | .dispatch(); 49 | 50 | assert_eq!(response.status(), Status::UnprocessableEntity); 51 | } 52 | 53 | #[test] 54 | fn test_lenient_form() { 55 | let client = client(); 56 | let mut response = client.post("/lenient") 57 | .header(ContentType::Form) 58 | .body(format!("field={}", FIELD_VALUE)) 59 | .dispatch(); 60 | 61 | assert_eq!(response.status(), Status::Ok); 62 | assert_eq!(response.body_string(), Some(FIELD_VALUE.into())); 63 | 64 | let mut response = client.post("/lenient") 65 | .header(ContentType::Form) 66 | .body(format!("field={}&extra=whoops", FIELD_VALUE)) 67 | .dispatch(); 68 | 69 | assert_eq!(response.status(), Status::Ok); 70 | assert_eq!(response.body_string(), Some(FIELD_VALUE.into())); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /core/lib/tests/uri-percent-encoding-issue-808.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::response::Redirect; 6 | use rocket::http::uri::Uri; 7 | 8 | const NAME: &str = "John[]|\\%@^"; 9 | 10 | #[get("/hello/")] 11 | fn hello(name: String) -> String { 12 | format!("Hello, {}!", name) 13 | } 14 | 15 | #[get("/raw")] 16 | fn raw_redirect() -> Redirect { 17 | Redirect::to(format!("/hello/{}", Uri::percent_encode(NAME))) 18 | } 19 | 20 | #[get("/uri")] 21 | fn uri_redirect() -> Redirect { 22 | Redirect::to(uri!(hello: NAME)) 23 | } 24 | 25 | fn rocket() -> rocket::Rocket { 26 | rocket::ignite().mount("/", routes![hello, uri_redirect, raw_redirect]) 27 | } 28 | 29 | 30 | mod tests { 31 | use super::*; 32 | use rocket::local::Client; 33 | use rocket::http::{Status, uri::Uri}; 34 | 35 | #[test] 36 | fn uri_percent_encoding_redirect() { 37 | let expected_location = vec!["/hello/John%5B%5D%7C%5C%25@%5E"]; 38 | let client = Client::new(rocket()).unwrap(); 39 | 40 | let response = client.get("/raw").dispatch(); 41 | let location: Vec<_> = response.headers().get("location").collect(); 42 | assert_eq!(response.status(), Status::SeeOther); 43 | assert_eq!(&location, &expected_location); 44 | 45 | let response = client.get("/uri").dispatch(); 46 | let location: Vec<_> = response.headers().get("location").collect(); 47 | assert_eq!(response.status(), Status::SeeOther); 48 | assert_eq!(&location, &expected_location); 49 | } 50 | 51 | #[test] 52 | fn uri_percent_encoding_get() { 53 | let client = Client::new(rocket()).unwrap(); 54 | let name = Uri::percent_encode(NAME); 55 | let mut response = client.get(format!("/hello/{}", name)).dispatch(); 56 | assert_eq!(response.status(), Status::Ok); 57 | assert_eq!(response.body_string().unwrap(), format!("Hello, {}!", NAME)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "config" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/config/Rocket.toml: -------------------------------------------------------------------------------- 1 | # Except for the secret key, none of these are actually needed; Rocket has sane 2 | # defaults. We show all of them here explicitly for demonstrative purposes. 3 | 4 | [global.limits] 5 | forms = 32768 6 | json = 1048576 # this is an extra used by the json contrib module 7 | msgpack = 1048576 # this is an extra used by the msgpack contrib module 8 | 9 | [development] 10 | address = "localhost" 11 | port = 8000 12 | workers = 1 13 | keep_alive = 5 14 | log = "normal" 15 | hi = "Hello!" # this is an unused extra; maybe application specific? 16 | is_extra = true # this is an unused extra; maybe application specific? 17 | 18 | [staging] 19 | address = "0.0.0.0" 20 | port = 8000 21 | workers = 8 22 | keep_alive = 5 23 | log = "normal" 24 | # don't use this key! generate your own and keep it private! 25 | secret_key = "8Xui8SN4mI+7egV/9dlfYYLGQJeEx4+DwmSQLwDVXJg=" 26 | 27 | [production] 28 | address = "0.0.0.0" 29 | port = 8000 30 | workers = 12 31 | keep_alive = 5 32 | log = "critical" 33 | # don't use this key! generate your own and keep it private! 34 | secret_key = "hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk=" 35 | -------------------------------------------------------------------------------- /examples/config/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate rocket; 2 | 3 | // This example's illustration is the Rocket.toml file. 4 | fn main() { 5 | rocket::ignite().launch(); 6 | } 7 | -------------------------------------------------------------------------------- /examples/config/tests/development.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | mod common; 6 | 7 | #[test] 8 | fn test_development_config() { 9 | common::test_config(rocket::config::Environment::Development); 10 | } 11 | -------------------------------------------------------------------------------- /examples/config/tests/production.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | mod common; 6 | 7 | #[test] 8 | fn test_production_config() { 9 | common::test_config(rocket::config::Environment::Production); 10 | } 11 | -------------------------------------------------------------------------------- /examples/config/tests/staging.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | mod common; 6 | 7 | #[test] 8 | fn test_staging_config() { 9 | common::test_config(rocket::config::Environment::Staging); 10 | } 11 | -------------------------------------------------------------------------------- /examples/content_types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "content_types" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | serde = "1.0" 10 | serde_json = "1.0" 11 | serde_derive = "1.0" 12 | -------------------------------------------------------------------------------- /examples/content_types/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use super::serde_json; 3 | use super::Person; 4 | use rocket::http::{Accept, ContentType, Header, MediaType, Method, Status}; 5 | use rocket::local::Client; 6 | 7 | fn test(method: Method, uri: &str, header: H, status: Status, body: String) 8 | where H: Into> 9 | { 10 | let rocket = rocket::ignite() 11 | .mount("/hello", routes![super::get_hello, super::post_hello]) 12 | .register(catchers![super::not_found]); 13 | 14 | let client = Client::new(rocket).unwrap(); 15 | let mut response = client.req(method, uri).header(header).dispatch(); 16 | assert_eq!(response.status(), status); 17 | assert_eq!(response.body_string(), Some(body)); 18 | } 19 | 20 | #[test] 21 | fn test_hello() { 22 | let person = Person { name: "Michael".to_string(), age: 80, }; 23 | let body = serde_json::to_string(&person).unwrap(); 24 | test(Method::Get, "/hello/Michael/80", Accept::JSON, Status::Ok, body.clone()); 25 | test(Method::Get, "/hello/Michael/80", Accept::Any, Status::Ok, body.clone()); 26 | 27 | // No `Accept` header is an implicit */*. 28 | test(Method::Get, "/hello/Michael/80", ContentType::XML, Status::Ok, body); 29 | 30 | let person = Person { name: "".to_string(), age: 99, }; 31 | let body = serde_json::to_string(&person).unwrap(); 32 | test(Method::Post, "/hello/99", ContentType::Plain, Status::Ok, body); 33 | } 34 | 35 | #[test] 36 | fn test_hello_invalid_content_type() { 37 | let b = format!("

'{}' requests are not supported.

", MediaType::HTML); 38 | test(Method::Get, "/hello/Michael/80", Accept::HTML, Status::NotFound, b.clone()); 39 | test(Method::Post, "/hello/80", ContentType::HTML, Status::NotFound, b); 40 | } 41 | 42 | #[test] 43 | fn test_404() { 44 | let body = "

Sorry, '/unknown' is an invalid path! Try \ 45 | /hello/<name>/<age> instead.

"; 46 | test(Method::Get, "/unknown", Accept::JSON, Status::NotFound, body.to_string()); 47 | } 48 | -------------------------------------------------------------------------------- /examples/cookies/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cookies" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | 10 | [dependencies.rocket_contrib] 11 | path = "../../contrib/lib" 12 | default-features = false 13 | features = ["handlebars_templates"] 14 | -------------------------------------------------------------------------------- /examples/cookies/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | extern crate rocket_contrib; 5 | 6 | #[cfg(test)] 7 | mod tests; 8 | 9 | use std::collections::HashMap; 10 | 11 | use rocket::request::Form; 12 | use rocket::response::Redirect; 13 | use rocket::http::{Cookie, Cookies}; 14 | use rocket_contrib::templates::Template; 15 | 16 | #[derive(FromForm)] 17 | struct Message { 18 | message: String, 19 | } 20 | 21 | #[post("/submit", data = "")] 22 | fn submit(mut cookies: Cookies, message: Form) -> Redirect { 23 | cookies.add(Cookie::new("message", message.into_inner().message)); 24 | Redirect::to("/") 25 | } 26 | 27 | #[get("/")] 28 | fn index(cookies: Cookies) -> Template { 29 | let cookie = cookies.get("message"); 30 | let mut context = HashMap::new(); 31 | if let Some(ref cookie) = cookie { 32 | context.insert("message", cookie.value()); 33 | } 34 | 35 | Template::render("index", &context) 36 | } 37 | 38 | fn rocket() -> rocket::Rocket { 39 | rocket::ignite().mount("/", routes![submit, index]).attach(Template::fairing()) 40 | } 41 | 42 | fn main() { 43 | rocket().launch(); 44 | } 45 | -------------------------------------------------------------------------------- /examples/cookies/src/tests.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use super::rocket; 4 | use rocket::local::Client; 5 | use rocket::http::*; 6 | use rocket_contrib::templates::Template; 7 | 8 | #[test] 9 | fn test_submit() { 10 | let client = Client::new(rocket()).unwrap(); 11 | let response = client.post("/submit") 12 | .header(ContentType::Form) 13 | .body("message=Hello from Rocket!") 14 | .dispatch(); 15 | 16 | let cookie_headers: Vec<_> = response.headers().get("Set-Cookie").collect(); 17 | let location_headers: Vec<_> = response.headers().get("Location").collect(); 18 | 19 | assert_eq!(response.status(), Status::SeeOther); 20 | assert_eq!(cookie_headers, vec!["message=Hello%20from%20Rocket!".to_string()]); 21 | assert_eq!(location_headers, vec!["/".to_string()]); 22 | } 23 | 24 | fn test_body(optional_cookie: Option>, expected_body: String) { 25 | // Attach a cookie if one is given. 26 | let client = Client::new(rocket()).unwrap(); 27 | let mut response = match optional_cookie { 28 | Some(cookie) => client.get("/").cookie(cookie).dispatch(), 29 | None => client.get("/").dispatch(), 30 | }; 31 | 32 | assert_eq!(response.status(), Status::Ok); 33 | assert_eq!(response.body_string(), Some(expected_body)); 34 | } 35 | 36 | #[test] 37 | fn test_index() { 38 | let client = Client::new(rocket()).unwrap(); 39 | 40 | // Render the template with an empty context. 41 | let mut context: HashMap<&str, &str> = HashMap::new(); 42 | let template = Template::show(client.rocket(), "index", &context).unwrap(); 43 | test_body(None, template); 44 | 45 | // Render the template with a context that contains the message. 46 | context.insert("message", "Hello from Rocket!"); 47 | let template = Template::show(client.rocket(), "index", &context).unwrap(); 48 | test_body(Some(Cookie::new("message", "Hello from Rocket!")), template); 49 | } 50 | -------------------------------------------------------------------------------- /examples/cookies/templates/index.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Rocket: Cookie Examples 7 | 8 | 9 |

Rocket Cookie Examples

10 | {{#if message }} 11 |

{{message}}

12 | {{else}} 13 |

No message yet.

14 | {{/if}} 15 | 16 | 17 | 19 |

20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/errors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "errors" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/errors/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | use rocket::response::content; 8 | 9 | #[get("/hello//")] 10 | fn hello(name: String, age: i8) -> String { 11 | format!("Hello, {} year old named {}!", age, name) 12 | } 13 | 14 | #[catch(404)] 15 | fn not_found(req: &rocket::Request) -> content::Html { 16 | content::Html(format!("

Sorry, but '{}' is not a valid path!

17 |

Try visiting /hello/<name>/<age> instead.

", 18 | req.uri())) 19 | } 20 | 21 | fn main() { 22 | let e = rocket::ignite() 23 | // .mount("/", routes![hello, hello]) // uncoment this to get an error 24 | .mount("/", routes![hello]) 25 | .register(catchers![not_found]) 26 | .launch(); 27 | 28 | println!("Whoops! Rocket didn't launch!"); 29 | println!("This went wrong: {}", e); 30 | } 31 | -------------------------------------------------------------------------------- /examples/errors/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | use rocket::http::Status; 4 | 5 | fn test(uri: &str, status: Status, body: String) { 6 | let rocket = rocket::ignite() 7 | .mount("/", routes![super::hello]) 8 | .register(catchers![super::not_found]); 9 | 10 | let client = Client::new(rocket).unwrap(); 11 | let mut response = client.get(uri).dispatch(); 12 | assert_eq!(response.status(), status); 13 | assert_eq!(response.body_string(), Some(body)); 14 | } 15 | 16 | #[test] 17 | fn test_hello() { 18 | let (name, age) = ("Arthur", 42); 19 | let uri = format!("/hello/{}/{}", name, age); 20 | test(&uri, Status::Ok, format!("Hello, {} year old named {}!", age, name)); 21 | } 22 | 23 | #[test] 24 | fn test_hello_invalid_age() { 25 | for &(name, age) in &[("Ford", -129), ("Trillian", 128)] { 26 | let uri = format!("/hello/{}/{}", name, age); 27 | let body = format!("

Sorry, but '{}' is not a valid path!

28 |

Try visiting /hello/<name>/<age> instead.

", 29 | uri); 30 | test(&uri, Status::NotFound, body); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/fairings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fairings" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/fairings/Rocket.toml: -------------------------------------------------------------------------------- 1 | [global] 2 | token = 123 3 | -------------------------------------------------------------------------------- /examples/fairings/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | 4 | #[test] 5 | fn rewrite_get_put() { 6 | let client = Client::new(rocket()).unwrap(); 7 | let mut response = client.get("/").dispatch(); 8 | assert_eq!(response.body_string(), Some("Hello, fairings!".into())); 9 | } 10 | 11 | #[test] 12 | fn counts() { 13 | let client = Client::new(rocket()).unwrap(); 14 | 15 | // Issue 1 GET request. 16 | client.get("/").dispatch(); 17 | 18 | // Check the GET count, taking into account _this_ GET request. 19 | let mut response = client.get("/counts").dispatch(); 20 | assert_eq!(response.body_string(), Some("Get: 2\nPost: 0".into())); 21 | 22 | // Issue 1 more GET request and a POST. 23 | client.get("/").dispatch(); 24 | client.post("/").dispatch(); 25 | 26 | // Check the counts. 27 | let mut response = client.get("/counts").dispatch(); 28 | assert_eq!(response.body_string(), Some("Get: 4\nPost: 1".into())); 29 | } 30 | 31 | #[test] 32 | fn token() { 33 | let client = Client::new(rocket()).unwrap(); 34 | 35 | // Ensure the token is '123', which is what we have in `Rocket.toml`. 36 | let mut res = client.get("/token").dispatch(); 37 | assert_eq!(res.body_string(), Some("123".into())); 38 | } 39 | -------------------------------------------------------------------------------- /examples/form_kitchen_sink/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "form_kitchen_sink" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/form_kitchen_sink/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use std::io; 6 | 7 | use rocket::request::{Form, FormError, FormDataError}; 8 | use rocket::response::NamedFile; 9 | use rocket::http::RawStr; 10 | 11 | #[cfg(test)] mod tests; 12 | 13 | #[derive(Debug, FromFormValue)] 14 | enum FormOption { 15 | A, B, C 16 | } 17 | 18 | #[derive(Debug, FromForm)] 19 | struct FormInput<'r> { 20 | checkbox: bool, 21 | number: usize, 22 | #[form(field = "type")] 23 | radio: FormOption, 24 | password: &'r RawStr, 25 | #[form(field = "textarea")] 26 | text_area: String, 27 | select: FormOption, 28 | } 29 | 30 | #[post("/", data = "")] 31 | fn sink(sink: Result, FormError>) -> String { 32 | match sink { 33 | Ok(form) => format!("{:?}", &*form), 34 | Err(FormDataError::Io(_)) => format!("Form input was invalid UTF-8."), 35 | Err(FormDataError::Malformed(f)) | Err(FormDataError::Parse(_, f)) => { 36 | format!("Invalid form input: {}", f) 37 | } 38 | } 39 | } 40 | 41 | #[get("/")] 42 | fn index() -> io::Result { 43 | NamedFile::open("static/index.html") 44 | } 45 | 46 | fn rocket() -> rocket::Rocket { 47 | rocket::ignite().mount("/", routes![index, sink]) 48 | } 49 | 50 | fn main() { 51 | rocket().launch(); 52 | } 53 | -------------------------------------------------------------------------------- /examples/form_kitchen_sink/static/index.html: -------------------------------------------------------------------------------- 1 |

Rocket Form Kitchen Sink

2 | 3 |
4 |

7 | 8 |

11 | 12 | 15 |

16 | 17 | 28 |

29 | 30 | 33 |

34 | 35 | 42 |

43 | 44 | 47 |

48 |
49 | -------------------------------------------------------------------------------- /examples/form_validation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "form_validation" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/form_validation/src/files.rs: -------------------------------------------------------------------------------- 1 | use rocket::response::NamedFile; 2 | 3 | use std::io; 4 | use std::path::{Path, PathBuf}; 5 | 6 | #[get("/")] 7 | pub fn index() -> io::Result { 8 | NamedFile::open("static/index.html") 9 | } 10 | 11 | #[get("/", rank = 2)] 12 | pub fn files(file: PathBuf) -> io::Result { 13 | NamedFile::open(Path::new("static/").join(file)) 14 | } 15 | -------------------------------------------------------------------------------- /examples/form_validation/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | mod files; 6 | #[cfg(test)] mod tests; 7 | 8 | use rocket::response::Redirect; 9 | use rocket::request::{Form, FromFormValue}; 10 | use rocket::http::RawStr; 11 | 12 | #[derive(Debug)] 13 | struct StrongPassword<'r>(&'r str); 14 | 15 | #[derive(Debug)] 16 | struct AdultAge(isize); 17 | 18 | #[derive(FromForm)] 19 | struct UserLogin<'r> { 20 | username: &'r RawStr, 21 | password: Result, &'static str>, 22 | age: Result, 23 | } 24 | 25 | impl<'v> FromFormValue<'v> for StrongPassword<'v> { 26 | type Error = &'static str; 27 | 28 | fn from_form_value(v: &'v RawStr) -> Result { 29 | if v.len() < 8 { 30 | Err("too short!") 31 | } else { 32 | Ok(StrongPassword(v.as_str())) 33 | } 34 | } 35 | } 36 | 37 | impl<'v> FromFormValue<'v> for AdultAge { 38 | type Error = &'static str; 39 | 40 | fn from_form_value(v: &'v RawStr) -> Result { 41 | let age = match isize::from_form_value(v) { 42 | Ok(v) => v, 43 | Err(_) => return Err("value is not a number."), 44 | }; 45 | 46 | match age > 20 { 47 | true => Ok(AdultAge(age)), 48 | false => Err("must be at least 21."), 49 | } 50 | } 51 | } 52 | 53 | #[post("/login", data = "")] 54 | fn login(user: Form) -> Result { 55 | if let Err(e) = user.age { 56 | return Err(format!("Age is invalid: {}", e)); 57 | } 58 | 59 | if let Err(e) = user.password { 60 | return Err(format!("Password is invalid: {}", e)); 61 | } 62 | 63 | if user.username == "Sergio" { 64 | if let Ok(StrongPassword("password")) = user.password { 65 | Ok(Redirect::to("/user/Sergio")) 66 | } else { 67 | Err("Wrong password!".to_string()) 68 | } 69 | } else { 70 | Err(format!("Unrecognized user, '{}'.", user.username)) 71 | } 72 | } 73 | 74 | #[get("/user/")] 75 | fn user_page(username: &RawStr) -> String { 76 | format!("This is {}'s page.", username) 77 | } 78 | 79 | fn rocket() -> rocket::Rocket { 80 | rocket::ignite() 81 | .mount("/", routes![files::index, files::files, user_page, login]) 82 | } 83 | 84 | fn main() { 85 | rocket().launch(); 86 | } 87 | -------------------------------------------------------------------------------- /examples/form_validation/static/index.html: -------------------------------------------------------------------------------- 1 |

Login

2 | 3 |
4 | Username: 5 | Password: 6 | Age: 7 | 8 |
9 | -------------------------------------------------------------------------------- /examples/handlebars_templates/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "handlebars_templates" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | serde = "1.0" 10 | serde_derive = "1.0" 11 | serde_json = "1.0" 12 | 13 | [dependencies.rocket_contrib] 14 | path = "../../contrib/lib" 15 | default-features = false 16 | features = ["handlebars_templates"] 17 | -------------------------------------------------------------------------------- /examples/handlebars_templates/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | #[macro_use] extern crate serde_derive; 5 | extern crate rocket_contrib; 6 | 7 | #[cfg(test)] mod tests; 8 | 9 | use rocket::Request; 10 | use rocket::response::Redirect; 11 | use rocket_contrib::templates::{Template, handlebars}; 12 | 13 | use handlebars::{Helper, Handlebars, Context, RenderContext, Output, HelperResult, JsonRender}; 14 | 15 | #[derive(Serialize)] 16 | struct TemplateContext { 17 | title: &'static str, 18 | name: Option, 19 | items: Vec<&'static str>, 20 | // This key tells handlebars which template is the parent. 21 | parent: &'static str, 22 | } 23 | 24 | #[get("/")] 25 | fn index() -> Redirect { 26 | Redirect::to("/hello/Unknown") 27 | } 28 | 29 | #[get("/hello/")] 30 | fn hello(name: String) -> Template { 31 | Template::render("index", &TemplateContext { 32 | title: "Hello", 33 | name: Some(name), 34 | items: vec!["One", "Two", "Three"], 35 | parent: "layout", 36 | }) 37 | } 38 | 39 | #[get("/about")] 40 | fn about() -> Template { 41 | Template::render("about", &TemplateContext { 42 | title: "About", 43 | name: None, 44 | items: vec!["Four", "Five", "Six"], 45 | parent: "layout", 46 | }) 47 | } 48 | 49 | #[catch(404)] 50 | fn not_found(req: &Request) -> Template { 51 | let mut map = std::collections::HashMap::new(); 52 | map.insert("path", req.uri().path()); 53 | Template::render("error/404", &map) 54 | } 55 | 56 | fn wow_helper( 57 | h: &Helper, 58 | _: &Handlebars, 59 | _: &Context, 60 | _: &mut RenderContext, 61 | out: &mut Output 62 | ) -> HelperResult { 63 | if let Some(param) = h.param(0) { 64 | out.write("")?; 65 | out.write(¶m.value().render())?; 66 | out.write("")?; 67 | } 68 | 69 | Ok(()) 70 | } 71 | 72 | fn rocket() -> rocket::Rocket { 73 | rocket::ignite() 74 | .mount("/", routes![index, hello, about]) 75 | .register(catchers![not_found]) 76 | .attach(Template::custom(|engines| { 77 | engines.handlebars.register_helper("wow", Box::new(wow_helper)); 78 | })) 79 | } 80 | 81 | fn main() { 82 | rocket().launch(); 83 | } 84 | -------------------------------------------------------------------------------- /examples/handlebars_templates/templates/about.hbs: -------------------------------------------------------------------------------- 1 | {{#*inline "page"}} 2 | 3 |
4 |

Here's another page!

5 |
    6 | {{#each items}} 7 |
  • {{ this }}
  • 8 | {{/each}} 9 |
10 |
11 | 12 | {{/inline}} 13 | {{~> (parent)~}} 14 | -------------------------------------------------------------------------------- /examples/handlebars_templates/templates/error/404.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 6 | 7 | 8 |

404: Hey! There's nothing here.

9 | The page at {{ path }} does not exist! 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/handlebars_templates/templates/footer.hbs: -------------------------------------------------------------------------------- 1 |
2 |

This is a footer partial.

3 |
4 | -------------------------------------------------------------------------------- /examples/handlebars_templates/templates/index.hbs: -------------------------------------------------------------------------------- 1 | {{#*inline "page"}} 2 | 3 |
4 |

Hi {{ name }}!

5 |

Here are your items:

6 |
    7 | {{#each items}} 8 |
  • {{ this }}
  • 9 | {{/each}} 10 |
11 |
12 | 13 |
14 |

Try going to /hello/YourName.

15 |

Also, check {{ wow "this" }} (custom helper) out!

16 |
17 | 18 | {{/inline}} 19 | {{~> (parent)~}} 20 | -------------------------------------------------------------------------------- /examples/handlebars_templates/templates/layout.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rocket Example - {{ title }} 5 | 6 | 7 | {{> nav}} 8 | {{~> page}} 9 | {{> footer}} 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/handlebars_templates/templates/nav.hbs: -------------------------------------------------------------------------------- 1 | Hello | About 2 | -------------------------------------------------------------------------------- /examples/hello_2018/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_2018" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | edition = "2018" 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/hello_2018/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[cfg(test)] mod tests; 4 | 5 | use rocket::{get, routes}; 6 | 7 | #[get("/")] 8 | fn hello() -> &'static str { 9 | "Hello, Rust 2018!" 10 | } 11 | 12 | fn main() { 13 | rocket::ignite().mount("/", routes![hello]).launch(); 14 | } 15 | -------------------------------------------------------------------------------- /examples/hello_2018/src/tests.rs: -------------------------------------------------------------------------------- 1 | use rocket::{self, routes, local::Client}; 2 | 3 | #[test] 4 | fn hello_world() { 5 | let rocket = rocket::ignite().mount("/", routes![super::hello]); 6 | let client = Client::new(rocket).unwrap(); 7 | let mut response = client.get("/").dispatch(); 8 | assert_eq!(response.body_string(), Some("Hello, Rust 2018!".into())); 9 | } 10 | 11 | // Tests unrelated to the example. 12 | mod scoped_uri_tests { 13 | use rocket::{get, routes}; 14 | 15 | mod inner { 16 | use rocket::uri; 17 | 18 | #[rocket::get("/")] 19 | pub fn hello() -> String { 20 | format!("Hello! Try {}.", uri!(super::hello_name: "Rust 2018")) 21 | } 22 | } 23 | 24 | #[get("/")] 25 | fn hello_name(name: String) -> String { 26 | format!("Hello, {}! This is {}.", name, rocket::uri!(hello_name: &name)) 27 | } 28 | 29 | fn rocket() -> rocket::Rocket { 30 | rocket::ignite() 31 | .mount("/", routes![hello_name]) 32 | .mount("/", rocket::routes![inner::hello]) 33 | } 34 | 35 | use rocket::local::Client; 36 | 37 | #[test] 38 | fn test_inner_hello() { 39 | let client = Client::new(rocket()).unwrap(); 40 | let mut response = client.get("/").dispatch(); 41 | assert_eq!(response.body_string(), Some("Hello! Try /Rust%202018.".into())); 42 | } 43 | 44 | #[test] 45 | fn test_hello_name() { 46 | let client = Client::new(rocket()).unwrap(); 47 | let mut response = client.get("/Rust%202018").dispatch(); 48 | assert_eq!(response.body_string().unwrap(), "Hello, Rust 2018! This is /Rust%202018."); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/hello_person/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_person" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/hello_person/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | #[get("/hello//")] 8 | fn hello(name: String, age: u8) -> String { 9 | format!("Hello, {} year old named {}!", age, name) 10 | } 11 | 12 | #[get("/hello/")] 13 | fn hi(name: String) -> String { 14 | name 15 | } 16 | 17 | fn main() { 18 | rocket::ignite().mount("/", routes![hello, hi]).launch(); 19 | } 20 | -------------------------------------------------------------------------------- /examples/hello_person/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | use rocket::http::Status; 4 | 5 | fn client() -> Client { 6 | Client::new(rocket::ignite().mount("/", routes![super::hello, super::hi])).unwrap() 7 | } 8 | 9 | fn test(uri: &str, expected: String) { 10 | let client = client(); 11 | assert_eq!(client.get(uri).dispatch().body_string(), Some(expected)); 12 | } 13 | 14 | fn test_404(uri: &str) { 15 | let client = client(); 16 | assert_eq!(client.get(uri).dispatch().status(), Status::NotFound); 17 | } 18 | 19 | #[test] 20 | fn test_hello() { 21 | for &(name, age) in &[("Mike", 22), ("Michael", 80), ("A", 0), ("a", 127)] { 22 | test(&format!("/hello/{}/{}", name, age), 23 | format!("Hello, {} year old named {}!", age, name)); 24 | } 25 | } 26 | 27 | #[test] 28 | fn test_failing_hello() { 29 | test_404("/hello/Mike/1000"); 30 | test_404("/hello/Mike/-129"); 31 | test_404("/hello/Mike/-1"); 32 | } 33 | 34 | #[test] 35 | fn test_hi() { 36 | for name in &["Mike", "A", "123", "hi", "c"] { 37 | test(&format!("/hello/{}", name), name.to_string()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/hello_world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_world" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/hello_world/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | #[get("/")] 8 | fn hello() -> &'static str { 9 | "Hello, world!" 10 | } 11 | 12 | fn main() { 13 | rocket::ignite().mount("/", routes![hello]).launch(); 14 | } 15 | -------------------------------------------------------------------------------- /examples/hello_world/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | 4 | #[test] 5 | fn hello_world() { 6 | let rocket = rocket::ignite().mount("/", routes![super::hello]); 7 | let client = Client::new(rocket).unwrap(); 8 | let mut response = client.get("/").dispatch(); 9 | assert_eq!(response.body_string(), Some("Hello, world!".into())); 10 | } 11 | -------------------------------------------------------------------------------- /examples/json/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "json" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | serde = "1.0" 10 | serde_json = "1.0" 11 | serde_derive = "1.0" 12 | 13 | [dependencies.rocket_contrib] 14 | path = "../../contrib/lib" 15 | default-features = false 16 | features = ["json"] 17 | -------------------------------------------------------------------------------- /examples/json/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | #[macro_use] extern crate rocket_contrib; 5 | #[macro_use] extern crate serde_derive; 6 | 7 | #[cfg(test)] mod tests; 8 | 9 | use std::sync::Mutex; 10 | use std::collections::HashMap; 11 | 12 | use rocket::State; 13 | use rocket_contrib::json::{Json, JsonValue}; 14 | 15 | // The type to represent the ID of a message. 16 | type ID = usize; 17 | 18 | // We're going to store all of the messages here. No need for a DB. 19 | type MessageMap = Mutex>; 20 | 21 | #[derive(Serialize, Deserialize)] 22 | struct Message { 23 | id: Option, 24 | contents: String 25 | } 26 | 27 | // TODO: This example can be improved by using `route` with multiple HTTP verbs. 28 | #[post("/", format = "json", data = "")] 29 | fn new(id: ID, message: Json, map: State) -> JsonValue { 30 | let mut hashmap = map.lock().expect("map lock."); 31 | if hashmap.contains_key(&id) { 32 | json!({ 33 | "status": "error", 34 | "reason": "ID exists. Try put." 35 | }) 36 | } else { 37 | hashmap.insert(id, message.0.contents); 38 | json!({ "status": "ok" }) 39 | } 40 | } 41 | 42 | #[put("/", format = "json", data = "")] 43 | fn update(id: ID, message: Json, map: State) -> Option { 44 | let mut hashmap = map.lock().unwrap(); 45 | if hashmap.contains_key(&id) { 46 | hashmap.insert(id, message.0.contents); 47 | Some(json!({ "status": "ok" })) 48 | } else { 49 | None 50 | } 51 | } 52 | 53 | #[get("/", format = "json")] 54 | fn get(id: ID, map: State) -> Option> { 55 | let hashmap = map.lock().unwrap(); 56 | hashmap.get(&id).map(|contents| { 57 | Json(Message { 58 | id: Some(id), 59 | contents: contents.clone() 60 | }) 61 | }) 62 | } 63 | 64 | #[catch(404)] 65 | fn not_found() -> JsonValue { 66 | json!({ 67 | "status": "error", 68 | "reason": "Resource was not found." 69 | }) 70 | } 71 | 72 | fn rocket() -> rocket::Rocket { 73 | rocket::ignite() 74 | .mount("/message", routes![new, update, get]) 75 | .register(catchers![not_found]) 76 | .manage(Mutex::new(HashMap::::new())) 77 | } 78 | 79 | fn main() { 80 | rocket().launch(); 81 | } 82 | -------------------------------------------------------------------------------- /examples/managed_queue/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "managed_queue" 3 | version = "0.0.0" 4 | workspace = "../.." 5 | publish = false 6 | 7 | [dependencies] 8 | crossbeam = "0.5" 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/managed_queue/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | extern crate crossbeam; 5 | 6 | #[cfg(test)] mod tests; 7 | 8 | use rocket::State; 9 | use crossbeam::queue::MsQueue; 10 | 11 | struct LogChannel(MsQueue); 12 | 13 | #[put("/push?")] 14 | fn push(event: String, queue: State) { 15 | queue.0.push(event); 16 | } 17 | 18 | #[get("/pop")] 19 | fn pop(queue: State) -> String { 20 | queue.0.pop() 21 | } 22 | 23 | fn rocket() -> rocket::Rocket { 24 | rocket::ignite() 25 | .mount("/", routes![push, pop]) 26 | .manage(LogChannel(MsQueue::new())) 27 | } 28 | 29 | fn main() { 30 | rocket().launch(); 31 | } 32 | -------------------------------------------------------------------------------- /examples/managed_queue/src/tests.rs: -------------------------------------------------------------------------------- 1 | use rocket::local::Client; 2 | use rocket::http::Status; 3 | 4 | #[test] 5 | fn test_push_pop() { 6 | let client = Client::new(super::rocket()).unwrap(); 7 | 8 | let response = client.put("/push?event=test1").dispatch(); 9 | assert_eq!(response.status(), Status::Ok); 10 | 11 | let mut response = client.get("/pop").dispatch(); 12 | assert_eq!(response.body_string(), Some("test1".to_string())); 13 | } 14 | -------------------------------------------------------------------------------- /examples/manual_routes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "manual_routes" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/manual_routes/Rocket.toml: -------------------------------------------------------------------------------- 1 | [global] 2 | port = 8000 3 | -------------------------------------------------------------------------------- /examples/manual_routes/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use rocket::local::Client; 3 | use rocket::http::{ContentType, Status}; 4 | 5 | fn test(uri: &str, content_type: ContentType, status: Status, body: String) { 6 | let client = Client::new(rocket()).unwrap();; 7 | let mut response = client.get(uri).header(content_type).dispatch(); 8 | assert_eq!(response.status(), status); 9 | assert_eq!(response.body_string(), Some(body)); 10 | } 11 | 12 | #[test] 13 | fn test_forward() { 14 | test("/", ContentType::Plain, Status::Ok, "Hello!".to_string()); 15 | } 16 | 17 | #[test] 18 | fn test_name() { 19 | for &name in &[("John"), ("Mike"), ("Angela")] { 20 | let uri = format!("/hello/{}", name); 21 | test(&uri, ContentType::Plain, Status::Ok, name.to_string()); 22 | } 23 | } 24 | 25 | #[test] 26 | fn test_echo() { 27 | let uri = format!("/echo/echo%20this%20text"); 28 | test(&uri, ContentType::Plain, Status::Ok, "echo this text".into()); 29 | } 30 | 31 | #[test] 32 | fn test_upload() { 33 | let client = Client::new(rocket()).unwrap();; 34 | let expected_body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, \ 35 | sed do eiusmod tempor incididunt ut labore et dolore \ 36 | magna aliqua".to_string(); 37 | 38 | // Upload the body. 39 | let response = client.post("/upload") 40 | .header(ContentType::Plain) 41 | .body(&expected_body) 42 | .dispatch(); 43 | 44 | assert_eq!(response.status(), Status::Ok); 45 | 46 | // Ensure we get back the same body. 47 | let mut response = client.get("/upload").dispatch(); 48 | assert_eq!(response.status(), Status::Ok); 49 | assert_eq!(response.body_string(), Some(expected_body)); 50 | } 51 | 52 | #[test] 53 | fn test_not_found() { 54 | let uri = "/wrong_address"; 55 | let expected_body = format!("Couldn't find: {}", uri); 56 | test(uri, ContentType::Plain, Status::NotFound, expected_body); 57 | } 58 | -------------------------------------------------------------------------------- /examples/msgpack/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "msgpack" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | serde = "1.0" 10 | serde_derive = "1.0" 11 | 12 | [dependencies.rocket_contrib] 13 | path = "../../contrib/lib" 14 | default-features = false 15 | features = ["msgpack"] 16 | -------------------------------------------------------------------------------- /examples/msgpack/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | #[macro_use] extern crate serde_derive; 5 | extern crate rocket_contrib; 6 | 7 | #[cfg(test)] mod tests; 8 | 9 | use rocket_contrib::msgpack::MsgPack; 10 | 11 | #[derive(Serialize, Deserialize)] 12 | struct Message<'r> { 13 | id: usize, 14 | contents: &'r str 15 | } 16 | 17 | #[get("/", format = "msgpack")] 18 | fn get(id: usize) -> MsgPack> { 19 | MsgPack(Message { id: id, contents: "Hello, world!", }) 20 | } 21 | 22 | #[post("/", data = "", format = "msgpack")] 23 | fn create(data: MsgPack) -> String { 24 | data.contents.to_string() 25 | } 26 | 27 | fn rocket() -> rocket::Rocket { 28 | rocket::ignite().mount("/message", routes![get, create]) 29 | } 30 | 31 | fn main() { 32 | rocket().launch(); 33 | } 34 | -------------------------------------------------------------------------------- /examples/msgpack/src/tests.rs: -------------------------------------------------------------------------------- 1 | use rocket; 2 | use rocket::local::Client; 3 | use rocket::http::{Status, ContentType}; 4 | 5 | #[derive(Serialize, Deserialize)] 6 | struct Message { 7 | id: usize, 8 | contents: String 9 | } 10 | 11 | #[test] 12 | fn msgpack_get() { 13 | let client = Client::new(rocket()).unwrap(); 14 | let mut res = client.get("/message/1").header(ContentType::MsgPack).dispatch(); 15 | assert_eq!(res.status(), Status::Ok); 16 | 17 | // Check that the message is `[1, "Hello, world!"]` 18 | assert_eq!(&res.body_bytes().unwrap(), 19 | &[146, 1, 173, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]); 20 | } 21 | 22 | #[test] 23 | fn msgpack_post() { 24 | // Dispatch request with a message of `[2, "Goodbye, world!"]`. 25 | let client = Client::new(rocket()).unwrap(); 26 | let mut res = client.post("/message") 27 | .header(ContentType::MsgPack) 28 | .body(&[146, 2, 175, 71, 111, 111, 100, 98, 121, 101, 44, 32, 119, 111, 114, 108, 100, 33]) 29 | .dispatch(); 30 | 31 | assert_eq!(res.status(), Status::Ok); 32 | assert_eq!(res.body_string(), Some("Goodbye, world!".into())); 33 | } 34 | -------------------------------------------------------------------------------- /examples/optional_redirect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "optional_redirect" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/optional_redirect/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] 6 | mod tests; 7 | 8 | use rocket::response::Redirect; 9 | use rocket::http::RawStr; 10 | 11 | #[get("/")] 12 | fn root() -> Redirect { 13 | Redirect::to("/users/login") 14 | } 15 | 16 | #[get("/users/")] 17 | fn user(name: &RawStr) -> Result<&'static str, Redirect> { 18 | match name.as_str() { 19 | "Sergio" => Ok("Hello, Sergio!"), 20 | _ => Err(Redirect::to("/users/login")), 21 | } 22 | } 23 | 24 | #[get("/users/login")] 25 | fn login() -> &'static str { 26 | "Hi! That user doesn't exist. Maybe you need to log in?" 27 | } 28 | 29 | fn main() { 30 | rocket::ignite().mount("/", routes![root, user, login]).launch(); 31 | } 32 | -------------------------------------------------------------------------------- /examples/optional_redirect/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | use rocket::http::Status; 4 | 5 | fn client() -> Client { 6 | let rocket = rocket::ignite() 7 | .mount("/", routes![super::root, super::user, super::login]); 8 | Client::new(rocket).unwrap() 9 | 10 | } 11 | 12 | fn test_200(uri: &str, expected_body: &str) { 13 | let client = client(); 14 | let mut response = client.get(uri).dispatch(); 15 | assert_eq!(response.status(), Status::Ok); 16 | assert_eq!(response.body_string(), Some(expected_body.to_string())); 17 | } 18 | 19 | fn test_303(uri: &str, expected_location: &str) { 20 | let client = client(); 21 | let response = client.get(uri).dispatch(); 22 | let location_headers: Vec<_> = response.headers().get("Location").collect(); 23 | assert_eq!(response.status(), Status::SeeOther); 24 | assert_eq!(location_headers, vec![expected_location]); 25 | } 26 | 27 | #[test] 28 | fn test() { 29 | test_200("/users/Sergio", "Hello, Sergio!"); 30 | test_200("/users/login", 31 | "Hi! That user doesn't exist. Maybe you need to log in?"); 32 | } 33 | 34 | #[test] 35 | fn test_redirects() { 36 | test_303("/", "/users/login"); 37 | test_303("/users/unknown", "/users/login"); 38 | } 39 | -------------------------------------------------------------------------------- /examples/pastebin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pastebin" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | rand = "0.6" 10 | -------------------------------------------------------------------------------- /examples/pastebin/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | extern crate rand; 5 | 6 | mod paste_id; 7 | #[cfg(test)] mod tests; 8 | 9 | use std::io; 10 | use std::fs::File; 11 | use std::path::Path; 12 | 13 | use rocket::Data; 14 | use rocket::response::content; 15 | 16 | use paste_id::PasteID; 17 | 18 | const HOST: &str = "http://localhost:8000"; 19 | const ID_LENGTH: usize = 3; 20 | 21 | #[post("/", data = "")] 22 | fn upload(paste: Data) -> io::Result { 23 | let id = PasteID::new(ID_LENGTH); 24 | let filename = format!("upload/{id}", id = id); 25 | let url = format!("{host}/{id}\n", host = HOST, id = id); 26 | 27 | paste.stream_to_file(Path::new(&filename))?; 28 | Ok(url) 29 | } 30 | 31 | #[get("/")] 32 | fn retrieve(id: PasteID) -> Option> { 33 | let filename = format!("upload/{id}", id = id); 34 | File::open(&filename).map(|f| content::Plain(f)).ok() 35 | } 36 | 37 | #[get("/")] 38 | fn index() -> &'static str { 39 | " 40 | USAGE 41 | 42 | POST / 43 | 44 | accepts raw data in the body of the request and responds with a URL of 45 | a page containing the body's content 46 | 47 | EXMAPLE: curl --data-binary @file.txt http://localhost:8000 48 | 49 | GET / 50 | 51 | retrieves the content for the paste with id `` 52 | " 53 | } 54 | 55 | fn rocket() -> rocket::Rocket { 56 | rocket::ignite().mount("/", routes![index, upload, retrieve]) 57 | } 58 | 59 | fn main() { 60 | rocket().launch(); 61 | } 62 | -------------------------------------------------------------------------------- /examples/pastebin/src/paste_id.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::borrow::Cow; 3 | 4 | use rocket::request::FromParam; 5 | use rocket::http::RawStr; 6 | use rand::{self, Rng}; 7 | 8 | /// Table to retrieve base62 values from. 9 | const BASE62: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 10 | 11 | /// A _probably_ unique paste ID. 12 | pub struct PasteID<'a>(Cow<'a, str>); 13 | 14 | impl<'a> PasteID<'a> { 15 | /// Generate a _probably_ unique ID with `size` characters. For readability, 16 | /// the characters used are from the sets [0-9], [A-Z], [a-z]. The 17 | /// probability of a collision depends on the value of `size` and the number 18 | /// of IDs generated thus far. 19 | pub fn new(size: usize) -> PasteID<'static> { 20 | let mut id = String::with_capacity(size); 21 | let mut rng = rand::thread_rng(); 22 | for _ in 0..size { 23 | id.push(BASE62[rng.gen::() % 62] as char); 24 | } 25 | 26 | PasteID(Cow::Owned(id)) 27 | } 28 | } 29 | 30 | impl<'a> fmt::Display for PasteID<'a> { 31 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 32 | write!(f, "{}", self.0) 33 | } 34 | } 35 | 36 | /// Returns `true` if `id` is a valid paste ID and `false` otherwise. 37 | fn valid_id(id: &str) -> bool { 38 | id.chars().all(|c| { 39 | (c >= 'a' && c <= 'z') 40 | || (c >= 'A' && c <= 'Z') 41 | || (c >= '0' && c <= '9') 42 | }) 43 | } 44 | 45 | /// Returns an instance of `PasteID` if the path segment is a valid ID. 46 | /// Otherwise returns the invalid ID as the `Err` value. 47 | impl<'a> FromParam<'a> for PasteID<'a> { 48 | type Error = &'a RawStr; 49 | 50 | fn from_param(param: &'a RawStr) -> Result, &'a RawStr> { 51 | match valid_id(param) { 52 | true => Ok(PasteID(Cow::Borrowed(param))), 53 | false => Err(param) 54 | } 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /examples/query_params/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "query_params" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/query_params/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | use rocket::request::{Form, LenientForm}; 8 | 9 | #[derive(FromForm)] 10 | struct Person { 11 | name: String, 12 | age: Option 13 | } 14 | 15 | #[get("/hello?")] 16 | fn hello(person: Option>) -> String { 17 | if let Some(person) = person { 18 | if let Some(age) = person.age { 19 | format!("Hello, {} year old named {}!", age, person.name) 20 | } else { 21 | format!("Hello {}!", person.name) 22 | } 23 | } else { 24 | "We're gonna need a name, and only a name.".into() 25 | } 26 | } 27 | 28 | #[get("/hello?age=20&")] 29 | fn hello_20(person: LenientForm) -> String { 30 | format!("20 years old? Hi, {}!", person.name) 31 | } 32 | 33 | fn rocket() -> rocket::Rocket { 34 | rocket::ignite().mount("/", routes![hello, hello_20]) 35 | } 36 | 37 | fn main() { 38 | rocket().launch(); 39 | } 40 | -------------------------------------------------------------------------------- /examples/query_params/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::{Client, LocalResponse as Response}; 3 | use rocket::http::Status; 4 | 5 | macro_rules! run_test { 6 | ($query:expr, $test_fn:expr) => ({ 7 | let client = Client::new(rocket()).unwrap(); 8 | $test_fn(client.get(format!("/hello{}", $query)).dispatch()); 9 | }) 10 | } 11 | 12 | #[test] 13 | fn age_and_name_params() { 14 | run_test!("?age=10&name=john", |mut response: Response| { 15 | assert_eq!(response.body_string(), 16 | Some("Hello, 10 year old named john!".into())); 17 | }); 18 | 19 | run_test!("?age=20&name=john", |mut response: Response| { 20 | assert_eq!(response.body_string(), 21 | Some("20 years old? Hi, john!".into())); 22 | }); 23 | } 24 | 25 | #[test] 26 | fn age_param_only() { 27 | run_test!("?age=10", |mut response: Response| { 28 | assert_eq!(response.body_string(), 29 | Some("We're gonna need a name, and only a name.".into())); 30 | }); 31 | 32 | run_test!("?age=20", |mut response: Response| { 33 | assert_eq!(response.body_string(), 34 | Some("We're gonna need a name, and only a name.".into())); 35 | }); 36 | } 37 | 38 | #[test] 39 | fn name_param_only() { 40 | run_test!("?name=John", |mut response: Response| { 41 | assert_eq!(response.body_string(), Some("Hello John!".into())); 42 | }); 43 | } 44 | 45 | #[test] 46 | fn no_params() { 47 | run_test!("", |mut response: Response| { 48 | assert_eq!(response.body_string(), 49 | Some("We're gonna need a name, and only a name.".into())); 50 | }); 51 | 52 | run_test!("?", |mut response: Response| { 53 | assert_eq!(response.body_string(), 54 | Some("We're gonna need a name, and only a name.".into())); 55 | }); 56 | } 57 | 58 | #[test] 59 | fn extra_params() { 60 | run_test!("?age=20&name=Bob&extra", |mut response: Response| { 61 | assert_eq!(response.body_string(), 62 | Some("20 years old? Hi, Bob!".into())); 63 | }); 64 | 65 | run_test!("?age=30&name=Bob&extra", |mut response: Response| { 66 | assert_eq!(response.body_string(), 67 | Some("We're gonna need a name, and only a name.".into())); 68 | }); 69 | } 70 | 71 | #[test] 72 | fn wrong_path() { 73 | run_test!("/other?age=20&name=Bob", |response: Response| { 74 | assert_eq!(response.status(), Status::NotFound); 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /examples/ranking/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ranking" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/ranking/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::http::RawStr; 6 | 7 | #[cfg(test)] mod tests; 8 | 9 | #[get("/hello//")] 10 | fn hello(name: String, age: i8) -> String { 11 | format!("Hello, {} year old named {}!", age, name) 12 | } 13 | 14 | #[get("/hello//", rank = 2)] 15 | fn hi(name: String, age: &RawStr) -> String { 16 | format!("Hi {}! Your age ({}) is kind of funky.", name, age) 17 | } 18 | 19 | fn main() { 20 | rocket::ignite().mount("/", routes![hi, hello]).launch(); 21 | } 22 | -------------------------------------------------------------------------------- /examples/ranking/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | 4 | fn test(uri: &str, expected: String) { 5 | let rocket = rocket::ignite().mount("/", routes![super::hello, super::hi]); 6 | let client = Client::new(rocket).unwrap(); 7 | let mut response = client.get(uri).dispatch(); 8 | assert_eq!(response.body_string(), Some(expected)); 9 | } 10 | 11 | #[test] 12 | fn test_hello() { 13 | for &(name, age) in &[("Mike", 22), ("Michael", 80), ("A", 0), ("a", 127)] { 14 | test(&format!("/hello/{}/{}", name, age), 15 | format!("Hello, {} year old named {}!", age, name)); 16 | } 17 | } 18 | 19 | #[test] 20 | fn test_failing_hello_hi() { 21 | // Invalid integers. 22 | for &(name, age) in &[("Mike", 1000), ("Michael", 128), ("A", -800), ("a", -200)] { 23 | test(&format!("/hello/{}/{}", name, age), 24 | format!("Hi {}! Your age ({}) is kind of funky.", name, age)); 25 | } 26 | 27 | // Non-integers. 28 | for &(name, age) in &[("Mike", "!"), ("Michael", "hi"), ("A", "blah"), ("a", "0-1")] { 29 | test(&format!("/hello/{}/{}", name, age), 30 | format!("Hi {}! Your age ({}) is kind of funky.", name, age)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/raw_sqlite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "raw_sqlite" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | rusqlite = "0.14" 10 | -------------------------------------------------------------------------------- /examples/raw_sqlite/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | extern crate rusqlite; 5 | 6 | #[cfg(test)] mod tests; 7 | 8 | use std::sync::Mutex; 9 | use rocket::{Rocket, State}; 10 | use rusqlite::{Connection, Error}; 11 | 12 | type DbConn = Mutex; 13 | 14 | fn init_database(conn: &Connection) { 15 | conn.execute("CREATE TABLE entries ( 16 | id INTEGER PRIMARY KEY, 17 | name TEXT NOT NULL 18 | )", &[]) 19 | .expect("create entries table"); 20 | 21 | conn.execute("INSERT INTO entries (id, name) VALUES ($1, $2)", 22 | &[&0, &"Rocketeer"]) 23 | .expect("insert single entry into entries table"); 24 | } 25 | 26 | #[get("/")] 27 | fn hello(db_conn: State) -> Result { 28 | db_conn.lock() 29 | .expect("db connection lock") 30 | .query_row("SELECT name FROM entries WHERE id = 0", 31 | &[], |row| { row.get(0) }) 32 | } 33 | 34 | fn rocket() -> Rocket { 35 | // Open a new in-memory SQLite database. 36 | let conn = Connection::open_in_memory().expect("in memory db"); 37 | 38 | // Initialize the `entries` table in the in-memory database. 39 | init_database(&conn); 40 | 41 | // Have Rocket manage the database pool. 42 | rocket::ignite() 43 | .manage(Mutex::new(conn)) 44 | .mount("/", routes![hello]) 45 | } 46 | 47 | fn main() { 48 | rocket().launch(); 49 | } 50 | -------------------------------------------------------------------------------- /examples/raw_sqlite/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | 4 | #[test] 5 | fn hello() { 6 | let client = Client::new(rocket()).unwrap(); 7 | let mut response = client.get("/").dispatch(); 8 | assert_eq!(response.body_string(), Some("Rocketeer".into())); 9 | } 10 | -------------------------------------------------------------------------------- /examples/raw_upload/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "raw_upload" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/raw_upload/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | use std::{io, env}; 8 | use rocket::Data; 9 | 10 | #[post("/upload", format = "plain", data = "")] 11 | fn upload(data: Data) -> io::Result { 12 | data.stream_to_file(env::temp_dir().join("upload.txt")).map(|n| n.to_string()) 13 | } 14 | 15 | #[get("/")] 16 | fn index() -> &'static str { 17 | "Upload your text files by POSTing them to /upload." 18 | } 19 | 20 | fn rocket() -> rocket::Rocket { 21 | rocket::ignite().mount("/", routes![index, upload]) 22 | } 23 | 24 | fn main() { 25 | rocket().launch(); 26 | } 27 | -------------------------------------------------------------------------------- /examples/raw_upload/src/tests.rs: -------------------------------------------------------------------------------- 1 | use rocket::local::Client; 2 | use rocket::http::{Status, ContentType}; 3 | 4 | use std::env; 5 | use std::io::Read; 6 | use std::fs::{self, File}; 7 | 8 | const UPLOAD_CONTENTS: &str = "Hey! I'm going to be uploaded. :D Yay!"; 9 | 10 | #[test] 11 | fn test_index() { 12 | let client = Client::new(super::rocket()).unwrap(); 13 | let mut res = client.get("/").dispatch(); 14 | assert_eq!(res.body_string(), Some(super::index().to_string())); 15 | } 16 | 17 | #[test] 18 | fn test_raw_upload() { 19 | // Delete the upload file before we begin. 20 | let upload_file = env::temp_dir().join("upload.txt"); 21 | let _ = fs::remove_file(&upload_file); 22 | 23 | // Do the upload. Make sure we get the expected results. 24 | let client = Client::new(super::rocket()).unwrap(); 25 | let mut res = client.post("/upload") 26 | .header(ContentType::Plain) 27 | .body(UPLOAD_CONTENTS) 28 | .dispatch(); 29 | 30 | assert_eq!(res.status(), Status::Ok); 31 | assert_eq!(res.body_string(), Some(UPLOAD_CONTENTS.len().to_string())); 32 | 33 | // Ensure we find the body in the /tmp/upload.txt file. 34 | let mut file_contents = String::new(); 35 | let mut file = File::open(&upload_file).expect("open upload.txt file"); 36 | file.read_to_string(&mut file_contents).expect("read upload.txt"); 37 | assert_eq!(&file_contents, UPLOAD_CONTENTS); 38 | } 39 | -------------------------------------------------------------------------------- /examples/redirect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redirect" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/redirect/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | use rocket::response::Redirect; 8 | 9 | #[get("/")] 10 | fn root() -> Redirect { 11 | Redirect::to(uri!(login)) 12 | } 13 | 14 | #[get("/login")] 15 | fn login() -> &'static str { 16 | "Hi! Please log in before continuing." 17 | } 18 | 19 | fn main() { 20 | rocket::ignite().mount("/", routes![root, login]).launch(); 21 | } 22 | -------------------------------------------------------------------------------- /examples/redirect/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | use rocket::http::Status; 4 | 5 | fn client() -> Client { 6 | let rocket = rocket::ignite().mount("/", routes![super::root, super::login]); 7 | Client::new(rocket).unwrap() 8 | } 9 | 10 | #[test] 11 | fn test_root() { 12 | let client = client(); 13 | let mut response = client.get("/").dispatch(); 14 | 15 | assert!(response.body().is_none()); 16 | assert_eq!(response.status(), Status::SeeOther); 17 | for h in response.headers().iter() { 18 | match h.name.as_str() { 19 | "Location" => assert_eq!(h.value, "/login"), 20 | "Content-Length" => assert_eq!(h.value.parse::().unwrap(), 0), 21 | _ => { /* let these through */ } 22 | } 23 | } 24 | } 25 | 26 | #[test] 27 | fn test_login() { 28 | let client = client(); 29 | let mut r = client.get("/login").dispatch(); 30 | assert_eq!(r.body_string(), Some("Hi! Please log in before continuing.".into())); 31 | } 32 | -------------------------------------------------------------------------------- /examples/request_guard/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "request_guard" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/request_guard/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro, never_type)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::request::{self, Request, FromRequest}; 6 | use rocket::outcome::Outcome::*; 7 | 8 | #[derive(Debug)] 9 | struct HeaderCount(usize); 10 | 11 | impl<'a, 'r> FromRequest<'a, 'r> for HeaderCount { 12 | type Error = !; 13 | 14 | fn from_request(request: &'a Request<'r>) -> request::Outcome { 15 | Success(HeaderCount(request.headers().len())) 16 | } 17 | } 18 | 19 | #[get("/")] 20 | fn header_count(header_count: HeaderCount) -> String { 21 | format!("Your request contained {} headers!", header_count.0) 22 | } 23 | 24 | fn rocket() -> rocket::Rocket { 25 | rocket::ignite().mount("/", routes![header_count]) 26 | } 27 | 28 | fn main() { 29 | rocket().launch(); 30 | } 31 | 32 | #[cfg(test)] 33 | mod test { 34 | use rocket::local::Client; 35 | use rocket::http::Header; 36 | 37 | fn test_header_count<'h>(headers: Vec>) { 38 | let client = Client::new(super::rocket()).unwrap(); 39 | let mut req = client.get("/"); 40 | for header in headers.iter().cloned() { 41 | req.add_header(header); 42 | } 43 | 44 | let mut response = req.dispatch(); 45 | let expect = format!("Your request contained {} headers!", headers.len()); 46 | assert_eq!(response.body_string(), Some(expect)); 47 | } 48 | 49 | #[test] 50 | fn test_n_headers() { 51 | for i in 0..50 { 52 | let headers = (0..i) 53 | .map(|n| Header::new(n.to_string(), n.to_string())) 54 | .collect(); 55 | 56 | test_header_count(headers); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/request_local_state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "request_local_state" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/request_local_state/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use std::sync::atomic::{AtomicUsize, Ordering}; 6 | 7 | use rocket::request::{self, Request, FromRequest, State}; 8 | use rocket::outcome::Outcome::*; 9 | 10 | #[cfg(test)] mod tests; 11 | 12 | #[derive(Default)] 13 | struct Atomics { 14 | uncached: AtomicUsize, 15 | cached: AtomicUsize, 16 | } 17 | 18 | struct Guard1; 19 | struct Guard2; 20 | 21 | impl<'a, 'r> FromRequest<'a, 'r> for Guard1 { 22 | type Error = (); 23 | 24 | fn from_request(req: &'a Request<'r>) -> request::Outcome { 25 | let atomics = req.guard::>()?; 26 | atomics.uncached.fetch_add(1, Ordering::Relaxed); 27 | req.local_cache(|| atomics.cached.fetch_add(1, Ordering::Relaxed)); 28 | 29 | Success(Guard1) 30 | } 31 | } 32 | 33 | impl<'a, 'r> FromRequest<'a, 'r> for Guard2 { 34 | type Error = (); 35 | 36 | fn from_request(req: &'a Request<'r>) -> request::Outcome { 37 | req.guard::()?; 38 | Success(Guard2) 39 | } 40 | } 41 | 42 | #[get("/")] 43 | fn index(_g1: Guard1, _g2: Guard2) { 44 | // This exists only to run the request guards. 45 | } 46 | 47 | fn rocket() -> rocket::Rocket { 48 | rocket::ignite() 49 | .manage(Atomics::default()) 50 | .mount("/", routes!(index)) 51 | } 52 | 53 | fn main() { 54 | rocket().launch(); 55 | } 56 | -------------------------------------------------------------------------------- /examples/request_local_state/src/tests.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{Ordering}; 2 | 3 | use super::{rocket, Atomics}; 4 | use rocket::local::Client; 5 | 6 | #[test] 7 | fn test() { 8 | let client = Client::new(rocket()).unwrap(); 9 | client.get("/").dispatch(); 10 | 11 | let atomics = client.rocket().state::().unwrap(); 12 | assert_eq!(atomics.uncached.load(Ordering::Relaxed), 2); 13 | assert_eq!(atomics.cached.load(Ordering::Relaxed), 1); 14 | } 15 | -------------------------------------------------------------------------------- /examples/session/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "session" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib", features = ["private-cookies"] } 9 | 10 | [dependencies.rocket_contrib] 11 | path = "../../contrib/lib" 12 | default-features = false 13 | features = ["handlebars_templates"] 14 | -------------------------------------------------------------------------------- /examples/session/Rocket.toml: -------------------------------------------------------------------------------- 1 | [global] 2 | secret_key = "itlYmFR2vYKrOmFhupMIn/hyB6lYCCTXz4yaQX89XVg=" 3 | -------------------------------------------------------------------------------- /examples/session/templates/index.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Rocket: Session Example 7 | 8 | 9 |

Rocket Session Example

10 |

Logged in with user ID {{ user_id }}.

11 |
12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/session/templates/login.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Rocket: Sessions 7 | 8 | 9 |

Rocket Session: Please Login

10 | 11 |

Please login to continue.

12 | 13 | {{#if flash}} 14 |

Error: {{ flash }}

15 | {{/if}} 16 | 17 |
18 | 19 | 20 | 21 | 22 |

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "state" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/state/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | use std::sync::atomic::{AtomicUsize, Ordering}; 8 | 9 | use rocket::State; 10 | use rocket::response::content; 11 | 12 | struct HitCount(AtomicUsize); 13 | 14 | #[get("/")] 15 | fn index(hit_count: State) -> content::Html { 16 | hit_count.0.fetch_add(1, Ordering::Relaxed); 17 | let msg = "Your visit has been recorded!"; 18 | let count = format!("Visits: {}", count(hit_count)); 19 | content::Html(format!("{}

{}", msg, count)) 20 | } 21 | 22 | #[get("/count")] 23 | fn count(hit_count: State) -> String { 24 | hit_count.0.load(Ordering::Relaxed).to_string() 25 | } 26 | 27 | fn rocket() -> rocket::Rocket { 28 | rocket::ignite() 29 | .mount("/", routes![index, count]) 30 | .manage(HitCount(AtomicUsize::new(0))) 31 | } 32 | 33 | fn main() { 34 | rocket().launch(); 35 | } 36 | -------------------------------------------------------------------------------- /examples/state/src/tests.rs: -------------------------------------------------------------------------------- 1 | use rocket::local::Client; 2 | use rocket::http::Status; 3 | 4 | fn register_hit(client: &Client) { 5 | let response = client.get("/").dispatch();; 6 | assert_eq!(response.status(), Status::Ok); 7 | } 8 | 9 | fn get_count(client: &Client) -> usize { 10 | let mut response = client.get("/count").dispatch(); 11 | response.body_string().and_then(|s| s.parse().ok()).unwrap() 12 | } 13 | 14 | #[test] 15 | fn test_count() { 16 | let client = Client::new(super::rocket()).unwrap(); 17 | 18 | // Count should start at 0. 19 | assert_eq!(get_count(&client), 0); 20 | 21 | for _ in 0..99 { register_hit(&client); } 22 | assert_eq!(get_count(&client), 99); 23 | 24 | register_hit(&client); 25 | assert_eq!(get_count(&client), 100); 26 | } 27 | 28 | #[test] 29 | fn test_raw_state_count() { 30 | use rocket::State; 31 | use super::{count, index}; 32 | 33 | let rocket = super::rocket(); 34 | 35 | assert_eq!(count(State::from(&rocket).unwrap()), "0"); 36 | assert!(index(State::from(&rocket).unwrap()).0.contains("Visits: 1")); 37 | assert_eq!(count(State::from(&rocket).unwrap()), "1"); 38 | } 39 | 40 | // Cargo runs each test in parallel on different threads. We use all of these 41 | // tests below to show (and assert) that state is managed per-Rocket instance. 42 | #[test] fn test_count_parallel() { test_count() } 43 | #[test] fn test_count_parallel_2() { test_count() } 44 | #[test] fn test_count_parallel_3() { test_count() } 45 | #[test] fn test_count_parallel_4() { test_count() } 46 | #[test] fn test_count_parallel_5() { test_count() } 47 | #[test] fn test_count_parallel_6() { test_count() } 48 | #[test] fn test_count_parallel_7() { test_count() } 49 | #[test] fn test_count_parallel_8() { test_count() } 50 | #[test] fn test_count_parallel_9() { test_count() } 51 | -------------------------------------------------------------------------------- /examples/static_files/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static_files" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | rocket_contrib = { path = "../../contrib/lib" } 10 | -------------------------------------------------------------------------------- /examples/static_files/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate rocket; 2 | extern crate rocket_contrib; 3 | 4 | #[cfg(test)] mod tests; 5 | 6 | use rocket_contrib::serve::StaticFiles; 7 | 8 | fn rocket() -> rocket::Rocket { 9 | rocket::ignite().mount("/", StaticFiles::from("static")) 10 | } 11 | 12 | fn main() { 13 | rocket().launch(); 14 | } 15 | -------------------------------------------------------------------------------- /examples/static_files/src/tests.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Read; 3 | 4 | use rocket::local::Client; 5 | use rocket::http::Status; 6 | 7 | use super::rocket; 8 | 9 | fn test_query_file (path: &str, file: T, status: Status) 10 | where T: Into> 11 | { 12 | let client = Client::new(rocket()).unwrap(); 13 | let mut response = client.get(path).dispatch(); 14 | assert_eq!(response.status(), status); 15 | 16 | let body_data = response.body().and_then(|body| body.into_bytes()); 17 | if let Some(filename) = file.into() { 18 | let expected_data = read_file_content(filename); 19 | assert!(body_data.map_or(false, |s| s == expected_data)); 20 | } 21 | } 22 | 23 | fn read_file_content(path: &str) -> Vec { 24 | let mut fp = File::open(&path).expect(&format!("Can't open {}", path)); 25 | let mut file_content = vec![]; 26 | 27 | fp.read_to_end(&mut file_content).expect(&format!("Reading {} failed.", path)); 28 | file_content 29 | } 30 | 31 | #[test] 32 | fn test_index_html() { 33 | test_query_file("/", "static/index.html", Status::Ok); 34 | test_query_file("/?v=1", "static/index.html", Status::Ok); 35 | test_query_file("/?this=should&be=ignored", "static/index.html", Status::Ok); 36 | } 37 | 38 | #[test] 39 | fn test_hidden_file() { 40 | test_query_file("/hidden/hi.txt", "static/hidden/hi.txt", Status::Ok); 41 | test_query_file("/hidden/hi.txt?v=1", "static/hidden/hi.txt", Status::Ok); 42 | test_query_file("/hidden/hi.txt?v=1&a=b", "static/hidden/hi.txt", Status::Ok); 43 | } 44 | 45 | #[test] 46 | fn test_icon_file() { 47 | test_query_file("/rocket-icon.jpg", "static/rocket-icon.jpg", Status::Ok); 48 | test_query_file("/rocket-icon.jpg", "static/rocket-icon.jpg", Status::Ok); 49 | } 50 | 51 | #[test] 52 | fn test_invalid_path() { 53 | test_query_file("/thou_shalt_not_exist", None, Status::NotFound); 54 | test_query_file("/thou/shalt/not/exist", None, Status::NotFound); 55 | test_query_file("/thou/shalt/not/exist?a=b&c=d", None, Status::NotFound); 56 | } 57 | -------------------------------------------------------------------------------- /examples/static_files/static/hidden/hi.txt: -------------------------------------------------------------------------------- 1 | You found me! :o 2 | -------------------------------------------------------------------------------- /examples/static_files/static/index.html: -------------------------------------------------------------------------------- 1 |

Hello, world!

2 | 3 | 4 | A rocket icon. 5 | 6 | -------------------------------------------------------------------------------- /examples/static_files/static/rocket-icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackblitz/template-rust-rocket/master/examples/static_files/static/rocket-icon.jpg -------------------------------------------------------------------------------- /examples/stream/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stream" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/stream/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | use rocket::response::{content, Stream}; 8 | 9 | use std::io::{self, repeat, Repeat, Read, Take}; 10 | use std::fs::File; 11 | 12 | type LimitedRepeat = Take; 13 | 14 | // Generate this file using: head -c BYTES /dev/random > big_file.dat 15 | const FILENAME: &str = "big_file.dat"; 16 | 17 | #[get("/")] 18 | fn root() -> content::Plain> { 19 | content::Plain(Stream::from(repeat('a' as u8).take(25000))) 20 | } 21 | 22 | #[get("/big_file")] 23 | fn file() -> io::Result> { 24 | File::open(FILENAME).map(|file| Stream::from(file)) 25 | } 26 | 27 | fn rocket() -> rocket::Rocket { 28 | rocket::ignite().mount("/", routes![root, file]) 29 | } 30 | 31 | fn main() { 32 | rocket().launch(); 33 | } 34 | -------------------------------------------------------------------------------- /examples/stream/src/tests.rs: -------------------------------------------------------------------------------- 1 | use std::fs::{self, File}; 2 | use std::io::prelude::*; 3 | 4 | use rocket::local::Client; 5 | 6 | #[test] 7 | fn test_root() { 8 | let client = Client::new(super::rocket()).unwrap(); 9 | let mut res = client.get("/").dispatch(); 10 | 11 | // Check that we have exactly 25,000 'a'. 12 | let res_str = res.body_string().unwrap(); 13 | assert_eq!(res_str.len(), 25000); 14 | for byte in res_str.as_bytes() { 15 | assert_eq!(*byte, b'a'); 16 | } 17 | } 18 | 19 | #[test] 20 | fn test_file() { 21 | // Create the 'big_file' 22 | const CONTENTS: &str = "big_file contents...not so big here"; 23 | let mut file = File::create(super::FILENAME).expect("create big_file"); 24 | file.write_all(CONTENTS.as_bytes()).expect("write to big_file"); 25 | 26 | // Get the big file contents, hopefully. 27 | let client = Client::new(super::rocket()).unwrap(); 28 | let mut res = client.get("/big_file").dispatch(); 29 | assert_eq!(res.body_string(), Some(CONTENTS.into())); 30 | 31 | // Delete the 'big_file'. 32 | fs::remove_file(super::FILENAME).expect("remove big_file"); 33 | } 34 | -------------------------------------------------------------------------------- /examples/tera_templates/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tera_templates" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | serde = "1.0" 10 | serde_derive = "1.0" 11 | serde_json = "1.0" 12 | 13 | [dependencies.rocket_contrib] 14 | path = "../../contrib/lib" 15 | default-features = false 16 | features = ["tera_templates"] 17 | -------------------------------------------------------------------------------- /examples/tera_templates/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | #[macro_use] extern crate serde_derive; 5 | extern crate serde_json; 6 | extern crate rocket_contrib; 7 | 8 | #[cfg(test)] mod tests; 9 | 10 | use std::collections::HashMap; 11 | 12 | use rocket::Request; 13 | use rocket::response::Redirect; 14 | use rocket_contrib::templates::Template; 15 | 16 | #[derive(Serialize)] 17 | struct TemplateContext { 18 | name: String, 19 | items: Vec<&'static str> 20 | } 21 | 22 | #[get("/")] 23 | fn index() -> Redirect { 24 | Redirect::to(uri!(get: name = "Unknown")) 25 | } 26 | 27 | #[get("/hello/")] 28 | fn get(name: String) -> Template { 29 | let context = TemplateContext { name, items: vec!["One", "Two", "Three"] }; 30 | Template::render("index", &context) 31 | } 32 | 33 | #[catch(404)] 34 | fn not_found(req: &Request) -> Template { 35 | let mut map = HashMap::new(); 36 | map.insert("path", req.uri().path()); 37 | Template::render("error/404", &map) 38 | } 39 | 40 | fn rocket() -> rocket::Rocket { 41 | rocket::ignite() 42 | .mount("/", routes![index, get]) 43 | .attach(Template::fairing()) 44 | .register(catchers![not_found]) 45 | } 46 | 47 | fn main() { 48 | rocket().launch(); 49 | } 50 | -------------------------------------------------------------------------------- /examples/tera_templates/templates/base.html.tera: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tera Demo 6 | 7 | 8 | {% block content %}{% endblock content %} 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/tera_templates/templates/error/404.html.tera: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 6 | 7 | 8 |

404: Hey! There's nothing here.

9 | The page at {{ path }} does not exist! 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/tera_templates/templates/index.html.tera: -------------------------------------------------------------------------------- 1 | {% extends "base" %} 2 | 3 | {% block content %} 4 |

Hi {{name}}

5 |

Here are your items:

6 |
    7 | {% for s in items %} 8 |
  • {{ s }}
  • 9 | {% endfor %} 10 |
11 | 12 |

Try going to /hello/YourName

13 | {% endblock content %} 14 | -------------------------------------------------------------------------------- /examples/testing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "testing" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | -------------------------------------------------------------------------------- /examples/testing/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[get("/")] 6 | fn hello() -> &'static str { 7 | "Hello, world!" 8 | } 9 | 10 | fn rocket() -> rocket::Rocket { 11 | rocket::ignite().mount("/", routes![hello]) 12 | } 13 | 14 | fn main() { 15 | rocket().launch(); 16 | } 17 | 18 | #[cfg(test)] 19 | mod test { 20 | use super::rocket; 21 | use rocket::local::Client; 22 | use rocket::http::Status; 23 | 24 | #[test] 25 | fn test_hello() { 26 | let client = Client::new(rocket()).unwrap(); 27 | let mut response = client.get("/").dispatch(); 28 | assert_eq!(response.status(), Status::Ok); 29 | assert_eq!(response.body_string(), Some("Hello, world!".into())); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/tls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tls" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib", features = ["tls"] } 9 | -------------------------------------------------------------------------------- /examples/tls/Rocket.toml: -------------------------------------------------------------------------------- 1 | # The certificate/private key pair used here was generated via openssl using the 2 | # `gen_cert.sh` script located in the `private/` subdirectory. 3 | # 4 | # The certificate is self-signed. As such, you will need to trust it directly 5 | # for your browser to refer to the connection as secure. You should NEVER use 6 | # this certificate/key pair. It is here for DEMONSTRATION PURPOSES ONLY. 7 | [global.tls] 8 | certs = "private/cert.pem" 9 | key = "private/key.pem" 10 | -------------------------------------------------------------------------------- /examples/tls/private/ca_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFuzCCA6OgAwIBAgIJAKGZ7Q2UtrXSMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNV 3 | BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEChMJUm9ja2V0IENBMRcwFQYDVQQD 4 | Ew5Sb2NrZXQgUm9vdCBDQTAeFw0xNzA5MDExMDAyMjRaFw0yNzA4MzAxMDAyMjRa 5 | MEcxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEChMJUm9ja2V0IENB 6 | MRcwFQYDVQQDEw5Sb2NrZXQgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP 7 | ADCCAgoCggIBANpHgKt28+RYw3z+RyvsBqQXCLfJfv7a8ZXnuIScNapjxisTih4u 8 | HqiuC2DsUg6jF1zYzEBwCUKKjAXhPBKl2sRPxvTOK4kOy3a9kde/a/vLFkdt3CSJ 9 | CDhJk3CxT1HEDi7e62G8jNZw6DlEwpWpYwkiQccL5Myi8GIn7vw/hNZ//wzFsYSj 10 | G4ztAubN5dnbsdI0kpYp+QZ3RmDGx6T/FCpocWmCPt7qJqvwpcPTK7CfOVhF4ecg 11 | lFs55CPn821ckFnHpzO1ffI//fiS9ZqOnpOt0zs8nGPIX+Mu+YHnvb6af6A8cqBm 12 | odm32mcwCx67f7Cgob+MqfPSTe/tTxgA49IcLDZaybPWv3POngh9T5yRPdDKLsSb 13 | oHRTE2+6H+Dg5HDkSz9OTCWbMx+ItjvxfYFgIlpqjEQYoKh9iuiTx6qI1k9Drdxk 14 | Ymps+108xwCwkKuLqCE91lR8gWPNziv5Ja90VMjhi9/HrtIQAC5RCVMUZwE1Lz3S 15 | PJy/z6hByQG0aIeT6KdLiwHQKSdzTwwc49fEjtRI2mX2m7JQrtS/vllcdeslYsUu 16 | HBIrXbI/F3sD2N09fJnG2A74eWtC9tQ3eo2EKveB9FFRO20aWP5Ho3P+wo1eWdRJ 17 | qItpgV0h+d+bpsEJP1LBsNhhaLkSJYAibejYX0fYSxd+mtQmDKT5WGSfAgMBAAGj 18 | gakwgaYwHQYDVR0OBBYEFHcd2x5m+UOJOXvSsVpeCzs5lMJoMHcGA1UdIwRwMG6A 19 | FHcd2x5m+UOJOXvSsVpeCzs5lMJooUukSTBHMQswCQYDVQQGEwJVUzELMAkGA1UE 20 | CBMCQ0ExEjAQBgNVBAoTCVJvY2tldCBDQTEXMBUGA1UEAxMOUm9ja2V0IFJvb3Qg 21 | Q0GCCQChme0NlLa10jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQC4 22 | OPHtrvRp2nX437zfCRZXz5RcHWm0LgjpbLVE77BihgE1GUT9/DxxvkbgRaP/Mu7e 23 | Ox3mXJuD0eJMW3HK0N7blk25pDm7KLPhGmaSMEHmnsYkEbxwYez5t1xdumA+IwGp 24 | uKscB0ymeIO6Z72IxXhyb5BmjjzeCChOiEWmann6JTGs9Y0C4ZBd2+3JoC6v6yzz 25 | nnqYqlfxklAQ9FL4hbDsVib8cClVnyIBM9CEsdav8fzb1e5a8jv6pxMXFeTPYNay 26 | fgdo2AvST+1PMZBU5tMrp9DY+GQo3RG1eU08v8wZQSFGfPr8Tu3Ak1WYGUT4cV5/ 27 | lJMNFdtYLMDcOvrTZz2mLCjQx8H2cN+PPZWkG/aCIrhmGYNdNbksCPVFg1B3uNwh 28 | kUcbxgBuDXxiz1gAeDbx5/GeVMRhTDFH9VnGdeBnUo3MAzH5Vg/OBcm74Mqcsljc 29 | oUm4H7wZghLnA8Gb3zsR5LvFfF+pCSNkVMPuVGyl+k7su+3ibX04DhrPR0b2vqNJ 30 | G2m0sabQZGdGst5LNcBbSMxBk+qDClGgRPgA3z+2aElswFR1a8Kj+fBb7lNqPc5H 31 | ZygN3ZFWY0QyKyWR6CPat/vYKu8HuIT5Ad6nb9q/JH3Qllsk7tUoIASujjHMGZaf 32 | GOik+8ewqlk60rcVbtUlkakpRu57hB6STj9K5HoeWw== 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /examples/tls/private/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFITCCAwmgAwIBAgIJAII1fQkonYEEMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV 3 | BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEChMJUm9ja2V0IENBMRcwFQYDVQQD 4 | Ew5Sb2NrZXQgUm9vdCBDQTAeFw0xNzA5MDExMDAyMjhaFw0yNzA4MzAxMDAyMjha 5 | MD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGUm9ja2V0MRIw 6 | EAYDVQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC 7 | AQDqe/Ps0tJf11HBuxJ4HvgC4VJeeiSl3D4P8ZT6uamCj8XD0MPtfRjGgfZPRjfY 8 | ksiYRs4Wg3Wy3aiQR6IVrNAxtfU1ZA3vRGCBwV0oWkfyPJKQOtF0Ih0/MhmYdiWG 9 | gDqs5qF/6B9K8qbinexal8v1oXpwQC5dod/NOuSLZQtQfkiYIeNqo0BbxtcaNE2u 10 | kgOYg1Cvc9ui3KPNA2JTN+Uzq6A8n4Pej6erG2NeCAoov9nrkPyustDWLQ76wdTp 11 | 5YU6zwwsl+fJtb5scNUmagujoXTTqn06WoCMDUsSjC/jlGMIrzmx90Wq8Dg6HBGn 12 | Cscz3M/AUXYzJtShkxMNZCsdxH+8x5oyO/RrtyeRyN8iDiOolz+SfQROVXMU0zkx 13 | nRl7hIxgB/QeDi6MMXGLTd08vpIAohk3hnycsGgTwTCT5LxWJnorpm4wdr1bDmCY 14 | InUO5hX0rFWtS0ij78GTUbpajkNTEXIXXwa1VnSE2kIeUX6aiKhJsm3KWp496JuM 15 | ahIR7XCP9PyGclWI+Pa0eq5L8nnuSfqUAwCeOvvwdBOxUvKmecly1IHLoUXGnhy0 16 | 46MjYo80yYFqrGgop6lUEZ0ThYpDpMxq+JIeUoyGaCJFDvundzt0u0sh9i+hUCVe 17 | v3zsgxwvBeJy0L1G1uGkpCqERkYJQt9O+qLM8i7hf7ONkQIDAQABoxgwFjAUBgNV 18 | HREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggIBAAcXycXdWVvwLl+7 19 | ryG8V7FpB9bp0lHNA4q3DpEINCNyuA2cbnVU/u2L3ddvroTcrPjE+hhNbcVaz/NH 20 | w4sQqlDzkV+G9kZ4qBTlk5zon6aGGow181J+B5SVznt6lO4/KYYpEN0vX+uMvsgK 21 | OG7ydsRMDxPpsnVS9SFx0Ke8AlmUet5S/NGYCfedd4rwCu+oJHUWhXNwFZqLF3Yn 22 | s8lg3xdM0kJt8g4m1/KUpunanX3w+DdZaIwbltEZs4NriXn0VVbEPRpHyiGMosgf 23 | mEUV2z49f6S2joEnSn2Y/ILOdKFQ2mKFXtXJP43Qzj8Mr5mSb2bXyABlrn0pl/+o 24 | HBkyVyDx5BKqWKe5uK3YCDsbIJj026AkCdTKF+BSBWfB+EqdSIOvVrpHtQK7BwFx 25 | pS5rdQBLA86f1NC0e235L6pwFKm+imazr6Jn7fbbwq1y9PSL36rUn4e/+R2Yoia9 26 | S7zDOqGbnyv9h7eE3Muiy26kJsJfCrjse/dmce+6YnB1FC5RKPn7kM86t7MyDrgx 27 | W60xRMdgmcGfPjei2V4MdVM6ysOlNoeh39DizjkV9+r8iGl4vngplJrPgAIvywQz 28 | v1pLk6dSlSOwgqY94hqxqNvG80xSoYsmMjDrPmtBVERjhbffsdIDHjcPVsJKH6l6 29 | 8wg+/u6aK2bMHt41f3XE/UTY+A57 30 | -----END CERTIFICATE----- 31 | -------------------------------------------------------------------------------- /examples/tls/private/gen_cert.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # TODO: `rustls` (really, `webpki`) doesn't currently use the CN in the subject 4 | # to check if a certificate is valid for a server name sent via SNI. It's not 5 | # clear if this is intended, since certificates _should_ have a `subjectAltName` 6 | # with a DNS name, or if it simply hasn't been implemented yet. See 7 | # https://bugzilla.mozilla.org/show_bug.cgi?id=552346 for a bit more info. 8 | 9 | CA_SUBJECT="/C=US/ST=CA/O=Rocket CA/CN=Rocket Root CA" 10 | SUBJECT="/C=US/ST=CA/O=Rocket/CN=localhost" 11 | ALT="DNS:localhost" 12 | 13 | openssl genrsa -out ca_key.pem 4096 14 | openssl req -new -x509 -days 3650 -key ca_key.pem -subj "${CA_SUBJECT}" -out ca_cert.pem 15 | 16 | openssl req -newkey rsa:4096 -nodes -sha256 -keyout key.pem -subj "${SUBJECT}" -out server.csr 17 | openssl x509 -req -sha256 -extfile <(printf "subjectAltName=${ALT}") -days 3650 \ 18 | -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ 19 | -in server.csr -out cert.pem 20 | 21 | rm ca_cert.srl server.csr 22 | -------------------------------------------------------------------------------- /examples/tls/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | #[get("/")] 8 | fn hello() -> &'static str { 9 | "Hello, world!" 10 | } 11 | 12 | fn main() { 13 | rocket::ignite().mount("/", routes![hello]).launch(); 14 | } 15 | -------------------------------------------------------------------------------- /examples/tls/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | 4 | #[test] 5 | fn hello_world() { 6 | let rocket = rocket::ignite().mount("/", routes![super::hello]); 7 | let client = Client::new(rocket).unwrap(); 8 | let mut response = client.get("/").dispatch(); 9 | assert_eq!(response.body_string(), Some("Hello, world!".into())); 10 | } 11 | -------------------------------------------------------------------------------- /examples/todo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "todo" 3 | version = "0.0.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | serde = "1.0" 10 | serde_json = "1.0" 11 | serde_derive = "1.0" 12 | diesel = { version = "1.3", features = ["sqlite", "r2d2"] } 13 | diesel_migrations = "1.3" 14 | log = "0.4" 15 | 16 | [dev-dependencies] 17 | parking_lot = { version = "0.6", features = ["nightly"] } 18 | rand = "0.6" 19 | 20 | [dependencies.rocket_contrib] 21 | path = "../../contrib/lib" 22 | default_features = false 23 | features = ["tera_templates", "diesel_sqlite_pool", "serve"] 24 | -------------------------------------------------------------------------------- /examples/todo/README.md: -------------------------------------------------------------------------------- 1 | # Rocket Todo Example 2 | 3 | This example makes use of a SQLite database via `diesel` to store todo tasks. As 4 | a result, you'll need to have `sqlite3` and its headers installed: 5 | 6 | * **OS X:** `brew install sqlite` 7 | * **Debian/Ubuntu:** `apt-get install libsqlite3-dev` 8 | * **Arch:** `pacman -S sqlite` 9 | -------------------------------------------------------------------------------- /examples/todo/Rocket.toml: -------------------------------------------------------------------------------- 1 | [global] 2 | template_dir = "static" 3 | 4 | [global.databases.sqlite_database] 5 | url = "db/db.sqlite" 6 | -------------------------------------------------------------------------------- /examples/todo/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | SCRIPT_PATH=$(cd "$(dirname "$0")" ; pwd -P) 4 | DATABASE_URL="${SCRIPT_PATH}/db/db.sqlite" 5 | 6 | rm -f "${DATABASE_URL}" 7 | -------------------------------------------------------------------------------- /examples/todo/db/DB_LIVES_HERE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackblitz/template-rust-rocket/master/examples/todo/db/DB_LIVES_HERE -------------------------------------------------------------------------------- /examples/todo/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackblitz/template-rust-rocket/master/examples/todo/migrations/.gitkeep -------------------------------------------------------------------------------- /examples/todo/migrations/20160720150332_create_tasks_table/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE tasks 2 | -------------------------------------------------------------------------------- /examples/todo/migrations/20160720150332_create_tasks_table/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE tasks ( 2 | id INTEGER PRIMARY KEY AUTOINCREMENT, 3 | description VARCHAR NOT NULL, 4 | completed BOOLEAN NOT NULL DEFAULT 0 5 | ); 6 | 7 | INSERT INTO tasks (description) VALUES ("demo task"); 8 | INSERT INTO tasks (description) VALUES ("demo task2"); 9 | -------------------------------------------------------------------------------- /examples/todo/src/task.rs: -------------------------------------------------------------------------------- 1 | use diesel::{self, prelude::*}; 2 | 3 | mod schema { 4 | table! { 5 | tasks { 6 | id -> Nullable, 7 | description -> Text, 8 | completed -> Bool, 9 | } 10 | } 11 | } 12 | 13 | use self::schema::tasks; 14 | use self::schema::tasks::dsl::{tasks as all_tasks, completed as task_completed}; 15 | 16 | #[table_name="tasks"] 17 | #[derive(Serialize, Queryable, Insertable, Debug, Clone)] 18 | pub struct Task { 19 | pub id: Option, 20 | pub description: String, 21 | pub completed: bool 22 | } 23 | 24 | #[derive(FromForm)] 25 | pub struct Todo { 26 | pub description: String, 27 | } 28 | 29 | impl Task { 30 | pub fn all(conn: &SqliteConnection) -> Vec { 31 | all_tasks.order(tasks::id.desc()).load::(conn).unwrap() 32 | } 33 | 34 | pub fn insert(todo: Todo, conn: &SqliteConnection) -> bool { 35 | let t = Task { id: None, description: todo.description, completed: false }; 36 | diesel::insert_into(tasks::table).values(&t).execute(conn).is_ok() 37 | } 38 | 39 | pub fn toggle_with_id(id: i32, conn: &SqliteConnection) -> bool { 40 | let task = all_tasks.find(id).get_result::(conn); 41 | if task.is_err() { 42 | return false; 43 | } 44 | 45 | let new_status = !task.unwrap().completed; 46 | let updated_task = diesel::update(all_tasks.find(id)); 47 | updated_task.set(task_completed.eq(new_status)).execute(conn).is_ok() 48 | } 49 | 50 | pub fn delete_with_id(id: i32, conn: &SqliteConnection) -> bool { 51 | diesel::delete(all_tasks.find(id)).execute(conn).is_ok() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/todo/static/css/style.css: -------------------------------------------------------------------------------- 1 | .field-error { 2 | border: 1px solid #ff0000 !important; 3 | } 4 | 5 | .field-error-msg { 6 | color: #ff0000; 7 | display: block; 8 | margin: -10px 0 10px 0; 9 | } 10 | 11 | .field-success { 12 | border: 1px solid #5AB953 !important; 13 | } 14 | 15 | .field-success-msg { 16 | color: #5AB953; 17 | display: block; 18 | margin: -10px 0 10px 0; 19 | } 20 | 21 | span.completed { 22 | text-decoration: line-through; 23 | } 24 | 25 | form.inline { 26 | display: inline; 27 | } 28 | 29 | form.link, 30 | button.link { 31 | display: inline; 32 | color: #1EAEDB; 33 | border: none; 34 | outline: none; 35 | background: none; 36 | cursor: pointer; 37 | padding: 0; 38 | margin: 0 0 0 0; 39 | height: inherit; 40 | text-decoration: underline; 41 | font-size: inherit; 42 | text-transform: none; 43 | font-weight: normal; 44 | line-height: inherit; 45 | letter-spacing: inherit; 46 | } 47 | 48 | form.link:hover, button.link:hover { 49 | color: #0FA0CE; 50 | } 51 | 52 | button.small { 53 | height: 20px; 54 | padding: 0 10px; 55 | font-size: 10px; 56 | line-height: 20px; 57 | margin: 0 2.5px; 58 | } 59 | -------------------------------------------------------------------------------- /examples/todo/static/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackblitz/template-rust-rocket/master/examples/todo/static/images/favicon.png -------------------------------------------------------------------------------- /examples/uuid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uuid" 3 | version = "0.1.0" 4 | workspace = "../../" 5 | publish = false 6 | 7 | [dependencies] 8 | rocket = { path = "../../core/lib" } 9 | lazy_static = "1.0" 10 | uuid = "0.7" 11 | 12 | [dependencies.rocket_contrib] 13 | default-features = false 14 | path = "../../contrib/lib" 15 | features = ["uuid"] 16 | -------------------------------------------------------------------------------- /examples/uuid/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] extern crate rocket; 4 | #[macro_use] extern crate lazy_static; 5 | extern crate rocket_contrib; 6 | extern crate uuid; 7 | 8 | use std::collections::HashMap; 9 | use rocket_contrib::uuid::Uuid; 10 | 11 | #[cfg(test)] mod tests; 12 | 13 | lazy_static! { 14 | // A small people lookup table for the sake of this example. In a real 15 | // application this could be a database lookup. Notice that we use the 16 | // uuid::Uuid type here and not the rocket_contrib::uuid::Uuid type. 17 | static ref PEOPLE: HashMap = { 18 | let mut m = HashMap::new(); 19 | let lacy_id = uuid::Uuid::parse_str("7f205202-7ba1-4c39-b2fc-3e630722bf9f").unwrap(); 20 | let bob_id = uuid::Uuid::parse_str("4da34121-bc7d-4fc1-aee6-bf8de0795333").unwrap(); 21 | let george_id = uuid::Uuid::parse_str("ad962969-4e3d-4de7-ac4a-2d86d6d10839").unwrap(); 22 | m.insert(lacy_id, "Lacy"); 23 | m.insert(bob_id, "Bob"); 24 | m.insert(george_id, "George"); 25 | m 26 | }; 27 | } 28 | 29 | #[get("/people/")] 30 | fn people(id: Uuid) -> Result { 31 | // Because Uuid implements the Deref trait, we use Deref coercion to convert 32 | // rocket_contrib::uuid::Uuid to uuid::Uuid. 33 | Ok(PEOPLE.get(&id) 34 | .map(|person| format!("We found: {}", person)) 35 | .ok_or_else(|| format!("Person not found for UUID: {}", id))?) 36 | } 37 | 38 | fn rocket() -> rocket::Rocket { 39 | rocket::ignite().mount("/", routes![people]) 40 | } 41 | 42 | fn main() { 43 | rocket().launch(); 44 | } 45 | -------------------------------------------------------------------------------- /examples/uuid/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::Client; 3 | use rocket::http::Status; 4 | 5 | fn test(uri: &str, expected: &str) { 6 | let client = Client::new(rocket()).unwrap(); 7 | let mut res = client.get(uri).dispatch(); 8 | assert_eq!(res.body_string(), Some(expected.into())); 9 | } 10 | 11 | fn test_404(uri: &str) { 12 | let client = Client::new(rocket()).unwrap(); 13 | let res = client.get(uri).dispatch(); 14 | assert_eq!(res.status(), Status::NotFound); 15 | } 16 | 17 | #[test] 18 | fn test_people() { 19 | test("/people/7f205202-7ba1-4c39-b2fc-3e630722bf9f", "We found: Lacy"); 20 | test("/people/4da34121-bc7d-4fc1-aee6-bf8de0795333", "We found: Bob"); 21 | test("/people/ad962969-4e3d-4de7-ac4a-2d86d6d10839", "We found: George"); 22 | test("/people/e18b3a5c-488f-4159-a240-2101e0da19fd", 23 | "Person not found for UUID: e18b3a5c-488f-4159-a240-2101e0da19fd"); 24 | test_404("/people/invalid_uuid"); 25 | } 26 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackblitz/template-rust-rocket/master/logo.png -------------------------------------------------------------------------------- /scripts/bump_version.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # 4 | # Bumps the version number from to on all libraries. 5 | # 6 | 7 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 8 | source "${SCRIPT_DIR}/config.sh" 9 | 10 | if [ -z "${1}" ] || [ -z "${2}" ]; then 11 | echo "Usage: $0 " 12 | echo "Example: $0 0.1.1 0.1.2" 13 | exit 1 14 | fi 15 | 16 | if ! git grep -c "${1}" > /dev/null; then 17 | echo "The version '${1}' doesn't appear to be correct." 18 | echo "Exiting." 19 | exit 1 20 | fi 21 | 22 | function major() { 23 | echo "${1}" | cut -d'.' -f1-2 24 | } 25 | 26 | function do_replace() { 27 | find "${PROJECT_ROOT}" -name "*.rs" | xargs sed -i.bak "s/${1}/${2}/g" 28 | find "${PROJECT_ROOT}" -name "*.toml" | xargs sed -i.bak "s/${1}/${2}/g" 29 | find "${SITE_ROOT}" -name "*.md" | xargs sed -i.bak "s/${1}/${2}/g" 30 | sed -i.bak "s/${1}/${2}/g" "${SCRIPT_DIR}/config.sh" 31 | sed -i.bak "s/${1}/${2}/g" "${PROJECT_ROOT}/README.md" 32 | } 33 | 34 | do_replace "v$(major ${1})" "v$(major ${2})" 35 | do_replace "${1}" "${2}" 36 | 37 | today=$(date "+%b %d, %Y") 38 | sed -i.bak "s/^date.*/date = \"$today\"/" "${SITE_ROOT}/index.toml" 39 | 40 | find ${PROJECT_ROOT} -name "*.bak" | xargs rm 41 | -------------------------------------------------------------------------------- /scripts/mk-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # 5 | # Builds the rustdocs for all of the libraries. 6 | # 7 | 8 | # Brings in: PROJECT_ROOT, EXAMPLES_DIR, LIB_DIR, CODEGEN_DIR, CONTRIB_DIR, DOC_DIR 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 10 | source "${SCRIPT_DIR}/config.sh" 11 | 12 | if [ "${1}" != "-d" ]; then 13 | # We need to clean-up beforehand so we don't get all of the dependencies. 14 | echo ":::: Cleaning up before documenting..." 15 | cargo clean 16 | cargo update 17 | fi 18 | 19 | # Generate the rustdocs for all of the crates. 20 | echo ":::: Generating the docs..." 21 | pushd "${PROJECT_ROOT}" > /dev/null 2>&1 22 | RUSTDOCFLAGS="-Z unstable-options --crate-version ${ROCKET_VERSION}" \ 23 | cargo doc -p rocket -p rocket_contrib -p rocket_codegen --no-deps --all-features 24 | popd > /dev/null 2>&1 25 | 26 | # Blank index, for redirection. 27 | touch "${DOC_DIR}/index.html" 28 | -------------------------------------------------------------------------------- /scripts/publish.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | set -e 3 | 4 | # 5 | # Publishes the current versions of all Rocket crates to crates.io. 6 | # 7 | 8 | # Brings in _ROOT, _DIR, _DIRS globals. 9 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 10 | source "${SCRIPT_DIR}/config.sh" 11 | 12 | function strip_dev_dependencies() { 13 | perl -i.bak -p0e 's/\[dev-dependencies\].*//smg' "${1}/Cargo.toml" 14 | } 15 | 16 | function restore_dev_dependencies() { 17 | mv "${1}/Cargo.toml.bak" "${1}/Cargo.toml" 18 | } 19 | 20 | if ! [ -z "$(git status --porcelain)" ]; then 21 | echo "There are uncommited changes! Aborting." 22 | exit 1 23 | fi 24 | 25 | # Ensure everything passes before trying to publish. 26 | echo ":::: Running test suite..." 27 | cargo clean 28 | bash "${SCRIPT_DIR}/test.sh" 29 | bash "${SCRIPT_DIR}/test.sh" --contrib 30 | bash "${SCRIPT_DIR}/test.sh" --release 31 | 32 | # Temporarily remove dev-dependencies so crates.io verifies. 33 | echo ":::: Stripping [dev-dependencies]..." 34 | for dir in "${ALL_PROJECT_DIRS[@]}"; do 35 | strip_dev_dependencies "${dir}" 36 | done 37 | 38 | # Publish all the things. 39 | for dir in "${ALL_PROJECT_DIRS[@]}"; do 40 | pushd "${dir}" 41 | echo ":::: Publishing '${dir}'..." 42 | # We already checked things ourselves. Don't spend time reverifying. 43 | cargo publish --no-verify --allow-dirty ${@:1} 44 | popd 45 | done 46 | 47 | # Restore dev-dependencies. 48 | echo ":::: Restoring [dev-dependencies]..." 49 | for dir in "${ALL_PROJECT_DIRS[@]}"; do 50 | restore_dev_dependencies "${dir}" 51 | done 52 | -------------------------------------------------------------------------------- /site/README.md: -------------------------------------------------------------------------------- 1 | # Rocket Website Source 2 | 3 | This directory contains the source files for the content on [Rocket's 4 | website](https://rocket.rs). 5 | 6 | ## Contents 7 | 8 | This directory contains the following: 9 | 10 | * `index.toml` - Source data for the index. 11 | * `overview.toml` - Source data for the overview page (`overview/`). 12 | * `news/index.toml` - Source data for the news page (`news/`). 13 | * `news/*.md` - News articles linked to from `news/index.toml`. 14 | * `guide/*.md` - Guide pages linked to from `guide.md`. 15 | 16 | [Rocket Programming Guide]: https://rocket.rs/v0.4/guide/ 17 | 18 | ### Guide Links 19 | 20 | Cross-linking guide pages is accomplished via relative links. Outside of the 21 | index, this is: `../{page}#anchor`. For instance, to link to the **Quickstart > 22 | Running Examples** page, use `../quickstart#running-examples`. 23 | 24 | ### Aliases 25 | 26 | Aliases are shorthand URLs that start with `@` (e.g, `@api`). They are used 27 | throughout the guide to simplify versioning URLs to Rocket's source code and the 28 | Rocket API. They are replaced at build time with a URL prefix. At present, the 29 | following aliases are available, where `${version}` is Rocket's version string 30 | at the time of compilation: 31 | 32 | * `@example`: https://github.com/SergioBenitez/Rocket/tree/${version}/examples 33 | * `@github`: https://github.com/SergioBenitez/Rocket/tree/${version} 34 | * `@api`: https://api.rocket.rs/${version} 35 | 36 | For example, to link to `Rocket::launch()`, you might write: 37 | 38 | ```md 39 | Launch an instance of your application using the [`launch()`] method. 40 | 41 | [`launch()`]: @api/rocket/struct.Rocket.html#method.launch 42 | ``` 43 | 44 | ## License 45 | 46 | The Rocket website source is licensed under the [GNU General Public License v3.0](LICENSE). 47 | -------------------------------------------------------------------------------- /site/guide/1-quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | Before you can start writing a Rocket application, you'll need a **nightly** 4 | version of Rust installed. We recommend you use [rustup](https://rustup.rs/) to 5 | install or configure such a version. If you don't have Rust installed and would 6 | like extra guidance doing so, see the [getting started](../getting-started) 7 | section. 8 | 9 | ## Running Examples 10 | 11 | The absolute fastest way to start experimenting with Rocket is to clone the 12 | Rocket repository and run the included examples in the `examples/` directory. 13 | For instance, the following set of commands runs the `hello_world` example: 14 | 15 | ```sh 16 | git clone https://github.com/SergioBenitez/Rocket 17 | cd Rocket 18 | git checkout v0.4.0 19 | cd examples/hello_world 20 | cargo run 21 | ``` 22 | 23 | There are numerous examples in the `examples/` directory. They can all be run 24 | with `cargo run`. 25 | 26 | ! note 27 | 28 | The examples' `Cargo.toml` files will point to the locally cloned `rocket` 29 | libraries. When copying the examples for your own use, you should modify the 30 | `Cargo.toml` files as explained in the [Getting Started] guide. 31 | 32 | [Getting Started]: ../getting-started 33 | -------------------------------------------------------------------------------- /site/guide/11-conclusion.md: -------------------------------------------------------------------------------- 1 | # Conclusion 2 | 3 | We hope you agree that Rocket is a refreshing take on web frameworks. As with 4 | any software project, Rocket is _alive_. There are always things to improve, and 5 | we're happy to take the best ideas. If you have something in mind, please 6 | [submit an issue](https://github.com/SergioBenitez/Rocket/issues). 7 | 8 | ## Getting Help 9 | 10 | If you find yourself having trouble developing Rocket applications, you can get 11 | help via the `#rocket` IRC channel on the [Mozilla IRC 12 | Server](https://wiki.mozilla.org/IRC) at `irc.mozilla.org` and the bridged 13 | [Rocket room on Matrix](https://riot.im/app/#/room/#mozilla_#rocket:matrix.org). 14 | If you're not familiar with IRC, we recommend chatting through [Matrix via 15 | Riot](https://riot.im/app/#/room/#mozilla_#rocket:matrix.org) or via the [Kiwi 16 | web IRC client](https://kiwiirc.com/client/irc.mozilla.org/#rocket). You can 17 | learn more about IRC via Mozilla's [Getting Started with 18 | IRC](https://developer.mozilla.org/en-US/docs/Mozilla/QA/Getting_Started_with_IRC) 19 | guide. 20 | 21 | ## What's next? 22 | 23 | The best way to learn Rocket is to _build something_. It should be fun and easy, 24 | and there's always someone to help. Alternatively, you can read through the 25 | [Rocket examples](@example) or the [Rocket source code](@github/lib/src). 26 | Whatever you decide to do next, we hope you have a blast! 27 | -------------------------------------------------------------------------------- /site/guide/index.md: -------------------------------------------------------------------------------- 1 | # The Rocket Programming Guide 2 | 3 | Welcome to Rocket! 4 | 5 | This is the official guide for Rocket v0.4. It is designed to serve as a 6 | starting point to writing web applications with Rocket and Rust. The guide is 7 | also designed to be a reference for experienced Rocket developers. This guide is 8 | conversational in tone. For purely technical documentation with examples, see 9 | the [API documentation](@api). 10 | 11 | The guide is split into several sections, each with a focus on a different 12 | aspect of Rocket. The sections are: 13 | 14 | - **[Introduction](introduction/):** introduces Rocket and its philosophy. 15 | - **[Quickstart](quickstart/):** presents the minimal steps necessary to 16 | run your first Rocket application. 17 | - **[Getting Started](getting-started/):** a gentle introduction to getting 18 | your first Rocket application running. 19 | - **[Overview](overview/):** describes the core concepts of Rocket. 20 | - **[Requests](requests/):** discusses handling requests: control-flow, 21 | parsing, and validating. 22 | - **[Responses](responses/):** discusses generating responses. 23 | - **[State](state/):** how to manage state in a Rocket application. 24 | - **[Fairings](fairings/):** provides an overview of Rocket's structured 25 | middleware. 26 | - **[Testing](testing/):** how to unit and integration test a Rocket 27 | application. 28 | - **[Configuration](configuration/):** how to configure a Rocket application. 29 | - **[Pastebin](pastebin/):** a tutorial on how to create a pastebin with 30 | Rocket. 31 | - **[Conclusion](conclusion/):** concludes the guide and discusses next steps 32 | for learning. 33 | 34 | ## Getting Help 35 | 36 | The official community support channels are the `#rocket` IRC channel on the 37 | [Mozilla IRC Server](https://wiki.mozilla.org/IRC) at `irc.mozilla.org` and the 38 | bridged [Rocket room on 39 | Matrix](https://riot.im/app/#/room/#mozilla_#rocket:matrix.org). If you're not 40 | familiar with IRC, we recommend chatting through [Matrix via 41 | Riot](https://riot.im/app/#/room/#mozilla_#rocket:matrix.org) or via the [Kiwi 42 | web IRC client](https://kiwiirc.com/client/irc.mozilla.org/#rocket). You can 43 | learn more about IRC via Mozilla's [Getting Started with 44 | IRC](https://developer.mozilla.org/en-US/docs/Mozilla/QA/Getting_Started_with_IRC) 45 | guide. 46 | -------------------------------------------------------------------------------- /site/news/2018-10-31-version-0.4-rc.md: -------------------------------------------------------------------------------- 1 | # Rocket v0.4 Release Candidate 2 | 3 | 6 | 7 | I am delighted to announce that a release candidate for Rocket v0.4 is available 8 | today! This release brings over a year of features, improvements, and 9 | refinements, resolving some of the most called for requests and bringing Rocket 10 | measurably closer to stable compatibility. 11 | 12 | The release candidate is an opportunity to discover issues with Rocket v0.4 and 13 | its documentation before its general release. We encourage all users to migrate 14 | their applications to the release candidate and report any issues to the [GitHub 15 | issue tracker]. 16 | 17 | Barring any major issues, the general release of Rocket v0.4 is planned for 18 | Friday, November 9th, when we'll post a full news article covering the biggest 19 | features and changes in Rocket v0.4. Until then, the [CHANGELOG] contains every 20 | feature addition, change, and improvement since v0.3, as well as information on 21 | migrating your applications to v0.4. All documentation, including the [guide] 22 | and [API docs], has been updated in full for v0.4. 23 | 24 | We're excited for your feedback, and we look forward to seeing you again on 25 | Friday, November 9th for the general release! 26 | 27 | [GitHub issue tracker]: https://github.com/SergioBenitez/Rocket/issues 28 | [API docs]: https://api.rocket.rs/v0.4/rocket/ 29 | [guide]: ../../guide 30 | [CHANGELOG]: https://github.com/SergioBenitez/Rocket/tree/v0.4/CHANGELOG.md#version-040-rc-oct-31-2018 31 | 32 | ## About Rocket 33 | 34 | Rocket is a web framework for Rust with a focus on ease of use, expressibility, 35 | and speed. Rocket makes it simple to write fast web applications without 36 | sacrificing flexibility or type safety. All with minimal code. 37 | 38 | Not already using Rocket? Join the tens of thousands of users and hundreds of 39 | companies happily using Rocket today! Rocket's extensive documentation makes it 40 | easy. Get started now by [reading through the guide](../../guide) or learning 41 | more from [the overview](../../overview). 42 | -------------------------------------------------------------------------------- /site/news/2018-11-30-version-0.4-rc-2.md: -------------------------------------------------------------------------------- 1 | # Rocket's 2nd v0.4 Release Candidate 2 | 3 | 6 | 7 | After a successful and productive initial v0.4 release candidate, I am happy to 8 | announce that the second release candidate for Rocket v0.4 is now available. 9 | 10 | This release candidate fixes issues identified during the first release 11 | candidate, introduces further features, and leverages upstream `rustc` 12 | contributions for improved diagnostics and stability. As before, this is an 13 | opportunity to discover issues with Rocket v0.4 and its documentation before its 14 | general release. We encourage all users to migrate their applications to the 15 | second release candidate and report any issues to the [GitHub issue tracker]. 16 | To update to `v0.4.0`, manually update `rocket` in your `Cargo.toml` file: 17 | 18 | ```toml 19 | [dependencies] 20 | rocket = "0.4.0" 21 | ``` 22 | 23 | Barring any major issues, of which none are expected, the general release of 24 | Rocket v0.4 is planned for Wednesday, December 5th, when we'll post a full news 25 | article covering the biggest features and changes in Rocket v0.4. Until then, 26 | the [CHANGELOG] contains every feature addition, change, and improvement since 27 | v0.4.0-rc.1 and v0.3, as well as information on migrating your applications to 28 | v0.4. All documentation, including the [guide] and [API docs], has been updated 29 | in full for the second release candidate. 30 | 31 | We're excited for your feedback, and we look forward to seeing you again on 32 | Wednesday, December 5th for the general release! 33 | 34 | [GitHub issue tracker]: https://github.com/SergioBenitez/Rocket/issues 35 | [API docs]: https://api.rocket.rs/v0.4/rocket/ 36 | [guide]: ../../guide 37 | [CHANGELOG]: https://github.com/SergioBenitez/Rocket/tree/v0.4/CHANGELOG.md#version-040-rc2-nov-30-2018 38 | 39 | ## About Rocket 40 | 41 | Rocket is a web framework for Rust with a focus on ease of use, expressibility, 42 | and speed. Rocket makes it simple to write fast web applications without 43 | sacrificing flexibility or type safety. All with minimal code. 44 | 45 | Not already using Rocket? Join the tens of thousands of users and hundreds of 46 | companies happily using Rocket today! Rocket's extensive documentation makes it 47 | easy. Get started now by [reading through the guide](../../guide) or learning 48 | more from [the overview](../../overview). 49 | --------------------------------------------------------------------------------