├── .gitattributes ├── .github ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ ├── doc-problem.yml │ ├── feature-request.yml │ └── suggestion.yml └── workflows │ ├── ci.yml │ └── trigger.yaml ├── .gitignore ├── .rustfmt.toml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benchmarks ├── Cargo.toml ├── src │ ├── bench.rs │ └── routing.rs └── static │ ├── bitwarden_rs.routes │ └── rust-lang.routes ├── contrib ├── db_pools │ ├── README.md │ ├── codegen │ │ ├── Cargo.toml │ │ ├── LICENSE-APACHE │ │ ├── LICENSE-MIT │ │ ├── src │ │ │ ├── database.rs │ │ │ └── lib.rs │ │ └── tests │ │ │ ├── ui-fail-nightly │ │ │ ├── database-syntax.rs │ │ │ ├── database-syntax.stderr │ │ │ ├── database-types.rs │ │ │ └── database-types.stderr │ │ │ ├── ui-fail-stable │ │ │ ├── database-syntax.rs │ │ │ ├── database-syntax.stderr │ │ │ ├── database-types.rs │ │ │ └── database-types.stderr │ │ │ ├── ui-fail.rs │ │ │ └── ui-fail │ │ │ ├── database-syntax.rs │ │ │ └── database-types.rs │ └── lib │ │ ├── Cargo.toml │ │ ├── LICENSE-APACHE │ │ ├── LICENSE-MIT │ │ ├── src │ │ ├── config.rs │ │ ├── database.rs │ │ ├── diesel.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ └── pool.rs │ │ └── tests │ │ └── databases.rs ├── dyn_templates │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── src │ │ ├── context.rs │ │ ├── engine │ │ │ ├── handlebars.rs │ │ │ ├── minijinja.rs │ │ │ ├── mod.rs │ │ │ └── tera.rs │ │ ├── fairing.rs │ │ ├── lib.rs │ │ ├── metadata.rs │ │ └── template.rs │ └── tests │ │ ├── templates.rs │ │ └── templates │ │ ├── hbs │ │ ├── common │ │ │ ├── footer.html.hbs │ │ │ └── header.html.hbs │ │ ├── reload.txt.hbs │ │ └── test.html.hbs │ │ ├── j2 │ │ ├── [test] │ │ │ └── html_test.html.j2 │ │ ├── base.txt.j2 │ │ ├── html_test.html.j2 │ │ └── txt_test.txt.j2 │ │ └── tera │ │ ├── [test] │ │ └── html_test.html.tera │ │ ├── base.txt.tera │ │ ├── html_test.html.tera │ │ └── txt_test.txt.tera ├── sync_db_pools │ ├── README.md │ ├── codegen │ │ ├── Cargo.toml │ │ ├── LICENSE-APACHE │ │ ├── LICENSE-MIT │ │ ├── src │ │ │ ├── database.rs │ │ │ └── lib.rs │ │ └── tests │ │ │ ├── ui-fail-nightly │ │ │ ├── database-syntax.rs │ │ │ ├── database-syntax.stderr │ │ │ ├── database-types.rs │ │ │ └── database-types.stderr │ │ │ ├── ui-fail-stable │ │ │ ├── database-syntax.rs │ │ │ ├── database-syntax.stderr │ │ │ ├── database-types.rs │ │ │ └── database-types.stderr │ │ │ ├── ui-fail.rs │ │ │ └── ui-fail │ │ │ ├── database-syntax.rs │ │ │ └── database-types.rs │ └── lib │ │ ├── Cargo.toml │ │ ├── LICENSE-APACHE │ │ ├── LICENSE-MIT │ │ ├── build.rs │ │ ├── src │ │ ├── config.rs │ │ ├── connection.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ └── poolable.rs │ │ └── tests │ │ ├── databases.rs │ │ ├── drop-with-connection.rs │ │ └── shutdown.rs └── ws │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ └── src │ ├── duplex.rs │ ├── lib.rs │ └── websocket.rs ├── core ├── codegen │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── src │ │ ├── attribute │ │ │ ├── async_bound │ │ │ │ └── mod.rs │ │ │ ├── catch │ │ │ │ ├── mod.rs │ │ │ │ └── parse.rs │ │ │ ├── entry │ │ │ │ ├── launch.rs │ │ │ │ ├── main.rs │ │ │ │ ├── mod.rs │ │ │ │ └── test.rs │ │ │ ├── mod.rs │ │ │ ├── param │ │ │ │ ├── guard.rs │ │ │ │ ├── mod.rs │ │ │ │ └── parse.rs │ │ │ ├── route │ │ │ │ ├── mod.rs │ │ │ │ └── parse.rs │ │ │ └── suppress │ │ │ │ ├── lint.rs │ │ │ │ └── mod.rs │ │ ├── bang │ │ │ ├── export.rs │ │ │ ├── mod.rs │ │ │ ├── test_guide.rs │ │ │ ├── typed_stream.rs │ │ │ ├── uri.rs │ │ │ └── uri_parsing.rs │ │ ├── derive │ │ │ ├── form_field.rs │ │ │ ├── from_form.rs │ │ │ ├── from_form_field.rs │ │ │ ├── from_param.rs │ │ │ ├── mod.rs │ │ │ ├── responder.rs │ │ │ └── uri_display.rs │ │ ├── exports.rs │ │ ├── http_codegen.rs │ │ ├── lib.rs │ │ ├── name.rs │ │ ├── proc_macro_ext.rs │ │ └── syn_ext.rs │ └── tests │ │ ├── async-entry.rs │ │ ├── async-routes.rs │ │ ├── catcher.rs │ │ ├── expansion.rs │ │ ├── from_form.rs │ │ ├── from_form_field.rs │ │ ├── from_param.rs │ │ ├── responder.rs │ │ ├── route-data.rs │ │ ├── route-format.rs │ │ ├── route-ranking.rs │ │ ├── route-raw.rs │ │ ├── route-uniqueness.rs │ │ ├── route.rs │ │ ├── segment-ignore.rs │ │ ├── typed-uris.rs │ │ ├── ui-fail-nightly │ │ ├── async-entry.rs │ │ ├── async-entry.stderr │ │ ├── bad-ignored-segments.rs │ │ ├── bad-ignored-segments.stderr │ │ ├── catch.rs │ │ ├── catch.stderr │ │ ├── catch_type_errors.rs │ │ ├── catch_type_errors.stderr │ │ ├── catchers.rs │ │ ├── catchers.stderr │ │ ├── from_form.rs │ │ ├── from_form.stderr │ │ ├── from_form_field.rs │ │ ├── from_form_field.stderr │ │ ├── from_form_type_errors.rs │ │ ├── from_form_type_errors.stderr │ │ ├── from_param.rs │ │ ├── from_param.stderr │ │ ├── responder-types.rs │ │ ├── responder-types.stderr │ │ ├── responder.rs │ │ ├── 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 │ │ ├── uri_display.rs │ │ ├── uri_display.stderr │ │ ├── uri_display_type_errors.rs │ │ └── uri_display_type_errors.stderr │ │ ├── ui-fail-stable │ │ ├── async-entry.rs │ │ ├── async-entry.stderr │ │ ├── bad-ignored-segments.rs │ │ ├── bad-ignored-segments.stderr │ │ ├── catch.rs │ │ ├── catch.stderr │ │ ├── catch_type_errors.rs │ │ ├── catch_type_errors.stderr │ │ ├── catchers.rs │ │ ├── catchers.stderr │ │ ├── from_form.rs │ │ ├── from_form.stderr │ │ ├── from_form_field.rs │ │ ├── from_form_field.stderr │ │ ├── from_form_type_errors.rs │ │ ├── from_form_type_errors.stderr │ │ ├── from_param.rs │ │ ├── from_param.stderr │ │ ├── responder-types.rs │ │ ├── responder-types.stderr │ │ ├── responder.rs │ │ ├── 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 │ │ ├── uri_display.rs │ │ ├── uri_display.stderr │ │ ├── uri_display_type_errors.rs │ │ └── uri_display_type_errors.stderr │ │ ├── ui-fail.rs │ │ ├── ui-fail │ │ ├── async-entry.rs │ │ ├── bad-ignored-segments.rs │ │ ├── catch.rs │ │ ├── catch_type_errors.rs │ │ ├── catchers.rs │ │ ├── from_form.rs │ │ ├── from_form_field.rs │ │ ├── from_form_type_errors.rs │ │ ├── from_param.rs │ │ ├── responder-types.rs │ │ ├── responder.rs │ │ ├── route-attribute-general-syntax.rs │ │ ├── route-path-bad-syntax.rs │ │ ├── route-type-errors.rs │ │ ├── route-warnings.rs │ │ ├── routes.rs │ │ ├── synchronize.sh │ │ ├── typed-uri-bad-type.rs │ │ ├── typed-uris-bad-params.rs │ │ ├── typed-uris-invalid-syntax.rs │ │ ├── uri_display.rs │ │ └── uri_display_type_errors.rs │ │ └── uri_display.rs ├── http │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── ext.rs │ │ ├── header │ │ ├── accept.rs │ │ ├── content_type.rs │ │ ├── header.rs │ │ ├── known_media_types.rs │ │ ├── media_type.rs │ │ ├── mod.rs │ │ └── proxy_proto.rs │ │ ├── lib.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 │ │ ├── status.rs │ │ └── uri │ │ ├── absolute.rs │ │ ├── asterisk.rs │ │ ├── authority.rs │ │ ├── error.rs │ │ ├── fmt │ │ ├── encoding.rs │ │ ├── formatter.rs │ │ ├── from_uri_param.rs │ │ ├── mod.rs │ │ ├── part.rs │ │ └── uri_display.rs │ │ ├── host.rs │ │ ├── mod.rs │ │ ├── origin.rs │ │ ├── path_query.rs │ │ ├── reference.rs │ │ ├── segments.rs │ │ └── uri.rs └── lib │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── build.rs │ ├── fuzz │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── corpus │ │ ├── collision-matching │ │ │ ├── another.seed │ │ │ ├── base.seed │ │ │ ├── complex.seed │ │ │ └── large.seed │ │ └── uri-parsing │ │ │ ├── absolute.seed │ │ │ ├── asterisk.seed │ │ │ ├── authority.seed │ │ │ ├── origin.seed │ │ │ └── reference.seed │ └── targets │ │ ├── collision-matching.rs │ │ ├── uri-normalization.rs │ │ ├── uri-parsing.rs │ │ └── uri-roundtrip.rs │ ├── src │ ├── catcher │ │ ├── catcher.rs │ │ ├── handler.rs │ │ └── mod.rs │ ├── config │ │ ├── cli_colors.rs │ │ ├── config.rs │ │ ├── http_header.rs │ │ ├── ident.rs │ │ ├── mod.rs │ │ ├── secret_key.rs │ │ └── tests.rs │ ├── data │ │ ├── capped.rs │ │ ├── data.rs │ │ ├── data_stream.rs │ │ ├── from_data.rs │ │ ├── io_stream.rs │ │ ├── limits.rs │ │ ├── mod.rs │ │ ├── peekable.rs │ │ └── transform.rs │ ├── erased.rs │ ├── error.rs │ ├── fairing │ │ ├── ad_hoc.rs │ │ ├── fairings.rs │ │ ├── info_kind.rs │ │ └── mod.rs │ ├── form │ │ ├── buffer.rs │ │ ├── context.rs │ │ ├── error.rs │ │ ├── field.rs │ │ ├── form.rs │ │ ├── from_form.rs │ │ ├── from_form_field.rs │ │ ├── lenient.rs │ │ ├── mod.rs │ │ ├── name │ │ │ ├── buf.rs │ │ │ ├── key.rs │ │ │ ├── mod.rs │ │ │ ├── name.rs │ │ │ └── view.rs │ │ ├── options.rs │ │ ├── parser.rs │ │ ├── strict.rs │ │ ├── tests.rs │ │ └── validate.rs │ ├── fs │ │ ├── file_name.rs │ │ ├── mod.rs │ │ ├── named_file.rs │ │ ├── rewrite.rs │ │ ├── server.rs │ │ └── temp_file.rs │ ├── http │ │ ├── cookies.rs │ │ └── mod.rs │ ├── lib.rs │ ├── lifecycle.rs │ ├── listener │ │ ├── bind.rs │ │ ├── bounced.rs │ │ ├── cancellable.rs │ │ ├── connection.rs │ │ ├── default.rs │ │ ├── endpoint.rs │ │ ├── listener.rs │ │ ├── mod.rs │ │ ├── quic.rs │ │ ├── tcp.rs │ │ └── unix.rs │ ├── local │ │ ├── asynchronous │ │ │ ├── client.rs │ │ │ ├── mod.rs │ │ │ ├── request.rs │ │ │ └── response.rs │ │ ├── blocking │ │ │ ├── client.rs │ │ │ ├── mod.rs │ │ │ ├── request.rs │ │ │ └── response.rs │ │ ├── client.rs │ │ ├── mod.rs │ │ ├── request.rs │ │ └── response.rs │ ├── mtls │ │ ├── certificate.rs │ │ ├── config.rs │ │ ├── error.rs │ │ ├── mod.rs │ │ └── name.rs │ ├── outcome.rs │ ├── phase.rs │ ├── request │ │ ├── atomic_method.rs │ │ ├── from_param.rs │ │ ├── from_request.rs │ │ ├── mod.rs │ │ ├── request.rs │ │ └── tests.rs │ ├── response │ │ ├── body.rs │ │ ├── content.rs │ │ ├── debug.rs │ │ ├── flash.rs │ │ ├── mod.rs │ │ ├── redirect.rs │ │ ├── responder.rs │ │ ├── response.rs │ │ ├── status.rs │ │ └── stream │ │ │ ├── bytes.rs │ │ │ ├── mod.rs │ │ │ ├── one.rs │ │ │ ├── raw_sse.rs │ │ │ ├── reader.rs │ │ │ ├── sse.rs │ │ │ └── text.rs │ ├── rocket.rs │ ├── route │ │ ├── handler.rs │ │ ├── mod.rs │ │ ├── route.rs │ │ ├── segment.rs │ │ └── uri.rs │ ├── router │ │ ├── collider.rs │ │ ├── matcher.rs │ │ ├── mod.rs │ │ └── router.rs │ ├── sentinel.rs │ ├── serde │ │ ├── json.rs │ │ ├── mod.rs │ │ ├── msgpack.rs │ │ └── uuid.rs │ ├── server.rs │ ├── shield │ │ ├── mod.rs │ │ ├── policy.rs │ │ └── shield.rs │ ├── shutdown │ │ ├── config.rs │ │ ├── handle.rs │ │ ├── mod.rs │ │ ├── sig.rs │ │ └── tripwire.rs │ ├── state.rs │ ├── tls │ │ ├── config.rs │ │ ├── error.rs │ │ ├── listener.rs │ │ ├── mod.rs │ │ └── resolver.rs │ ├── trace │ │ ├── level.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── subscriber │ │ │ ├── common.rs │ │ │ ├── compact.rs │ │ │ ├── dynamic.rs │ │ │ ├── mod.rs │ │ │ ├── pretty.rs │ │ │ ├── request_id.rs │ │ │ └── visit.rs │ │ └── traceable.rs │ └── util │ │ ├── chain.rs │ │ ├── join.rs │ │ ├── mod.rs │ │ ├── reader_stream.rs │ │ └── unix.rs │ └── tests │ ├── absolute-uris-okay-issue-443.rs │ ├── adhoc-uri-normalizer.rs │ ├── byte-slices-form-field-issue-2148.rs │ ├── can-correct-bad-local-uri.rs │ ├── can-launch-tls.rs │ ├── catcher-cookies-1213.rs │ ├── conditionally-set-server-header-996.rs │ ├── config-proxy-proto-header.rs │ ├── config-real-ip-header.rs │ ├── config-secret-key-1500.rs │ ├── content-length.rs │ ├── cookies-private.rs │ ├── derive-reexports.rs │ ├── deserialize-limits-issue-2268.rs │ ├── encoded-uris.rs │ ├── fairing_before_head_strip-issue-546.rs │ ├── file_server.rs │ ├── flash-lazy-removes-issue-466.rs │ ├── form-validation-names.rs │ ├── form_method-issue-45.rs │ ├── form_value_decoding-issue-82.rs │ ├── form_value_from_encoded_str-issue-1425.rs │ ├── forward-includes-status-1560.rs │ ├── head_handling.rs │ ├── http_serde.rs │ ├── launch-inspect.rs │ ├── limits.rs │ ├── local-client-access-runtime-in-drop.rs │ ├── local-client-json.rs │ ├── local-request-content-type-issue-505.rs │ ├── local_request_private_cookie-issue-368.rs │ ├── many-cookie-jars-at-once.rs │ ├── mapped-base-issue-1262.rs │ ├── mount_point.rs │ ├── msgpack_encoding.rs │ ├── multipart-limit.rs │ ├── nested-fairing-attaches.rs │ ├── on_launch_fairing_can_inspect_port.rs │ ├── panic-handling.rs │ ├── precise-content-type-matching.rs │ ├── raw-strings-multipart-files-1987.rs │ ├── recursive-singleton-fairing.rs │ ├── redirect_from_catcher-issue-113.rs │ ├── replace-content-type-518.rs │ ├── responder_lifetime-issue-345.rs │ ├── route_guard.rs │ ├── scoped-uri.rs │ ├── segments-issues-41-86.rs │ ├── sentinel.rs │ ├── session-cookies-issue-1506.rs │ ├── shield.rs │ ├── shutdown-fairings.rs │ ├── static │ ├── .hidden │ ├── index.html │ ├── inner │ │ ├── .hideme │ │ ├── goodbye │ │ └── index.html │ └── other │ │ ├── hello.txt │ │ └── index.htm │ ├── strict_and_lenient_forms.rs │ ├── timer-on-attach.rs │ ├── tls-config-from-source-1503.rs │ ├── twice_managed_state.rs │ ├── typed-uri-docs-redef-issue-1373.rs │ ├── unsound-local-request-1312.rs │ ├── untracked-vs-tracked.rs │ └── uri-percent-encoding-issue-808.rs ├── docs ├── LICENSE ├── guide │ ├── 00-introduction.md │ ├── 01-upgrading.md │ ├── 02-quickstart.md │ ├── 03-getting-started.md │ ├── 04-overview.md │ ├── 05-requests.md │ ├── 06-responses.md │ ├── 07-state.md │ ├── 08-fairings.md │ ├── 09-testing.md │ ├── 10-configuration.md │ ├── 11-deploying.md │ ├── 12-pastebin.md │ ├── 13-conclusion.md │ ├── 14-faq.md │ └── index.md └── tests │ ├── Cargo.toml │ └── src │ ├── guide.rs │ ├── lib.rs │ └── readme.rs ├── examples ├── Cargo.toml ├── README.md ├── chat │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── static │ │ ├── index.html │ │ ├── reset.css │ │ ├── script.js │ │ └── style.css ├── config │ ├── Cargo.toml │ ├── Rocket.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── cookies │ ├── Cargo.toml │ ├── Rocket.toml │ ├── src │ │ ├── main.rs │ │ ├── message.rs │ │ ├── session.rs │ │ └── tests.rs │ └── templates │ │ ├── login.html.hbs │ │ ├── message.html.hbs │ │ └── session.html.hbs ├── databases │ ├── .sqlx │ │ ├── query-11e3096becb72f427c8d3911ef4327afd9516143806981e11f8e34d069c14472.json │ │ ├── query-4415c35941e52a981b10707fe2e1ceb0bad0e473701e51ef21ecb2973c76b4df.json │ │ ├── query-668690acaca0a0c0b4ac306b14d82aa1bee940f0776fae3f9962639b78328858.json │ │ ├── query-79301b44b77802e0096efd73b1e9adac27b27a3cf7bf853af3a9f130b1684d91.json │ │ └── query-bea4ef6e25064f6b383e854f8bc2770d89cfaf9859d0bfca78b2ca24627675b7.json │ ├── Cargo.toml │ ├── README.md │ ├── Rocket.toml │ ├── db │ │ ├── diesel │ │ │ ├── migrations │ │ │ │ ├── .gitkeep │ │ │ │ └── 20210329150332_create_posts_table │ │ │ │ │ ├── down.sql │ │ │ │ │ └── up.sql │ │ │ └── mysql-migrations │ │ │ │ └── 20210329150332_create_posts_table │ │ │ │ ├── down.sql │ │ │ │ └── up.sql │ │ └── sqlx │ │ │ └── migrations │ │ │ └── 20210331024424_create-posts-table.sql │ └── src │ │ ├── diesel_mysql.rs │ │ ├── diesel_sqlite.rs │ │ ├── main.rs │ │ ├── rusqlite.rs │ │ ├── sqlx.rs │ │ └── tests.rs ├── error-handling │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── fairings │ ├── Cargo.toml │ ├── Rocket.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── forms │ ├── Cargo.toml │ ├── Rocket.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ ├── static │ │ └── chota.min.css │ └── templates │ │ ├── index.html.tera │ │ ├── macros.html.tera │ │ └── success.html.tera ├── hello │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── manual-routing │ ├── Cargo.toml │ ├── Rocket.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── pastebin │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ ├── paste_id.rs │ │ └── tests.rs │ └── upload │ │ └── UPLOADS_GO_HERE ├── responders │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── tests.rs ├── serialization │ ├── Cargo.toml │ └── src │ │ ├── json.rs │ │ ├── main.rs │ │ ├── msgpack.rs │ │ ├── tests.rs │ │ └── uuid.rs ├── state │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── managed_hit_count.rs │ │ ├── managed_queue.rs │ │ ├── request_local.rs │ │ └── tests.rs ├── static-files │ ├── Cargo.toml │ ├── src │ │ ├── main.rs │ │ └── tests.rs │ └── static │ │ ├── hidden │ │ ├── hi.txt │ │ └── index.html │ │ ├── index.html │ │ └── rocket-icon.jpg ├── templating │ ├── Cargo.toml │ ├── Rocket.toml │ ├── src │ │ ├── hbs.rs │ │ ├── main.rs │ │ ├── minijinja.rs │ │ ├── tera.rs │ │ └── tests.rs │ └── templates │ │ ├── hbs │ │ ├── error │ │ │ └── 404.html.hbs │ │ ├── footer.html.hbs │ │ ├── index.html.hbs │ │ ├── layout.html.hbs │ │ └── nav.html.hbs │ │ ├── minijinja │ │ ├── error │ │ │ └── 404.html.j2 │ │ ├── footer.html.j2 │ │ ├── index.html.j2 │ │ ├── layout.html.j2 │ │ └── nav.html.j2 │ │ └── tera │ │ ├── base.html.tera │ │ ├── error │ │ └── 404.html.tera │ │ ├── index.html.tera │ │ └── nav.html.tera ├── testing │ ├── Cargo.toml │ └── src │ │ ├── async_required.rs │ │ └── main.rs ├── tls │ ├── Cargo.toml │ ├── Rocket.toml │ ├── private │ │ ├── ca_cert.pem │ │ ├── ca_key.pem │ │ ├── client.pem │ │ ├── ecdsa_nistp256_sha256.p12 │ │ ├── ecdsa_nistp256_sha256_cert.pem │ │ ├── ecdsa_nistp256_sha256_key_pkcs8.pem │ │ ├── ecdsa_nistp256_sha256_key_sec1.pem │ │ ├── ecdsa_nistp384_sha384.p12 │ │ ├── ecdsa_nistp384_sha384_cert.pem │ │ ├── ecdsa_nistp384_sha384_key_pkcs8.pem │ │ ├── ecdsa_nistp384_sha384_key_sec1.pem │ │ ├── ecdsa_nistp521_sha512.p12 │ │ ├── ecdsa_nistp521_sha512_cert.pem │ │ ├── ecdsa_nistp521_sha512_key_pkcs8.pem │ │ ├── ed25519.p12 │ │ ├── ed25519_cert.pem │ │ ├── ed25519_key.pem │ │ ├── gen_certs.sh │ │ ├── rsa_sha256.p12 │ │ ├── rsa_sha256_cert.pem │ │ └── rsa_sha256_key.pem │ └── src │ │ ├── main.rs │ │ ├── redirector.rs │ │ └── tests.rs ├── todo │ ├── Cargo.toml │ ├── README.md │ ├── Rocket.toml │ ├── 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 └── upgrade │ ├── Cargo.toml │ ├── src │ └── main.rs │ └── static │ └── index.html ├── scripts ├── config.sh ├── mk-docs.sh ├── publish.sh └── test.sh └── testbench ├── Cargo.toml └── src ├── client.rs ├── config.rs ├── lib.rs ├── main.rs ├── runner.rs ├── server.rs └── servers ├── bind.rs ├── http_extensions.rs ├── ignite_failure.rs ├── infinite_stream.rs ├── mod.rs ├── mtls.rs ├── no_content.rs ├── sni_resolver.rs ├── tls.rs ├── tls_resolver.rs └── tracing.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | 3 | # Denote all files that are truly binary and should not be modified. 4 | *.png binary 5 | *.jpg binary 6 | *.gif binary 7 | *.svg binary 8 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: rwf2 2 | open_collective: rwf2 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: FAQ 4 | url: https://rocket.rs/guide/faq/ 5 | about: Please see our FAQ for answers to common questions. 6 | - name: Questions 7 | url: https://github.com/rwf2/Rocket/discussions/new?category=questions 8 | about: For other questions or help, please use GitHub discussions. 9 | - name: Feedback 10 | url: https://github.com/rwf2/Rocket/discussions/new/choose 11 | about: For general chat or feedback, please use GitHub discussions. 12 | - name: Chat 13 | url: https://chat.mozilla.org/#/room/#rocket:mozilla.org 14 | about: Chat with us live on rocket:mozilla.org on Matrix. 15 | -------------------------------------------------------------------------------- /.github/workflows/trigger.yaml: -------------------------------------------------------------------------------- 1 | name: Trigger 2 | on: [push] 3 | jobs: 4 | trigger: 5 | name: api.rocket.rs 6 | runs-on: ubuntu-latest 7 | if: github.repository == 'rwf2/Rocket' 8 | steps: 9 | - uses: actions/github-script@v7 10 | with: 11 | github-token: ${{ secrets.API_DOCS_DEPLOY_TOKEN }} 12 | script: | 13 | github.rest.actions.createWorkflowDispatch({ 14 | owner: 'rwf2', 15 | repo: 'api.rocket.rs', 16 | workflow_id: 'deploy.yaml', 17 | ref: 'master' 18 | }) 19 | -------------------------------------------------------------------------------- /.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 | db.sqlite-shm 16 | db.sqlite-wal 17 | 18 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 19 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 20 | Cargo.lock 21 | 22 | # Cargo config directory 23 | .cargo/ 24 | 25 | # The upload script, for now. 26 | scripts/upload-docs.sh 27 | scripts/redirect.html 28 | 29 | # Backup files. 30 | *.bak 31 | 32 | # Uploads in pastebin example. 33 | examples/pastebin/upload/* 34 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | disable_all_formatting = true 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "core/lib/", 5 | "core/codegen/", 6 | "core/http/", 7 | "contrib/db_pools/codegen/", 8 | "contrib/db_pools/lib/", 9 | "contrib/sync_db_pools/codegen/", 10 | "contrib/sync_db_pools/lib/", 11 | "contrib/dyn_templates/", 12 | "contrib/ws/", 13 | "docs/tests", 14 | ] 15 | 16 | [workspace.lints.rust] 17 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(nightly)'] } 18 | rust_2018_idioms = "warn" 19 | async_fn_in_trait = "allow" 20 | refining_impl_trait = "allow" 21 | # unreachable_pub = "warn" 22 | # single_use_lifetimes = "warn" 23 | # missing_docs = "warn" 24 | 25 | [workspace.lints.clippy] 26 | type_complexity = "allow" 27 | module_inception = "allow" 28 | multiple_bound_locations = "allow" 29 | manual_range_contains = "allow" 30 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 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 | -------------------------------------------------------------------------------- /benchmarks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket-benchmarks" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [workspace] 8 | 9 | [[bench]] 10 | name = "main" 11 | path = "src/bench.rs" 12 | harness = false 13 | 14 | [dev-dependencies] 15 | rocket = { path = "../core/lib/" } 16 | criterion = "0.5.1" 17 | -------------------------------------------------------------------------------- /benchmarks/src/bench.rs: -------------------------------------------------------------------------------- 1 | mod routing; 2 | 3 | criterion::criterion_main!(routing::routing); 4 | -------------------------------------------------------------------------------- /benchmarks/static/rust-lang.routes: -------------------------------------------------------------------------------- 1 | GET / (index) 2 | GET / (category) 3 | GET /governance (governance) 4 | GET /governance/
/ [2] (team) 5 | GET /production/users (production) 6 | GET /sponsors (sponsors) 7 | GET // [4] (subject) 8 | GET /static/ (files) 9 | GET /robots.txt (robots_txt) 10 | GET /logos/ (logos) 11 | GET /components/<_file..> (components) 12 | GET / [3] (index_locale) 13 | GET // [11] (category_locale) 14 | GET //governance [10] (governance_locale) 15 | GET //governance/
/ [12] (team_locale) 16 | GET //production/users [10] (production_locale) 17 | GET //sponsors [10] (sponsors_locale) 18 | GET /// [14] (subject_locale) 19 | GET //components/<_file..> [12] (components_locale) 20 | GET / [19] (redirect) 21 | GET /pdfs/ (redirect_pdfs) 22 | GET /en-US (redirect_bare_en_us) 23 | GET /<_locale> [20] (redirect_bare_locale) 24 | GET /en-US/ (redirect_en_us) 25 | GET /<_locale>/ [20] (redirect_locale) 26 | -------------------------------------------------------------------------------- /contrib/db_pools/codegen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_db_pools_codegen" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez ", "Jeb Rosen "] 5 | description = "Procedural macros for rocket_db_pools." 6 | repository = "https://github.com/rwf2/Rocket/tree/master/contrib/db_pools" 7 | readme = "../README.md" 8 | keywords = ["rocket", "framework", "database", "pools"] 9 | license = "MIT OR Apache-2.0" 10 | edition = "2021" 11 | rust-version = "1.75" 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [lints] 17 | workspace = true 18 | 19 | [dependencies] 20 | devise = "0.4" 21 | quote = "1" 22 | 23 | [dev-dependencies] 24 | rocket = { path = "../../../core/lib", default-features = false } 25 | rocket_db_pools = { path = "../lib", features = ["deadpool_postgres"] } 26 | trybuild = "1.0" 27 | version_check = "0.9" 28 | -------------------------------------------------------------------------------- /contrib/db_pools/codegen/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-APACHE -------------------------------------------------------------------------------- /contrib/db_pools/codegen/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-MIT -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail-nightly/database-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-syntax.rs -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail-nightly/database-types.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-types.rs -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail-nightly/database-types.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `Unknown: Pool` is not satisfied 2 | --> tests/ui-fail-nightly/database-types.rs:7:10 3 | | 4 | 7 | struct A(Unknown); 5 | | ^^^^^^^ the trait `Pool` is not implemented for `Unknown` 6 | | 7 | = help: the trait `Pool` is implemented for `deadpool::managed::Pool` 8 | note: required by a bound in `rocket_db_pools::Database::Pool` 9 | --> $WORKSPACE/contrib/db_pools/lib/src/database.rs 10 | | 11 | | type Pool: Pool; 12 | | ^^^^ required by this bound in `Database::Pool` 13 | 14 | error[E0277]: the trait bound `Vec: Pool` is not satisfied 15 | --> tests/ui-fail-nightly/database-types.rs:11:10 16 | | 17 | 11 | struct B(Vec); 18 | | ^^^^^^^^ the trait `Pool` is not implemented for `Vec` 19 | | 20 | = help: the trait `Pool` is implemented for `deadpool::managed::Pool` 21 | note: required by a bound in `rocket_db_pools::Database::Pool` 22 | --> $WORKSPACE/contrib/db_pools/lib/src/database.rs 23 | | 24 | | type Pool: Pool; 25 | | ^^^^ required by this bound in `Database::Pool` 26 | -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail-stable/database-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-syntax.rs -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail-stable/database-types.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-types.rs -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail-stable/database-types.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `Unknown: Pool` is not satisfied 2 | --> tests/ui-fail-stable/database-types.rs:7:10 3 | | 4 | 7 | struct A(Unknown); 5 | | ^^^^^^^ the trait `Pool` is not implemented for `Unknown` 6 | | 7 | = help: the trait `Pool` is implemented for `deadpool::managed::Pool` 8 | note: required by a bound in `rocket_db_pools::Database::Pool` 9 | --> $WORKSPACE/contrib/db_pools/lib/src/database.rs 10 | | 11 | | type Pool: Pool; 12 | | ^^^^ required by this bound in `Database::Pool` 13 | 14 | error[E0277]: the trait bound `Vec: Pool` is not satisfied 15 | --> tests/ui-fail-stable/database-types.rs:11:10 16 | | 17 | 11 | struct B(Vec); 18 | | ^^^^^^^^ the trait `Pool` is not implemented for `Vec` 19 | | 20 | = help: the trait `Pool` is implemented for `deadpool::managed::Pool` 21 | note: required by a bound in `rocket_db_pools::Database::Pool` 22 | --> $WORKSPACE/contrib/db_pools/lib/src/database.rs 23 | | 24 | | type Pool: Pool; 25 | | ^^^^ required by this bound in `Database::Pool` 26 | -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | #[ignore] 3 | fn ui() { 4 | let path = match version_check::is_feature_flaggable() { 5 | Some(true) => "ui-fail-nightly", 6 | _ => "ui-fail-stable" 7 | }; 8 | 9 | let t = trybuild::TestCases::new(); 10 | t.compile_fail(format!("tests/{}/*.rs", path)); 11 | } 12 | -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail/database-syntax.rs: -------------------------------------------------------------------------------- 1 | use rocket_db_pools::{deadpool_postgres, Database}; 2 | 3 | #[derive(Database)] 4 | #[database(123)] 5 | struct A(deadpool_postgres::Pool); 6 | 7 | #[derive(Database)] 8 | #[database("some-name", "another")] 9 | struct B(deadpool_postgres::Pool); 10 | 11 | #[derive(Database)] 12 | #[database("some-name", name = "another")] 13 | struct C(deadpool_postgres::Pool); 14 | 15 | #[derive(Database)] 16 | #[database("foo")] 17 | enum D { } 18 | 19 | #[derive(Database)] 20 | struct E(deadpool_postgres::Pool); 21 | 22 | #[derive(Database)] 23 | #[database("foo")] 24 | struct F; 25 | 26 | #[derive(Database)] 27 | #[database("foo")] 28 | struct G(deadpool_postgres::Pool, deadpool_postgres::Pool); 29 | 30 | #[derive(Database)] 31 | #[database("foo")] 32 | struct H { 33 | foo: deadpool_postgres::Pool, 34 | } 35 | 36 | fn main() { } 37 | -------------------------------------------------------------------------------- /contrib/db_pools/codegen/tests/ui-fail/database-types.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket_db_pools; 2 | 3 | struct Unknown; 4 | 5 | #[derive(Database)] 6 | #[database("foo")] 7 | struct A(Unknown); 8 | 9 | #[derive(Database)] 10 | #[database("bar")] 11 | struct B(Vec); 12 | 13 | fn main() { } 14 | -------------------------------------------------------------------------------- /contrib/db_pools/lib/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-APACHE -------------------------------------------------------------------------------- /contrib/db_pools/lib/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-MIT -------------------------------------------------------------------------------- /contrib/db_pools/lib/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | /// A general error type for use by [`Pool`](crate::Pool#implementing) 4 | /// implementors and returned by the [`Connection`](crate::Connection) request 5 | /// guard. 6 | #[derive(Debug)] 7 | pub enum Error { 8 | /// An error that occurred during database/pool initialization. 9 | Init(A), 10 | 11 | /// An error that occurred while retrieving a connection from the pool. 12 | Get(B), 13 | 14 | /// A [`Figment`](crate::figment::Figment) configuration error. 15 | Config(crate::figment::Error), 16 | } 17 | 18 | impl fmt::Display for Error { 19 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 | match self { 21 | Error::Init(e) => write!(f, "failed to initialize database: {}", e), 22 | Error::Get(e) => write!(f, "failed to get db connection: {}", e), 23 | Error::Config(e) => write!(f, "bad configuration: {}", e), 24 | } 25 | } 26 | } 27 | 28 | impl std::error::Error for Error 29 | where A: fmt::Debug + fmt::Display, B: fmt::Debug + fmt::Display {} 30 | 31 | impl From for Error { 32 | fn from(e: crate::figment::Error) -> Self { 33 | Self::Config(e) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contrib/db_pools/lib/tests/databases.rs: -------------------------------------------------------------------------------- 1 | macro_rules! check_types_match { 2 | ($feature:expr, $name:ident, $Pool:ty, $Conn:ty $(,)?) => ( 3 | #[cfg(feature = $feature)] 4 | mod $name { 5 | use rocket::*; 6 | use rocket_db_pools::{Connection, Database}; 7 | 8 | #[derive(Database)] 9 | #[database("foo")] 10 | struct Db($Pool); 11 | 12 | #[get("/")] 13 | fn _db(conn: Connection) { 14 | let _: &$Conn = &*conn; 15 | } 16 | } 17 | ) 18 | } 19 | 20 | check_types_match!( 21 | "deadpool_postgres", 22 | deadpool_postgres, 23 | deadpool_postgres::Pool, 24 | deadpool_postgres::ClientWrapper, 25 | ); 26 | 27 | check_types_match!( 28 | "deadpool_redis", 29 | deadpool_redis, 30 | deadpool_redis::Pool, 31 | deadpool_redis::Connection, 32 | ); 33 | 34 | check_types_match!( 35 | "sqlx_postgres", 36 | sqlx_postgres, 37 | sqlx::PgPool, 38 | sqlx::pool::PoolConnection, 39 | ); 40 | 41 | check_types_match!( 42 | "sqlx_mysql", 43 | sqlx_mysql, 44 | sqlx::MySqlPool, 45 | sqlx::pool::PoolConnection, 46 | ); 47 | 48 | check_types_match!( 49 | "sqlx_sqlite", 50 | sqlx_sqlite, 51 | sqlx::SqlitePool, 52 | sqlx::pool::PoolConnection, 53 | ); 54 | 55 | check_types_match!( 56 | "mongodb", 57 | mongodb, 58 | mongodb::Client, 59 | mongodb::Client, 60 | ); 61 | -------------------------------------------------------------------------------- /contrib/dyn_templates/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_dyn_templates" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | description = "Dynamic templating engine integration for Rocket." 6 | documentation = "https://api.rocket.rs/master/rocket_dyn_templates/" 7 | homepage = "https://rocket.rs" 8 | repository = "https://github.com/rwf2/Rocket/tree/master/contrib/dyn_templates" 9 | readme = "README.md" 10 | keywords = ["rocket", "framework", "templates", "templating", "engine"] 11 | license = "MIT OR Apache-2.0" 12 | edition = "2021" 13 | rust-version = "1.75" 14 | 15 | [lints] 16 | workspace = true 17 | 18 | [features] 19 | tera = ["dep:tera"] 20 | handlebars = ["dep:handlebars"] 21 | minijinja = ["dep:minijinja"] 22 | 23 | [dependencies] 24 | walkdir = "2.4" 25 | notify = "7" 26 | normpath = "1" 27 | 28 | tera = { version = "1.19.0", optional = true } 29 | handlebars = { version = "6.0", optional = true } 30 | 31 | [dependencies.minijinja] 32 | version = "2.0.1" 33 | optional = true 34 | features = ["loader", "speedups", "json", "urlencode"] 35 | 36 | [dependencies.rocket] 37 | version = "0.6.0-dev" 38 | path = "../../core/lib" 39 | default-features = false 40 | 41 | [dev-dependencies] 42 | pretty_assertions = "1.4" 43 | 44 | [package.metadata.docs.rs] 45 | all-features = true 46 | -------------------------------------------------------------------------------- /contrib/dyn_templates/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../LICENSE-APACHE -------------------------------------------------------------------------------- /contrib/dyn_templates/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../LICENSE-MIT -------------------------------------------------------------------------------- /contrib/dyn_templates/src/engine/handlebars.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | use handlebars::Handlebars; 4 | use rocket::serde::Serialize; 5 | 6 | use crate::engine::Engine; 7 | 8 | impl Engine for Handlebars<'static> { 9 | const EXT: &'static str = "hbs"; 10 | 11 | fn init<'a>(templates: impl Iterator) -> Option { 12 | let mut hb = Handlebars::new(); 13 | let mut ok = true; 14 | for (template, path) in templates { 15 | if let Err(e) = hb.register_template_file(template, path) { 16 | error!(template, path = %path.display(), 17 | "failed to register Handlebars template: {e}"); 18 | 19 | ok = false; 20 | } 21 | } 22 | 23 | ok.then_some(hb) 24 | } 25 | 26 | fn render(&self, template: &str, context: C) -> Option { 27 | if self.get_template(template).is_none() { 28 | error!(template, "requested Handlebars template does not exist."); 29 | return None; 30 | } 31 | 32 | Handlebars::render(self, template, &context) 33 | .map_err(|e| error!("Handlebars render error: {}", e)) 34 | .ok() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/hbs/common/footer.html.hbs: -------------------------------------------------------------------------------- 1 | Done. 2 | -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/hbs/common/header.html.hbs: -------------------------------------------------------------------------------- 1 | Hello {{ title }}! 2 | -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/hbs/reload.txt.hbs: -------------------------------------------------------------------------------- 1 | initial -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/hbs/test.html.hbs: -------------------------------------------------------------------------------- 1 | {{> hbs/common/header }} 2 |
{{ content }}
3 | {{> hbs/common/footer }} 4 | -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/j2/[test]/html_test.html.j2: -------------------------------------------------------------------------------- 1 | {% extends "j2/base" %} 2 | {% block title %}{{ title }}{% endblock title %} 3 | {% block content %} 4 | {{ content }} 5 | {% endblock content %} 6 | -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/j2/base.txt.j2: -------------------------------------------------------------------------------- 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/dyn_templates/tests/templates/j2/html_test.html.j2: -------------------------------------------------------------------------------- 1 | {% extends "j2/base" %} 2 | {% block title %}{{ title }}{% endblock title %} 3 | {% block content %} 4 | {{ content }} 5 | {% endblock content %} 6 | -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/j2/txt_test.txt.j2: -------------------------------------------------------------------------------- 1 | {% extends "j2/base" %} 2 | {% block title %}{{ title }}{% endblock title %} 3 | {% block content %} 4 | {{ content }} 5 | {% endblock content %} 6 | -------------------------------------------------------------------------------- /contrib/dyn_templates/tests/templates/tera/[test]/html_test.html.tera: -------------------------------------------------------------------------------- 1 | {% extends "tera/base" %} 2 | {% block title %}{{ title }}{% endblock title %} 3 | {% block content %} 4 | {{ content }} 5 | {% endblock content %} 6 | -------------------------------------------------------------------------------- /contrib/dyn_templates/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/dyn_templates/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/dyn_templates/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 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_sync_db_pools_codegen" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | description = "Procedural macros for rocket_sync_db_pools." 6 | repository = "https://github.com/rwf2/Rocket/tree/master/contrib/sync_db_pools" 7 | readme = "../README.md" 8 | keywords = ["rocket", "framework", "database", "pools"] 9 | license = "MIT OR Apache-2.0" 10 | edition = "2021" 11 | rust-version = "1.75" 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [lints] 17 | workspace = true 18 | 19 | [dependencies] 20 | quote = "1.0" 21 | devise = "0.4" 22 | 23 | [dev-dependencies] 24 | version_check = "0.9" 25 | trybuild = "1.0" 26 | rocket_sync_db_pools = { path = "../lib" } 27 | rocket = { path = "../../../core/lib" } 28 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-APACHE -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-MIT -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-syntax.rs -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-types.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-types.rs -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-syntax.rs -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-types.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/database-types.rs -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/tests/ui-fail.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | #[ignore] 3 | fn ui() { 4 | let path = match version_check::is_feature_flaggable() { 5 | Some(true) => "ui-fail-nightly", 6 | _ => "ui-fail-stable" 7 | }; 8 | 9 | let t = trybuild::TestCases::new(); 10 | t.compile_fail(format!("tests/{}/*.rs", path)); 11 | } 12 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/tests/ui-fail/database-syntax.rs: -------------------------------------------------------------------------------- 1 | use rocket_sync_db_pools::database; 2 | 3 | struct Connection; 4 | struct Manager; 5 | 6 | use rocket::{Rocket, Build}; 7 | use rocket_sync_db_pools::{r2d2, Poolable, PoolResult}; 8 | 9 | impl r2d2::ManageConnection for Manager { 10 | type Connection = Connection; 11 | type Error = std::convert::Infallible; 12 | 13 | fn connect(&self) -> Result { Ok(Connection) } 14 | fn is_valid(&self, _: &mut Self::Connection) -> Result<(), Self::Error> { Ok(()) } 15 | fn has_broken(&self, _: &mut Self::Connection) -> bool { true } 16 | } 17 | 18 | impl Poolable for Connection { 19 | type Manager = Manager; 20 | type Error = std::convert::Infallible; 21 | 22 | fn pool(_: &str, _: &Rocket) -> PoolResult { 23 | todo!() 24 | } 25 | } 26 | 27 | #[database] 28 | struct A(Connection); 29 | 30 | #[database(1)] 31 | struct B(Connection); 32 | 33 | #[database(123)] 34 | struct C(Connection); 35 | 36 | #[database("hello" "hi")] 37 | struct D(Connection); 38 | 39 | #[database("test")] 40 | enum Foo { } 41 | 42 | #[database("test")] 43 | struct Bar(Connection, Connection); 44 | 45 | #[database("test")] 46 | union Baz { } 47 | 48 | #[database("test")] 49 | struct E<'r>(&'r str); 50 | 51 | #[database("test")] 52 | struct F(T); 53 | 54 | fn main() { } 55 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/codegen/tests/ui-fail/database-types.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket_sync_db_pools; 2 | 3 | struct Unknown; 4 | 5 | #[database("foo")] 6 | struct A(Unknown); 7 | 8 | #[database("foo")] 9 | struct B(Vec); 10 | 11 | fn main() { } 12 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/lib/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-APACHE -------------------------------------------------------------------------------- /contrib/sync_db_pools/lib/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../../LICENSE-MIT -------------------------------------------------------------------------------- /contrib/sync_db_pools/lib/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Some(true) = version_check::is_feature_flaggable() { 3 | println!("cargo:rustc-cfg=nightly"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/lib/src/error.rs: -------------------------------------------------------------------------------- 1 | use rocket::figment; 2 | 3 | /// A wrapper around `r2d2::Error`s or a custom database error type. 4 | /// 5 | /// This type is only relevant to implementors of the [`Poolable`] trait. See 6 | /// the [`Poolable`] documentation for more information on how to use this type. 7 | /// 8 | /// [`Poolable`]: crate::Poolable 9 | #[derive(Debug)] 10 | pub enum Error { 11 | /// A custom error of type `T`. 12 | Custom(T), 13 | /// An error occurred while initializing an `r2d2` pool. 14 | Pool(r2d2::Error), 15 | /// An error occurred while extracting a `figment` configuration. 16 | Config(figment::Error), 17 | } 18 | 19 | impl From for Error { 20 | fn from(error: figment::Error) -> Self { 21 | Error::Config(error) 22 | } 23 | } 24 | 25 | impl From for Error { 26 | fn from(error: r2d2::Error) -> Self { 27 | Error::Pool(error) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/lib/tests/drop-with-connection.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "diesel_sqlite_pool")] 2 | 3 | use rocket::figment::Figment; 4 | use rocket_sync_db_pools::database; 5 | 6 | #[database("example")] 7 | struct ExampleDb(diesel::SqliteConnection); 8 | 9 | #[test] 10 | fn can_drop_connection_in_sync_context() { 11 | let conn = rocket::execute(async { 12 | let figment = Figment::from(rocket::Config::debug_default()) 13 | .merge(("databases.example.url", ":memory:")); 14 | 15 | let rocket = rocket::custom(figment) 16 | .attach(ExampleDb::fairing()) 17 | .ignite().await 18 | .expect("rocket"); 19 | 20 | ExampleDb::get_one(&rocket).await 21 | .expect("attach => connection") 22 | }); 23 | 24 | drop(conn); 25 | } 26 | -------------------------------------------------------------------------------- /contrib/sync_db_pools/lib/tests/shutdown.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | #[cfg(all(feature = "diesel_sqlite_pool"))] 3 | mod sqlite_shutdown_test { 4 | use rocket::{async_test, Build, Rocket}; 5 | use rocket_sync_db_pools::database; 6 | 7 | #[database("test")] 8 | struct Pool(diesel::SqliteConnection); 9 | 10 | async fn rocket() -> Rocket { 11 | use rocket::figment::{util::map, Figment}; 12 | 13 | let options = map!["url" => ":memory:"]; 14 | let config = Figment::from(rocket::Config::debug_default()) 15 | .merge(("port", 0)) 16 | .merge(("databases", map!["test" => &options])); 17 | 18 | rocket::custom(config).attach(Pool::fairing()) 19 | } 20 | 21 | #[test] 22 | fn test_shutdown() { 23 | let _rocket = async_test( 24 | async { 25 | let rocket = rocket().await.ignite().await.expect("unable to ignite"); 26 | // request shutdown 27 | rocket.shutdown().notify(); 28 | rocket.launch().await.expect("unable to launch") 29 | } 30 | ); 31 | // _rocket is dropped here after the runtime is dropped 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contrib/ws/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_ws" 3 | version = "0.1.0" 4 | authors = ["Sergio Benitez "] 5 | description = "WebSocket support for Rocket." 6 | documentation = "https://api.rocket.rs/master/rocket_ws/" 7 | homepage = "https://rocket.rs" 8 | repository = "https://github.com/rwf2/Rocket/tree/master/contrib/ws" 9 | readme = "README.md" 10 | keywords = ["rocket", "web", "framework", "websocket"] 11 | license = "MIT OR Apache-2.0" 12 | edition = "2021" 13 | rust-version = "1.75" 14 | 15 | [lints] 16 | workspace = true 17 | 18 | [features] 19 | default = ["tungstenite"] 20 | tungstenite = ["tokio-tungstenite"] 21 | 22 | [dependencies] 23 | tokio-tungstenite = { version = "0.24", optional = true } 24 | 25 | [dependencies.rocket] 26 | version = "0.6.0-dev" 27 | path = "../../core/lib" 28 | default-features = false 29 | 30 | [package.metadata.docs.rs] 31 | all-features = true 32 | -------------------------------------------------------------------------------- /contrib/ws/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../LICENSE-APACHE -------------------------------------------------------------------------------- /contrib/ws/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../LICENSE-MIT -------------------------------------------------------------------------------- /contrib/ws/README.md: -------------------------------------------------------------------------------- 1 | # `ws` [![ci.svg]][ci] [![crates.io]][crate] [![docs.svg]][crate docs] 2 | 3 | [crates.io]: https://img.shields.io/crates/v/rocket_ws.svg 4 | [crate]: https://crates.io/crates/rocket_ws 5 | [docs.svg]: https://img.shields.io/badge/web-master-red.svg?style=flat&label=docs&colorB=d33847 6 | [crate docs]: https://api.rocket.rs/master/rocket_ws 7 | [ci.svg]: https://github.com/rwf2/Rocket/workflows/CI/badge.svg 8 | [ci]: https://github.com/rwf2/Rocket/actions 9 | 10 | This crate provides WebSocket support for Rocket via integration with Rocket's 11 | [connection upgrades] API. 12 | 13 | # Usage 14 | 15 | 1. Depend on `rocket_ws`, renamed here to `ws`: 16 | 17 | ```toml 18 | [dependencies] 19 | ws = { package = "rocket_ws", version = "0.1.0" } 20 | ``` 21 | 22 | 2. Use it! 23 | 24 | ```rust 25 | #[get("/echo")] 26 | fn echo_stream(ws: ws::WebSocket) -> ws::Stream!['static] { 27 | ws::Stream! { ws => 28 | for await message in ws { 29 | yield message?; 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | See the [crate docs] for full details. 36 | -------------------------------------------------------------------------------- /core/codegen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_codegen" 3 | version = "0.6.0-dev" 4 | authors = ["Sergio Benitez "] 5 | description = "Procedural macros for the Rocket web framework." 6 | documentation = "https://api.rocket.rs/master/rocket_codegen/" 7 | homepage = "https://rocket.rs" 8 | repository = "https://github.com/rwf2/Rocket" 9 | readme = "../../README.md" 10 | keywords = ["rocket", "web", "framework", "code", "generation"] 11 | license = "MIT OR Apache-2.0" 12 | edition = "2021" 13 | rust-version = "1.75" 14 | 15 | [lints] 16 | workspace = true 17 | 18 | [lib] 19 | proc-macro = true 20 | 21 | [dependencies] 22 | indexmap = "2" 23 | quote = "1.0" 24 | syn = { version = "2.0", features = ["full", "visit", "visit-mut", "extra-traits"] } 25 | proc-macro2 = "1.0.60" 26 | devise = "0.4" 27 | rocket_http = { version = "0.6.0-dev", path = "../http/" } 28 | unicode-xid = "0.2" 29 | version_check = "0.9" 30 | glob = "0.3" 31 | 32 | [dev-dependencies] 33 | rocket = { path = "../lib", features = ["json", "msgpack"] } 34 | time = { version = "0.3", features = ["macros"] } 35 | pretty_assertions = "1" 36 | version_check = "0.9" 37 | trybuild = "1.0" 38 | -------------------------------------------------------------------------------- /core/codegen/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../LICENSE-APACHE -------------------------------------------------------------------------------- /core/codegen/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../LICENSE-MIT -------------------------------------------------------------------------------- /core/codegen/src/attribute/entry/main.rs: -------------------------------------------------------------------------------- 1 | use crate::attribute::suppress::Lint; 2 | 3 | use super::EntryAttr; 4 | 5 | use devise::{Spanned, Result}; 6 | use devise::ext::SpanDiagnosticExt; 7 | use proc_macro2::{TokenStream, Span}; 8 | 9 | /// `#[rocket::async_main]`: calls the attributed fn inside `rocket::async_main` 10 | pub struct Main; 11 | 12 | impl EntryAttr for Main { 13 | const REQUIRES_ASYNC: bool = true; 14 | 15 | fn function(f: &mut syn::ItemFn) -> Result { 16 | let (attrs, vis, block, sig) = (&f.attrs, &f.vis, &f.block, &mut f.sig); 17 | let lint = Lint::ArbitraryMain; 18 | if sig.ident != "main" && lint.enabled(sig.ident.span()) { 19 | Span::call_site() 20 | .warning("attribute is typically applied to `main` function") 21 | .span_note(sig.ident.span(), "this function is not `main`") 22 | .note(lint.how_to_suppress()) 23 | .emit_as_item_tokens(); 24 | } 25 | 26 | sig.asyncness = None; 27 | Ok(quote_spanned!(block.span() => #(#attrs)* #vis #sig { 28 | ::rocket::async_main(async move #block) 29 | })) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/codegen/src/attribute/entry/test.rs: -------------------------------------------------------------------------------- 1 | use super::EntryAttr; 2 | 3 | use devise::{Spanned, Result}; 4 | use proc_macro2::TokenStream; 5 | 6 | /// `#[rocket::async_test]`: calls the attributed fn inside `rocket::async_test` 7 | pub struct Test; 8 | 9 | impl EntryAttr for Test { 10 | const REQUIRES_ASYNC: bool = true; 11 | 12 | fn function(f: &mut syn::ItemFn) -> Result { 13 | let (attrs, vis, block, sig) = (&f.attrs, &f.vis, &f.block, &mut f.sig); 14 | sig.asyncness = None; 15 | Ok(quote_spanned!(block.span() => #(#attrs)* #[test] #vis #sig { 16 | ::rocket::async_test(async move #block) 17 | })) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/codegen/src/attribute/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod entry; 2 | pub mod catch; 3 | pub mod route; 4 | pub mod param; 5 | pub mod async_bound; 6 | pub mod suppress; 7 | -------------------------------------------------------------------------------- /core/codegen/src/attribute/param/guard.rs: -------------------------------------------------------------------------------- 1 | use std::hash::{Hash, Hasher}; 2 | 3 | use devise::{FromMeta, MetaItem, Result}; 4 | use proc_macro2::Span; 5 | 6 | use crate::name::Name; 7 | use crate::proc_macro_ext::StringLit; 8 | use crate::http::uri; 9 | 10 | impl Dynamic { 11 | pub fn is_wild(&self) -> bool { 12 | self.value == "_" 13 | } 14 | } 15 | 16 | impl FromMeta for Dynamic { 17 | fn from_meta(meta: &MetaItem) -> Result { 18 | let string = StringLit::from_meta(meta)?; 19 | let span = string.subspan(1..string.len() + 1); 20 | 21 | // We don't allow `_`. We abuse `fmt::Query` to enforce this. 22 | Ok(Dynamic::parse::(&string, span)?) 23 | } 24 | } 25 | 26 | impl PartialEq for Dynamic { 27 | fn eq(&self, other: &Dynamic) -> bool { 28 | self.value == other.value 29 | } 30 | } 31 | 32 | impl Eq for Dynamic {} 33 | 34 | impl Hash for Dynamic { 35 | fn hash(&self, state: &mut H) { 36 | self.value.hash(state) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/codegen/src/attribute/suppress/mod.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use devise::Spanned; 3 | 4 | mod lint; 5 | 6 | pub use lint::Lint; 7 | 8 | pub fn suppress_attribute( 9 | args: proc_macro::TokenStream, 10 | input: proc_macro::TokenStream 11 | ) -> TokenStream { 12 | let input: TokenStream = input.into(); 13 | match Lint::suppress_tokens(args.into(), input.span()) { 14 | Ok(_) => input, 15 | Err(e) => { 16 | let error: TokenStream = e.to_compile_error().into(); 17 | quote!(#error #input) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/codegen/src/derive/from_param.rs: -------------------------------------------------------------------------------- 1 | use devise::*; 2 | use devise::ext::SpanDiagnosticExt; 3 | 4 | use quote::quote; 5 | use proc_macro2::TokenStream; 6 | use syn::ext::IdentExt; 7 | 8 | use crate::exports::*; 9 | 10 | pub fn derive_from_param(input: proc_macro::TokenStream) -> TokenStream { 11 | DeriveGenerator::build_for(input, quote!(impl<'a> #_request::FromParam<'a>)) 12 | .support(Support::Enum) 13 | .validator(ValidatorBuild::new().fields_validate(|_, fields| { 14 | if !fields.is_empty() { 15 | return Err(fields.span().error("variants with data fields are not supported")); 16 | } 17 | 18 | Ok(()) 19 | })) 20 | .inner_mapper(MapperBuild::new().enum_map(|_, data| { 21 | let matches = data.variants().map(|field| { 22 | let field_name = field.ident.unraw(); 23 | quote!(stringify!(#field_name) => Ok(Self::#field)) 24 | }); 25 | 26 | let names = data.variants().map(|field| { 27 | let field_name = field.ident.unraw(); 28 | quote!(stringify!(#field_name)) 29 | }); 30 | 31 | quote! { 32 | type Error = #_error::InvalidOption<'a>; 33 | 34 | fn from_param(param: &'a str) -> Result { 35 | match param { 36 | #(#matches,)* 37 | _ => Err(#_error::InvalidOption::new(param, &[#(#names),*])), 38 | } 39 | } 40 | } 41 | })) 42 | .to_tokens() 43 | } 44 | -------------------------------------------------------------------------------- /core/codegen/src/derive/mod.rs: -------------------------------------------------------------------------------- 1 | mod form_field; 2 | pub mod from_form; 3 | pub mod from_form_field; 4 | pub mod responder; 5 | pub mod uri_display; 6 | pub mod from_param; 7 | -------------------------------------------------------------------------------- /core/codegen/tests/async-routes.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | #[macro_use] extern crate rocket; 4 | use rocket::http::uri::Origin; 5 | use rocket::request::Request; 6 | 7 | async fn noop() { } 8 | 9 | #[get("/")] 10 | async fn hello(_origin: &Origin<'_>) -> &'static str { 11 | noop().await; 12 | "Hello, world!" 13 | } 14 | 15 | #[get("/repeated_query?")] 16 | async fn repeated_query(sort: Vec<&str>) -> &str { 17 | noop().await; 18 | sort[0] 19 | } 20 | 21 | #[catch(404)] 22 | async fn not_found(req: &Request<'_>) -> String { 23 | noop().await; 24 | format!("{} not found", req.uri()) 25 | } 26 | -------------------------------------------------------------------------------- /core/codegen/tests/from_param.rs: -------------------------------------------------------------------------------- 1 | use rocket::request::FromParam; 2 | 3 | #[allow(non_camel_case_types)] 4 | #[derive(Debug, FromParam, PartialEq)] 5 | enum Test { 6 | Test1, 7 | Test2, 8 | r#for, 9 | } 10 | 11 | #[test] 12 | fn derive_from_param() { 13 | assert_eq!(Test::from_param("Test1").unwrap(), Test::Test1); 14 | assert_eq!(Test::from_param("Test2").unwrap(), Test::Test2); 15 | assert_eq!(Test::from_param("for").unwrap(), Test::r#for); 16 | 17 | let err = Test::from_param("For").unwrap_err(); 18 | assert_eq!(err.value, "For"); 19 | assert_eq!(err.options, &["Test1", "Test2", "for"]); 20 | 21 | let err = Test::from_param("not_test").unwrap_err(); 22 | assert_eq!(err.value, "not_test"); 23 | assert_eq!(err.options, &["Test1", "Test2", "for"]); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/codegen/tests/route-data.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::{Request, Data}; 4 | use rocket::local::blocking::Client; 5 | use rocket::data::{self, FromData}; 6 | use rocket::http::ContentType; 7 | use rocket::form::Form; 8 | 9 | // Test that the data parameters works as expected. 10 | 11 | #[derive(FromForm)] 12 | struct Inner<'r> { 13 | field: &'r str 14 | } 15 | 16 | struct Simple<'r>(&'r str); 17 | 18 | #[async_trait] 19 | impl<'r> FromData<'r> for Simple<'r> { 20 | type Error = std::io::Error; 21 | 22 | async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> { 23 | <&'r str>::from_data(req, data).await.map(Simple) 24 | } 25 | } 26 | 27 | #[post("/f", data = "
")] 28 | fn form<'r>(form: Form>) -> &'r str { form.into_inner().field } 29 | 30 | #[post("/s", data = "")] 31 | fn simple<'r>(simple: Simple<'r>) -> &'r str { simple.0 } 32 | 33 | #[test] 34 | fn test_data() { 35 | let rocket = rocket::build().mount("/", routes![form, simple]); 36 | let client = Client::debug(rocket).unwrap(); 37 | 38 | let response = client.post("/f") 39 | .header(ContentType::Form) 40 | .body("field=this%20is%20here") 41 | .dispatch(); 42 | 43 | assert_eq!(response.into_string().unwrap(), "this is here"); 44 | 45 | let response = client.post("/s").body("this is here").dispatch(); 46 | assert_eq!(response.into_string().unwrap(), "this is here"); 47 | 48 | let response = client.post("/s").body("this%20is%20here").dispatch(); 49 | assert_eq!(response.into_string().unwrap(), "this%20is%20here"); 50 | } 51 | -------------------------------------------------------------------------------- /core/codegen/tests/route-raw.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::local::blocking::Client; 4 | 5 | // Test that raw idents can be used for route parameter names 6 | 7 | #[get("/?")] 8 | fn get(r#enum: String, r#type: i32) -> String { 9 | format!("{} is {}", r#enum, r#type) 10 | } 11 | 12 | #[get("/swap//")] 13 | fn swap(r#raw: String, bare: String) -> String { 14 | format!("{}, {}", raw, bare) 15 | } 16 | 17 | #[catch(400)] 18 | fn catch(r#raw: &rocket::Request<'_>) -> String { 19 | format!("{}", raw.method()) 20 | } 21 | 22 | #[test] 23 | fn test_raw_ident() { 24 | let rocket = rocket::build() 25 | .mount("/", routes![get, swap]) 26 | .register("/", catchers![catch]); 27 | 28 | let client = Client::debug(rocket).unwrap(); 29 | 30 | let response = client.get("/example?type=1").dispatch(); 31 | assert_eq!(response.into_string().unwrap(), "example is 1"); 32 | 33 | let uri_named = uri!(get(r#enum = "test_named", r#type = 1)); 34 | assert_eq!(uri_named.to_string(), "/test_named?type=1"); 35 | 36 | let uri_unnamed = uri!(get("test_unnamed", 2)); 37 | assert_eq!(uri_unnamed.to_string(), "/test_unnamed?type=2"); 38 | 39 | let uri_raws = uri!(swap(r#raw = "1", r#bare = "2")); 40 | assert_eq!(uri_raws.to_string(), "/swap/1/2"); 41 | let uri_bare = uri!(swap(raw = "1", bare = "2")); 42 | assert_eq!(uri_bare.to_string(), "/swap/1/2"); 43 | } 44 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/async-entry.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/async-entry.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/bad-ignored-segments.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/bad-ignored-segments.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/bad-ignored-segments.stderr: -------------------------------------------------------------------------------- 1 | error: parameter must be named 2 | --> tests/ui-fail-nightly/bad-ignored-segments.rs:6:12 3 | | 4 | 6 | #[get("/c?<_>")] 5 | | ^ 6 | | 7 | = help: use a name such as `_guard` or `_param` 8 | 9 | error: parameter must be named 10 | --> tests/ui-fail-nightly/bad-ignored-segments.rs:9:22 11 | | 12 | 9 | #[post("/d", data = "<_>")] 13 | | ^^^ 14 | | 15 | = help: use a name such as `_guard` or `_param` 16 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/catch.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/catch.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/catch_type_errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/catch_type_errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/catchers.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/catchers.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/catchers.stderr: -------------------------------------------------------------------------------- 1 | error: expected `,` 2 | --> tests/ui-fail-nightly/catchers.rs:4:25 3 | | 4 | 4 | let _ = catchers![a b]; 5 | | ^ 6 | 7 | error: expected identifier 8 | --> tests/ui-fail-nightly/catchers.rs:6:26 9 | | 10 | 6 | let _ = catchers![a::, ]; 11 | | ^ 12 | 13 | error: unexpected end of input, expected identifier 14 | --> tests/ui-fail-nightly/catchers.rs:7:13 15 | | 16 | 7 | let _ = catchers![a::]; 17 | | ^^^^^^^^^^^^^^ 18 | | 19 | = note: this error originates in the macro `catchers` (in Nightly builds, run with -Z macro-backtrace for more info) 20 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/from_form.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_form.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/from_form_field.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_form_field.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/from_form_type_errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_form_type_errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/from_param.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_param.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/responder-types.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/responder-types.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/responder.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/responder.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/route-attribute-general-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-attribute-general-syntax.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/route-path-bad-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-path-bad-syntax.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/route-type-errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-type-errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/route-warnings.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-warnings.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/routes.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/routes.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/routes.stderr: -------------------------------------------------------------------------------- 1 | error: expected `,` 2 | --> tests/ui-fail-nightly/routes.rs:4:23 3 | | 4 | 4 | let _ = routes![a b]; 5 | | ^ 6 | 7 | error: expected identifier 8 | --> tests/ui-fail-nightly/routes.rs:6:24 9 | | 10 | 6 | let _ = routes![a::, ]; 11 | | ^ 12 | 13 | error: unexpected end of input, expected identifier 14 | --> tests/ui-fail-nightly/routes.rs:7:13 15 | | 16 | 7 | let _ = routes![a::]; 17 | | ^^^^^^^^^^^^ 18 | | 19 | = note: this error originates in the macro `routes` (in Nightly builds, run with -Z macro-backtrace for more info) 20 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/typed-uri-bad-type.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/typed-uri-bad-type.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/typed-uris-bad-params.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/typed-uris-bad-params.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/typed-uris-invalid-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/typed-uris-invalid-syntax.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/uri_display.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/uri_display.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-nightly/uri_display_type_errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/uri_display_type_errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/async-entry.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/async-entry.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/bad-ignored-segments.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/bad-ignored-segments.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/bad-ignored-segments.stderr: -------------------------------------------------------------------------------- 1 | error: parameter must be named 2 | = help: use a name such as `_guard` or `_param` 3 | --> tests/ui-fail-stable/bad-ignored-segments.rs:6:12 4 | | 5 | 6 | #[get("/c?<_>")] 6 | | ^ 7 | 8 | error: parameter must be named 9 | = help: use a name such as `_guard` or `_param` 10 | --> tests/ui-fail-stable/bad-ignored-segments.rs:9:22 11 | | 12 | 9 | #[post("/d", data = "<_>")] 13 | | ^^^ 14 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/catch.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/catch.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/catch_type_errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/catch_type_errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/catchers.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/catchers.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/catchers.stderr: -------------------------------------------------------------------------------- 1 | error: expected `,` 2 | --> $DIR/catchers.rs:4:25 3 | | 4 | 4 | let _ = catchers![a b]; 5 | | ^ 6 | 7 | error: expected identifier 8 | --> $DIR/catchers.rs:6:26 9 | | 10 | 6 | let _ = catchers![a::, ]; 11 | | ^ 12 | 13 | error: unexpected end of input, expected identifier 14 | --> $DIR/catchers.rs:7:13 15 | | 16 | 7 | let _ = catchers![a::]; 17 | | ^^^^^^^^^^^^^^ 18 | | 19 | = note: this error originates in the macro `catchers` (in Nightly builds, run with -Z macro-backtrace for more info) 20 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/from_form.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_form.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/from_form_field.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_form_field.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/from_form_type_errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_form_type_errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/from_param.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/from_param.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/responder-types.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/responder-types.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/responder.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/responder.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/route-attribute-general-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-attribute-general-syntax.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/route-path-bad-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-path-bad-syntax.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/route-type-errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-type-errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/route-warnings.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/route-warnings.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/route-warnings.stderr: -------------------------------------------------------------------------------- 1 | error: checking for warnings! 2 | --> tests/ui-fail-stable/route-warnings.rs:33:5 3 | | 4 | 33 | compile_error!("checking for warnings!") 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/routes.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/routes.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/routes.stderr: -------------------------------------------------------------------------------- 1 | error: expected `,` 2 | --> $DIR/routes.rs:4:23 3 | | 4 | 4 | let _ = routes![a b]; 5 | | ^ 6 | 7 | error: expected identifier 8 | --> $DIR/routes.rs:6:24 9 | | 10 | 6 | let _ = routes![a::, ]; 11 | | ^ 12 | 13 | error: unexpected end of input, expected identifier 14 | --> $DIR/routes.rs:7:13 15 | | 16 | 7 | let _ = routes![a::]; 17 | | ^^^^^^^^^^^^ 18 | | 19 | = note: this error originates in the macro `routes` (in Nightly builds, run with -Z macro-backtrace for more info) 20 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/typed-uri-bad-type.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/typed-uri-bad-type.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/typed-uris-bad-params.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/typed-uris-bad-params.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/typed-uris-invalid-syntax.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/typed-uris-invalid-syntax.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/uri_display.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/uri_display.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail-stable/uri_display_type_errors.rs: -------------------------------------------------------------------------------- 1 | ../ui-fail/uri_display_type_errors.rs -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | #[ignore] 3 | fn ui() { 4 | let path = match version_check::is_feature_flaggable() { 5 | Some(true) => "ui-fail-nightly", 6 | _ => "ui-fail-stable" 7 | }; 8 | 9 | let t = trybuild::TestCases::new(); 10 | t.compile_fail(format!("tests/{}/*.rs", path)); 11 | } 12 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/bad-ignored-segments.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[get("/<_>")] 4 | fn i0() {} 5 | 6 | #[get("/c?<_>")] 7 | fn i1() {} 8 | 9 | #[post("/d", data = "<_>")] 10 | fn i2() {} 11 | 12 | fn main() { } 13 | -------------------------------------------------------------------------------- /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 | 8 | #[catch(404)] 9 | const CATCH: &str = "Catcher"; 10 | 11 | #[catch("404")] 12 | fn e1(_request: &Request) { } 13 | 14 | #[catch(code = "404")] 15 | fn e2(_request: &Request) { } 16 | 17 | #[catch(code = 404)] 18 | fn e3(_request: &Request) { } 19 | 20 | #[catch(99)] 21 | fn e4(_request: &Request) { } 22 | 23 | #[catch(600)] 24 | fn e5(_request: &Request) { } 25 | 26 | #[catch(400, message = "foo")] 27 | fn e5(_request: &Request) { } 28 | 29 | #[catch(404)] 30 | fn f3(_request: &Request, _other: bool) { } 31 | 32 | fn main() { } 33 | -------------------------------------------------------------------------------- /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 | 10 8 | } 9 | 10 | #[catch(404)] 11 | fn f2(_request: &Request) -> bool { 12 | false 13 | } 14 | 15 | #[catch(404)] 16 | fn f3(_request: bool) -> usize { 17 | 10 18 | } 19 | 20 | #[catch(404)] 21 | fn f4() -> usize { 22 | 10 23 | } 24 | 25 | fn main() { } 26 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/catchers.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | fn main() { 4 | let _ = catchers![a b]; 5 | let _ = catchers![]; 6 | let _ = catchers![a::, ]; 7 | let _ = catchers![a::]; 8 | } 9 | -------------------------------------------------------------------------------- /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 | } 9 | 10 | struct Foo(T); 11 | 12 | #[derive(FromForm)] 13 | struct Other { 14 | field: Foo, 15 | } 16 | 17 | fn main() { } 18 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/from_param.rs: -------------------------------------------------------------------------------- 1 | use rocket::request::FromParam; 2 | 3 | #[derive(FromParam)] 4 | struct Foo1 { 5 | a: String 6 | } 7 | 8 | #[derive(FromParam)] 9 | struct Foo2 {} 10 | 11 | #[derive(FromParam)] 12 | enum Foo3 { 13 | A(String), 14 | B(String) 15 | } 16 | 17 | #[derive(FromParam)] 18 | struct Foo4(usize); 19 | 20 | fn main() {} 21 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/responder-types.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[derive(Responder)] 4 | struct Thing1 { 5 | thing: u8, 6 | } 7 | 8 | #[derive(Responder)] 9 | struct Thing2 { 10 | thing: String, 11 | other: u8, 12 | } 13 | 14 | #[derive(Responder)] 15 | struct Thing3 { 16 | thing: u8, 17 | other: u8, 18 | } 19 | 20 | #[derive(Responder)] 21 | struct Thing4 { 22 | thing: String, 23 | other: rocket::http::ContentType, 24 | then: String, 25 | } 26 | 27 | #[get("/")] 28 | fn foo() -> usize { 0 } 29 | 30 | fn main() { } 31 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/responder.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[derive(Responder)] 4 | struct Thing1; 5 | 6 | #[derive(Responder)] 7 | struct Thing2(); 8 | 9 | #[derive(Responder)] 10 | enum Bar { } // NO ERROR 11 | 12 | #[derive(Responder)] 13 | enum Foo { Bark, } 14 | 15 | #[derive(Responder)] 16 | struct Thing4<'a, 'b>(&'a str, &'b str); 17 | 18 | #[derive(Responder)] 19 | struct Thing5(T); // NO ERROR 20 | 21 | #[derive(Responder)] 22 | struct Thing6(T, E); 23 | 24 | #[derive(Responder)] 25 | #[response(content_type = "")] 26 | struct Thing7(()); 27 | 28 | #[derive(Responder)] 29 | #[response(content_type = "idk")] 30 | struct Thing8(()); 31 | 32 | #[derive(Responder)] 33 | #[response(content_type = 100)] 34 | struct Thing9(()); 35 | 36 | #[derive(Responder)] 37 | #[response(status = 8)] 38 | struct Thing10(()); 39 | 40 | #[derive(Responder)] 41 | #[response(status = "404")] 42 | struct Thing11(()); 43 | 44 | #[derive(Responder)] 45 | #[response(status = "404", content_type = "html")] 46 | struct Thing12(()); 47 | 48 | #[derive(Responder)] 49 | #[response(status = 404, content_type = 120)] 50 | struct Thing13(()); 51 | 52 | #[derive(Responder)] // NO ERROR 53 | enum Error<'r, T> { 54 | #[response(status = 400)] 55 | Unauthorized(T), 56 | #[response(status = 404)] 57 | NotFound(rocket::fs::NamedFile), 58 | #[response(status = 500)] 59 | A(&'r str, rocket::http::ContentType), 60 | } 61 | 62 | #[derive(Responder)] // NO ERROR 63 | enum Error2<'r, T> { 64 | Unauthorized(&'r T), 65 | } 66 | 67 | fn main() {} 68 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/route-type-errors.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | struct Q; 4 | 5 | #[get("/<_foo>")] 6 | fn f0(_foo: Q) {} 7 | 8 | #[get("/<_foo..>")] 9 | fn f1(_foo: Q) {} 10 | 11 | #[get("/?<_foo>")] 12 | fn f2(_foo: Q) {} 13 | 14 | #[get("/?<_foo..>")] 15 | fn f3(_foo: Q) {} 16 | 17 | #[post("/", data = "<_foo>")] 18 | fn f4(_foo: Q) {} 19 | 20 | #[get("/<_foo>")] 21 | fn f5(_a: Q, _foo: Q) {} 22 | 23 | #[get("/<_foo>/other/<_bar>/<_good>/okay")] 24 | fn f6(_a: Q, _foo: Q, _good: usize, _bar: Q) {} 25 | 26 | fn main() { } 27 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/route-warnings.rs: -------------------------------------------------------------------------------- 1 | // must-compile-successfully 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | // Check for unknown media types. 6 | 7 | #[get("/", format = "application/x-custom")] 8 | fn f0() {} 9 | 10 | #[get("/", format = "x-custom/plain")] 11 | fn f1() {} 12 | 13 | #[get("/", format = "x-custom/x-custom")] 14 | fn f2() {} 15 | 16 | #[suppress(unknown_format)] 17 | #[get("/", format = "x-custom/x-custom")] 18 | fn f3() {} 19 | 20 | // Check if a data argument is used with a usually non-payload bearing method. 21 | 22 | #[get("/", data = "<_foo>")] 23 | fn g0(_foo: rocket::Data<'_>) {} 24 | 25 | #[head("/", data = "<_foo>")] 26 | fn g1(_foo: rocket::Data<'_>) {} 27 | 28 | #[suppress(dubious_payload)] 29 | #[head("/", data = "<_foo>")] 30 | fn g2(_foo: rocket::Data<'_>) {} 31 | 32 | fn main() { 33 | compile_error!("checking for warnings!") 34 | } 35 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/routes.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | fn main() { 4 | let _ = routes![a b]; 5 | let _ = routes![]; 6 | let _ = routes![a::, ]; 7 | let _ = routes![a::]; 8 | } 9 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/synchronize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Symlinks all of the tests in this directory with those in sibling 5 | # `ui-fail-stable` and `ui-fail-nightly` directories. 6 | 7 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 8 | 9 | stable="${SCRIPT_DIR}/../ui-fail-stable" 10 | nightly="${SCRIPT_DIR}/../ui-fail-nightly" 11 | anchor="$(basename ${SCRIPT_DIR})" 12 | 13 | echo ":: Synchronizing..." 14 | echo " stable: ${stable}" 15 | echo " nightly: ${nightly}" 16 | echo " anchor: ${anchor}" 17 | 18 | for dir in "${stable}" "${nightly}"; do 19 | find "${dir}" -type l -delete 20 | 21 | for file in "${SCRIPT_DIR}"/*.rs; do 22 | ln -s "../${anchor}/$(basename $file)" "${dir}/" 23 | done 24 | done 25 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/typed-uris-invalid-syntax.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[get("/")] 4 | fn index() { } 5 | 6 | #[post("/<_id>/<_name>")] 7 | fn simple(_id: i32, _name: String) -> &'static str { "" } 8 | 9 | fn main() { 10 | uri!(simple: id = 100, "Hello"); 11 | uri!(simple(id = 100, "Hello")); 12 | uri!(simple("Hello", id = 100)); 13 | uri!(simple,); 14 | uri!(simple:); 15 | uri!("/mount",); 16 | uri!("mount", simple); 17 | uri!("mount", simple, "http://"); 18 | uri!("/mount", simple, "http://"); 19 | uri!("/mount", simple, "#foo", "?foo"); 20 | uri!("mount", simple(10, "hi"), "http://"); 21 | uri!("/mount", simple(10, "hi"), "http://"); 22 | uri!("/mount?foo", simple(10, "hi"), "foo/bar?foo#bar"); 23 | uri!("/mount", simple(10, "hi"), "a/b"); 24 | uri!("/mount", simple(10, "hi"), "#foo", "?foo"); 25 | uri!("/mount/", simple); 26 | uri!(); 27 | uri!(simple: id = ); 28 | uri!(simple(id = )); 29 | uri!("*", simple(10), "hi"); 30 | uri!("some.host:8088", simple(10), "hi"); 31 | uri!("?foo"); 32 | uri!(""); 33 | uri!("/foo", "bar"); 34 | uri!("/foo" ("bar")); 35 | uri!("ftp:?", index); 36 | uri!("ftp:", index, "foo#bar"); 37 | uri!("ftp:", index, "foo?bar"); 38 | } 39 | -------------------------------------------------------------------------------- /core/codegen/tests/ui-fail/uri_display.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[derive(UriDisplayQuery)] 4 | struct Foo1; 5 | 6 | #[derive(UriDisplayQuery)] 7 | struct Foo2(); 8 | 9 | #[derive(UriDisplayQuery)] 10 | enum Foo3 { } 11 | 12 | #[derive(UriDisplayQuery)] 13 | enum Foo4 { 14 | Variant, 15 | } 16 | 17 | #[derive(UriDisplayQuery)] 18 | struct Foo5(String, String); 19 | 20 | #[derive(UriDisplayQuery)] 21 | struct Foo6 { 22 | #[field(name = 123)] 23 | field: String, 24 | } 25 | 26 | #[derive(UriDisplayPath)] 27 | struct Foo7(String, usize); 28 | 29 | #[derive(UriDisplayPath)] 30 | struct Foo8; 31 | 32 | #[derive(UriDisplayPath)] 33 | enum Foo9 { } 34 | 35 | #[derive(UriDisplayPath)] 36 | struct Foo10 { 37 | named: usize 38 | } 39 | 40 | fn main() { } 41 | -------------------------------------------------------------------------------- /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 | 8 | #[derive(UriDisplayQuery)] 9 | struct Bar2 { 10 | field: BadType, 11 | } 12 | 13 | #[derive(UriDisplayQuery)] 14 | struct Bar3 { 15 | field: String, 16 | bad: BadType, 17 | } 18 | 19 | #[derive(UriDisplayQuery)] 20 | enum Bar4 { 21 | Inner(BadType), 22 | } 23 | 24 | #[derive(UriDisplayQuery)] 25 | enum Bar5 { 26 | Inner { 27 | field: BadType, 28 | }, 29 | } 30 | 31 | #[derive(UriDisplayQuery)] 32 | enum Bar6 { 33 | Inner { 34 | field: String, 35 | other: BadType, 36 | }, 37 | } 38 | 39 | #[derive(UriDisplayPath)] 40 | struct Baz(BadType); 41 | 42 | fn main() { } 43 | -------------------------------------------------------------------------------- /core/http/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_http" 3 | version = "0.6.0-dev" 4 | authors = ["Sergio Benitez "] 5 | description = """ 6 | Types, traits, and parsers for HTTP requests, responses, and headers. 7 | """ 8 | documentation = "https://api.rocket.rs/master/rocket_http/" 9 | homepage = "https://rocket.rs" 10 | repository = "https://github.com/rwf2/Rocket" 11 | readme = "../../README.md" 12 | keywords = ["rocket", "web", "framework", "http"] 13 | license = "MIT OR Apache-2.0" 14 | categories = ["web-programming"] 15 | edition = "2021" 16 | rust-version = "1.75" 17 | 18 | [lints] 19 | workspace = true 20 | 21 | [features] 22 | default = [] 23 | serde = ["dep:serde", "uncased/with-serde-alloc"] 24 | uuid = ["dep:uuid"] 25 | 26 | [dependencies] 27 | tinyvec = { version = "1.6", features = ["std", "rustc_1_57"] } 28 | percent-encoding = "2" 29 | time = { version = "0.3", features = ["formatting", "macros"] } 30 | indexmap = "2" 31 | ref-cast = "1.0" 32 | uncased = "0.9.10" 33 | either = "1" 34 | pear = "0.2.9" 35 | memchr = "2" 36 | stable-pattern = "0.1" 37 | cookie = { version = "0.18", features = ["percent-encode"] } 38 | state = "0.6" 39 | 40 | [dependencies.serde] 41 | version = "1.0" 42 | optional = true 43 | default-features = false 44 | features = ["std"] 45 | 46 | [dependencies.uuid] 47 | version = "1" 48 | optional = true 49 | default-features = false 50 | 51 | [dev-dependencies] 52 | rocket = { path = "../lib", features = ["mtls"] } 53 | -------------------------------------------------------------------------------- /core/http/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../LICENSE-APACHE -------------------------------------------------------------------------------- /core/http/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../LICENSE-MIT -------------------------------------------------------------------------------- /core/http/src/header/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod known_media_types; 3 | mod media_type; 4 | mod content_type; 5 | mod accept; 6 | mod header; 7 | mod proxy_proto; 8 | 9 | pub use self::content_type::ContentType; 10 | pub use self::accept::{Accept, QMediaType}; 11 | pub use self::media_type::MediaType; 12 | pub use self::header::{Header, HeaderMap}; 13 | pub use self::proxy_proto::ProxyProto; 14 | 15 | pub(crate) use self::media_type::Source; 16 | -------------------------------------------------------------------------------- /core/http/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![warn(missing_docs)] 3 | 4 | //! Types that map to concepts in HTTP. 5 | //! 6 | //! This module exports types that map to HTTP concepts or to the underlying 7 | //! HTTP library when needed. 8 | 9 | #[macro_use] 10 | extern crate pear; 11 | 12 | pub mod uri; 13 | pub mod ext; 14 | 15 | #[macro_use] 16 | mod header; 17 | mod method; 18 | mod status; 19 | mod raw_str; 20 | mod parse; 21 | 22 | /// Case-preserving, ASCII case-insensitive string types. 23 | /// 24 | /// An _uncased_ string is case-preserving. That is, the string itself contains 25 | /// cased characters, but comparison (including ordering, equality, and hashing) 26 | /// is ASCII case-insensitive. **Note:** the `alloc` feature _is_ enabled. 27 | pub mod uncased { 28 | #[doc(inline)] pub use uncased::*; 29 | } 30 | 31 | // Types that we expose for use _only_ by core. Please don't use this. 32 | #[doc(hidden)] 33 | #[path = "."] 34 | pub mod private { 35 | pub use crate::parse::Indexed; 36 | } 37 | 38 | pub use crate::method::Method; 39 | pub use crate::status::{Status, StatusClass}; 40 | pub use crate::raw_str::{RawStr, RawStrBuf}; 41 | pub use crate::header::*; 42 | 43 | /// HTTP Protocol version 44 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 45 | #[non_exhaustive] 46 | pub enum HttpVersion { 47 | /// `HTTP/0.9` 48 | Http09, 49 | /// `HTTP/1.0` 50 | Http10, 51 | /// `HTTP/1.1` 52 | Http11, 53 | /// `HTTP/2` 54 | Http2, 55 | /// `HTTP/3` 56 | Http3, 57 | } 58 | -------------------------------------------------------------------------------- /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 | matches!(c, '0'..='9' | 'A'..='Z' | '^'..='~' | '#'..='\'' 9 | | '!' | '*' | '+' | '-' | '.') 10 | } 11 | -------------------------------------------------------------------------------- /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 | pub use self::indexed::*; 12 | -------------------------------------------------------------------------------- /core/http/src/parse/uri/mod.rs: -------------------------------------------------------------------------------- 1 | mod parser; 2 | mod error; 3 | pub(crate) mod tables; 4 | 5 | #[cfg(test)] mod tests; 6 | 7 | use crate::uri::{Uri, Origin, Absolute, Authority, Reference, Asterisk}; 8 | 9 | use self::parser::*; 10 | 11 | pub use self::error::Error; 12 | 13 | type RawInput<'a> = pear::input::Pear>; 14 | 15 | #[inline] 16 | pub fn from_str(s: &str) -> Result, Error<'_>> { 17 | Ok(parse!(uri: RawInput::new(s.as_bytes()))?) 18 | } 19 | 20 | #[inline] 21 | pub fn origin_from_str(s: &str) -> Result, Error<'_>> { 22 | Ok(parse!(origin: RawInput::new(s.as_bytes()))?) 23 | } 24 | 25 | #[inline] 26 | pub fn authority_from_str(s: &str) -> Result, Error<'_>> { 27 | Ok(parse!(authority: RawInput::new(s.as_bytes()))?) 28 | } 29 | 30 | #[inline] 31 | pub fn authority_from_bytes(s: &[u8]) -> Result, Error<'_>> { 32 | Ok(parse!(authority: RawInput::new(s))?) 33 | } 34 | 35 | #[inline] 36 | pub fn scheme_from_str(s: &str) -> Result<&str, Error<'_>> { 37 | let _validated = parse!(scheme: RawInput::new(s.as_bytes()))?; 38 | Ok(s) 39 | } 40 | 41 | #[inline] 42 | pub fn absolute_from_str(s: &str) -> Result, Error<'_>> { 43 | Ok(parse!(absolute: RawInput::new(s.as_bytes()))?) 44 | } 45 | 46 | #[inline] 47 | pub fn asterisk_from_str(s: &str) -> Result> { 48 | Ok(parse!(asterisk: RawInput::new(s.as_bytes()))?) 49 | } 50 | 51 | #[inline] 52 | pub fn reference_from_str(s: &str) -> Result, Error<'_>> { 53 | Ok(parse!(reference: RawInput::new(s.as_bytes()))?) 54 | } 55 | -------------------------------------------------------------------------------- /core/http/src/uri/error.rs: -------------------------------------------------------------------------------- 1 | //! Errors arising from parsing invalid URIs. 2 | 3 | use std::fmt; 4 | 5 | pub use crate::parse::uri::Error; 6 | 7 | /// The error type returned when a URI conversion fails. 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 9 | pub struct TryFromUriError(pub(crate) ()); 10 | 11 | impl fmt::Display for TryFromUriError { 12 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 13 | "invalid conversion from general to specific URI variant".fmt(f) 14 | } 15 | } 16 | 17 | /// An error interpreting a segment as a [`PathBuf`] component in 18 | /// [`Segments::to_path_buf()`]. 19 | /// 20 | /// [`PathBuf`]: std::path::PathBuf 21 | /// [`Segments::to_path_buf()`]: crate::uri::Segments::to_path_buf() 22 | #[derive(Debug, PartialEq, Eq, Clone)] 23 | pub enum PathError { 24 | /// The segment started with the wrapped invalid character. 25 | BadStart(char), 26 | /// The segment contained the wrapped invalid character. 27 | BadChar(char), 28 | /// The segment ended with the wrapped invalid character. 29 | BadEnd(char), 30 | } 31 | 32 | impl fmt::Display for PathError { 33 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 34 | match self { 35 | PathError::BadStart(c) => write!(f, "invalid initial character: {c:?}"), 36 | PathError::BadChar(c) => write!(f, "invalid character: {c:?}"), 37 | PathError::BadEnd(c) => write!(f, "invalid terminal character: {c:?}"), 38 | } 39 | } 40 | } 41 | 42 | impl std::error::Error for PathError { } 43 | -------------------------------------------------------------------------------- /core/http/src/uri/fmt/mod.rs: -------------------------------------------------------------------------------- 1 | //! Type safe and URI safe formatting types and traits. 2 | 3 | mod uri_display; 4 | mod formatter; 5 | mod from_uri_param; 6 | mod encoding; 7 | mod part; 8 | 9 | pub use self::formatter::*; 10 | pub use self::uri_display::*; 11 | pub use self::from_uri_param::*; 12 | pub use self::part::*; 13 | 14 | pub(crate) use self::encoding::*; 15 | -------------------------------------------------------------------------------- /core/http/src/uri/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types for URIs and traits for rendering URI components. 2 | 3 | #[macro_use] 4 | mod uri; 5 | mod origin; 6 | mod reference; 7 | mod authority; 8 | mod absolute; 9 | mod segments; 10 | mod path_query; 11 | mod asterisk; 12 | mod host; 13 | 14 | pub mod error; 15 | pub mod fmt; 16 | 17 | #[doc(inline)] 18 | pub use self::error::Error; 19 | 20 | pub use self::uri::*; 21 | pub use self::authority::*; 22 | pub use self::origin::*; 23 | pub use self::absolute::*; 24 | pub use self::segments::*; 25 | pub use self::reference::*; 26 | pub use self::path_query::*; 27 | pub use self::asterisk::*; 28 | pub use self::host::*; 29 | -------------------------------------------------------------------------------- /core/lib/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../LICENSE-APACHE -------------------------------------------------------------------------------- /core/lib/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../LICENSE-MIT -------------------------------------------------------------------------------- /core/lib/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Some((version, channel, _)) = version_check::triple() { 3 | if channel.supports_features() { 4 | println!("cargo:rustc-cfg=nightly"); 5 | } 6 | 7 | if version.at_least("1.67") && version.at_most("1.68.2") { 8 | println!("cargo:rustc-cfg=broken_fmt"); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/lib/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus/*/* 3 | artifacts 4 | !*.seed 5 | -------------------------------------------------------------------------------- /core/lib/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket-fuzz" 3 | version = "0.0.0" 4 | authors = ["Automatically generated"] 5 | publish = false 6 | edition = "2021" 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [lints.rust] 12 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(honggfuzz)', 'cfg(afl)'] } 13 | 14 | [dependencies] 15 | libfuzzer-sys = "0.4" 16 | arbitrary = { version = "1.3", features = ["derive"] } 17 | 18 | [target.'cfg(afl)'.dependencies] 19 | afl = "*" 20 | 21 | [target.'cfg(honggfuzz)'.dependencies] 22 | honggfuzz = "*" 23 | 24 | [dependencies.rocket] 25 | path = ".." 26 | 27 | # Prevent this from interfering with workspaces 28 | [workspace] 29 | members = ["."] 30 | 31 | [[bin]] 32 | name = "uri-parsing" 33 | path = "targets/uri-parsing.rs" 34 | test = false 35 | doc = false 36 | 37 | [[bin]] 38 | name = "uri-roundtrip" 39 | path = "targets/uri-roundtrip.rs" 40 | test = false 41 | doc = false 42 | 43 | [[bin]] 44 | name = "uri-normalization" 45 | path = "targets/uri-normalization.rs" 46 | test = false 47 | doc = false 48 | 49 | [[bin]] 50 | name = "collision-matching" 51 | path = "targets/collision-matching.rs" 52 | test = false 53 | doc = false 54 | -------------------------------------------------------------------------------- /core/lib/fuzz/README.md: -------------------------------------------------------------------------------- 1 | # Fuzzing 2 | 3 | Install `cargo-fuzz`: 4 | 5 | ```sh 6 | cargo install -f cargo-fuzz 7 | ``` 8 | 9 | Run any available target where `$target` is the name of the target and `$n` is 10 | the number of CPUs to use for fuzzing: 11 | 12 | ```sh 13 | cargo fuzz list # get list of targets 14 | cargo fuzz run $target -j $n 15 | ``` 16 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/collision-matching/another.seed: -------------------------------------------------------------------------------- 1 | 01//foo/bar/b01/foo/a/b1/text/html 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/collision-matching/base.seed: -------------------------------------------------------------------------------- 1 | 01//a/b01//a/b0/a/b 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/collision-matching/complex.seed: -------------------------------------------------------------------------------- 1 | 44/foo/bar/applicatiom/json1bazb01/foo/a/btext/plain1/fooktext/html 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/collision-matching/large.seed: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------ 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/uri-parsing/absolute.seed: -------------------------------------------------------------------------------- 1 | http://user:pass@domain.com:4444/foo/bar?some=query 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/uri-parsing/asterisk.seed: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/uri-parsing/authority.seed: -------------------------------------------------------------------------------- 1 | username:password@some.host:8088 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/uri-parsing/origin.seed: -------------------------------------------------------------------------------- 1 | /first_segment/second_segment/third?optional=query 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/corpus/uri-parsing/reference.seed: -------------------------------------------------------------------------------- 1 | http://user:pass@domain.com:4444/foo/bar?some=query#and-fragment 2 | -------------------------------------------------------------------------------- /core/lib/fuzz/targets/uri-normalization.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use rocket::http::uri::*; 4 | use libfuzzer_sys::fuzz_target; 5 | 6 | fn fuzz(data: &str) { 7 | if let Ok(uri) = Uri::parse_any(data) { 8 | match uri { 9 | Uri::Origin(uri) if uri.is_normalized() => { 10 | assert_eq!(uri.clone(), uri.into_normalized()); 11 | } 12 | Uri::Absolute(uri) if uri.is_normalized() => { 13 | assert_eq!(uri.clone(), uri.into_normalized()); 14 | } 15 | Uri::Reference(uri) if uri.is_normalized() => { 16 | assert_eq!(uri.clone(), uri.into_normalized()); 17 | } 18 | _ => { /* not normalizable */ }, 19 | } 20 | } 21 | } 22 | 23 | fuzz_target!(|data: &str| fuzz(data)); 24 | -------------------------------------------------------------------------------- /core/lib/fuzz/targets/uri-parsing.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use rocket::http::uri::*; 4 | use libfuzzer_sys::fuzz_target; 5 | 6 | fn fuzz(data: &str) { 7 | // Fuzz the top-level parser. 8 | if let Ok(uri) = Uri::parse_any(data) { 9 | // Ensure Uri::parse::() => T::parse(). 10 | match uri { 11 | Uri::Asterisk(_) => { Asterisk::parse(data).expect("Asterisk"); }, 12 | Uri::Origin(_) => { Origin::parse(data).expect("Origin"); }, 13 | Uri::Authority(_) => { Authority::parse(data).expect("Authority"); }, 14 | Uri::Absolute(_) => { Absolute::parse(data).expect("Absolute"); }, 15 | Uri::Reference(_) => { Reference::parse(data).expect("Reference"); }, 16 | } 17 | } 18 | } 19 | 20 | fuzz_target!(|data: &[u8]| { 21 | let _ = std::str::from_utf8(data).map(fuzz); 22 | }); 23 | -------------------------------------------------------------------------------- /core/lib/fuzz/targets/uri-roundtrip.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use rocket::http::uri::*; 4 | use libfuzzer_sys::fuzz_target; 5 | 6 | fn fuzz(data: &str) { 7 | if let Ok(uri) = Uri::parse_any(data) { 8 | let string = uri.to_string(); 9 | let _ = match uri { 10 | Uri::Asterisk(_) => Asterisk::parse_owned(string).expect("Asterisk").to_string(), 11 | Uri::Origin(_) => Origin::parse_owned(string).expect("Origin").to_string(), 12 | Uri::Authority(_) => Authority::parse_owned(string).expect("Authority").to_string(), 13 | Uri::Absolute(_) => Absolute::parse_owned(string).expect("Absolute").to_string(), 14 | Uri::Reference(_) => Reference::parse_owned(string).expect("Reference").to_string(), 15 | }; 16 | } 17 | } 18 | 19 | fuzz_target!(|data: &[u8]| { 20 | let _ = std::str::from_utf8(data).map(fuzz); 21 | }); 22 | -------------------------------------------------------------------------------- /core/lib/src/catcher/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and traits for error catchers and their handlers and return types. 2 | 3 | mod catcher; 4 | mod handler; 5 | 6 | pub use catcher::*; 7 | pub use handler::*; 8 | -------------------------------------------------------------------------------- /core/lib/src/data/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and traits for handling incoming body data. 2 | 3 | #[macro_use] 4 | mod capped; 5 | mod data; 6 | mod data_stream; 7 | mod from_data; 8 | mod limits; 9 | mod io_stream; 10 | mod transform; 11 | mod peekable; 12 | 13 | pub use self::data::Data; 14 | pub use self::data_stream::DataStream; 15 | pub use self::from_data::{FromData, Outcome}; 16 | pub use self::limits::Limits; 17 | pub use self::capped::{N, Capped}; 18 | pub use self::io_stream::{IoHandler, IoStream}; 19 | pub use ubyte::{ByteUnit, ToByteUnit}; 20 | pub use self::transform::{Transform, TransformBuf}; 21 | 22 | pub(crate) use self::data_stream::RawStream; 23 | -------------------------------------------------------------------------------- /core/lib/src/data/peekable.rs: -------------------------------------------------------------------------------- 1 | use tokio::io::{AsyncRead, AsyncReadExt}; 2 | 3 | pub struct Peekable { 4 | pub(crate) buffer: Vec, 5 | pub(crate) complete: bool, 6 | pub(crate) reader: R, 7 | } 8 | 9 | impl Peekable { 10 | pub fn new(reader: R) -> Self { 11 | Self { buffer: Vec::new(), complete: false, reader } 12 | } 13 | 14 | pub fn with_buffer(buffer: Vec, complete: bool, reader: R) -> Self { 15 | Self { buffer, complete, reader } 16 | } 17 | 18 | pub async fn peek(&mut self, num: usize) -> &[u8] { 19 | if self.complete { 20 | return self.buffer.as_slice(); 21 | } 22 | 23 | let to_read = std::cmp::min(N, num); 24 | if self.buffer.len() >= to_read { 25 | return self.buffer.as_slice(); 26 | } 27 | 28 | if self.buffer.capacity() == 0 { 29 | self.buffer.reserve(N); 30 | } 31 | 32 | while self.buffer.len() < to_read { 33 | match self.reader.read_buf::>(&mut self.buffer).await { 34 | Ok(0) => { 35 | self.complete = self.buffer.capacity() > self.buffer.len(); 36 | break; 37 | }, 38 | Ok(_) => { /* continue */ }, 39 | Err(e) => { 40 | error!("failed to read into peek buffer: {:?}.", e); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | self.buffer.as_slice() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/lib/src/form/name/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types for field names, name keys, and key indices. 2 | 3 | mod name; 4 | mod view; 5 | mod key; 6 | mod buf; 7 | 8 | pub use name::Name; 9 | pub use view::NameView; 10 | pub use key::Key; 11 | pub use buf::NameBuf; 12 | -------------------------------------------------------------------------------- /core/lib/src/form/options.rs: -------------------------------------------------------------------------------- 1 | /// Form guard options. 2 | /// 3 | /// See [`Form#leniency`](crate::form::Form#leniency) for details. 4 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 5 | pub struct Options { 6 | /// Whether parsing should be strict (no extra parameters) or not. 7 | pub strict: bool, 8 | } 9 | 10 | #[allow(non_upper_case_globals, dead_code)] 11 | impl Options { 12 | /// `Options` with `strict` set to `false`. 13 | pub const Lenient: Self = Options { strict: false }; 14 | 15 | /// `Options` with `strict` set to `true`. 16 | pub const Strict: Self = Options { strict: true }; 17 | } 18 | -------------------------------------------------------------------------------- /core/lib/src/http/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types that map to concepts in HTTP. 2 | //! 3 | //! This module exports types that map to HTTP concepts or to the underlying 4 | //! HTTP library when needed. 5 | 6 | mod cookies; 7 | 8 | #[doc(inline)] 9 | pub use rocket_http::*; 10 | 11 | #[doc(inline)] 12 | pub use cookies::*; 13 | -------------------------------------------------------------------------------- /core/lib/src/listener/bind.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | use crate::listener::{Endpoint, Listener}; 4 | use crate::{Rocket, Ignite}; 5 | 6 | pub trait Bind: Listener + 'static { 7 | type Error: Error + Send + 'static; 8 | 9 | #[crate::async_bound(Send)] 10 | async fn bind(rocket: &Rocket) -> Result; 11 | 12 | fn bind_endpoint(to: &Rocket) -> Result; 13 | } 14 | -------------------------------------------------------------------------------- /core/lib/src/listener/mod.rs: -------------------------------------------------------------------------------- 1 | mod cancellable; 2 | mod bounced; 3 | mod listener; 4 | mod endpoint; 5 | mod connection; 6 | mod bind; 7 | mod default; 8 | 9 | #[cfg(unix)] 10 | #[cfg_attr(nightly, doc(cfg(unix)))] 11 | pub mod unix; 12 | pub mod tcp; 13 | #[cfg(feature = "http3-preview")] 14 | pub mod quic; 15 | 16 | pub use endpoint::*; 17 | pub use listener::*; 18 | pub use connection::*; 19 | pub use bind::*; 20 | pub use default::*; 21 | 22 | pub(crate) use cancellable::*; 23 | pub(crate) use bounced::*; 24 | -------------------------------------------------------------------------------- /core/lib/src/local/asynchronous/mod.rs: -------------------------------------------------------------------------------- 1 | //! Asynchronous local dispatching of requests. 2 | //! 3 | //! This module contains the `asynchronous` variant of the `local` API: it can 4 | //! be used with `#[rocket::async_test]` or another asynchronous test harness. 5 | //! For the blocking variant, see [`blocking`](super::blocking). 6 | //! 7 | //! See the [top-level documentation](super) for more usage details. 8 | 9 | mod client; 10 | mod request; 11 | mod response; 12 | 13 | pub use client::*; 14 | pub use request::*; 15 | pub use response::*; 16 | -------------------------------------------------------------------------------- /core/lib/src/local/blocking/mod.rs: -------------------------------------------------------------------------------- 1 | //! Blocking local dispatching of requests. 2 | //! 3 | //! This module contains the `blocking` variant of the `local` API: it can be 4 | //! used in Rust's synchronous `#[test]` harness. This is accomplished by 5 | //! starting and running an internal asynchronous Runtime as needed. For the 6 | //! asynchronous variant, see [`asynchronous`](super::asynchronous). 7 | //! 8 | //! See the [top-level documentation](super) for more usage details. 9 | 10 | mod client; 11 | mod request; 12 | mod response; 13 | 14 | pub use self::client::*; 15 | pub use self::request::*; 16 | pub use self::response::*; 17 | -------------------------------------------------------------------------------- /core/lib/src/mtls/mod.rs: -------------------------------------------------------------------------------- 1 | //! Support for mutual TLS client certificates. 2 | //! 3 | //! For details on how to configure mutual TLS, see [`MtlsConfig`] and the [TLS 4 | //! guide](https://rocket.rs/master/guide/configuration/#tls). See 5 | //! [`Certificate`] for a request guard that validates, verifies, and retrieves 6 | //! client certificates. 7 | 8 | pub mod oid { 9 | //! Lower-level OID types re-exported from 10 | //! [`oid_registry`](https://docs.rs/oid-registry/0.4) and 11 | //! [`der-parser`](https://docs.rs/der-parser/7). 12 | 13 | pub use x509_parser::oid_registry::*; 14 | pub use x509_parser::objects::*; 15 | } 16 | 17 | pub mod bigint { 18 | //! Signed and unsigned big integer types re-exported from 19 | //! [`num_bigint`](https://docs.rs/num-bigint/0.4). 20 | pub use x509_parser::der_parser::num_bigint::*; 21 | } 22 | 23 | pub mod x509 { 24 | //! Lower-level X.509 types re-exported from 25 | //! [`x509_parser`](https://docs.rs/x509-parser/0.13). 26 | //! 27 | //! Lack of documentation is directly inherited from the source crate. 28 | //! Prefer to use Rocket's wrappers when possible. 29 | 30 | pub use x509_parser::prelude::*; 31 | } 32 | 33 | mod certificate; 34 | mod error; 35 | mod name; 36 | mod config; 37 | 38 | pub use error::Error; 39 | pub use name::Name; 40 | pub use config::MtlsConfig; 41 | pub use certificate::{Certificate, CertificateDer}; 42 | 43 | /// A type alias for `Result` with the error type set to [`Error`]. 44 | pub type Result = std::result::Result; 45 | -------------------------------------------------------------------------------- /core/lib/src/request/atomic_method.rs: -------------------------------------------------------------------------------- 1 | use crate::http::Method; 2 | 3 | pub struct AtomicMethod(ref_swap::RefSwap<'static, Method>); 4 | 5 | impl AtomicMethod { 6 | #[inline] 7 | pub fn new(value: Method) -> Self { 8 | Self(ref_swap::RefSwap::new(value.as_ref())) 9 | } 10 | 11 | #[inline] 12 | pub fn load(&self) -> Method { 13 | *self.0.load(std::sync::atomic::Ordering::Acquire) 14 | } 15 | 16 | #[inline] 17 | pub fn set(&mut self, new: Method) { 18 | *self = Self::new(new); 19 | } 20 | 21 | #[inline] 22 | pub fn store(&self, new: Method) { 23 | self.0.store(new.as_ref(), std::sync::atomic::Ordering::Release) 24 | } 25 | } 26 | 27 | impl Clone for AtomicMethod { 28 | fn clone(&self) -> Self { 29 | let inner = self.0.load(std::sync::atomic::Ordering::Acquire); 30 | Self(ref_swap::RefSwap::new(inner)) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /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`] trait, which means that the type knows how to generate a 5 | //! [`Response`]. Among other things, this module contains several such types. 6 | //! 7 | //! # Composing 8 | //! 9 | //! Many of the built-in `Responder` types _chain_ responses: they take in 10 | //! another `Responder` and add, remove, or change information in the response. 11 | //! In other words, many `Responder` types are built to compose well. As a 12 | //! result, you'll often have types of the form `A>` consisting of three 13 | //! `Responder`s `A`, `B`, and `C`. This is normal and encouraged as the type 14 | //! names typically illustrate the intended response. 15 | 16 | mod responder; 17 | mod redirect; 18 | mod response; 19 | mod debug; 20 | mod body; 21 | 22 | pub(crate) mod flash; 23 | 24 | pub mod content; 25 | pub mod status; 26 | pub mod stream; 27 | 28 | #[doc(hidden)] 29 | pub use rocket_codegen::Responder; 30 | 31 | pub use self::response::{Response, Builder}; 32 | pub use self::body::Body; 33 | pub use self::responder::Responder; 34 | pub use self::redirect::Redirect; 35 | pub use self::flash::Flash; 36 | pub use self::debug::Debug; 37 | 38 | /// Type alias for the `Result` of a [`Responder::respond_to()`] call. 39 | pub type Result<'r> = std::result::Result, crate::http::Status>; 40 | -------------------------------------------------------------------------------- /core/lib/src/response/stream/one.rs: -------------------------------------------------------------------------------- 1 | use std::pin::Pin; 2 | use std::task::{Context, Poll}; 3 | 4 | use futures::stream::Stream; 5 | 6 | /// A stream that yields exactly one value. 7 | /// 8 | /// A `ReaderStream` which wraps this type and yields one `AsyncRead` is 9 | /// returned by [`ReaderStream::one()`]. A `One` can also be constructed via 10 | /// [`One::from()`]. 11 | /// 12 | /// [`ReaderStream::one()`]: crate::response::stream::ReaderStream::one() 13 | /// 14 | /// # Example 15 | /// 16 | /// ```rust 17 | /// use rocket::response::stream::One; 18 | /// use rocket::futures::stream::StreamExt; 19 | /// 20 | /// # rocket::async_test(async { 21 | /// let mut stream = One::from("hello!"); 22 | /// let values: Vec<_> = stream.collect().await; 23 | /// assert_eq!(values, ["hello!"]); 24 | /// # }); 25 | /// ``` 26 | pub struct One(Option); 27 | 28 | /// Returns a `One` stream that will yield `value` exactly once. 29 | /// 30 | /// # Example 31 | /// 32 | /// ```rust 33 | /// use rocket::response::stream::One; 34 | /// 35 | /// let mut stream = One::from("hello!"); 36 | /// ``` 37 | impl From for One { 38 | fn from(value: T) -> Self { 39 | One(Some(value)) 40 | } 41 | } 42 | 43 | impl Stream for One { 44 | type Item = T; 45 | 46 | fn poll_next( 47 | mut self: Pin<&mut Self>, 48 | _: &mut Context<'_>, 49 | ) -> Poll> { 50 | Poll::Ready(self.0.take()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/lib/src/route/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and traits for routes and their request handlers and return types. 2 | 3 | mod route; 4 | mod handler; 5 | mod uri; 6 | mod segment; 7 | 8 | pub use route::*; 9 | pub use handler::*; 10 | pub use uri::*; 11 | 12 | pub(crate) use segment::Segment; 13 | -------------------------------------------------------------------------------- /core/lib/src/route/segment.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct Segment { 3 | /// The name of the parameter or just the static string. 4 | pub value: String, 5 | /// This is a ``. 6 | pub dynamic: bool, 7 | /// This is a ``. 8 | pub dynamic_trail: bool, 9 | } 10 | 11 | impl Segment { 12 | pub fn from(segment: &crate::http::RawStr) -> Self { 13 | let mut value = segment; 14 | let mut dynamic = false; 15 | let mut dynamic_trail = false; 16 | 17 | if segment.starts_with('<') && segment.ends_with('>') { 18 | dynamic = true; 19 | value = &segment[1..(segment.len() - 1)]; 20 | 21 | if value.ends_with("..") { 22 | dynamic_trail = true; 23 | value = &value[..(value.len() - 2)]; 24 | } 25 | } 26 | 27 | Segment { value: value.to_string(), dynamic, dynamic_trail } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/lib/src/router/mod.rs: -------------------------------------------------------------------------------- 1 | //! Rocket's router. 2 | 3 | mod router; 4 | mod collider; 5 | mod matcher; 6 | 7 | pub(crate) use router::*; 8 | pub(crate) use collider::*; 9 | -------------------------------------------------------------------------------- /core/lib/src/shutdown/mod.rs: -------------------------------------------------------------------------------- 1 | //! Shutdown configuration and notification handle. 2 | 3 | mod tripwire; 4 | mod handle; 5 | mod sig; 6 | mod config; 7 | 8 | pub(crate) use tripwire::TripWire; 9 | pub(crate) use handle::Stages; 10 | 11 | pub use config::ShutdownConfig; 12 | pub use handle::Shutdown; 13 | pub use sig::Sig; 14 | -------------------------------------------------------------------------------- /core/lib/src/tls/mod.rs: -------------------------------------------------------------------------------- 1 | mod error; 2 | mod resolver; 3 | mod listener; 4 | pub(crate) mod config; 5 | 6 | pub use error::{Error, Result}; 7 | pub use config::{TlsConfig, CipherSuite}; 8 | pub use resolver::{Resolver, ClientHello, ServerConfig}; 9 | pub use listener::{TlsListener, TlsStream}; 10 | -------------------------------------------------------------------------------- /core/lib/src/trace/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | mod traceable; 4 | 5 | #[cfg(feature = "trace")] 6 | #[cfg_attr(nightly, doc(cfg(feature = "trace")))] 7 | pub mod subscriber; 8 | 9 | pub(crate) mod level; 10 | 11 | #[doc(inline)] 12 | pub use macros::*; 13 | 14 | #[doc(inline)] 15 | pub use traceable::{Trace, TraceAll}; 16 | 17 | #[doc(inline)] 18 | pub use tracing::{Level, level_filters::LevelFilter}; 19 | 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)] 21 | #[serde(crate = "rocket::serde")] 22 | #[non_exhaustive] 23 | pub enum TraceFormat { 24 | #[serde(rename = "pretty")] 25 | #[serde(alias = "PRETTY")] 26 | Pretty, 27 | #[serde(rename = "compact")] 28 | #[serde(alias = "COMPACT")] 29 | Compact 30 | } 31 | 32 | #[cfg_attr(nightly, doc(cfg(feature = "trace")))] 33 | pub fn init<'a, T: Into>>(config: T) { 34 | #[cfg(not(feature = "trace"))] 35 | let _ = config; 36 | 37 | #[cfg(feature = "trace")] 38 | crate::trace::subscriber::RocketDynFmt::init(config.into()) 39 | } 40 | -------------------------------------------------------------------------------- /core/lib/src/trace/subscriber/mod.rs: -------------------------------------------------------------------------------- 1 | mod visit; 2 | mod pretty; 3 | mod compact; 4 | mod dynamic; 5 | mod common; 6 | mod request_id; 7 | 8 | pub use pretty::Pretty; 9 | pub use compact::Compact; 10 | pub use common::RocketFmt; 11 | pub use request_id::{RequestId, RequestIdLayer}; 12 | pub use dynamic::RocketDynFmt; 13 | 14 | pub(crate) use visit::{RecordDisplay, Data}; 15 | -------------------------------------------------------------------------------- /core/lib/src/util/chain.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::task::{Poll, Context}; 3 | use std::pin::Pin; 4 | 5 | use pin_project_lite::pin_project; 6 | use tokio::io::{AsyncRead, ReadBuf}; 7 | 8 | pin_project! { 9 | /// Stream for the [`chain`](super::AsyncReadExt::chain) method. 10 | #[must_use = "streams do nothing unless polled"] 11 | pub struct Chain { 12 | #[pin] 13 | first: Option, 14 | #[pin] 15 | second: U, 16 | } 17 | } 18 | 19 | impl Chain { 20 | pub(crate) fn new(first: T, second: U) -> Self { 21 | Self { first: Some(first), second } 22 | } 23 | } 24 | 25 | impl Chain { 26 | /// Gets references to the underlying readers in this `Chain`. 27 | pub fn get_ref(&self) -> (Option<&T>, &U) { 28 | (self.first.as_ref(), &self.second) 29 | } 30 | } 31 | 32 | impl AsyncRead for Chain { 33 | fn poll_read( 34 | mut self: Pin<&mut Self>, 35 | cx: &mut Context<'_>, 36 | buf: &mut ReadBuf<'_>, 37 | ) -> Poll> { 38 | let me = self.as_mut().project(); 39 | if let Some(first) = me.first.as_pin_mut() { 40 | let init_rem = buf.remaining(); 41 | futures::ready!(first.poll_read(cx, buf))?; 42 | if buf.remaining() == init_rem { 43 | self.as_mut().project().first.set(None); 44 | } else { 45 | return Poll::Ready(Ok(())); 46 | } 47 | } 48 | 49 | let me = self.as_mut().project(); 50 | me.second.poll_read(cx, buf) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/lib/src/util/unix.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::os::fd::AsRawFd; 3 | 4 | pub fn lock_exclusive_nonblocking(file: &T) -> io::Result<()> { 5 | let raw_fd = file.as_raw_fd(); 6 | let res = unsafe { 7 | libc::flock(raw_fd, libc::LOCK_EX | libc::LOCK_NB) 8 | }; 9 | 10 | match res { 11 | 0 => Ok(()), 12 | _ => Err(io::Error::last_os_error()), 13 | } 14 | } 15 | 16 | pub fn unlock_nonblocking(file: &T) -> io::Result<()> { 17 | let res = unsafe { 18 | libc::flock(file.as_raw_fd(), libc::LOCK_UN | libc::LOCK_NB) 19 | }; 20 | 21 | match res { 22 | 0 => Ok(()), 23 | _ => Err(io::Error::last_os_error()), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/lib/tests/absolute-uris-okay-issue-443.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::response::Redirect; 4 | 5 | #[get("/http")] 6 | fn http() -> Redirect { 7 | Redirect::to(uri!("http://rocket.rs")) 8 | } 9 | 10 | #[get("/rocket")] 11 | fn redirect() -> Redirect { 12 | Redirect::to("https://rocket.rs:80") 13 | } 14 | 15 | mod test_absolute_uris_okay { 16 | use super::*; 17 | use rocket::local::blocking::Client; 18 | 19 | #[test] 20 | fn redirect_works() { 21 | let client = Client::debug_with(routes![http, redirect]).unwrap(); 22 | 23 | let response = client.get(uri!(http)).dispatch(); 24 | let location = response.headers().get_one("Location"); 25 | assert_eq!(location, Some("http://rocket.rs")); 26 | 27 | let response = client.get(uri!(redirect)).dispatch(); 28 | let location = response.headers().get_one("Location"); 29 | assert_eq!(location, Some("https://rocket.rs:80")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/lib/tests/can-correct-bad-local-uri.rs: -------------------------------------------------------------------------------- 1 | use rocket::http::uri::Origin; 2 | use rocket::local::blocking::Client; 3 | 4 | #[test] 5 | fn can_correct_bad_local_uri() { 6 | #[rocket::get("/")] fn f() {} 7 | 8 | let client = Client::debug_with(rocket::routes![f]).unwrap(); 9 | let mut req = client.get("this is a bad URI"); 10 | req.set_uri(Origin::parse("/").unwrap()); 11 | 12 | assert_eq!(req.uri(), "/"); 13 | assert!(req.dispatch().status().class().is_success()); 14 | 15 | let req = client.get("this is a bad URI"); 16 | assert!(req.dispatch().status().class().is_client_error()); 17 | } 18 | -------------------------------------------------------------------------------- /core/lib/tests/can-launch-tls.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "tls")] 2 | 3 | use rocket::fs::relative; 4 | use rocket::local::asynchronous::Client; 5 | use rocket::tls::{TlsConfig, CipherSuite}; 6 | use rocket::figment::providers::Serialized; 7 | 8 | #[rocket::async_test] 9 | async fn can_launch_tls() { 10 | let cert_path = relative!("examples/tls/private/rsa_sha256_cert.pem"); 11 | let key_path = relative!("examples/tls/private/rsa_sha256_key.pem"); 12 | 13 | let tls = TlsConfig::from_paths(cert_path, key_path) 14 | .with_ciphers([ 15 | CipherSuite::TLS_AES_128_GCM_SHA256, 16 | CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 17 | ]); 18 | 19 | let config = rocket::Config::figment().merge(Serialized::defaults(tls)); 20 | let client = Client::debug(rocket::custom(config)).await.unwrap(); 21 | client.rocket().shutdown().notify(); 22 | client.rocket().shutdown().await; 23 | } 24 | -------------------------------------------------------------------------------- /core/lib/tests/config-secret-key-1500.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "secrets")] 2 | 3 | use rocket::figment::Figment; 4 | use rocket::config::{Config, SecretKey}; 5 | 6 | #[test] 7 | fn secret_key_in_config_not_zero() { 8 | let original_key = SecretKey::generate().expect("get key"); 9 | 10 | let config = Config { secret_key: original_key.clone(), ..Default::default() }; 11 | let figment = Figment::from(config); 12 | let figment_key: SecretKey = figment.extract_inner("secret_key").unwrap(); 13 | assert_eq!(original_key, figment_key); 14 | } 15 | -------------------------------------------------------------------------------- /core/lib/tests/content-length.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate rocket; 3 | 4 | #[get("/")] 5 | fn index() -> String { 6 | "Hello, world!".into() 7 | } 8 | 9 | #[test] 10 | fn content_length_header() { 11 | let rocket = rocket::build().mount("/", routes![index]); 12 | let client = rocket::local::blocking::Client::debug(rocket).unwrap(); 13 | let response = client.get("/").dispatch(); 14 | assert!(response.headers().get_one("Content-Length").is_some()); 15 | } 16 | -------------------------------------------------------------------------------- /core/lib/tests/derive-reexports.rs: -------------------------------------------------------------------------------- 1 | use rocket::{get, routes}; 2 | use rocket::form::{FromForm, FromFormField}; 3 | use rocket::response::Responder; 4 | 5 | #[derive(FromFormField)] 6 | enum Thing { 7 | A, 8 | B, 9 | C, 10 | } 11 | 12 | impl std::fmt::Display for Thing { 13 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 14 | match *self { 15 | Thing::A => write!(f, "a"), 16 | Thing::B => write!(f, "b"), 17 | Thing::C => write!(f, "c"), 18 | } 19 | } 20 | } 21 | 22 | #[derive(FromForm)] 23 | struct ThingForm { 24 | thing: Thing, 25 | } 26 | 27 | #[derive(Responder)] 28 | struct DerivedResponder { 29 | data: String, 30 | } 31 | 32 | #[get("/")] 33 | fn index() -> DerivedResponder { 34 | DerivedResponder { data: "hello".to_string() } 35 | } 36 | 37 | #[get("/?")] 38 | fn number(params: ThingForm) -> DerivedResponder { 39 | DerivedResponder { data: params.thing.to_string() } 40 | } 41 | 42 | #[test] 43 | fn test_derive_reexports() { 44 | use rocket::local::blocking::Client; 45 | 46 | let client = Client::debug_with(routes![index, number]).unwrap(); 47 | 48 | let response = client.get("/").dispatch(); 49 | assert_eq!(response.into_string().unwrap(), "hello"); 50 | 51 | let response = client.get("/?thing=b").dispatch(); 52 | assert_eq!(response.into_string().unwrap(), "b"); 53 | } 54 | -------------------------------------------------------------------------------- /core/lib/tests/deserialize-limits-issue-2268.rs: -------------------------------------------------------------------------------- 1 | use rocket::config::Config; 2 | use rocket::data::Limits; 3 | use rocket::figment::{providers::Serialized, Figment}; 4 | use ubyte::ToByteUnit; 5 | 6 | #[test] 7 | fn deserialize_mixed_case_limits_should_work() { 8 | let figment = Figment::default() 9 | .merge(Serialized::default("key1", 1.kibibytes())) 10 | .merge(Serialized::default("key5", 5.kibibytes())) 11 | .merge(Serialized::default("key3", 3.kibibytes())) 12 | .merge(Serialized::default("Key2", 2.kibibytes())) 13 | .merge(Serialized::default("Key4", 4.kibibytes())) 14 | .merge(Serialized::default("Key6", 6.kibibytes())); 15 | 16 | let limits: Limits = figment.extract().unwrap(); 17 | assert_eq!(limits.get("key1"), Some(1.kibibytes())); 18 | assert_eq!(limits.get("key2"), Some(2.kibibytes())); 19 | assert_eq!(limits.get("key3"), Some(3.kibibytes())); 20 | assert_eq!(limits.get("key4"), Some(4.kibibytes())); 21 | assert_eq!(limits.get("key5"), Some(5.kibibytes())); 22 | assert_eq!(limits.get("key6"), Some(6.kibibytes())); 23 | } 24 | 25 | #[test] 26 | fn deserialize_extra_limits_in_config_should_work() { 27 | let extra_limits = Limits::new().limit("Phactory", 1.kibibytes()); 28 | let figment = Config::figment().merge(("limits", extra_limits)); 29 | let config = Config::from(figment); 30 | assert_eq!(config.limits.get("Phactory"), Some(1.kibibytes())); 31 | } 32 | -------------------------------------------------------------------------------- /core/lib/tests/encoded-uris.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[get("/hello süper $?a&?&")] 4 | fn index(value: &str) -> &str { 5 | value 6 | } 7 | 8 | mod encoded_uris { 9 | use rocket::local::blocking::Client; 10 | 11 | #[test] 12 | fn can_route_to_encoded_uri() { 13 | let client = Client::debug_with(routes![super::index]).unwrap(); 14 | let response = client.get("/hello%20s%C3%BCper%20%24?a&%3F&value=a+b") 15 | .dispatch() 16 | .into_string(); 17 | 18 | assert_eq!(response.unwrap(), "a b"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/lib/tests/form_value_decoding-issue-82.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::form::Form; 4 | 5 | #[post("/", data = "")] 6 | fn bug(form_data: Form) -> String { 7 | form_data.into_inner() 8 | } 9 | 10 | mod tests { 11 | use super::*; 12 | use rocket::local::blocking::Client; 13 | use rocket::http::ContentType; 14 | use rocket::http::Status; 15 | 16 | fn check_decoding(raw: &str, decoded: &str) { 17 | let client = Client::debug_with(routes![bug]).unwrap(); 18 | let response = client.post("/") 19 | .header(ContentType::Form) 20 | .body(format!("form_data={}", raw)) 21 | .dispatch(); 22 | 23 | assert_eq!(response.status(), Status::Ok); 24 | assert_eq!(Some(decoded.to_string()), response.into_string()); 25 | } 26 | 27 | #[test] 28 | fn test_proper_decoding() { 29 | check_decoding("password", "password"); 30 | check_decoding("", ""); 31 | check_decoding("+", " "); 32 | check_decoding("%2B", "+"); 33 | check_decoding("1+1", "1 1"); 34 | check_decoding("1%2B1", "1+1"); 35 | check_decoding("%3Fa%3D1%26b%3D2", "?a=1&b=2"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/lib/tests/form_value_from_encoded_str-issue-1425.rs: -------------------------------------------------------------------------------- 1 | use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; 2 | 3 | use rocket::http::RawStr; 4 | use rocket::form::Form; 5 | 6 | macro_rules! assert_from_form_field_eq { 7 | ($string:literal as $T:ty, $expected:expr) => ( 8 | let value_str = RawStr::new(concat!("=", $string)); 9 | let value = Form::<$T>::parse_encoded(value_str).unwrap(); 10 | assert_eq!(value, $expected); 11 | ) 12 | } 13 | 14 | #[test] 15 | fn test_from_form_value_encoded() { 16 | assert_from_form_field_eq!( 17 | "127.0.0.1%3A80" as SocketAddrV4, 18 | SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80) 19 | ); 20 | 21 | assert_from_form_field_eq!( 22 | "2001%3A0db8%3A85a3%3A0000%3A0000%3A8a2e%3A0370%3A7334" as Ipv6Addr, 23 | Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0, 0, 0x8a2e, 0x0370, 0x7334) 24 | ); 25 | 26 | assert_from_form_field_eq!( 27 | "%5B2001%3Adb8%3A%3A1%5D%3A8080" as SocketAddrV6, 28 | SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0) 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /core/lib/tests/local-client-access-runtime-in-drop.rs: -------------------------------------------------------------------------------- 1 | use rocket::local::blocking::Client; 2 | 3 | struct SpawnBlockingOnDrop; 4 | 5 | impl Drop for SpawnBlockingOnDrop { 6 | fn drop(&mut self) { 7 | rocket::tokio::task::spawn_blocking(|| ()); 8 | } 9 | } 10 | 11 | #[test] 12 | fn test_access_runtime_in_state_drop() { 13 | Client::debug(rocket::build().manage(SpawnBlockingOnDrop)).unwrap(); 14 | } 15 | -------------------------------------------------------------------------------- /core/lib/tests/local-client-json.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "json")] 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::serde::json::Json; 6 | 7 | #[get("/int")] fn int() -> Json { Json(5) } 8 | #[get("/nil")] fn nil() -> Json<()> { Json(()) } 9 | 10 | #[async_test] 11 | async fn async_json_works() { 12 | use rocket::local::asynchronous::Client; 13 | 14 | let client = Client::debug_with(routes![int, nil]).await.unwrap(); 15 | 16 | let int0 = client.get("/int").dispatch().await.into_json::().await; 17 | let int1 = client.get("/int").dispatch().await.into_json::().await; 18 | 19 | assert_eq!(int0, Some(5)); 20 | assert_eq!(int1, Some(5)); 21 | 22 | let nil0 = client.get("/nil").dispatch().await.into_json::<()>().await; 23 | assert_eq!(nil0, Some(())); 24 | } 25 | -------------------------------------------------------------------------------- /core/lib/tests/local_request_private_cookie-issue-368.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "secrets")] 2 | 3 | use rocket::http::CookieJar; 4 | 5 | #[rocket::get("/")] 6 | fn return_private_cookie(cookies: &CookieJar<'_>) -> Option { 7 | match cookies.get_private("cookie_name") { 8 | Some(cookie) => Some(cookie.value().into()), 9 | None => None, 10 | } 11 | } 12 | 13 | mod tests { 14 | use super::*; 15 | use rocket::routes; 16 | use rocket::local::blocking::Client; 17 | use rocket::http::Status; 18 | 19 | #[test] 20 | fn private_cookie_is_returned() { 21 | let rocket = rocket::build().mount("/", routes![return_private_cookie]); 22 | 23 | let client = Client::debug(rocket).unwrap(); 24 | let req = client.get("/").private_cookie(("cookie_name", "cookie_value")); 25 | let response = req.dispatch(); 26 | 27 | assert_eq!(response.headers().get_one("Set-Cookie"), None); 28 | assert_eq!(response.into_string(), Some("cookie_value".into())); 29 | } 30 | 31 | #[test] 32 | fn regular_cookie_is_not_returned() { 33 | let rocket = rocket::build().mount("/", routes![return_private_cookie]); 34 | 35 | let client = Client::debug(rocket).unwrap(); 36 | let req = client.get("/").cookie(("cookie_name", "cookie_value")); 37 | let response = req.dispatch(); 38 | 39 | assert_eq!(response.status(), Status::NotFound); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/lib/tests/mount_point.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | #[should_panic] 3 | fn bad_dynamic_mount() { 4 | let _ = rocket::build().mount("", vec![]); 5 | } 6 | 7 | #[test] 8 | fn good_static_mount() { 9 | let _ = rocket::build().mount("/abcdefghijkl_mno", vec![]); 10 | } 11 | -------------------------------------------------------------------------------- /core/lib/tests/on_launch_fairing_can_inspect_port.rs: -------------------------------------------------------------------------------- 1 | use std::net::{SocketAddr, Ipv4Addr}; 2 | 3 | use rocket::config::Config; 4 | use rocket::fairing::AdHoc; 5 | use rocket::futures::channel::oneshot; 6 | use rocket::listener::tcp::TcpListener; 7 | 8 | #[rocket::async_test] 9 | async fn on_ignite_fairing_can_inspect_port() { 10 | let (tx, rx) = oneshot::channel(); 11 | let rocket = rocket::custom(Config::debug_default()) 12 | .attach(AdHoc::on_liftoff("Send Port -> Channel", move |rocket| { 13 | Box::pin(async move { 14 | let tcp = rocket.endpoints().find_map(|v| v.tcp()); 15 | tx.send(tcp.unwrap().port()).expect("send okay"); 16 | }) 17 | })); 18 | 19 | let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 0)); 20 | rocket::tokio::spawn(rocket.try_launch_on(TcpListener::bind(addr))); 21 | assert_ne!(rx.await.unwrap(), 0); 22 | } 23 | -------------------------------------------------------------------------------- /core/lib/tests/raw-strings-multipart-files-1987.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::form::Form; 4 | use rocket::http::ContentType; 5 | use rocket::local::blocking::Client; 6 | 7 | #[derive(FromForm)] 8 | struct Data<'r> { 9 | foo: &'r str, 10 | bar: &'r str, 11 | baz: &'r str, 12 | } 13 | 14 | #[rocket::post("/", data = "")] 15 | fn form(form: Form>) -> String { 16 | form.foo.to_string() + form.bar + form.baz 17 | } 18 | 19 | #[test] 20 | fn test_multipart_raw_strings_from_files() { 21 | let body = &[ 22 | "--X-BOUNDARY", 23 | r#"Content-Disposition: form-data; name="foo"; filename="foo.txt""#, 24 | "Content-Type: text/plain", 25 | "", 26 | "hi", 27 | "--X-BOUNDARY", 28 | r#"Content-Disposition: form-data; name="bar"; filename="bar.txt""#, 29 | "Content-Type: text/plain", 30 | "", 31 | "hey", 32 | "--X-BOUNDARY", 33 | r#"Content-Disposition: form-data; name="baz"; filename="baz.txt""#, 34 | "Content-Type: text/plain", 35 | "", 36 | "bye", 37 | "--X-BOUNDARY--", 38 | "", 39 | ].join("\r\n"); 40 | 41 | let client = Client::debug_with(rocket::routes![form]).unwrap(); 42 | let response = client.post("/") 43 | .header("multipart/form-data; boundary=X-BOUNDARY".parse::().unwrap()) 44 | .body(body) 45 | .dispatch(); 46 | 47 | assert_eq!(response.into_string().unwrap(), "hiheybye"); 48 | } 49 | -------------------------------------------------------------------------------- /core/lib/tests/redirect_from_catcher-issue-113.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::response::Redirect; 4 | 5 | #[catch(404)] 6 | fn not_found() -> Redirect { 7 | Redirect::to("/") 8 | } 9 | 10 | mod tests { 11 | use super::*; 12 | use rocket::local::blocking::Client; 13 | use rocket::http::Status; 14 | 15 | #[test] 16 | fn error_catcher_redirect() { 17 | let client = Client::debug(rocket::build().register("/", catchers![not_found])).unwrap(); 18 | let response = client.get("/unknown").dispatch(); 19 | 20 | let location: Vec<_> = response.headers().get("location").collect(); 21 | assert_eq!(response.status(), Status::SeeOther); 22 | assert_eq!(location, vec!["/"]); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/lib/tests/replace-content-type-518.rs: -------------------------------------------------------------------------------- 1 | use rocket::{Rocket, Build}; 2 | use rocket::{fairing::AdHoc, http::ContentType, local::blocking::Client}; 3 | 4 | #[rocket::post("/", data = "<_data>", format = "json")] 5 | fn index(_data: rocket::Data<'_>) -> &'static str { "json" } 6 | 7 | #[rocket::post("/", data = "<_data>", rank = 2)] 8 | fn other_index(_data: rocket::Data<'_>) -> &'static str { "other" } 9 | 10 | fn rocket() -> Rocket { 11 | rocket::build() 12 | .mount("/", rocket::routes![index, other_index]) 13 | .attach(AdHoc::on_request("Change CT", |req, _| Box::pin(async move { 14 | let need_ct = req.content_type().is_none(); 15 | if req.uri().path().starts_with("/add") { 16 | req.set_uri(rocket::uri!(index)); 17 | if need_ct { req.add_header(ContentType::JSON); } 18 | } else if need_ct { 19 | req.replace_header(ContentType::JSON); 20 | } 21 | }))) 22 | } 23 | 24 | #[test] 25 | fn check_fairing_changes_content_type() { 26 | let client = Client::debug(rocket()).unwrap(); 27 | let response = client.post("/").header(ContentType::PNG).dispatch(); 28 | assert_eq!(response.into_string().unwrap(), "other"); 29 | 30 | let response = client.post("/").dispatch(); 31 | assert_eq!(response.into_string().unwrap(), "json"); 32 | 33 | let response = client.post("/add").dispatch(); 34 | assert_eq!(response.into_string().unwrap(), "json"); 35 | 36 | let response = client.post("/add").header(ContentType::HTML).dispatch(); 37 | assert_eq!(response.into_string().unwrap(), "other"); 38 | } 39 | -------------------------------------------------------------------------------- /core/lib/tests/responder_lifetime-issue-345.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] // This test is only here so that we can ensure it compiles. 2 | 3 | #[macro_use] extern crate rocket; 4 | 5 | use rocket::{Request, State}; 6 | use rocket::response::{Responder, Result}; 7 | 8 | struct SomeState; 9 | 10 | pub struct CustomResponder<'r, R> { 11 | responder: R, 12 | state: &'r SomeState, 13 | } 14 | 15 | impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for CustomResponder<'r, R> { 16 | fn respond_to(self, req: &'r Request<'_>) -> Result<'o> { 17 | self.responder.respond_to(req) 18 | } 19 | } 20 | 21 | #[get("/unit_state")] 22 | fn unit_state(state: &State) -> CustomResponder<'_, ()> { 23 | CustomResponder { responder: (), state: &*state } 24 | } 25 | 26 | #[get("/string_state")] 27 | fn string_state(state: &State) -> CustomResponder<'_, String> { 28 | CustomResponder { responder: "".to_string(), state: &*state } 29 | } 30 | -------------------------------------------------------------------------------- /core/lib/tests/route_guard.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use std::path::{Path, PathBuf}; 4 | use rocket::http::ext::Normalize; 5 | use rocket::Route; 6 | 7 | #[get("/")] 8 | fn files(route: &Route, path: PathBuf) -> String { 9 | Path::new(&route.uri.base()).join(path).normalized_str().to_string() 10 | } 11 | 12 | mod route_guard_tests { 13 | use super::*; 14 | use rocket::local::blocking::Client; 15 | 16 | fn assert_path(client: &Client, path: &str) { 17 | let res = client.get(path).dispatch(); 18 | assert_eq!(res.into_string(), Some(path.into())); 19 | } 20 | 21 | #[test] 22 | fn check_mount_path() { 23 | let rocket = rocket::build() 24 | .mount("/first", routes![files]) 25 | .mount("/second", routes![files]); 26 | 27 | let client = Client::debug(rocket).unwrap(); 28 | assert_path(&client, "/first/some/path"); 29 | assert_path(&client, "/second/some/path"); 30 | assert_path(&client, "/first/second/b/c"); 31 | assert_path(&client, "/second/a/b/c"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/lib/tests/scoped-uri.rs: -------------------------------------------------------------------------------- 1 | use rocket::{Rocket, Build}; 2 | use rocket::local::blocking::Client; 3 | 4 | mod inner { 5 | use rocket::uri; 6 | 7 | #[rocket::get("/")] 8 | pub fn hello() -> String { 9 | format!("Hello! Try {}.", uri!(super::hello_name("Rust 2018"))) 10 | } 11 | } 12 | 13 | #[rocket::get("/")] 14 | fn hello_name(name: String) -> String { 15 | format!("Hello, {}! This is {}.", name, rocket::uri!(hello_name(&name))) 16 | } 17 | 18 | fn rocket() -> Rocket { 19 | rocket::build() 20 | .mount("/", rocket::routes![hello_name]) 21 | .mount("/", rocket::routes![inner::hello]) 22 | } 23 | 24 | #[test] 25 | fn test_inner_hello() { 26 | let client = Client::debug(rocket()).unwrap(); 27 | let response = client.get("/").dispatch(); 28 | assert_eq!(response.into_string(), Some("Hello! Try /Rust%202018.".into())); 29 | } 30 | 31 | #[test] 32 | fn test_hello_name() { 33 | let client = Client::debug(rocket()).unwrap(); 34 | let response = client.get("/Rust%202018").dispatch(); 35 | assert_eq!(response.into_string().unwrap(), "Hello, Rust 2018! This is /Rust%202018."); 36 | } 37 | -------------------------------------------------------------------------------- /core/lib/tests/session-cookies-issue-1506.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "secrets")] 2 | 3 | use rocket::http::{CookieJar, Cookie}; 4 | 5 | #[rocket::get("/")] 6 | fn index(jar: &CookieJar<'_>) { 7 | jar.add_private(Cookie::build(("key", "value")).expires(None)); 8 | } 9 | 10 | mod test_session_cookies { 11 | use super::*; 12 | use rocket::local::blocking::Client; 13 | 14 | #[test] 15 | fn session_cookie_is_session() { 16 | let rocket = rocket::build().mount("/", rocket::routes![index]); 17 | let client = Client::debug(rocket).unwrap(); 18 | 19 | let response = client.get("/").dispatch(); 20 | let cookie = response.cookies().get_private("key").unwrap(); 21 | assert_eq!(cookie.expires_datetime(), None); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/lib/tests/static/.hidden: -------------------------------------------------------------------------------- 1 | Peek-a-boo. 2 | -------------------------------------------------------------------------------- /core/lib/tests/static/index.html: -------------------------------------------------------------------------------- 1 | Just a file here: index.html. 2 | -------------------------------------------------------------------------------- /core/lib/tests/static/inner/.hideme: -------------------------------------------------------------------------------- 1 | Oh no! 2 | -------------------------------------------------------------------------------- /core/lib/tests/static/inner/goodbye: -------------------------------------------------------------------------------- 1 | Thanks for coming! 2 | -------------------------------------------------------------------------------- /core/lib/tests/static/inner/index.html: -------------------------------------------------------------------------------- 1 | Inner index.html 2 | -------------------------------------------------------------------------------- /core/lib/tests/static/other/hello.txt: -------------------------------------------------------------------------------- 1 | Hi! 2 | -------------------------------------------------------------------------------- /core/lib/tests/static/other/index.htm: -------------------------------------------------------------------------------- 1 | Inner index.htm 2 | -------------------------------------------------------------------------------- /core/lib/tests/timer-on-attach.rs: -------------------------------------------------------------------------------- 1 | #[rocket::async_test] 2 | async fn test_await_timer_inside_attach() { 3 | 4 | async fn do_async_setup() { 5 | // By using a timer or I/O resource, we ensure that do_async_setup will 6 | // deadlock if no thread is able to tick the time or I/O drivers. 7 | rocket::tokio::time::sleep(std::time::Duration::from_millis(100)).await; 8 | } 9 | 10 | let _ = rocket::build() 11 | .attach(rocket::fairing::AdHoc::on_ignite("1", |rocket| async { 12 | do_async_setup().await; 13 | rocket 14 | })); 15 | } 16 | -------------------------------------------------------------------------------- /core/lib/tests/tls-config-from-source-1503.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "tls")] 2 | 3 | macro_rules! relative { 4 | ($path:expr) => { 5 | std::path::Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/", $path)) 6 | }; 7 | } 8 | 9 | #[test] 10 | fn tls_config_from_source() { 11 | use rocket::tls::TlsConfig; 12 | use rocket::figment::{Figment, providers::Serialized}; 13 | 14 | let cert_path = relative!("examples/tls/private/cert.pem"); 15 | let key_path = relative!("examples/tls/private/key.pem"); 16 | let config = TlsConfig::from_paths(cert_path, key_path); 17 | 18 | let tls: TlsConfig = Figment::from(Serialized::globals(config)).extract().unwrap(); 19 | assert_eq!(tls.certs().unwrap_left(), cert_path); 20 | assert_eq!(tls.key().unwrap_left(), key_path); 21 | } 22 | -------------------------------------------------------------------------------- /core/lib/tests/twice_managed_state.rs: -------------------------------------------------------------------------------- 1 | struct A; 2 | 3 | #[test] 4 | #[should_panic] 5 | fn twice_managed_state() { 6 | let _ = rocket::build().manage(A).manage(A); 7 | } 8 | -------------------------------------------------------------------------------- /core/lib/tests/typed-uri-docs-redef-issue-1373.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] // This test is only here to ensure it compiles. 2 | #![allow(unused_variables)] // This test is only here to ensure it compiles. 3 | 4 | mod a { 5 | /// Docs. 6 | #[rocket::post("/typed_uris/")] 7 | fn simple(id: i32) { } 8 | } 9 | 10 | mod b { 11 | /// Docs. 12 | #[rocket::post("/typed_uris/")] 13 | fn simple(id: i32) { } 14 | } 15 | -------------------------------------------------------------------------------- /core/lib/tests/unsound-local-request-1312.rs: -------------------------------------------------------------------------------- 1 | use rocket::http::Header; 2 | use rocket::local::blocking::Client; 3 | 4 | #[test] 5 | fn test_local_request_clone_soundness() { 6 | let client = Client::debug_with(vec![]).unwrap(); 7 | 8 | // creates two LocalRequest instances that shouldn't share the same req 9 | let r1 = client.get("/").header(Header::new("key", "val1")); 10 | let mut r2 = r1.clone(); 11 | 12 | // save the iterator, which internally holds a slice 13 | let mut iter = r1.inner().headers().get("key"); 14 | 15 | // insert headers to force header map reallocation. 16 | for i in 0..100 { 17 | r2.add_header(Header::new(i.to_string(), i.to_string())); 18 | } 19 | 20 | // Replace the original key/val. 21 | r2.add_header(Header::new("key", "val2")); 22 | 23 | // Heap massage: so we've got crud to print. 24 | let _: Vec = vec![0, 0xcafebabe, 31337, 0]; 25 | 26 | // Ensure we're good. 27 | let s = iter.next().unwrap(); 28 | println!("{}", s); 29 | 30 | // And that we've got the right data. 31 | assert_eq!(r1.inner().headers().get("key").collect::>(), vec!["val1"]); 32 | assert_eq!(r2.inner().headers().get("key").collect::>(), vec!["val1", "val2"]); 33 | } 34 | -------------------------------------------------------------------------------- /core/lib/tests/untracked-vs-tracked.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::http::CookieJar; 4 | 5 | #[post("/")] 6 | fn add(jar: &CookieJar<'_>) { 7 | jar.add(("name", "value")); 8 | } 9 | 10 | #[get("/")] 11 | fn get<'a>(jar: &'a CookieJar<'_>) -> Option<&'a str> { 12 | jar.get("name").map(|c| c.value()) 13 | } 14 | 15 | #[cfg(test)] 16 | mod many_cookie_jars_tests { 17 | use super::*; 18 | use rocket::{Rocket, local::blocking::Client, Build}; 19 | use rocket::http::Status; 20 | 21 | fn rocket() -> Rocket { 22 | rocket::custom(rocket::Config::debug_default()) 23 | .mount("/", routes![add, get]) 24 | } 25 | 26 | #[test] 27 | fn test_tracked() { 28 | let client = Client::tracked(rocket()).unwrap(); 29 | 30 | assert_eq!(client.get("/").dispatch().status(), Status::NotFound); 31 | assert_eq!(client.post("/").dispatch().status(), Status::Ok); 32 | 33 | let response = client.get("/").dispatch(); 34 | assert_eq!(response.status(), Status::Ok); 35 | assert_eq!(response.into_string().unwrap(), "value"); 36 | } 37 | 38 | #[test] 39 | fn test_untracked() { 40 | let client = Client::untracked(rocket()).unwrap(); 41 | 42 | assert_eq!(client.get("/").dispatch().status(), Status::NotFound); 43 | assert_eq!(client.post("/").dispatch().status(), Status::Ok); 44 | assert_eq!(client.get("/").dispatch().status(), Status::NotFound); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /docs/guide/01-upgrading.md: -------------------------------------------------------------------------------- 1 | +++ 2 | summary = "a migration guide from Rocket v0.5 to v0.6" 3 | +++ 4 | 5 | # Upgrading 6 | 7 | This a placeholder for an eventual migration guide from v0.5 to v0.6. 8 | 9 | ## Getting Help 10 | 11 | If you run into any issues upgrading, we encourage you to ask questions via 12 | [GitHub discussions] or via chat at [`#rocket:mozilla.org`] on Matrix. The 13 | [FAQ](../faq/) also provides answers to commonly asked questions. 14 | 15 | [GitHub discussions]: @github/discussions 16 | [`#rocket:mozilla.org`]: @chat 17 | -------------------------------------------------------------------------------- /docs/guide/02-quickstart.md: -------------------------------------------------------------------------------- 1 | +++ 2 | summary = "the minimal steps to running your first Rocket application" 3 | +++ 4 | 5 | # Quickstart 6 | 7 | Before you can start writing a Rocket application, you'll need to install the 8 | Rust toolchain. We recommend using [rustup](https://rustup.rs/). If you don't 9 | have Rust installed and would like extra guidance doing so, see [Getting 10 | Started]. 11 | 12 | ## Running Examples 13 | 14 | The absolute fastest way to start experimenting with Rocket is to clone the 15 | Rocket repository and run the included examples in the `examples/` directory. 16 | For instance, the following set of commands runs the `hello` example: 17 | 18 | ```sh 19 | git clone https://github.com/rwf2/Rocket 20 | cd Rocket 21 | git checkout master 22 | cd examples/hello 23 | cargo run 24 | ``` 25 | 26 | There are numerous examples in the `examples/` directory. They can all be run 27 | with `cargo run`. 28 | 29 | ! note 30 | 31 | The examples' `Cargo.toml` files will point to the locally cloned `rocket` 32 | libraries. When copying the examples for your own use, you should modify the 33 | `Cargo.toml` files as explained in the [Getting Started] guide. 34 | 35 | [Getting Started]: ../getting-started/ 36 | -------------------------------------------------------------------------------- /docs/guide/13-conclusion.md: -------------------------------------------------------------------------------- 1 | +++ 2 | summary = "next steps, and learning more about Rocket" 3 | +++ 4 | 5 | # Conclusion 6 | 7 | We hope you agree that Rocket is a refreshing take on web frameworks. As with 8 | any software project, Rocket is _alive_. There are always things to improve, and 9 | we're happy to take the best ideas. If you have something in mind, please 10 | [submit an issue](https://github.com/rwf2/Rocket/issues). 11 | 12 | ## Getting Help 13 | 14 | If you find yourself having trouble developing Rocket applications, you can get 15 | help via chat at [`#rocket:mozilla.org`] on Matrix. The [FAQ](../faq/) also 16 | provides answers to commonly asked questions. 17 | 18 | [`#rocket:mozilla.org`]: @chat 19 | 20 | ## What's next? 21 | 22 | The best way to learn Rocket is to _build something_. It should be fun and easy, 23 | and there's always someone to help. Alternatively, you can read through the 24 | [Rocket examples](@git/master/examples) or the [Rocket source code](@git/master/core/lib/src). 25 | Whatever you decide to do next, we hope you have a blast! 26 | -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | # The Rocket Programming Guide 2 | 3 | Welcome to Rocket! 4 | 5 | This is the official guide for Rocket v0.6. 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/master/rocket). 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 | ================================================================================ 15 | 16 | ## Getting Help 17 | 18 | The official community support channels are via Matrix chat on 19 | [`#rocket:mozilla.org`] and via [GitHub Discussions]. To join us on Matrix, we 20 | recommend the browser-based [Element] client. The [FAQ](faq/) also provides 21 | answers to commonly asked questions. 22 | 23 | [`#rocket:mozilla.org`]: @chat 24 | [GitHub Discussions]: https://github.com/rwf2/Rocket/discussions 25 | [Element]: https://chat.mozilla.org/#/room/#rocket:mozilla.org 26 | -------------------------------------------------------------------------------- /docs/tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_docs_tests" 3 | version = "0.6.0-dev" 4 | workspace = "../../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [lints] 9 | workspace = true 10 | 11 | [dependencies] 12 | rocket = { path = "../../core/lib", features = ["secrets"] } 13 | 14 | [dev-dependencies] 15 | rocket = { path = "../../core/lib", features = ["secrets", "json", "mtls"] } 16 | figment = { version = "0.10.17", features = ["toml", "env"] } 17 | tokio = { version = "1", features = ["macros", "io-std"] } 18 | rand = "0.8" 19 | 20 | [dev-dependencies.rocket_dyn_templates] 21 | path = "../../contrib/dyn_templates" 22 | features = ["tera"] 23 | 24 | [dev-dependencies.rocket_db_pools] 25 | path = "../../contrib/db_pools/lib" 26 | features = ["sqlx_sqlite"] 27 | 28 | [dev-dependencies.rocket_ws] 29 | path = "../../contrib/ws" 30 | -------------------------------------------------------------------------------- /docs/tests/src/guide.rs: -------------------------------------------------------------------------------- 1 | rocket::internal_guide_tests!("../guide/*.md"); 2 | -------------------------------------------------------------------------------- /docs/tests/src/readme.rs: -------------------------------------------------------------------------------- 1 | rocket::internal_guide_tests!("../../README.md"); 2 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "config", 5 | "cookies", 6 | "databases", 7 | "error-handling", 8 | "fairings", 9 | "forms", 10 | "hello", 11 | "manual-routing", 12 | "responders", 13 | "serialization", 14 | "state", 15 | "static-files", 16 | "templating", 17 | "testing", 18 | "tls", 19 | "upgrade", 20 | 21 | "pastebin", 22 | "todo", 23 | "chat", 24 | ] 25 | -------------------------------------------------------------------------------- /examples/chat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chat" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib", features = ["json"] } 10 | 11 | [dev-dependencies] 12 | rand = "0.8" 13 | -------------------------------------------------------------------------------- /examples/chat/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rocket Rooms 6 | 7 | 8 | 9 | 10 | 11 |
12 | 27 | 28 |
29 | 30 |
31 | 37 |
38 | 39 |
40 | 42 | 44 | 45 |
46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/chat/static/reset.css: -------------------------------------------------------------------------------- 1 | html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe,button,input{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} 2 | -------------------------------------------------------------------------------- /examples/config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "config" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib", features = ["secrets"] } 10 | -------------------------------------------------------------------------------- /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 | [default.limits] 5 | forms = "64 kB" 6 | json = "1 MiB" 7 | msgpack = "2 MiB" 8 | "file/jpg" = "5 MiB" 9 | 10 | [default] 11 | key = "a default app-key" 12 | extra = false 13 | ident = "Rocket" 14 | ip_header = "CF-Connecting-IP" 15 | 16 | [debug] 17 | address = "127.0.0.1" 18 | port = 8000 19 | workers = 1 20 | keep_alive = 0 21 | log_level = "info" 22 | log_format = "pretty" 23 | 24 | [release] 25 | address = "127.0.0.1" 26 | port = 8000 27 | workers = 12 28 | keep_alive = 5 29 | log_level = "error" 30 | log_format = "compact" 31 | # NOTE: Don't (!) use this key! Generate your own and keep it private! 32 | # e.g. via `head -c64 /dev/urandom | base64` 33 | secret_key = "hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk=" 34 | key = "a release app-key" 35 | extra = false 36 | -------------------------------------------------------------------------------- /examples/config/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[cfg(test)] mod tests; 4 | 5 | use rocket::{State, Config}; 6 | use rocket::fairing::AdHoc; 7 | use rocket::serde::Deserialize; 8 | 9 | #[derive(Debug, Deserialize)] 10 | #[serde(crate = "rocket::serde")] 11 | #[allow(dead_code)] 12 | struct AppConfig { 13 | key: String, 14 | port: u16 15 | } 16 | 17 | #[get("/")] 18 | fn read_config(rocket_config: &Config, app_config: &State) -> String { 19 | format!("{:#?}\n{:#?}", app_config, rocket_config) 20 | } 21 | 22 | // See Rocket.toml file. Running this server will print the config. Try running 23 | // with `ROCKET_PROFILE=release` manually by setting the environment variable 24 | // and automatically by compiling with `--release`. 25 | #[launch] 26 | fn rocket() -> _ { 27 | rocket::build() 28 | .mount("/", routes![read_config]) 29 | .attach(AdHoc::config::()) 30 | } 31 | -------------------------------------------------------------------------------- /examples/config/src/tests.rs: -------------------------------------------------------------------------------- 1 | use rocket::config::Config; 2 | use rocket::trace::{Level, TraceFormat}; 3 | 4 | async fn test_config(profile: &str) { 5 | let provider = Config::figment().select(profile); 6 | let rocket = rocket::custom(provider).ignite().await.unwrap(); 7 | let config = rocket.config(); 8 | match profile { 9 | "debug" => { 10 | assert_eq!(config.workers, 1); 11 | assert_eq!(config.keep_alive, 0); 12 | assert_eq!(config.log_level, Some(Level::INFO)); 13 | assert_eq!(config.log_format, TraceFormat::Pretty); 14 | } 15 | "release" => { 16 | assert_eq!(config.workers, 12); 17 | assert_eq!(config.keep_alive, 5); 18 | assert_eq!(config.log_level, Some(Level::ERROR)); 19 | assert_eq!(config.log_format, TraceFormat::Compact); 20 | assert!(!config.secret_key.is_zero()); 21 | } 22 | _ => { 23 | panic!("Unknown profile: {}", profile); 24 | } 25 | } 26 | } 27 | 28 | #[async_test] 29 | async fn test_debug_config() { 30 | test_config("debug").await; 31 | } 32 | 33 | #[async_test] 34 | async fn test_release_config() { 35 | test_config("release").await; 36 | } 37 | -------------------------------------------------------------------------------- /examples/cookies/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cookies" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib", features = ["secrets"] } 10 | 11 | [dependencies.rocket_dyn_templates] 12 | path = "../../contrib/dyn_templates" 13 | features = ["handlebars"] 14 | -------------------------------------------------------------------------------- /examples/cookies/Rocket.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | secret_key = "itlYmFR2vYKrOmFhupMIn/hyB6lYCCTXz4yaQX89XVg=" 3 | template_dir = "templates" 4 | -------------------------------------------------------------------------------- /examples/cookies/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[cfg(test)] mod tests; 4 | 5 | mod session; 6 | mod message; 7 | 8 | use rocket::response::content::RawHtml; 9 | use rocket_dyn_templates::Template; 10 | 11 | #[get("/")] 12 | fn index() -> RawHtml<&'static str> { 13 | RawHtml(r#"
Set a Message or Use Sessions."#) 14 | } 15 | 16 | #[launch] 17 | fn rocket() -> _ { 18 | rocket::build() 19 | .attach(Template::fairing()) 20 | .mount("/", routes![index]) 21 | .mount("/message", message::routes()) 22 | .mount("/session", session::routes()) 23 | } 24 | -------------------------------------------------------------------------------- /examples/cookies/src/message.rs: -------------------------------------------------------------------------------- 1 | use rocket::form::Form; 2 | use rocket::response::Redirect; 3 | use rocket::http::CookieJar; 4 | use rocket_dyn_templates::{Template, context}; 5 | 6 | #[macro_export] 7 | macro_rules! message_uri { 8 | ($($t:tt)*) => (rocket::uri!("/message", $crate::message:: $($t)*)) 9 | } 10 | 11 | pub use message_uri as uri; 12 | 13 | #[post("/", data = "")] 14 | fn submit(cookies: &CookieJar<'_>, message: Form<&str>) -> Redirect { 15 | cookies.add(("message", message.to_string())); 16 | Redirect::to(uri!(index)) 17 | } 18 | 19 | #[delete("/")] 20 | fn delete(cookies: &CookieJar<'_>) -> Redirect { 21 | cookies.remove("message"); 22 | Redirect::to(uri!(index)) 23 | } 24 | 25 | #[get("/")] 26 | fn index(cookies: &CookieJar<'_>) -> Template { 27 | let message = cookies.get("message").map(|c| c.value()); 28 | let present = cookies.get("message").is_some(); 29 | Template::render("message", context! { present, message }) 30 | } 31 | 32 | pub fn routes() -> Vec { 33 | routes![index, submit, delete] 34 | } 35 | -------------------------------------------------------------------------------- /examples/cookies/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 message}} 14 |

{{#if kind}}{{kind}}: {{/if}}{{ message }}

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

23 |
24 | 25 | Home 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/cookies/templates/message.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Rocket: Cookie Message 7 | 8 | 9 |

Rocket Cookie Message

10 | 11 |

12 | {{#if present}} 13 | {{#if message}} 14 | Message: {{message}} 15 | {{else}} 16 | Message: [empty message] 17 | {{/if}} 18 | {{else}} 19 | No message yet. 20 | {{/if}} 21 |

22 | 23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 | 31 |

32 | 33 | 34 |

35 | 36 | Home 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/cookies/templates/session.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 | Home 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/databases/.sqlx/query-11e3096becb72f427c8d3911ef4327afd9516143806981e11f8e34d069c14472.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "SELECT id, title, text FROM posts WHERE id = ?", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "id", 8 | "ordinal": 0, 9 | "type_info": "Integer" 10 | }, 11 | { 12 | "name": "title", 13 | "ordinal": 1, 14 | "type_info": "Text" 15 | }, 16 | { 17 | "name": "text", 18 | "ordinal": 2, 19 | "type_info": "Text" 20 | } 21 | ], 22 | "parameters": { 23 | "Right": 1 24 | }, 25 | "nullable": [ 26 | false, 27 | false, 28 | false 29 | ] 30 | }, 31 | "hash": "11e3096becb72f427c8d3911ef4327afd9516143806981e11f8e34d069c14472" 32 | } 33 | -------------------------------------------------------------------------------- /examples/databases/.sqlx/query-4415c35941e52a981b10707fe2e1ceb0bad0e473701e51ef21ecb2973c76b4df.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "SELECT id FROM posts", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "id", 8 | "ordinal": 0, 9 | "type_info": "Integer" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 0 14 | }, 15 | "nullable": [ 16 | false 17 | ] 18 | }, 19 | "hash": "4415c35941e52a981b10707fe2e1ceb0bad0e473701e51ef21ecb2973c76b4df" 20 | } 21 | -------------------------------------------------------------------------------- /examples/databases/.sqlx/query-668690acaca0a0c0b4ac306b14d82aa1bee940f0776fae3f9962639b78328858.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "DELETE FROM posts", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 0 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "668690acaca0a0c0b4ac306b14d82aa1bee940f0776fae3f9962639b78328858" 12 | } 13 | -------------------------------------------------------------------------------- /examples/databases/.sqlx/query-79301b44b77802e0096efd73b1e9adac27b27a3cf7bf853af3a9f130b1684d91.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "DELETE FROM posts WHERE id = ?", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 1 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "79301b44b77802e0096efd73b1e9adac27b27a3cf7bf853af3a9f130b1684d91" 12 | } 13 | -------------------------------------------------------------------------------- /examples/databases/.sqlx/query-bea4ef6e25064f6b383e854f8bc2770d89cfaf9859d0bfca78b2ca24627675b7.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "INSERT INTO posts (title, text) VALUES (?, ?) RETURNING id", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "id", 8 | "ordinal": 0, 9 | "type_info": "Integer" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 2 14 | }, 15 | "nullable": [ 16 | false 17 | ] 18 | }, 19 | "hash": "bea4ef6e25064f6b383e854f8bc2770d89cfaf9859d0bfca78b2ca24627675b7" 20 | } 21 | -------------------------------------------------------------------------------- /examples/databases/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "databases" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib", features = ["json"] } 10 | diesel = { version = "2", features = ["returning_clauses_for_sqlite_3_35"] } 11 | diesel_migrations = "2" 12 | 13 | [dependencies.sqlx] 14 | version = "0.8.0" 15 | default-features = false 16 | features = ["macros", "migrate"] 17 | 18 | [dependencies.rocket_db_pools] 19 | path = "../../contrib/db_pools/lib/" 20 | features = ["sqlx_sqlite", "diesel_mysql"] 21 | 22 | [dependencies.rocket_sync_db_pools] 23 | path = "../../contrib/sync_db_pools/lib/" 24 | features = ["diesel_sqlite_pool", "sqlite_pool"] 25 | -------------------------------------------------------------------------------- /examples/databases/Rocket.toml: -------------------------------------------------------------------------------- 1 | [default.databases.rusqlite] 2 | url = "file:rusqlite?mode=memory&cache=shared" 3 | 4 | [default.databases.sqlx] 5 | url = "db/sqlx/db.sqlite" 6 | 7 | [default.databases.diesel] 8 | url = "db/diesel/db.sqlite" 9 | timeout = 10 10 | 11 | [default.databases.diesel_mysql] 12 | url = "mysql://user:password@127.0.0.1/database" 13 | -------------------------------------------------------------------------------- /examples/databases/db/diesel/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/databases/db/diesel/migrations/.gitkeep -------------------------------------------------------------------------------- /examples/databases/db/diesel/migrations/20210329150332_create_posts_table/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE posts; 2 | -------------------------------------------------------------------------------- /examples/databases/db/diesel/migrations/20210329150332_create_posts_table/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE posts ( 2 | id INTEGER PRIMARY KEY AUTOINCREMENT, 3 | title VARCHAR NOT NULL, 4 | text VARCHAR NOT NULL, 5 | published BOOLEAN NOT NULL DEFAULT 0 6 | ); 7 | -------------------------------------------------------------------------------- /examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE posts; 2 | -------------------------------------------------------------------------------- /examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE posts ( 2 | id INTEGER AUTO_INCREMENT PRIMARY KEY, 3 | title VARCHAR(255) NOT NULL, 4 | text TEXT NOT NULL, 5 | published BOOLEAN NOT NULL DEFAULT FALSE 6 | ); 7 | -------------------------------------------------------------------------------- /examples/databases/db/sqlx/migrations/20210331024424_create-posts-table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE posts ( 2 | id INTEGER PRIMARY KEY AUTOINCREMENT, 3 | title VARCHAR NOT NULL, 4 | text VARCHAR NOT NULL, 5 | published BOOLEAN NOT NULL DEFAULT 0 6 | ); 7 | -------------------------------------------------------------------------------- /examples/databases/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | #[macro_use] extern crate rocket_sync_db_pools; 3 | 4 | #[cfg(test)] mod tests; 5 | 6 | mod sqlx; 7 | mod diesel_sqlite; 8 | mod diesel_mysql; 9 | mod rusqlite; 10 | 11 | use rocket::response::Redirect; 12 | 13 | #[get("/")] 14 | fn index() -> Redirect { 15 | Redirect::to(uri!("/sqlx", sqlx::list())) 16 | } 17 | 18 | #[launch] 19 | fn rocket() -> _ { 20 | rocket::build() 21 | .mount("/", routes![index]) 22 | .attach(sqlx::stage()) 23 | .attach(rusqlite::stage()) 24 | .attach(diesel_sqlite::stage()) 25 | .attach(diesel_mysql::stage()) 26 | } 27 | -------------------------------------------------------------------------------- /examples/error-handling/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "error-handling" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/fairings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fairings" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/fairings/Rocket.toml: -------------------------------------------------------------------------------- 1 | [global] 2 | token = 123 3 | -------------------------------------------------------------------------------- /examples/fairings/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::rocket; 2 | use rocket::local::blocking::Client; 3 | 4 | #[test] 5 | fn rewrite_get_put() { 6 | let client = Client::tracked(rocket()).unwrap(); 7 | let response = client.get("/").dispatch(); 8 | assert_eq!(response.into_string(), Some("Hello, fairings!".into())); 9 | } 10 | 11 | #[test] 12 | fn counts() { 13 | let client = Client::tracked(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 response = client.get("/counts").dispatch(); 20 | assert_eq!(response.into_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 response = client.get("/counts").dispatch(); 28 | assert_eq!(response.into_string(), Some("Get: 4\nPost: 1".into())); 29 | } 30 | 31 | #[test] 32 | fn token() { 33 | let client = Client::tracked(rocket()).unwrap(); 34 | 35 | // Ensure the token is '123', which is what we have in `Rocket.toml`. 36 | let res = client.get("/token").dispatch(); 37 | assert_eq!(res.into_string(), Some("123".into())); 38 | } 39 | -------------------------------------------------------------------------------- /examples/forms/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "forms" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | 11 | [dependencies.rocket_dyn_templates] 12 | path = "../../contrib/dyn_templates" 13 | features = ["tera"] 14 | -------------------------------------------------------------------------------- /examples/forms/Rocket.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | limits.data-form = "2MiB" 3 | template_dir = "templates/" 4 | -------------------------------------------------------------------------------- /examples/forms/templates/success.html.tera: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Rocket Form Example 7 | 8 | 15 | 16 | 17 |
18 |

Success!

19 | 20 |

Submission Data

21 | 22 |
    23 | {% for key, value in values %} 24 |
  • {{ key }} - {{ value }}
  • 25 | {% endfor %} 26 |
27 | 28 | < Submit Another 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/hello/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/manual-routing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "manual_routes" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/manual-routing/Rocket.toml: -------------------------------------------------------------------------------- 1 | [global] 2 | port = 8000 3 | -------------------------------------------------------------------------------- /examples/pastebin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pastebin" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | rand = "0.8" 11 | -------------------------------------------------------------------------------- /examples/pastebin/upload/UPLOADS_GO_HERE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/pastebin/upload/UPLOADS_GO_HERE -------------------------------------------------------------------------------- /examples/responders/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "responders" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | parking_lot = "0.12" 11 | -------------------------------------------------------------------------------- /examples/serialization/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serialization" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies.rocket] 9 | path = "../../core/lib" 10 | features = ["json", "msgpack", "uuid"] 11 | -------------------------------------------------------------------------------- /examples/serialization/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[cfg(test)] mod tests; 4 | 5 | mod json; 6 | mod msgpack; 7 | mod uuid; 8 | 9 | #[launch] 10 | fn rocket() -> _ { 11 | rocket::build() 12 | .attach(json::stage()) 13 | .attach(msgpack::stage()) 14 | .attach(uuid::stage()) 15 | } 16 | -------------------------------------------------------------------------------- /examples/serialization/src/msgpack.rs: -------------------------------------------------------------------------------- 1 | use rocket::serde::{Serialize, Deserialize, msgpack::MsgPack}; 2 | 3 | #[derive(Serialize, Deserialize)] 4 | #[serde(crate = "rocket::serde")] 5 | struct Message<'r> { 6 | id: usize, 7 | message: &'r str 8 | } 9 | 10 | #[get("/", format = "msgpack")] 11 | fn get(id: usize) -> MsgPack> { 12 | MsgPack(Message { id, message: "Hello, world!", }) 13 | } 14 | 15 | #[post("/", data = "", format = "msgpack")] 16 | fn echo(data: MsgPack>) -> &str { 17 | data.message 18 | } 19 | 20 | pub fn stage() -> rocket::fairing::AdHoc { 21 | rocket::fairing::AdHoc::on_ignite("MessagePack", |rocket| async { 22 | rocket.mount("/msgpack", routes![echo, get]) 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /examples/serialization/src/uuid.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use rocket::State; 4 | use rocket::serde::uuid::Uuid; 5 | 6 | // A small people mapping in managed state for the sake of this example. In a 7 | // real application this would be a database. 8 | struct People(HashMap); 9 | 10 | #[get("/people/")] 11 | fn people(id: Uuid, people: &State) -> Result { 12 | people.0.get(&id) 13 | .map(|person| format!("We found: {}", person)) 14 | .ok_or_else(|| format!("Missing person for UUID: {}", id)) 15 | } 16 | 17 | pub fn stage() -> rocket::fairing::AdHoc { 18 | // Seed the "database". 19 | let mut map = HashMap::new(); 20 | map.insert("7f205202-7ba1-4c39-b2fc-3e630722bf9f".parse().unwrap(), "Lacy"); 21 | map.insert("4da34121-bc7d-4fc1-aee6-bf8de0795333".parse().unwrap(), "Bob"); 22 | map.insert("ad962969-4e3d-4de7-ac4a-2d86d6d10839".parse().unwrap(), "George"); 23 | 24 | rocket::fairing::AdHoc::on_ignite("UUID", |rocket| async { 25 | rocket 26 | .manage(People(map)) 27 | .mount("/", routes![people]) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /examples/state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "state" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | flume = "0.11" 11 | -------------------------------------------------------------------------------- /examples/state/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | #[cfg(test)] mod tests; 4 | 5 | mod request_local; 6 | mod managed_hit_count; 7 | mod managed_queue; 8 | 9 | #[launch] 10 | fn rocket() -> _ { 11 | rocket::build() 12 | .attach(request_local::stage()) 13 | .attach(managed_hit_count::stage()) 14 | .attach(managed_queue::stage()) 15 | } 16 | -------------------------------------------------------------------------------- /examples/state/src/managed_hit_count.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicUsize, Ordering}; 2 | 3 | use rocket::State; 4 | use rocket::response::content::RawHtml; 5 | use rocket::fairing::AdHoc; 6 | 7 | struct HitCount(AtomicUsize); 8 | 9 | #[get("/")] 10 | fn index(hit_count: &State) -> RawHtml { 11 | let count = hit_count.0.fetch_add(1, Ordering::Relaxed) + 1; 12 | RawHtml(format!("Your visit is recorded!

Visits: {}", count)) 13 | } 14 | 15 | pub fn stage() -> AdHoc { 16 | AdHoc::on_ignite("Managed Hit Count", |rocket| async { 17 | rocket.mount("/count", routes![index]) 18 | .manage(HitCount(AtomicUsize::new(0))) 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /examples/state/src/managed_queue.rs: -------------------------------------------------------------------------------- 1 | use rocket::State; 2 | use rocket::fairing::AdHoc; 3 | use rocket::http::Status; 4 | 5 | struct Tx(flume::Sender); 6 | struct Rx(flume::Receiver); 7 | 8 | #[put("/push?")] 9 | fn push(event: String, tx: &State) -> Result<(), Status> { 10 | tx.0.try_send(event).map_err(|_| Status::ServiceUnavailable) 11 | } 12 | 13 | #[get("/pop")] 14 | fn pop(rx: &State) -> Option { 15 | rx.0.try_recv().ok() 16 | } 17 | 18 | pub fn stage() -> AdHoc { 19 | AdHoc::on_ignite("Managed Queue", |rocket| async { 20 | let (tx, rx) = flume::bounded(32); 21 | rocket.mount("/queue", routes![push, pop]) 22 | .manage(Tx(tx)) 23 | .manage(Rx(rx)) 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /examples/static-files/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static-files" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/static-files/src/main.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] mod tests; 2 | 3 | use rocket::fs::{FileServer, relative}; 4 | 5 | // If we wanted or needed to serve files manually, we'd use `NamedFile`. Always 6 | // prefer to use `FileServer`! 7 | mod manual { 8 | use std::path::{PathBuf, Path}; 9 | use rocket::fs::NamedFile; 10 | 11 | #[rocket::get("/second/")] 12 | pub async fn second(path: PathBuf) -> Option { 13 | let mut path = Path::new(super::relative!("static")).join(path); 14 | if path.is_dir() { 15 | path.push("index.html"); 16 | } 17 | 18 | NamedFile::open(path).await.ok() 19 | } 20 | } 21 | 22 | #[rocket::launch] 23 | fn rocket() -> _ { 24 | rocket::build() 25 | .mount("/", rocket::routes![manual::second]) 26 | .mount("/", FileServer::new(relative!("static"))) 27 | } 28 | -------------------------------------------------------------------------------- /examples/static-files/static/hidden/hi.txt: -------------------------------------------------------------------------------- 1 | You found me! :o 2 | -------------------------------------------------------------------------------- /examples/static-files/static/hidden/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hmm... 7 | 8 | 9 | 👀 10 | 11 | 12 | -------------------------------------------------------------------------------- /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/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/static-files/static/rocket-icon.jpg -------------------------------------------------------------------------------- /examples/templating/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "templating" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | 11 | # in your application, you should enable only the template engine(s) used 12 | [dependencies.rocket_dyn_templates] 13 | path = "../../contrib/dyn_templates" 14 | features = ["tera", "handlebars", "minijinja"] 15 | -------------------------------------------------------------------------------- /examples/templating/Rocket.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | template_dir = "templates" 3 | -------------------------------------------------------------------------------- /examples/templating/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate rocket; 3 | 4 | mod hbs; 5 | mod minijinja; 6 | mod tera; 7 | 8 | #[cfg(test)] 9 | mod tests; 10 | 11 | use rocket::response::content::RawHtml; 12 | use rocket_dyn_templates::Template; 13 | 14 | #[get("/")] 15 | fn index() -> RawHtml<&'static str> { 16 | RawHtml( 17 | r#"See Tera, 18 | Handlebars, 19 | or MiniJinja."#, 20 | ) 21 | } 22 | 23 | #[launch] 24 | fn rocket() -> _ { 25 | rocket::build() 26 | .mount("/", routes![index]) 27 | .mount("/tera", routes![tera::index, tera::hello, tera::about]) 28 | .mount("/hbs", routes![hbs::index, hbs::hello, hbs::about]) 29 | .mount( 30 | "/minijinja", 31 | routes![minijinja::index, minijinja::hello, minijinja::about], 32 | ) 33 | .register("/hbs", catchers![hbs::not_found]) 34 | .register("/tera", catchers![tera::not_found]) 35 | .register("/minijinja", catchers![minijinja::not_found]) 36 | .attach(Template::custom(|engines| { 37 | hbs::customize(&mut engines.handlebars); 38 | tera::customize(&mut engines.tera); 39 | minijinja::customize(&mut engines.minijinja); 40 | })) 41 | } 42 | -------------------------------------------------------------------------------- /examples/templating/src/minijinja.rs: -------------------------------------------------------------------------------- 1 | use rocket::response::Redirect; 2 | use rocket::Request; 3 | 4 | use rocket_dyn_templates::{context, minijinja::Environment, Template}; 5 | 6 | // use self::minijinja::; 7 | 8 | #[get("/")] 9 | pub fn index() -> Redirect { 10 | Redirect::to(uri!("/minijinja", hello(name = "Your Name"))) 11 | } 12 | 13 | #[get("/hello/")] 14 | pub fn hello(name: &str) -> Template { 15 | Template::render( 16 | "minijinja/index", 17 | context! { 18 | title: "Hello", 19 | name: Some(name), 20 | items: vec!["One", "Two", "Three"], 21 | }, 22 | ) 23 | } 24 | 25 | #[get("/about")] 26 | pub fn about() -> Template { 27 | Template::render( 28 | "minijinja/about.html", 29 | context! { 30 | title: "About", 31 | }, 32 | ) 33 | } 34 | 35 | #[catch(404)] 36 | pub fn not_found(req: &Request<'_>) -> Template { 37 | println!("Handling 404 for URI: {}", req.uri()); 38 | 39 | Template::render( 40 | "minijinja/error/404", 41 | context! { 42 | uri: req.uri() 43 | }, 44 | ) 45 | } 46 | 47 | pub fn customize(env: &mut Environment) { 48 | env.add_template( 49 | "minijinja/about.html", 50 | r#" 51 | {% extends "minijinja/layout" %} 52 | 53 | {% block page %} 54 |
55 |

About - Here's another page!

56 |
57 | {% endblock %} 58 | "#, 59 | ) 60 | .expect("valid Jinja2 template"); 61 | } 62 | -------------------------------------------------------------------------------- /examples/templating/src/tera.rs: -------------------------------------------------------------------------------- 1 | use rocket::Request; 2 | use rocket::response::Redirect; 3 | 4 | use rocket_dyn_templates::{Template, tera::Tera, context}; 5 | 6 | #[get("/")] 7 | pub fn index() -> Redirect { 8 | Redirect::to(uri!("/tera", hello(name = "Your Name"))) 9 | } 10 | 11 | #[get("/hello/")] 12 | pub fn hello(name: &str) -> Template { 13 | Template::render("tera/index", context! { 14 | title: "Hello", 15 | name: Some(name), 16 | items: vec!["One", "Two", "Three"], 17 | }) 18 | } 19 | 20 | #[get("/about")] 21 | pub fn about() -> Template { 22 | Template::render("tera/about.html", context! { 23 | title: "About", 24 | }) 25 | } 26 | 27 | #[catch(404)] 28 | pub fn not_found(req: &Request<'_>) -> Template { 29 | Template::render("tera/error/404", context! { 30 | uri: req.uri() 31 | }) 32 | } 33 | 34 | pub fn customize(tera: &mut Tera) { 35 | tera.add_raw_template("tera/about.html", r#" 36 | {% extends "tera/base" %} 37 | 38 | {% block content %} 39 |
40 |

About - Here's another page!

41 |
42 | {% endblock content %} 43 | "#).expect("valid Tera template"); 44 | } 45 | -------------------------------------------------------------------------------- /examples/templating/templates/hbs/error/404.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 - hbs 6 | 7 | 8 |

404: Hey! There's nothing here.

9 | The page at {{ uri }} does not exist! 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/templating/templates/hbs/footer.html.hbs: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/templating/templates/hbs/index.html.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 /hbs/hello/Your Name.

15 |

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

16 |
17 | 18 | {{/inline}} 19 | {{> hbs/layout}} 20 | -------------------------------------------------------------------------------- /examples/templating/templates/hbs/layout.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rocket Example - {{ title }} 5 | 6 | 7 | {{> hbs/nav}} 8 | {{~> page}} 9 | {{> hbs/footer}} 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/templating/templates/hbs/nav.html.hbs: -------------------------------------------------------------------------------- 1 | Hello | About 2 | -------------------------------------------------------------------------------- /examples/templating/templates/minijinja/error/404.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 - minijinja 6 | 7 | 8 |

404: Hey! There's nothing here.

9 | The page at {{ uri }} does not exist! 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/templating/templates/minijinja/footer.html.j2: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/templating/templates/minijinja/index.html.j2: -------------------------------------------------------------------------------- 1 | {% extends "minijinja/layout" %} 2 | 3 | {% block page %} 4 |
5 |

Hi {{ name }}!

6 |

Here are your items:

7 |
    8 | {% for item in items %} 9 |
  • {{ item }}
  • 10 | {% endfor %} 11 |
12 |
13 | 14 |
15 |

Try going to /minijinja/hello/Your Name.

16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /examples/templating/templates/minijinja/layout.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rocket Example - {{ title }} 5 | 6 | 7 | {% include "minijinja/nav" %} 8 | {% block page %}{% endblock %} 9 | {% include "minijinja/footer" %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/templating/templates/minijinja/nav.html.j2: -------------------------------------------------------------------------------- 1 | Hello | About 2 | -------------------------------------------------------------------------------- /examples/templating/templates/tera/base.html.tera: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tera Demo - {{ title }} 6 | 7 | 8 | {% include "tera/nav" %} 9 | 10 | {% block content %}{% endblock content %} 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/templating/templates/tera/error/404.html.tera: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 - tera 6 | 7 | 8 |

404: Hey! There's nothing here.

9 | The page at {{ uri }} does not exist! 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/templating/templates/tera/index.html.tera: -------------------------------------------------------------------------------- 1 | {% extends "tera/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 /tera/hello/Your Name

13 | {% endblock content %} 14 | -------------------------------------------------------------------------------- /examples/templating/templates/tera/nav.html.tera: -------------------------------------------------------------------------------- 1 | Hello | About 2 | -------------------------------------------------------------------------------- /examples/testing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "testing" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | -------------------------------------------------------------------------------- /examples/testing/src/async_required.rs: -------------------------------------------------------------------------------- 1 | use rocket::{Rocket, State, Build}; 2 | use rocket::fairing::AdHoc; 3 | use rocket::tokio::sync::Barrier; 4 | 5 | #[get("/barrier")] 6 | async fn rendezvous(barrier: &State) -> &'static str { 7 | println!("Waiting for second task..."); 8 | barrier.wait().await; 9 | "Rendezvous reached." 10 | } 11 | 12 | pub fn rocket() -> Rocket { 13 | rocket::build() 14 | .mount("/", routes![rendezvous]) 15 | .attach(AdHoc::on_ignite("Add Channel", |rocket| async { 16 | rocket.manage(Barrier::new(2)) 17 | })) 18 | } 19 | 20 | #[cfg(test)] 21 | mod test { 22 | use super::rocket; 23 | use rocket::http::Status; 24 | 25 | #[rocket::async_test] 26 | async fn test_rendezvous() { 27 | use rocket::local::asynchronous::Client; 28 | 29 | let client = Client::tracked(rocket()).await.unwrap(); 30 | let req = client.get("/barrier"); 31 | 32 | let (r1, r2) = rocket::tokio::join!(req.clone().dispatch(), req.dispatch()); 33 | assert_eq!(r1.status(), r2.status()); 34 | assert_eq!(r1.status(), Status::Ok); 35 | 36 | let (s1, s2) = (r1.into_string().await, r2.into_string().await); 37 | assert_eq!(s1, s2); 38 | assert_eq!(s1.unwrap(), "Rendezvous reached."); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/testing/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | mod async_required; 4 | 5 | #[get("/")] 6 | fn hello() -> &'static str { 7 | "Hello, world!" 8 | } 9 | 10 | #[launch] 11 | fn rocket() -> _ { 12 | async_required::rocket().mount("/", routes![hello]) 13 | } 14 | 15 | #[cfg(test)] 16 | mod test { 17 | use super::rocket; 18 | use rocket::http::Status; 19 | 20 | #[test] 21 | fn test_hello() { 22 | use rocket::local::blocking::Client; 23 | 24 | let client = Client::tracked(rocket()).unwrap(); 25 | let response = client.get("/").dispatch(); 26 | assert_eq!(response.status(), Status::Ok); 27 | assert_eq!(response.into_string(), Some("Hello, world!".into())); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/tls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tls" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib", features = ["tls", "mtls", "secrets", "http3-preview"] } 10 | yansi = "1.0.1" 11 | 12 | [target.'cfg(unix)'.dependencies] 13 | rustls = { version = "0.23", features = ["aws_lc_rs"] } 14 | -------------------------------------------------------------------------------- /examples/tls/Rocket.toml: -------------------------------------------------------------------------------- 1 | # The certificate key pairs used here were generated with openssl via the 2 | # 'private/gen_certs.sh' script. 3 | # 4 | # These certificates are self-signed. As such, you will need to trust them 5 | # directly for your browser to show connections as secure. You should NEVER use 6 | # these certificate/key pairs. They are here for DEMONSTRATION PURPOSES ONLY. 7 | 8 | [default] 9 | log_format = "compact" 10 | 11 | [default.tls] 12 | certs = "private/rsa_sha256_cert.pem" 13 | key = "private/rsa_sha256_key.pem" 14 | 15 | [default.tls.mutual] 16 | ca_certs = "private/ca_cert.pem" 17 | mandatory = false 18 | 19 | [rsa_sha256.tls] 20 | certs = "private/rsa_sha256_cert.pem" 21 | key = "private/rsa_sha256_key.pem" 22 | 23 | [ecdsa_nistp256_sha256_pkcs8.tls] 24 | certs = "private/ecdsa_nistp256_sha256_cert.pem" 25 | key = "private/ecdsa_nistp256_sha256_key_pkcs8.pem" 26 | 27 | [ecdsa_nistp384_sha384_pkcs8.tls] 28 | certs = "private/ecdsa_nistp384_sha384_cert.pem" 29 | key = "private/ecdsa_nistp384_sha384_key_pkcs8.pem" 30 | 31 | [ecdsa_nistp521_sha512_pkcs8.tls] 32 | certs = "private/ecdsa_nistp521_sha512_cert.pem" 33 | key = "private/ecdsa_nistp521_sha512_key_pkcs8.pem" 34 | 35 | [ecdsa_nistp256_sha256_sec1.tls] 36 | certs = "private/ecdsa_nistp256_sha256_cert.pem" 37 | key = "private/ecdsa_nistp256_sha256_key_sec1.pem" 38 | 39 | [ecdsa_nistp384_sha384_sec1.tls] 40 | certs = "private/ecdsa_nistp384_sha384_cert.pem" 41 | key = "private/ecdsa_nistp384_sha384_key_sec1.pem" 42 | 43 | [ed25519.tls] 44 | certs = "private/ed25519_cert.pem" 45 | key = "private/ed25519_key.pem" 46 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp256_sha256.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/tls/private/ecdsa_nistp256_sha256.p12 -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp256_sha256_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDYTCCAUmgAwIBAgIUWET3Ypdh7TK5UE24E9Smn1r03d0wDQYJKoZIhvcNAQEL 3 | BQAwRzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQKDAlSb2NrZXQg 4 | Q0ExFzAVBgNVBAMMDlJvY2tldCBSb290IENBMB4XDTIxMDcwOTIzMzMzM1oXDTMx 5 | MDcwNzIzMzMzM1owPzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQK 6 | DAZSb2NrZXQxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49 7 | AwEHA0IABDtAvrDALV/ZGurSJdoRFDvB2q7PsdjWWvzFWvQortUzmWXuFO47QJ8v 8 | lqluDtQKK7gHmNm10MrDk2o0ipMkrzSjGDAWMBQGA1UdEQQNMAuCCWxvY2FsaG9z 9 | dDANBgkqhkiG9w0BAQsFAAOCAgEAGJ/mFUyJzomXpYqGHzBRUvBqGmY05F2YOu0a 10 | D620WyWUFYWOnbqSKqqrP2nI1eNQXbmTtcKokuC67I2laIYML/IwBuLj+JcenvaB 11 | TmtmHHFSb0fweXSK3r0m9KEQBvVeoMEFhTZ6NINmXjTZES2xOks47yVo704q3xhS 12 | 7Rm7YGu3Wgjyn4YAb7UQhgnvN0x4UlDHQAU8PB4nLHgKkgaczaERcIa/nhGA1D85 13 | obNkh+QSNsShnrOrDJ4iRt5ZBLjmTX3qcbJTjjzaKwwMuBTOr7f5zh417ahPWq2v 14 | r0GgmMW+8k8D7CjBM5TkNzOTQRjLUUKF1YjX39E4J8E/rtg8/GlHVfKRG8bvGIK8 15 | EIiAaSjUTY00cQltlt9QMFOTGlakF8Id4Dxkke+oP+62EK1pOroQiRvNeopEy+dO 16 | Gee7HN5eC6n548VrMMql1TMoraWMK4kiVy46xlBmwHXq/JPG0GV/I6i24jobYeGt 17 | 8yoeB1DlCX9uiLOKlPctxMeVPkErvVGvVZZKMR2KYNznSj/L22VXSh0xg0L6zVRX 18 | DsW97MZsef1t2RZf7nSz4JkSecuUHNsk12Z/Pe3G7zofz2UtV1o3G9oBHSm91a/j 19 | L/sAlvawy8CwLll8DRk26mg7YLwgxnNfJzG9M0G8Fwi6XPUBx2ywsSTWSO0KQ+5C 20 | p2mcGCY= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp256_sha256_key_pkcs8.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgz5+60CMzUC7X2U50 3 | S8KIDYQ6MHUtwMTsHcUrbDhLfLahRANCAAQ7QL6wwC1f2Rrq0iXaERQ7wdquz7HY 4 | 1lr8xVr0KK7VM5ll7hTuO0CfL5apbg7UCiu4B5jZtdDKw5NqNIqTJK80 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp256_sha256_key_sec1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIM+futAjM1Au19lOdEvCiA2EOjB1LcDE7B3FK2w4S3y2oAoGCCqGSM49 3 | AwEHoUQDQgAEO0C+sMAtX9ka6tIl2hEUO8Hars+x2NZa/MVa9Ciu1TOZZe4U7jtA 4 | ny+WqW4O1AoruAeY2bXQysOTajSKkySvNA== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp384_sha384.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/tls/private/ecdsa_nistp384_sha384.p12 -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp384_sha384_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDfjCCAWagAwIBAgIUB+Ff5LDKhcdjusOuaCqjePqScwQwDQYJKoZIhvcNAQEM 3 | BQAwRzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQKDAlSb2NrZXQg 4 | Q0ExFzAVBgNVBAMMDlJvY2tldCBSb290IENBMB4XDTIxMDcwOTIzMzMzM1oXDTMx 5 | MDcwNzIzMzMzM1owPzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQK 6 | DAZSb2NrZXQxEjAQBgNVBAMMCWxvY2FsaG9zdDB2MBAGByqGSM49AgEGBSuBBAAi 7 | A2IABNkp8NiqSoUc8bwJq0fIRFyvdDN0jUT4+9MdoJ/CJyKHjeVVBcMWXBJbKTmo 8 | rFbkJ6WcUbBU30K0+KTvqX9tFLXOmpwUZDyqmkeU78VV7DJrDKSy5Hgxz5hXJ309 9 | lz+Kr6MYMBYwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBDAUAA4IC 10 | AQATXjqJmDfj0/C1KzSoFgvuiDK6NseMJijkKauaGdHUSGf2P06izvwke8xW3P/b 11 | VifOkpKX3K9RxY4R7xDenTXIEDnKYlp2a77djbef8mBL914ZQSXBFF8Lhz1QD/QC 12 | sIM8exCuelgHbfPh/UdLY1CmEcYOlHQYUpIMYkH7U0KbLvqafY3d7WkERuXwzAUd 13 | kYCAV2V23f2HiuOaX616QYW7Ow6jPrhU1RwEW25Y/Ubw+jQKDSRE6NF+inR7WPot 14 | 2GN0ELY+6trxe0w0DL0syOsfF9SVkvgfKhwBKVCsJvCp4HmOIBDlZL40NhrnXK6L 15 | HmUsyckVVMSmPRrvNrIy7m6CoCbdb8wWPlhpygMrOFfhpGJ2fIMzf4JzQnsAKHO9 16 | 1D5mtzaHNNcwBdWNTvVOojy0BRsRrNYcO/Lkf5+VwZ3+AQVPPwG04kk7fA/iONQx 17 | hraiVy6Majl4pFfbWcAOaSDDSMsZ8Joc6AmCiPQGVelrqzZ1wa+a12BBfibqYdm7 18 | ab831J7KrkK2rfCC84ZdUcICcWkPCisMfPeoaQsp2R4Zw7Rcuyfce8UVZYZsmZ9X 19 | rmgp6O3oIWK31iHkgpb+bQM0YXykbK/fp7vxqnfk2kq+IadSlDwOJ/U8sdNMVHdK 20 | mct9ke+F1KFB+J8UU5w/JK/Tn7HtWY8lf9VTuK8pAkyQAg== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp384_sha384_key_pkcs8.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDClF5pKlKs9J5iaOAJE 3 | He7v7RfcSt14yMjrp6y1jntK9j9jzTXAGtHCyWwdW0GYTVmhZANiAATZKfDYqkqF 4 | HPG8CatHyERcr3QzdI1E+PvTHaCfwicih43lVQXDFlwSWyk5qKxW5CelnFGwVN9C 5 | tPik76l/bRS1zpqcFGQ8qppHlO/FVewyawyksuR4Mc+YVyd9PZc/iq8= 6 | -----END PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp384_sha384_key_sec1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MIGkAgEBBDClF5pKlKs9J5iaOAJEHe7v7RfcSt14yMjrp6y1jntK9j9jzTXAGtHC 3 | yWwdW0GYTVmgBwYFK4EEACKhZANiAATZKfDYqkqFHPG8CatHyERcr3QzdI1E+PvT 4 | HaCfwicih43lVQXDFlwSWyk5qKxW5CelnFGwVN9CtPik76l/bRS1zpqcFGQ8qppH 5 | lO/FVewyawyksuR4Mc+YVyd9PZc/iq8= 6 | -----END EC PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp521_sha512.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/tls/private/ecdsa_nistp521_sha512.p12 -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp521_sha512_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID5DCCAcygAwIBAgIUZ2n0Lhg+9cVPCOtK7Ov1D5n58GIwDQYJKoZIhvcNAQEN 3 | BQAwRzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQKDAlSb2NrZXQg 4 | Q0ExFzAVBgNVBAMMDlJvY2tldCBSb290IENBMB4XDTI0MDMyNzExMDYzMFoXDTM0 5 | MDMyNTExMDYzMFowPzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQK 6 | DAZSb2NrZXQxEjAQBgNVBAMMCWxvY2FsaG9zdDCBmzAQBgcqhkjOPQIBBgUrgQQA 7 | IwOBhgAEAYXtydjaJR3BsC6NVEPD8wxIobzKO004WjyKFupkQcuQPg4DDzLTimho 8 | SyH3ohaYX398MBSSgxo5A1zTb0TB/Yl1AYLiP6SWmZfejRdyZuRQSNrNIH07MIId 9 | e+l8VD0DVSb9+Zej5eet4sRgcVgxIzfSCi1mVzSCttbwagpvZW/HBEEgo1gwVjAU 10 | BgNVHREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYEFMvhtxA9Tm+8JRx1MfLdJk3Z 11 | XW5DMB8GA1UdIwQYMBaAFEQDJSPSVPCilnYHVWae8w99S0KTMA0GCSqGSIb3DQEB 12 | DQUAA4ICAQCscu1VBrqQRLON5s86UQv+sCATmW9kWWLCnHn78iGfxMa9N4L9rsf4 13 | aFTFpfklOHYBPLK0q2Jm681rzD09FN0DTxG5t9WIsQ2PEJc2akqbzx1Sm4sMZ/td 14 | 79oS/BLgKEOL8RDtU4dQu5DsrOqOYtDbH4ETwGs3TL3eWH+3sC9S25Sq/DJ9TFHm 15 | pZIzEB9rEwgXMsZ0KVYzEAByKZvJZJbp5nRFJPO4riuY+RkyeqQh+oWxRAplqk2s 16 | yZEgxgnJIPzVYJkZ8VxaWLF9mU2kHtJlHwlTf6Yp3LTuyr9mwVsNTY+xXco6d5p8 17 | bMVUBvVCxNmFHsv2maNOHF2AkxwncIkSNK00ohX5rSnZ1Tdipq3ckjpkbTccYWO2 18 | aEPUphZUkGNReSnJ0LKDyCW4Y4Yna3SG152DfMaIjQjflyh8jUnsrGdISxuemE/z 19 | 2RnTzoSJLGMZvw52BsPbq9aNiZy7kM495oANFSaHwDbkEAknYKyAj2uO2740qEOH 20 | xhmsa67lPeofZBoU86gydkszCOWN1GzGOmoF9OFfD5H9M6mtYJ6l1h6/80ofx2Fv 21 | SdaksbRdERx20hVPM6tsAbfeP2mmxelVmhxwziQe5ERybrBx23w+khsfsA8Ldv+7 22 | hbAqYufmcmsSxdEA+Fuo18vhHOT98UmKlXx1hyERm0hbJe9rW+rGKg== 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /examples/tls/private/ecdsa_nistp521_sha512_key_pkcs8.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIA3a6vdhcCDC8p/8yG 3 | eDASmWqQdkmgU9kaqqgmBh2gcLhTxxtjwAy8BxBy4UmRFo8VJtFUDLXt8ZR2vzTc 4 | zKybjrmhgYkDgYYABAGF7cnY2iUdwbAujVRDw/MMSKG8yjtNOFo8ihbqZEHLkD4O 5 | Aw8y04poaEsh96IWmF9/fDAUkoMaOQNc029Ewf2JdQGC4j+klpmX3o0XcmbkUEja 6 | zSB9OzCCHXvpfFQ9A1Um/fmXo+XnreLEYHFYMSM30gotZlc0grbW8GoKb2VvxwRB 7 | IA== 8 | -----END PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /examples/tls/private/ed25519.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/tls/private/ed25519.p12 -------------------------------------------------------------------------------- /examples/tls/private/ed25519_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDMjCCARqgAwIBAgIUdMGHQoLHGcks+Hnw7dC5dEl0/ogwDQYJKoZIhvcNAQEL 3 | BQAwRzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQKDAlSb2NrZXQg 4 | Q0ExFzAVBgNVBAMMDlJvY2tldCBSb290IENBMB4XDTIxMDcwOTIzMzMzM1oXDTMx 5 | MDcwNzIzMzMzM1owPzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQK 6 | DAZSb2NrZXQxEjAQBgNVBAMMCWxvY2FsaG9zdDAqMAUGAytlcAMhAP7ORUynwg2q 7 | IbwJwpOThFhc/IhiWxIIACcaiNKPtdEzoxgwFjAUBgNVHREEDTALgglsb2NhbGhv 8 | c3QwDQYJKoZIhvcNAQELBQADggIBAKcrsLA9ijRjE/h8FUNbEz547a8wCy6NskRh 9 | vCLIsC3k3pfhmKatM3BSwrpePFv6iSPIlp6rY9rTYx+vnLGVnT5bjPDA3Q5VwyIF 10 | lAYnbZP7VSQKWr2hLqFd/3sUvg7kSL16nVi4GaRYTAH2W9IQWyx+GKqv6lRmDFwS 11 | TCoPu2YnoboWTYMFdsrxdkzvBkQX+IF45aVTnUbAcLAc7hgZdK6+ZAhIk4ymDDWj 12 | FeGi/hJ5zF9a/zdV+62CHuIwgCT3ETUXeVLKWf6+v2pOMYXmpdPJf5g06zsrpcYY 13 | i+ZdYPXFs4/yzwcUpgYdkpszMJcxgUSn/u2E9/9BFtJa/kwDbHCDItyR2rSeDoUI 14 | 2mQY6Kjm8BucM8hBoNYh9HOHEn1450PHIyWzcSMFkhfqSAKzngVcuSmRkUYhIdHu 15 | bUu29CLJzvOCTFxAWd4uWO2EbH5QFOeD9sQjqzadw0KX5kZl3Oe0wJqLswpKXd7m 16 | uQzcIjGNhY3STk722z0sFuZOvZPoi2d46ZKRBIJ9OYQfUzLDWW1PjqIuX7gWOUfe 17 | PaSs8K2qQlfniPJzHFQ3XHB4KJoWP2BcTUh5mkmpq5st5Buox8JUeAH+SalltR+K 18 | Skvvyv6hIhKyUDrgqV3dhIdTiexRLsmosXdps7ifJdmDtJcuWVp5hCS05X5oHTk/ 19 | 6WWSkctl 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /examples/tls/private/ed25519_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MC4CAQAwBQYDK2VwBCIEIKzhuOs4KVtmEBw86yumn8ID4tYm/aPmz8QtBIrlJkTE 3 | -----END PRIVATE KEY----- 4 | -------------------------------------------------------------------------------- /examples/tls/private/rsa_sha256.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/tls/private/rsa_sha256.p12 -------------------------------------------------------------------------------- /examples/tls/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate rocket; 3 | 4 | #[cfg(test)] 5 | mod tests; 6 | mod redirector; 7 | 8 | use rocket::mtls::Certificate; 9 | use rocket::listener::Endpoint; 10 | 11 | #[get("/")] 12 | fn mutual(cert: Certificate<'_>) -> String { 13 | format!("Hello! Here's what we know: [{}] {}", cert.serial(), cert.subject()) 14 | } 15 | 16 | #[get("/", rank = 2)] 17 | fn hello(endpoint: Option<&Endpoint>) -> String { 18 | match endpoint { 19 | Some(endpoint) => format!("Hello, {endpoint}!"), 20 | None => "Hello, world!".into(), 21 | } 22 | } 23 | 24 | #[launch] 25 | fn rocket() -> _ { 26 | // See `Rocket.toml` and `Cargo.toml` for TLS configuration. 27 | // Run `./private/gen_certs.sh` to generate a CA and key pairs. 28 | rocket::build() 29 | .mount("/", routes![hello, mutual]) 30 | .attach(redirector::Redirector::on(3000)) 31 | } 32 | -------------------------------------------------------------------------------- /examples/todo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "todo" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | diesel = { version = "2.0.0", features = ["sqlite", "r2d2"] } 11 | diesel_migrations = "2.0.0" 12 | 13 | [dev-dependencies] 14 | parking_lot = "0.12" 15 | rand = "0.8" 16 | 17 | [dependencies.rocket_sync_db_pools] 18 | path = "../../contrib/sync_db_pools/lib/" 19 | features = ["diesel_sqlite_pool"] 20 | 21 | [dependencies.rocket_dyn_templates] 22 | path = "../../contrib/dyn_templates" 23 | features = ["tera"] 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 | [default] 2 | template_dir = "static" 3 | 4 | [default.databases.sqlite_database] 5 | url = "db/db.sqlite" 6 | -------------------------------------------------------------------------------- /examples/todo/db/DB_LIVES_HERE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/todo/db/DB_LIVES_HERE -------------------------------------------------------------------------------- /examples/todo/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/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/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/rwf2/Rocket/f9de1bf4671100b2f9c9bea6ce206fc4748ca999/examples/todo/static/images/favicon.png -------------------------------------------------------------------------------- /examples/upgrade/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "upgrade" 3 | version = "0.0.0" 4 | workspace = "../" 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | rocket = { path = "../../core/lib" } 10 | ws = { package = "rocket_ws", path = "../../contrib/ws" } 11 | -------------------------------------------------------------------------------- /examples/upgrade/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate rocket; 2 | 3 | use rocket::fs::{self, FileServer}; 4 | use rocket::futures::{SinkExt, StreamExt}; 5 | 6 | #[get("/echo?stream", rank = 1)] 7 | fn echo_stream(ws: ws::WebSocket) -> ws::Stream!['static] { 8 | ws::Stream! { ws => 9 | for await message in ws { 10 | yield message?; 11 | } 12 | } 13 | } 14 | 15 | #[get("/echo?channel", rank = 2)] 16 | fn echo_channel(ws: ws::WebSocket) -> ws::Channel<'static> { 17 | // This is entirely optional. Change default configuration. 18 | let ws = ws.config(ws::Config { 19 | // set max message size to 3MiB 20 | max_message_size: Some(3 << 20), 21 | ..Default::default() 22 | }); 23 | 24 | ws.channel(move |mut stream| Box::pin(async move { 25 | while let Some(message) = stream.next().await { 26 | let _ = stream.send(message?).await; 27 | } 28 | 29 | Ok(()) 30 | })) 31 | } 32 | 33 | #[get("/echo?raw", rank = 3)] 34 | fn echo_raw(ws: ws::WebSocket) -> ws::Stream!['static] { 35 | ws.stream(|stream| stream) 36 | } 37 | 38 | #[launch] 39 | fn rocket() -> _ { 40 | rocket::build() 41 | .mount("/", routes![echo_channel, echo_stream, echo_raw]) 42 | .mount("/", FileServer::new(fs::relative!("static"))) 43 | } 44 | -------------------------------------------------------------------------------- /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 docs (${DOC_VERSION})..." 21 | pushd "${PROJECT_ROOT}" > /dev/null 2>&1 22 | # Set the crate version and fill in missing doc URLs with docs.rs links. 23 | RUSTDOCFLAGS="-Z unstable-options \ 24 | --extern-html-root-url rocket=https://api.rocket.rs/${GIT_BRANCH}/rocket/ \ 25 | --crate-version ${DOC_VERSION} \ 26 | --enable-index-page \ 27 | --generate-link-to-definition" \ 28 | cargo doc -Zrustdoc-map --no-deps --all-features \ 29 | -p rocket \ 30 | -p rocket_db_pools \ 31 | -p rocket_sync_db_pools \ 32 | -p rocket_dyn_templates \ 33 | -p rocket_ws 34 | popd > /dev/null 2>&1 35 | -------------------------------------------------------------------------------- /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 | if ! [ -z "$(git status --porcelain)" ]; then 13 | echo "There are uncommitted changes! Aborting." 14 | exit 1 15 | fi 16 | 17 | # Ensure everything passes before trying to publish. 18 | echo ":::: Running complete test suite..." 19 | cargo clean 20 | bash "${SCRIPT_DIR}/test.sh" +stable --all 21 | bash "${SCRIPT_DIR}/test.sh" +stable --all --release 22 | 23 | # Publish all the things. 24 | for dir in "${ALL_CRATE_ROOTS[@]}"; do 25 | pushd "${dir}" 26 | echo ":::: Publishing '${dir}'..." 27 | # We already checked things ourselves. Don't spend time reverifying. 28 | cargo publish --no-verify --allow-dirty ${@:1} 29 | # Give the index some time to update so the deps are there if we need them. 30 | sleep 5 31 | popd 32 | done 33 | -------------------------------------------------------------------------------- /testbench/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "testbench" 3 | description = "End-to-end HTTP Rocket testbench." 4 | version = "0.0.0" 5 | edition = "2021" 6 | publish = false 7 | 8 | [workspace] 9 | 10 | [dependencies] 11 | thiserror = "1.0" 12 | procspawn = "1" 13 | pretty_assertions = "1.4.0" 14 | ipc-channel = "0.18" 15 | rustls-pemfile = "2.1" 16 | inventory = "0.3.15" 17 | 18 | [dependencies.nix] 19 | version = "0.28" 20 | features = ["signal"] 21 | 22 | [dependencies.rocket] 23 | path = "../core/lib/" 24 | features = ["secrets", "tls", "mtls"] 25 | 26 | [dependencies.reqwest] 27 | version = "0.12.3" 28 | default-features = false 29 | features = ["rustls-tls-manual-roots", "charset", "cookies", "blocking", "http2"] 30 | -------------------------------------------------------------------------------- /testbench/src/lib.rs: -------------------------------------------------------------------------------- 1 | // pub mod session; 2 | mod client; 3 | mod server; 4 | 5 | pub use server::*; 6 | pub use client::*; 7 | 8 | use std::io; 9 | use thiserror::Error; 10 | use procspawn::SpawnError; 11 | use rocket::http::uri; 12 | 13 | pub type Result = std::result::Result; 14 | 15 | #[derive(Error, Debug)] 16 | pub enum Error { 17 | #[error("join/kill failed: {0}")] 18 | JoinError(#[from] SpawnError), 19 | #[error("kill failed: {0}")] 20 | TermFailure(#[from] nix::errno::Errno), 21 | #[error("i/o error: {0}")] 22 | Io(#[from] io::Error), 23 | #[error("invalid URI: {0}")] 24 | Uri(#[from] uri::Error<'static>), 25 | #[error("invalid uri: {0}")] 26 | InvalidUri(uri::Uri<'static>), 27 | #[error("expected certificates are not present")] 28 | MissingCertificate, 29 | #[error("bad request: {0}")] 30 | Request(#[from] reqwest::Error), 31 | #[error("IPC failure: {0}")] 32 | Ipc(#[from] ipc_channel::ipc::IpcError), 33 | #[error("liftoff failed")] 34 | Liftoff(String, String), 35 | } 36 | -------------------------------------------------------------------------------- /testbench/src/main.rs: -------------------------------------------------------------------------------- 1 | mod runner; 2 | mod servers; 3 | mod config; 4 | 5 | pub mod prelude { 6 | pub use rocket::*; 7 | pub use rocket::fairing::*; 8 | pub use rocket::response::stream::*; 9 | 10 | pub use testbench::{Error, Result, *}; 11 | pub use crate::register; 12 | pub use crate::config::*; 13 | } 14 | 15 | pub use runner::Test; 16 | 17 | fn main() -> std::process::ExitCode { 18 | runner::run() 19 | } 20 | -------------------------------------------------------------------------------- /testbench/src/servers/bind.rs: -------------------------------------------------------------------------------- 1 | use rocket::{tokio::net::TcpListener}; 2 | 3 | use crate::prelude::*; 4 | 5 | #[cfg(unix)] 6 | fn tcp_unix_listener_fail() -> Result<()> { 7 | use rocket::listener::unix::UnixListener; 8 | 9 | let server = spawn! { 10 | Rocket::default().reconfigure_with_toml("[default]\naddress = 123") 11 | }; 12 | 13 | if let Err(Error::Liftoff(stdout, _)) = server { 14 | assert!(stdout.contains("expected: valid TCP (ip) or unix (path)")); 15 | assert!(stdout.contains("default.address")); 16 | } else { 17 | panic!("unexpected result: {server:#?}"); 18 | } 19 | 20 | let server = Server::spawn((), |(token, _)| { 21 | let rocket = Rocket::default().reconfigure_with_toml("[default]\naddress = \"unix:foo\""); 22 | token.launch_with::(rocket) 23 | }); 24 | 25 | if let Err(Error::Liftoff(stdout, _)) = server { 26 | assert!(stdout.contains("invalid tcp endpoint: unix:foo")); 27 | } else { 28 | panic!("unexpected result: {server:#?}"); 29 | } 30 | 31 | let server = Server::spawn((), |(token, _)| { 32 | token.launch_with::(Rocket::default()) 33 | }); 34 | 35 | if let Err(Error::Liftoff(stdout, _)) = server { 36 | assert!(stdout.contains("invalid unix endpoint: tcp:127.0.0.1:8000")); 37 | } else { 38 | panic!("unexpected result: {server:#?}"); 39 | } 40 | 41 | Ok(()) 42 | } 43 | 44 | #[cfg(unix)] 45 | register!(tcp_unix_listener_fail); 46 | -------------------------------------------------------------------------------- /testbench/src/servers/http_extensions.rs: -------------------------------------------------------------------------------- 1 | //! Test that HTTP method extensions unlike POST or GET work. 2 | 3 | use crate::prelude::*; 4 | 5 | use rocket::http::Method; 6 | 7 | #[route("/", method = PROPFIND)] 8 | fn route() -> &'static str { 9 | "Hello, World!" 10 | } 11 | 12 | pub fn test_http_extensions() -> Result<()> { 13 | let server = spawn! { 14 | Rocket::default().mount("/", routes![route]) 15 | }?; 16 | 17 | let client = Client::default(); 18 | let response = client.request(&server, Method::PropFind, "/")?.send()?; 19 | assert_eq!(response.status(), 200); 20 | assert_eq!(response.text()?, "Hello, World!"); 21 | 22 | // Make sure that verbs outside of extensions are marked as errors 23 | let res = client.request(&server, "BAKEMEACOOKIE", "/")?.send()?; 24 | assert_eq!(res.status(), 400); 25 | 26 | Ok(()) 27 | } 28 | 29 | register!(test_http_extensions); 30 | -------------------------------------------------------------------------------- /testbench/src/servers/ignite_failure.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | fn test_ignite_failure() -> Result<()> { 4 | let server = spawn! { 5 | let fail = AdHoc::try_on_ignite("FailNow", |rocket| async { Err(rocket) }); 6 | Rocket::default().attach(fail) 7 | }; 8 | 9 | if let Err(Error::Liftoff(stdout, _)) = server { 10 | assert!(stdout.contains("failed ignite")); 11 | assert!(stdout.contains("FailNow")); 12 | } else { 13 | panic!("unexpected result: {server:#?}"); 14 | } 15 | 16 | Ok(()) 17 | } 18 | 19 | register!(test_ignite_failure); 20 | -------------------------------------------------------------------------------- /testbench/src/servers/infinite_stream.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[get("/")] 4 | fn infinite() -> TextStream![&'static str] { 5 | TextStream! { 6 | loop { 7 | yield rocket::futures::future::pending::<&str>().await; 8 | } 9 | } 10 | } 11 | 12 | pub fn test_inifinite_streams_end() -> Result<()> { 13 | let mut server = spawn! { 14 | Rocket::default().mount("/", routes![infinite]) 15 | }?; 16 | 17 | let client = Client::default(); 18 | client.get(&server, "/")?.send()?; 19 | server.terminate()?; 20 | 21 | let stdout = server.read_stdout()?; 22 | assert!(stdout.contains("Rocket has launched on http")); 23 | assert!(stdout.contains("GET /")); 24 | assert!(stdout.contains("Graceful shutdown completed")); 25 | 26 | Ok(()) 27 | } 28 | 29 | register!(test_inifinite_streams_end); 30 | -------------------------------------------------------------------------------- /testbench/src/servers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ignite_failure; 2 | pub mod bind; 3 | pub mod http_extensions; 4 | pub mod infinite_stream; 5 | pub mod tls_resolver; 6 | pub mod mtls; 7 | pub mod sni_resolver; 8 | pub mod tracing; 9 | pub mod tls; 10 | pub mod no_content; 11 | -------------------------------------------------------------------------------- /testbench/src/servers/no_content.rs: -------------------------------------------------------------------------------- 1 | //! Ensure that responses with a status of 204 or 304 do not have a body, and 2 | //! for the former, do not have a Content-Length header. 3 | 4 | use crate::prelude::*; 5 | 6 | use rocket::http::Status; 7 | 8 | #[get("/")] 9 | fn status(code: u16) -> (Status, &'static [u8]) { 10 | (Status::new(code), &[1, 2, 3, 4]) 11 | } 12 | 13 | pub fn test_no_content() -> Result<()> { 14 | let server = spawn!(Rocket::default().mount("/", routes![status]))?; 15 | 16 | let client = Client::default(); 17 | let response = client.get(&server, "/204")?.send()?; 18 | assert_eq!(response.status(), 204); 19 | assert!(response.headers().get("Content-Length").is_none()); 20 | assert!(response.bytes()?.is_empty()); 21 | 22 | let response = client.get(&server, "/304")?.send()?; 23 | assert_eq!(response.status(), 304); 24 | assert_eq!(response.headers().get("Content-Length").unwrap(), "4"); 25 | assert!(response.bytes()?.is_empty()); 26 | 27 | Ok(()) 28 | } 29 | 30 | register!(test_no_content); 31 | --------------------------------------------------------------------------------