From adb9399890bc2b4431e146c233fe022f0991cf61 Mon Sep 17 00:00:00 2001 From: "Jonathan A. McCormick, Jr." <67705789+JonathanMcCormickJr@users.noreply.github.com> Date: Sun, 16 Mar 2025 12:29:14 -0500 Subject: [PATCH 1/8] Update 12-pastebin.md Fixing typo. --- docs/guide/12-pastebin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/12-pastebin.md b/docs/guide/12-pastebin.md index 7b41470720..96176b12f6 100644 --- a/docs/guide/12-pastebin.md +++ b/docs/guide/12-pastebin.md @@ -470,7 +470,7 @@ We note the following Rocket APIs being used in our implementation: * [`Data::open()`] to open [`Data`] as a [`DataStream`]. * [`DataStream::into_file()`] for writing the data stream into a file. * The [`UriDisplayPath`] derive, allowing `PasteId` to be used in [`uri!`]. - * The [`uri!`] macro to crate type-safe, URL-safe URIs. + * The [`uri!`] macro to create type-safe, URL-safe URIs. [`Data::open()`]: @api/master/rocket/data/struct.Data.html#method.open [`Data`]: @api/master/rocket/data/struct.Data.html From e2a8c6a45cf418bf3fab3bfb6344f5be2ea2f735 Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Sun, 4 May 2025 03:05:17 -0500 Subject: [PATCH 2/8] Fix testbench mtls tests - Update `gen_certs.sh` - Generate client cert as well by default - Set expiration to 10 years to match other certs - Set subject to match expected values in testbench test - Update testbench `mtls` to ignore key hash value, and only check issuer and subject. --- examples/tls/private/client.pem | 98 +++++++++++++++---------------- examples/tls/private/gen_certs.sh | 13 ++-- testbench/src/servers/mtls.rs | 8 +-- 3 files changed, 60 insertions(+), 59 deletions(-) diff --git a/examples/tls/private/client.pem b/examples/tls/private/client.pem index a5ba33910b..182f482090 100644 --- a/examples/tls/private/client.pem +++ b/examples/tls/private/client.pem @@ -1,58 +1,58 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjle13u/R/0+zw -eycXhdF7ZNYQfqXfkMpw9GlerbqRrxSLEc/YXXBuIO5AZKkXYeP8iM9KbSBD4p8F -wZD7LL47601c5WwWpNfOravCaSjYgvaYyhnoNzmG8NYaVYKB9kup6lOyQmesNXEK -NGNSrKpsoaQ7jBk+l+VV1jNBjMhNVWuz4AdFMsVD09QyL1GvQ0OvT/BbUKypaFFw -YcHruYvHuKGnrlXkvw05aZmKtKiSE6UQoDKtZWfV8yV2M6Sr75i9GKaGMyUZIl88 -MxVLGcGwO6To2wNFKfLkHLOGIWrKA7m/Bb2n1k2OT+6iOnDzU62BoAzG/j8dhNPL -mZ6a7cZfAgMBAAECggEANwiZe06gUuDZNY44+JDsiLbDzYjOBQiREq8nQ9LukVR1 -dNPpOME2sdYiUUeMG3GzYaIlGsTbtfrnxOf5/oZu+XmP7VDBrFyIvd9viVgXhb+J -dp2HWbg6gktDvFhIL7DMg71xqubsOeNAxE4bnBS6wREgT2gylfxECzykwci7Gki4 -AkeihvaxqdHk9WP8dtFOuCYhX5pyKd9veS1/L01dVMpoFrq72PHupplKYb3HIo+v -ga02DhNVcH3fomEbXzazC64k2h5Vz+8mgpu5/V1thKiB2izOwt/hv4tkf2iDNz43 -xdSYUEFsk80M97VI1dM1+TBe/JO0auZvKLkuOWUjAQKBgQDlBMr+d+guajgQ863I -uEFK4veEXrD51L6AKT+cqFUi894fhOodnnmK8l3JBKzO0zjgsaez8exKZPRN8An8 -4MejM+hMYciJsP7uDpPkhlI5zHd9CR7EFPWXXpt4PecQLvBbnJ/lDnWCrE4m5Zhs -9OR7izLMBAmaiPlTNAaXj22iqwKBgQC226wzXGr//lnTggZX+u9UdkZKewAYlgnB -Ywj3+JB6Q/kDDS8C6fdlAvWyHShxtO3gx2pJSI3hk7J8fZu/kbojlLF16ayO+tgg -t3EoTZxN5zncygPaULstdKHhnMp8a4AO8lLrHtackFbbX7fuUJft0w457FpARvM8 -DONjWI8LHQKBgBBY5TyAxpv5jQL4weDf9hkoVk6mi69plieDyjyeb2VNTv+k9yki -FL7sSfF9WfBxd0/innvjuuAckKu3hJ7+VIG7xMse97eMYMYRWFEpnVju1WChdAa/ -EEC7yhEtKf8nupRve6JYA99N+U4heV3dpSmEaB3T8/OJ73IW9pl+7W59AoGADxM/ -OCDHZYF3sFtI4Jn8fy8dDmjjkiNUfJAInkDs0FeoQNsmZAwb7ET5Moz615z9+4kV -NyN3JwDBN0g3vexqtyI8Gyd/pW4CwXe+KX90gmustoolFSuQsueprOr7OpS2QwUx -Vtb9BH1V29IhXNFiJSZARwA4VJJE3U+Gs5sKd/UCgYEAoCPE3gVaa89nOqQtalhT -9SISOGQxxMknjNFrEuF3UaGuR0cxDRLX6lSEneAATEpho0QB2Fj4vO8PiyYOGvH+ -5ouJD97rcU77OOixlLFt4+TAWI9AvT0mN7y+SHJ22RkwWGQyF4TIfkg0tQvu36D+ -35W26Li1WteB2O4wV9qVReA= +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCu68//dEJZTfUb +g6lKo0AkcjWevKMtZVpO6YnBCQ+7J0d1U0p7OCN+bisCx0nXvzDO6VxDgWEcnG44 +IR03qYVihq+C1r/96I+6chKIqK0LI2WhXvJ/sXnzz1feFyBYoz/oSM6QndcjUV83 +R8nzp1+eefuTDjuhcCddAk8fU5fJ9OLd7B2sKit8ZLHdHwqlZSWU32sS12xEjP// +TjazNzP137KVa/KKVvRu2xYlRWHRmR1zY8trSy1795GIdv7198nF2i+0oS4k0PrF +LzIUYgr1fCZr3QYjLK7mErSpkXUk5FoEhApmWo9iGLOOWv3HUSC8yCgdcIcauK8N +zTqz2iORAgMBAAECggEAEeG3d1+U3M5Jt/tYq3GkQAA7l7OkYXf9UxiFZZTIj+hZ +t2vBWcwJDNwJoj9p6W1OebMveb3YhfU+lexaBp5aLWf5ZJW8NiJidxFBmx4rOnqZ +jB/0XbYbR8pdgC27DR9QjC134x7PpyOivo2kiTewtbcLTyLjA64/HT9RhAamphWA +aGNex/imFfrWObHg9BNTtfMDekfsOwHOIgbWS/TvdJaVbUzOphZZLmM3mOG/VROG +BIlDS7mfIO1/YHCE88vfRD3iuiGe3H86Tb6qZL+3xNNAzXIu/UqpLz+FGc9TMJRK +FZ/u0beD1U6Ij9/BZ6XO3UF7tN84UqhudZ2rnlG35QKBgQDeg4f6lNpTOKRgrVYx +sLZN5HANWe9I5n8z+TZcv2/pPtQY1A9ZDPM7s0b+Zys089k4f5qXNew0u/JTpin8 +h2MYNvNxXt/fCMxw7PBTkXB1JW+Qofz9k04NRXvMXEtGA3VR+vQcUwdEa9t9dWjD +rM1k5vp2tSIgqJujZmqtqQdpJwKBgQDJPr9qlVCbWGNXn70HPl5G2MVPvRT6aHVo +Hx9XUTU4spyCIfmsckh0S2BODJZAHlTZctOKPz7KfnPC6T8V9Vgwzwnv18X71+9w +4Z8D4OznWL3FNP5RaXSkR7JkpyE79drjVS5MCWC1k7Rr5T9dMPLu6GyjjH6nLfrr +MsKuNa7QhwKBgBoP1dFntdqhe79HDh1r0S52XxlxOzGSrbtsqQ1b7sOm9DikPdf0 +SFjpupr5gnoFRZ/0cirbyfqzOMLLZ4eIY/bmGMVik14QLcHcPpnLIxzVcafDEVqx +8iZjyQg6lyZwKUGc3xKiNuuwplifc9HXX4c99oAI3yJsHS6aRExqy89pAoGACbTe +FKz5A1UjDYHl4yiN8YrZEXyEO4O4TfpaT6LaF07+H4S1/yxP9FQCZCFVSehsnURd +kah1Rd0NhlQrt8pqo4gI6amVog0LPn2TZuN9abctCAsDTTfx6U6P+yzYfITiNt7P +6dj18iwaoq2e/cazoPRS8RyAq12bYabEHxT1xpcCgYAIEOqYHdawRk7nexDRiHcc +8kDIofYXJRXzdjfWH+j1j5/Dk3Ssuiz+/mIZU3PeLwC/p8PS0MmuPe10fC7bHM43 +kI6rdzMEyM586eIEQGJoZmHanK6Ox27qTXoOtX0mpc7DfRVainH70Jseaz7WddNU +wOWmTtGwe4WcO7Ky1RB/oQ== -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIEwDCCAqigAwIBAgIUay5Z8sVQUkSTFpacn6o4iq2ElGowDQYJKoZIhvcNAQEL +MIIEwDCCAqigAwIBAgIUedqTn+lWoKa2Ns1KDFXAG15/uYYwDQYJKoZIhvcNAQEL BQAwRzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQKDAlSb2NrZXQg -Q0ExFzAVBgNVBAMMDlJvY2tldCBSb290IENBMB4XDTI0MDQxNDA4MTU0MVoXDTI1 -MDQxNDA4MTU0MVowgY4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh +Q0ExFzAVBgNVBAMMDlJvY2tldCBSb290IENBMB4XDTI1MDUwNDA4MDQwNFoXDTM1 +MDUwMjA4MDQwNFowgY4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh MRcwFQYDVQQHDA5TaWxpY29uIFZhbGxleTEPMA0GA1UECgwGUm9ja2V0MRswGQYD VQQDDBJSb2NrZXQgVExTIEV4YW1wbGUxIzAhBgkqhkiG9w0BCQEWFGV4YW1wbGVA -cm9ja2V0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo5Xt -d7v0f9Ps8HsnF4XRe2TWEH6l35DKcPRpXq26ka8UixHP2F1wbiDuQGSpF2Hj/IjP -Sm0gQ+KfBcGQ+yy+O+tNXOVsFqTXzq2rwmko2IL2mMoZ6Dc5hvDWGlWCgfZLqepT -skJnrDVxCjRjUqyqbKGkO4wZPpflVdYzQYzITVVrs+AHRTLFQ9PUMi9Rr0NDr0/w -W1CsqWhRcGHB67mLx7ihp65V5L8NOWmZirSokhOlEKAyrWVn1fMldjOkq++YvRim -hjMlGSJfPDMVSxnBsDuk6NsDRSny5ByzhiFqygO5vwW9p9ZNjk/uojpw81OtgaAM -xv4/HYTTy5memu3GXwIDAQABo1wwWjAYBgNVHREEETAPgg1ETlM6bG9jYWxob3N0 -MB0GA1UdDgQWBBSowDBXM26C7VogwXNB1F0vLpYO7DAfBgNVHSMEGDAWgBREAyUj -0lTwopZ2B1VmnvMPfUtCkzANBgkqhkiG9w0BAQsFAAOCAgEAbjF11+t8qVEF72ey -19p1sRkG9ygb0gE2UpLzVpPilucioIOwQuT4rvsVYZQxK+smQZURDI4uNXODIeoS -r3maL82VryLSYbkQADyShYjF0uCX8AfCI0YtOKOschNZDcZEJ5mUpHjJE0lEZnkO -x8ZVXwWf4pv1/8DZoCkMN3gDHwhQGPtrls4q7O38rI7zK9DNrzu7R1ZdGjQSDasL -6DqHee90O2ejpELUxO6lRl2EUosfklRvjV7hfrDHlpN9EuweXt0JiaKw3WZzHSLa -dKS8wtTMq5aWzOWrew1ZEhRr+B3KS6BSC5o9xSQMfcDyS0KJcIJI9bNh3nElWFhM -IBVtGxM/EYAwNJ++jLD10WHvaqW0epMV2cUu+dGJX+TPuI0c/wNehisS4ahvR64m -UpjAwNUBlYpR/Gb15/i2fVk2BbUyU3AcpZfWFDopQ8UqC8ALVcNjbNHq+yVkuTpj -gn5iiTTcTqb6qNfie4oDX4KR6ZgpNiTl/PWZo58qxSwdGiJwrINACkPJ6Qg6Qrpd -hp3CanTWjioHfvTSdiubqw5/XRnqa2Iav0Sttc6TPnTimodmtWkaYA8mvjS+jq8N -f9l2UYQz8yLabMkn98BM+gRJYwrVt6sCbVuEaHgPwq/qX9mQFhUrfw3iEPKlmezt -T3AhgPhybUpMFpu+4Tp8JE2JlKQ= +cm9ja2V0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAruvP +/3RCWU31G4OpSqNAJHI1nryjLWVaTumJwQkPuydHdVNKezgjfm4rAsdJ178wzulc +Q4FhHJxuOCEdN6mFYoavgta//eiPunISiKitCyNloV7yf7F5889X3hcgWKM/6EjO +kJ3XI1FfN0fJ86dfnnn7kw47oXAnXQJPH1OXyfTi3ewdrCorfGSx3R8KpWUllN9r +EtdsRIz//042szcz9d+ylWvyilb0btsWJUVh0Zkdc2PLa0ste/eRiHb+9ffJxdov +tKEuJND6xS8yFGIK9Xwma90GIyyu5hK0qZF1JORaBIQKZlqPYhizjlr9x1EgvMgo +HXCHGrivDc06s9ojkQIDAQABo1wwWjAYBgNVHREEETAPgg1ETlM6bG9jYWxob3N0 +MB0GA1UdDgQWBBRfHH7YEW3/jj2tvNsdcEU7hB3SlDAfBgNVHSMEGDAWgBREAyUj +0lTwopZ2B1VmnvMPfUtCkzANBgkqhkiG9w0BAQsFAAOCAgEAOTOF2u58WDp1kPKP +mTcjeVBunpu1qWmditSlu9+YNPmKwv22Lcwg9dMPh1o8bH80wdtmrGH0Yi857M9D +eosieaKHNN7WUU9DRqENJutknFxZ2hd1L3GOqADJujL43BDgOWL8b3ffmfP0f7b1 +5OsFmQALNWMlI5ThpK6naor7aWjXshCVVfjrDFfAouEyr6gLgKVpYyi4cQX7MCH2 +RfDgbksKy5OmqhI2374DEQgxlqadnnc+HTx2zKmLErUSvuE1K1CmKgwrZDyueTPh +aDKBNZrWh7t7okrcbyWFMmqaZtpMWMSvldvihIXv10v9LuRuHMd+QoNvfigrJofd +zEtk0+ZXx9DMSN5djhfyvxhapGGel68Kjt/XPamcx4pTzzxyKvoNLooEfV/WZnp7 +2n6MlNBcjmi0EBX8Xr7cbviBSXADAAGxnwFoLMUB/hK6oWdv5lkWPojzM7/E0cyW +cjIkF54wM/mXsxoHRqNFKo5pdjZYvoonguYADTU9+EsfM7Amp06Xqm/YR79L5yCa +GbRW0b4sUaYXGusTOuXpVqBfRxO7NG8J4r1OP9l3RP8tqwP+1JuDfyKyhD5yNmYl +OJFfHxS8udBM3ZbrzrfaT4/1T66prRC4QeufkjP6Zhj+l88rxgdg3KEN3VOjJ1IB +J3ig0HbpD/ETWVT21vrqhHXJXWg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbzCCA1egAwIBAgIURX345HUrWikAysSTFd8xoV5GSIYwDQYJKoZIhvcNAQEL diff --git a/examples/tls/private/gen_certs.sh b/examples/tls/private/gen_certs.sh index cb68ac5a1f..275de5bb60 100755 --- a/examples/tls/private/gen_certs.sh +++ b/examples/tls/private/gen_certs.sh @@ -138,13 +138,13 @@ function gen_ecdsa_nistp521_sha512() { } function gen_client_cert() { - openssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr - openssl x509 -req -extfile <(printf "subjectAltName=DNS:${ALT}") -days 365 \ - -in client.csr -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ - -out client.crt + openssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr -subj "/C=US/ST=California/L=Silicon Valley/O=Rocket/CN=Rocket TLS Example/emailAddress=example@rocket.local" + openssl x509 -req -extfile <(printf "subjectAltName=DNS:${ALT}") -days 3650 \ + -in client.csr -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \ + -out client.crt - cat client.key client.crt ca_cert.pem > client.pem - rm client.key client.crt client.csr ca_cert.srl + cat client.key client.crt ca_cert.pem > client.pem + rm client.key client.crt client.csr ca_cert.srl } case $1 in @@ -160,5 +160,6 @@ case $1 in gen_ecdsa_nistp256_sha256 gen_ecdsa_nistp384_sha384 gen_ecdsa_nistp521_sha512 + gen_client_cert ;; esac diff --git a/testbench/src/servers/mtls.rs b/testbench/src/servers/mtls.rs index 1fdaea7ae0..9c85840c92 100644 --- a/testbench/src/servers/mtls.rs +++ b/testbench/src/servers/mtls.rs @@ -28,10 +28,10 @@ fn test_mtls(mandatory: bool) -> Result<()> { .identity(reqwest::Identity::from_pem(&pem)?) .try_into()?; - let response = client.get(&server, "/")?.send()?; - assert_eq!(response.text()?, - "611895682361338926795452113263857440769284805738:2\ - [C=US, ST=CA, O=Rocket CA, CN=Rocket Root CA] \ + let response = client.get(&server, "/")?.send()?.text()?; + let (_key_hash, subject) = response.split_once(":2").unwrap(); + assert_eq!(subject, + "[C=US, ST=CA, O=Rocket CA, CN=Rocket Root CA] \ C=US, ST=California, L=Silicon Valley, O=Rocket, \ CN=Rocket TLS Example, Email=example@rocket.local"); From 64ef4e93b4df17f018928f0cd9ac3d45973cf7ab Mon Sep 17 00:00:00 2001 From: Cormac Relf Date: Sun, 4 May 2025 03:34:47 -0500 Subject: [PATCH 3/8] Squashed commit of the following: commit 9fcc5299c3ce020d0d0b9ae41d112436b786d083 Author: Cormac Relf Date: Mon Apr 14 17:36:07 2025 +1000 Improve db_pools init: do not crash if DB unavailable during startup ## Why? When using `Pool::connect[_with]`, sqlx attempts to connect to the given database immediately, and the fairing will fail if there are any problems in that attempt (beyond obvious configuration problems that are found before hitting the network), e.g.: - the database is unavailable; or - the username/password is incorrect; or - the ssl configuration is invalid; or - any other connection issue. There are a few pros and cons to this approach: Pros: - In development, configuration errors are surfaced slightly faster Cons: - Databases are expected to be unavailable sometimes. It does not normally crash a server if one becomes unavailable after startup, so why should it prevent a server from starting at all? See [deadpool's justification]{https://docs.rs/deadpool} for not crashing. - In production/testing, slower to debug configuration or networking errors as your edit-test loop now involves restarting an application rather than refreshing a page or trying a request again. - Causes database or configuration issues to appear as "failed deployments" in standard deployment scenarios. - Introduces hard ordering constraints on operator actions during database recovery, requiring reboots to follow a functioning database or applications not to be restarted at certain times ## Effect of change The sqlx backend now behaves like the deadpool backend: no connection issues are surfaced during startup. You will not see them until you attempt to get a connection from the pool. That means rocket will launch and you can find problems like these in smoke tests. --- contrib/db_pools/lib/src/pool.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/contrib/db_pools/lib/src/pool.rs b/contrib/db_pools/lib/src/pool.rs index b37fecced4..3d54dc485d 100644 --- a/contrib/db_pools/lib/src/pool.rs +++ b/contrib/db_pools/lib/src/pool.rs @@ -276,14 +276,12 @@ mod sqlx { } } - sqlx::pool::PoolOptions::new() + Ok(sqlx::pool::PoolOptions::new() .max_connections(config.max_connections as u32) .acquire_timeout(Duration::from_secs(config.connect_timeout)) .idle_timeout(config.idle_timeout.map(Duration::from_secs)) .min_connections(config.min_connections.unwrap_or_default()) - .connect_with(opts) - .await - .map_err(Error::Init) + .connect_lazy_with(opts)) } async fn get(&self) -> Result { From 207e1226d049bb0947513e1da45e8dbc8011f4ef Mon Sep 17 00:00:00 2001 From: Dan Fego Date: Sun, 4 May 2025 03:41:06 -0500 Subject: [PATCH 4/8] Squashed commit of the following: commit 74f884d7c7dd560972f5dce5b94d7997f691c1a3 Author: Dan Fego Date: Sat Mar 29 00:11:16 2025 -0400 Added test for new config values commit 0212e88f9e801a2cf4c537e12acefe432d91234a Author: Dan Fego Date: Sat Mar 29 00:03:01 2025 -0400 Fix 'Config' made defaults consistent with docs --- contrib/db_pools/lib/src/config.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/contrib/db_pools/lib/src/config.rs b/contrib/db_pools/lib/src/config.rs index 8d45ea63fc..cd423e7a47 100644 --- a/contrib/db_pools/lib/src/config.rs +++ b/contrib/db_pools/lib/src/config.rs @@ -50,7 +50,7 @@ use rocket::serde::{Deserialize, Serialize}; /// For higher-level details on configuring a database, see the [crate-level /// docs](crate#configuration). // NOTE: Defaults provided by the figment created in the `Initializer` fairing. -#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(crate = "rocket::serde")] pub struct Config { /// Database-specific connection and configuration URL. @@ -93,3 +93,28 @@ pub struct Config { /// _Default:_ `None`. pub extensions: Option>, } + +impl Default for Config { + fn default() -> Self { + Self { + url: Default::default(), + min_connections: Default::default(), + max_connections: rocket::Config::default().workers * 4, + connect_timeout: 5, + idle_timeout: Default::default(), + extensions: Default::default(), + } + } +} + +#[cfg(test)] +mod tests { + use super::Config; + + #[test] + fn default_values_sane() { + let config = Config::default(); + assert_ne!(config.max_connections, 0); + assert_eq!(config.connect_timeout, 5); + } +} From 1551b1bcd341015c8da1d8f9459b34bebe2d477c Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Sun, 4 May 2025 03:57:56 -0500 Subject: [PATCH 5/8] Squashed commit of the following: commit 599d5ee17fb1435b3f1a240a968d295f5f431d5e Author: Paul Adenot Date: Wed Jan 1 18:21:18 2025 +0100 Fix Dockerfile example in "Deploying" chapter This now matches the layout of a typical project, instead of erroring out. --- docs/guide/11-deploying.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide/11-deploying.md b/docs/guide/11-deploying.md index 245683ccec..8bdd4f8ade 100644 --- a/docs/guide/11-deploying.md +++ b/docs/guide/11-deploying.md @@ -262,9 +262,9 @@ WORKDIR /app COPY --from=build /build/main ./ ## copy runtime assets which may or may not exist -COPY --from=build /build/Rocket.tom[l] ./static -COPY --from=build /build/stati[c] ./static -COPY --from=build /build/template[s] ./templates +COPY --from=build /build/Rocket.tom[l] ./ +COPY --from=build /build/stati[c] ./static/ +COPY --from=build /build/template[s] ./templates/ ## ensure the container listens globally on port 8080 ENV ROCKET_ADDRESS=0.0.0.0 From 4358dae54fe850dc7e42c58869ba11a7677f75b9 Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Sun, 4 May 2025 04:32:11 -0500 Subject: [PATCH 6/8] Add HttpVersion field to Request - Based on #2930 - Populates value from hyper version - Adds method to override version for local requests --- core/http/src/lib.rs | 16 +++++++++++ core/lib/src/local/asynchronous/request.rs | 9 +++++- core/lib/src/local/blocking/request.rs | 7 +++++ core/lib/src/request/request.rs | 32 ++++++++++++++++++++-- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/core/http/src/lib.rs b/core/http/src/lib.rs index 86950c2428..d81d3e58c6 100644 --- a/core/http/src/lib.rs +++ b/core/http/src/lib.rs @@ -39,3 +39,19 @@ pub use crate::method::Method; pub use crate::status::{Status, StatusClass}; pub use crate::raw_str::{RawStr, RawStrBuf}; pub use crate::header::*; + +/// HTTP Protocol version +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum HttpVersion { + /// `HTTP/0.9` + Http09, + /// `HTTP/1.0` + Http10, + /// `HTTP/1.1` + Http11, + /// `HTTP/2` + Http2, + /// `HTTP/3` + Http3, +} diff --git a/core/lib/src/local/asynchronous/request.rs b/core/lib/src/local/asynchronous/request.rs index 4c85c02024..b9f2c777dc 100644 --- a/core/lib/src/local/asynchronous/request.rs +++ b/core/lib/src/local/asynchronous/request.rs @@ -1,5 +1,7 @@ use std::fmt; +use rocket_http::HttpVersion; + use crate::{Request, Data}; use crate::http::{Status, Method}; use crate::http::uri::Origin; @@ -48,7 +50,7 @@ impl<'c> LocalRequest<'c> { // Create a request. We'll handle bad URIs later, in `_dispatch`. let origin = try_origin.clone().unwrap_or_else(|bad| bad); - let mut request = Request::new(client.rocket(), method, origin); + let mut request = Request::new(client.rocket(), method, origin, None); // Add any cookies we know about. if client.tracked { @@ -62,6 +64,11 @@ impl<'c> LocalRequest<'c> { LocalRequest { client, request, uri: try_origin, data: vec![] } } + #[inline] + pub fn override_version(&mut self, version: HttpVersion) { + self.version = Some(version); + } + pub(crate) fn _request(&self) -> &Request<'c> { &self.request } diff --git a/core/lib/src/local/blocking/request.rs b/core/lib/src/local/blocking/request.rs index 4d8e35373e..8e34dd7192 100644 --- a/core/lib/src/local/blocking/request.rs +++ b/core/lib/src/local/blocking/request.rs @@ -1,5 +1,7 @@ use std::fmt; +use rocket_http::HttpVersion; + use crate::{Request, http::Method, local::asynchronous}; use crate::http::uri::Origin; @@ -42,6 +44,11 @@ impl<'c> LocalRequest<'c> { Self { inner, client } } + #[inline] + pub fn override_version(&mut self, version: HttpVersion) { + self.inner.override_version(version); + } + #[inline] fn _request(&self) -> &Request<'c> { self.inner._request() diff --git a/core/lib/src/request/request.rs b/core/lib/src/request/request.rs index e99e721d3b..4721bf83d7 100644 --- a/core/lib/src/request/request.rs +++ b/core/lib/src/request/request.rs @@ -6,6 +6,8 @@ use std::str::FromStr; use std::future::Future; use std::net::IpAddr; +use http::Version; +use rocket_http::HttpVersion; use state::{TypeMap, InitCell}; use futures::future::BoxFuture; use ref_swap::OptionRefSwap; @@ -31,6 +33,7 @@ pub struct Request<'r> { method: AtomicMethod, uri: Origin<'r>, headers: HeaderMap<'r>, + pub(crate) version: Option, pub(crate) errors: Vec, pub(crate) connection: ConnectionMeta, pub(crate) state: RequestState<'r>, @@ -84,12 +87,14 @@ impl<'r> Request<'r> { pub(crate) fn new<'s: 'r>( rocket: &'r Rocket, method: Method, - uri: Origin<'s> + uri: Origin<'s>, + version: Option, ) -> Request<'r> { Request { uri, method: AtomicMethod::new(method), headers: HeaderMap::new(), + version, errors: Vec::new(), connection: ConnectionMeta::default(), state: RequestState { @@ -104,6 +109,22 @@ impl<'r> Request<'r> { } } + /// Retrieve http protocol version, when applicable. + /// + /// # Example + /// + /// ```rust + /// use rocket::http::HttpVersion; + /// + /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap(); + /// # let mut req = c.get("/"); + /// # req.override_version(HttpVersion::Http11); + /// assert_eq!(req.version(), Some(HttpVersion::Http11)); + /// ``` + pub fn version(&self) -> Option { + self.version + } + /// Retrieve the method from `self`. /// /// # Example @@ -1130,7 +1151,14 @@ impl<'r> Request<'r> { }); // Construct the request object; fill in metadata and headers next. - let mut request = Request::new(rocket, method, uri); + let mut request = Request::new(rocket, method, uri, match hyper.version { + Version::HTTP_09 => Some(HttpVersion::Http09), + Version::HTTP_10 => Some(HttpVersion::Http10), + Version::HTTP_11 => Some(HttpVersion::Http11), + Version::HTTP_2 => Some(HttpVersion::Http2), + Version::HTTP_3 => Some(HttpVersion::Http3), + _ => None, + }); request.errors = errors; // Set the passed in connection metadata. From f9de1bf4671100b2f9c9bea6ce206fc4748ca999 Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Sun, 4 May 2025 05:05:08 -0500 Subject: [PATCH 7/8] Resolve new lifetime warnings Rust now warns when it determines that an elided lifetime has a name. This commit updates all of these cases to use the named lifetime instead. --- core/http/src/uri/uri.rs | 4 ++-- core/lib/src/form/context.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/http/src/uri/uri.rs b/core/http/src/uri/uri.rs index 14360e7bc1..03ba0297fe 100644 --- a/core/http/src/uri/uri.rs +++ b/core/http/src/uri/uri.rs @@ -79,7 +79,7 @@ impl<'a> Uri<'a> { /// // Invalid URIs fail to parse. /// Uri::parse::("foo bar").expect_err("invalid URI"); /// ``` - pub fn parse(string: &'a str) -> Result, Error<'_>> + pub fn parse(string: &'a str) -> Result, Error<'a>> where T: Into> + TryFrom<&'a str, Error = Error<'a>> { T::try_from(string).map(|v| v.into()) @@ -127,7 +127,7 @@ impl<'a> Uri<'a> { /// let uri: Origin = uri!("/a/b/c?query"); /// let uri: Reference = uri!("/a/b/c?query#fragment"); /// ``` - pub fn parse_any(string: &'a str) -> Result, Error<'_>> { + pub fn parse_any(string: &'a str) -> Result, Error<'a>> { crate::parse::uri::from_str(string) } diff --git a/core/lib/src/form/context.rs b/core/lib/src/form/context.rs index b733c83607..e91b281f8d 100644 --- a/core/lib/src/form/context.rs +++ b/core/lib/src/form/context.rs @@ -219,7 +219,7 @@ impl<'v> Context<'v> { /// let foo_bar = form.context.field_errors("foo.bar"); /// } /// ``` - pub fn field_errors<'a, N>(&'a self, name: N) -> impl Iterator> + '_ + pub fn field_errors<'a, N>(&'a self, name: N) -> impl Iterator> + 'a where N: AsRef + 'a { self.errors.values() @@ -267,7 +267,7 @@ impl<'v> Context<'v> { /// let foo_bar = form.context.exact_field_errors("foo.bar"); /// } /// ``` - pub fn exact_field_errors<'a, N>(&'a self, name: N) -> impl Iterator> + '_ + pub fn exact_field_errors<'a, N>(&'a self, name: N) -> impl Iterator> + 'a where N: AsRef + 'a { self.errors.values() From 8785af6510c58a4d82a793bc4b54b2bb44ca4b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Art=C3=A9mis?= Date: Thu, 12 Jun 2025 16:26:16 +0200 Subject: [PATCH 8/8] fixed stream responders lifetimes --- core/lib/src/response/stream/bytes.rs | 6 +++--- core/lib/src/response/stream/reader.rs | 6 +++--- core/lib/src/response/stream/sse.rs | 4 ++-- core/lib/src/response/stream/text.rs | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/lib/src/response/stream/bytes.rs b/core/lib/src/response/stream/bytes.rs index 52782aa241..d3a8eeb8be 100644 --- a/core/lib/src/response/stream/bytes.rs +++ b/core/lib/src/response/stream/bytes.rs @@ -61,10 +61,10 @@ impl From for ByteStream { } } -impl<'r, S: Stream> Responder<'r, 'r> for ByteStream - where S: Send + 'r, S::Item: AsRef<[u8]> + Send + Unpin + 'r +impl<'r, 'o, S: Stream> Responder<'r, 'o> for ByteStream + where S: Send + 'o, S::Item: AsRef<[u8]> + Send + Unpin + 'o, 'o: 'r { - fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> { Response::build() .header(ContentType::Binary) .streamed_body(ReaderStream::from(self.0.map(std::io::Cursor::new))) diff --git a/core/lib/src/response/stream/reader.rs b/core/lib/src/response/stream/reader.rs index d3a3da71bf..b4db5886ea 100644 --- a/core/lib/src/response/stream/reader.rs +++ b/core/lib/src/response/stream/reader.rs @@ -139,10 +139,10 @@ impl From for ReaderStream { } } -impl<'r, S: Stream> Responder<'r, 'r> for ReaderStream - where S: Send + 'r, S::Item: AsyncRead + Send, +impl<'r, 'o, S: Stream> Responder<'r, 'o> for ReaderStream + where S: Send + 'o, S::Item: AsyncRead + Send, 'o: 'r { - fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> { Response::build() .streamed_body(self) .ok() diff --git a/core/lib/src/response/stream/sse.rs b/core/lib/src/response/stream/sse.rs index de24ad2816..af9aabdc46 100644 --- a/core/lib/src/response/stream/sse.rs +++ b/core/lib/src/response/stream/sse.rs @@ -568,8 +568,8 @@ impl> From for EventStream { } } -impl<'r, S: Stream + Send + 'r> Responder<'r, 'r> for EventStream { - fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> { +impl<'r, 'o: 'r, S: Stream + Send + 'o> Responder<'r, 'o> for EventStream { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> { Response::build() .header(ContentType::EventStream) .raw_header("Cache-Control", "no-cache") diff --git a/core/lib/src/response/stream/text.rs b/core/lib/src/response/stream/text.rs index 3064e0f0e2..fb14a70af0 100644 --- a/core/lib/src/response/stream/text.rs +++ b/core/lib/src/response/stream/text.rs @@ -62,10 +62,10 @@ impl From for TextStream { } } -impl<'r, S: Stream> Responder<'r, 'r> for TextStream - where S: Send + 'r, S::Item: AsRef + Send + Unpin + 'r +impl<'r, 'o, S: Stream> Responder<'r, 'o> for TextStream + where S: Send + 'o, S::Item: AsRef + Send + Unpin + 'o, 'o: 'r { - fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> { struct ByteStr(T); impl> AsRef<[u8]> for ByteStr {