8000 Form parsing with data stream regression: Multipart(failed to lock multipart state) · Issue #2941 · rwf2/Rocket · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Form parsing with data stream regression: Multipart(failed to lock multipart state) #2941
Open
@johnli360

Description

@johnli360

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageA bug report being investigated

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0