Open
Description
Rocket Version
0.5.1
Operating System
Ubuntu 22.04.5 LTS
Rust Toolchain Version
rustc 1.86.0
What happened?
Executing the following request: touch test && curl -F file=@test http://localhost:8000/upload
, on the Rocket code provided in the test case on version 0.5.0 works (i.e. the request form is parsed without issue, and 200 OK is returned). On 0.5.1 I get:
POST /upload multipart/form-data:
>> Matched: (upload) POST /upload multipart/form-data
>> Data guard `Form < MyForm < '_ > >` failed: Errors([Error { name: None, value: None, kind: Multipart(failed to lock multipart state), entity: Form }]).
>> Outcome: Error(400 Bad Request)
>> No 400 catcher registered. Using Rocket default.
>> Response succeeded.
Test Case
use rocket::data::Data;
use rocket::form::{DataField, Errors, Form, FromFormField};
use rocket::{FromForm, launch, post, routes};
struct Upload<'r> {
data: Data<'r>,
}
#[rocket::async_trait]
impl<'v> FromFormField<'v> for Upload<'v> {
async fn from_data(f: DataField<'v, '_>) -> Result<Self, Errors<'v>> {
Ok(Upload { data: f.data })
}
}
#[derive(FromForm)]
struct MyForm<'a> {
file: Upload<'a>,
}
#[post("/upload", format = "multipart/form-data", data = "<form>")]
fn upload(form: Form<MyForm<'_>>) {
println!("upload!");
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![upload])
}
Log Output
-- configuration trace information --
>> "address" parameter source: rocket::Config::default()
>> "port" parameter source: rocket::Config::default()
>> "workers" parameter source: rocket::Config::default()
>> "max_blocking" parameter source: rocket::Config::default()
>> "keep_alive" parameter source: rocket::Config::default()
>> "ident" parameter source: rocket::Config::default()
>> "ip_header" parameter source: rocket::Config::default()
>> "limits" parameter source: rocket::Config::default()
>> "temp_dir" parameter source: rocket::Config::default()
>> "log_level" parameter source: `ROCKET_` environment variable(s)
>> "shutdown" parameter source: rocket::Config::default()
>> "cli_colors" parameter source: rocket::Config::default()
🔧 Configured for debug.
>> address: 127.0.0.1
>> port: 8000
>> workers: 12
>> max blocking threads: 512
>> ident: Rocket
>> IP header: X-Real-IP
>> limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB
>> temp dir: /tmp
>> http/2: true
>> keep-alive: 5s
>> tls: disabled
>> shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s
>> log level: debug
>> cli colors: true
📬 Routes:
>> (upload) POST /upload multipart/form-data
📡 Fairings:
>> Shield (liftoff, response, singleton)
🛡️ Shield:
>> Permissions-Policy: interest-cohort=()
>> X-Content-Type-Options: nosniff
>> X-Frame-Options: SAMEORIGIN
🚀 Rocket has launched from http://127.0.0.1:8000
--> /home/sejnld/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:77
received request: Request {
method: POST,
uri: /upload,
version: HTTP/1.1,
headers: {
"host": "localhost:8000",
"user-agent": "curl/7.81.0",
"accept": "*/*",
"content-length": "196",
"content-type": "multipart/form-data; boundary=------------------------954c7e155e174b71",
},
body: Body(
Streaming,
),
}
POST /upload multipart/form-data:
>> Matched: (upload) POST /upload multipart/form-data
>> multipart field: Field { state: Mutex { data: MultipartState { buffer: StreamBuffer, boundary: "------------------------954c7e155e174b71", stage: ReadingFieldData, next_field_idx: 1, curr_field_name: Some("file"), curr_field_size_limit: 2097152, curr_field_size_counter: 0, constraints: Constraints { size_limit: SizeLimit { whole_stream: 2097152, per_field: 2097152, field_map: {} }, allowed_fields: None } }}, done: false, headers: {"content-disposition": "form-data; name=\"file\"; filename=\"test\"", "content-type": "application/octet-stream"}, content_disposition: ContentDisposition { field_name: Some("file"), file_name: Some("test") }, content_type: Some("application/octet-stream"), idx: 0 }
>> Data guard `Form < MyForm < '_ > >` failed: Errors([Error { name: None, value: None, kind: Multipart(failed to lock multipart state), entity: Form }]).
>> Outcome: Error(400 Bad Request)
>> No 400 catcher registered. Using Rocket default.
--> /home/sejnld/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:166
sending response: Response {
status: 400,
version: HTTP/1.1,
headers: {
"content-type": "text/html; charset=utf-8",
"server": "Rocket",
"permissions-policy": "interest-cohort=()",
"x-content-type-options": "nosniff",
"x-frame-options": "SAMEORIGIN",
"content-length": "471",
},
body: Body(
Streaming,
),
}
>> Response succeeded.
Additional Context
No response
System Checks
- My bug report relates to functionality.
- I have tested against the latest Rocket release or a recent git commit.
- I have tested against the latest stable
rustc
toolchain. - I was unable to find this issue previously reported.