Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow wildcards in content-type #583

Open
haBuu opened this issue Mar 11, 2018 · 5 comments
Open

Allow wildcards in content-type #583

haBuu opened this issue Mar 11, 2018 · 5 comments
Labels
enhancement A minor feature request good first issue Beginner-friendly for new contributors

Comments

@haBuu
Copy link

haBuu commented Mar 11, 2018

Currently (Rocket version 0.4.0-dev) if you use a wildcard in content-type you will get a warning like this:

warning: 'image/*' is not a known media type
 --> src/handlers/image.rs:5:33
  |
5 | #[post("/image", format = "image/*", data = "<data>")]
  |                                 ^^^^^^^^^

Using wildcard e.g. for images is needed as you do not know what the actual type of the image will be (png, gif, jpg etc.) and you want to handle all of them in the same route.

@nickdonnelly
Copy link
Contributor

Would love to see a way to suppress these warnings.

@SergioBenitez
Copy link
Member

@nickdonnelly That's not currently possible with Rust's procedural macro infrastructure. I'm hoping to add it soon.

First, hopefully the ^^^^ are in the right place! Second: yes, we should handle this. It would require Rocket to know about some top-level types, which seems easy to do. I'd be happy to mentor an implementation of this.

@SergioBenitez SergioBenitez added enhancement A minor feature request mentored labels Apr 13, 2018
@SergioBenitez SergioBenitez added this to the 0.4.0 milestone Sep 30, 2018
@SergioBenitez SergioBenitez removed this from the 0.4.0 milestone Oct 9, 2018
@jwnhy
Copy link

jwnhy commented May 2, 2020

I am quite new to rust community and want to find something to try, may I take this issue?
Could your give me some guide?

@jebrosen
Copy link
Collaborator

jebrosen commented May 2, 2020

I think as a first step we need to decide what exactly to do and figure out how much work / how difficult the parts are. This is what I found so far:

  1. The format= is used for GET requests to match the Accept header (media type wanted by the client), and for POST requests to match the Content-Type header (media type sent by the client). The example seems clearly motivated for allowing POST to use wildcards; I'm not as certain about GET.
  2. The code generation (impl FromMeta for MediaType in core/codegen/src/http_codegen.rs) emits a warning on encountering an "unknown" media type (both top- and sub-level must be known as a unit). This should be relaxed at least to allow any known top-level with the * sub-level - */* may be nice to allow for consistency but should be the same as leaving format= off entirely. Currently the warning happens during parsing, but we may need to move that warning logic into the route macro especially if GET vs POST makes a difference.
  3. The route matching (formats_collide, formats_match, media_types_collide in core/lib/src/router/collider.rs) appears to already handle wildcards, treating image/png as a match to image/*. It also appears to match the (nonsensical) */png against image/*, but that's a separate issue.

This may not be the easiest thing to work on for a newcomer because of the code generation aspect, but any thoughts or concerns on the above points would be greatly appreciated.

@SergioBenitez SergioBenitez added the good first issue Beginner-friendly for new contributors label Apr 17, 2024
@giantcow
Copy link

I think this works? at least it seems to work out of the box for me...

Working example code
#[macro_use]
extern crate rocket;

use rocket::fs::TempFile;

type V1APIResult<T> = Result<T, rocket::response::Debug<anyhow::Error>>;

#[post("/upload", format = "*/*", data = "<file>", rank = 2)]
async fn post_upload(mut file: TempFile<'_>) -> V1APIResult<()> {
    println!("Temp file is {:?}", file);
    Ok(())
}

#[put("/upload", format = "*/*", data = "<file>", rank = 1)]
async fn put_upload(mut file: TempFile<'_>) -> V1APIResult<()> {
    println!("Temp file is {:?}", file);
    Ok(())
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/v1", routes![post_upload, put_upload])
}
# Rocket.toml
[debug.limits]
file = "1Gb"

Executing the following:

curl -svvv \
    -T ../bbb_sunflower_1080p_30fps_normal.mp4 \
    -H 'Content-Type: application/mp4' \
    -L http://127.0.0.1:8000/v1/upload

leads to a 200:

PUT /v1/upload application/mp4:
   >> Matched: (put_upload) PUT /v1/upload */*
Temp file is File { file_name: None, content_type: Some(ContentType(MediaType { source: Custom("application/mp4"), top: (0, 11), sub: (12, 15), params: Dynamic([]) })), path: Left("/tmp/.tmpYJX7Zc"), len: 276134947 }
   >> Outcome: Success(200 OK)
   >> Response succeeded.

However this doesn't seem to work with the limits config, ie having:

# Rocket.toml
[debug.limits]
"application/*" = "1Gb"

Executing the following:

curl -svvv \
    -T ../bbb_sunflower_1080p_30fps_normal.mp4 \
    -H 'Content-Type: application/mp4' \
    -L http://127.0.0.1:8000/v1/upload

leads to:

PUT /v1/upload application/mp4:
   >> Matched: (put_upload) PUT /v1/upload */*
   >> Data limit reached while reading the request body.
   >> Data guard `TempFile < '_ >` failed: Custom { kind: UnexpectedEof, error: "data limit exceeded" }.
   >> Outcome: Error(400 Bad Request)
   >> No 400 catcher registered. Using Rocket default.
   >> Response succeeded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement A minor feature request good first issue Beginner-friendly for new contributors
Projects
None yet
Development

No branches or pull requests

6 participants