Giter VIP home page Giter VIP logo

rocket-multipart-form-data's Introduction

Multipart Form Data for Rocket Framework

CI

This crate provides a multipart parser for the Rocket framework.

Example

#[macro_use] extern crate rocket;

use rocket::Data;
use rocket::http::ContentType;

use rocket_multipart_form_data::{mime, MultipartFormDataOptions, MultipartFormData, MultipartFormDataField, Repetition};

#[post("/", data = "<data>")]
async fn index(content_type: &ContentType, data: Data<'_>) -> &'static str {
    let mut options = MultipartFormDataOptions::with_multipart_form_data_fields(
        vec! [
            MultipartFormDataField::file("photo").content_type_by_string(Some(mime::IMAGE_STAR)).unwrap(),
            MultipartFormDataField::raw("fingerprint").size_limit(4096),
            MultipartFormDataField::text("name"),
            MultipartFormDataField::text("email").repetition(Repetition::fixed(3)),
            MultipartFormDataField::text("email"),
        ]
    );

    let mut multipart_form_data = MultipartFormData::parse(content_type, data, options).await.unwrap();

    let photo = multipart_form_data.files.get("photo"); // Use the get method to preserve file fields from moving out of the MultipartFormData instance in order to delete them automatically when the MultipartFormData instance is being dropped
    let fingerprint = multipart_form_data.raw.remove("fingerprint"); // Use the remove method to move raw fields out of the MultipartFormData instance (recommended)
    let name = multipart_form_data.texts.remove("name"); // Use the remove method to move text fields out of the MultipartFormData instance (recommended)
    let email = multipart_form_data.texts.remove("email");

    if let Some(file_fields) = photo {
        let file_field = &file_fields[0]; // Because we only put one "photo" field to the allowed_fields, the max length of this file_fields is 1.

        let _content_type = &file_field.content_type;
        let _file_name = &file_field.file_name;
        let _path = &file_field.path;

        // You can now deal with the uploaded file.
    }

    if let Some(mut raw_fields) = fingerprint {
        let raw_field = raw_fields.remove(0); // Because we only put one "fingerprint" field to the allowed_fields, the max length of this raw_fields is 1.

        let _content_type = raw_field.content_type;
        let _file_name = raw_field.file_name;
        let _raw = raw_field.raw;

        // You can now deal with the raw data.
    }

    if let Some(mut text_fields) = name {
        let text_field = text_fields.remove(0); // Because we only put one "text" field to the allowed_fields, the max length of this text_fields is 1.

        let _content_type = text_field.content_type;
        let _file_name = text_field.file_name;
        let _text = text_field.text;

        // You can now deal with the text data.
    }

    if let Some(text_fields) = email {
        for text_field in text_fields { // We put "email" field to the allowed_fields for two times and let the first time repeat for 3 times, so the max length of this text_fields is 4.
            let _content_type = text_field.content_type;
            let _file_name = text_field.file_name;
            let _text = text_field.text;

            // You can now deal with the text data.
        }
    }

    "ok"
}

Also see examples.

Crates.io

https://crates.io/crates/rocket-multipart-form-data

Documentation

https://docs.rs/rocket-multipart-form-data

License

MIT

rocket-multipart-form-data's People

Contributors

emmanuelantony2000 avatar gobanos avatar magiclen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

rocket-multipart-form-data's Issues

Fixed or infinite repetition support

Hi,

I've been playing with this multipart crate and wanted to have "infinite" repetition support. Unfortunately the current design forces "fixed" repetition. Moreover the current repetition support has issues among which the need to repeat all the field acceptance criteria (e.g. content type).

In this issue I propose to modify the API to take an repetition: Repetition in field options where Repetition is defined like this:

enum Repetition {
    Fixed(usize),
    Infinite,
}

It shall default to Fixed(1) when calling MultipartFormDataField helpers.

More generally I don't think we need anything like an optional lower boundary and an optional upper boundary.

Another consideration: it may be a good idea to forbid duplicated fields to avoid the mess of computing an actual repetition value for a given field.

What do you think?

--
Arnaud

Rocket 0.5.0-dev with multipart-async

Hi,

I've just spent some time making rocket-multipart-form-data compile against rocket's master branch: https://github.com/impero-com/rocket-multipart-form-data/tree/rocket-0.5.

The example actually does not compile because I didn't have the time to fix rocket-etag-if-none-match where I faced with a problem with hyper. However, I have quickly tested the whole thing with one use case and it seems to be working.

If you are interested in moving forward with this, I would be keen to do additional work.

Example doesn't run as expected...

I was running the examples, and it seems to me that it does not run as expected. No matter whichever file I try, the output is "Please input a file."

Repetition Bug

Bug Reports

rocket = "0.4.10"

Windows 10 2004

The bug seems to be in the following code
Broken:

 let upload_max: u32 = 10;

let options = MultipartFormDataOptions::with_multipart_form_data_fields(
     vec! [
			MultipartFormDataField::file("URL").
repetition(Repetition::fixed(upload_max))
.content_type_by_string(Some(mime::IMAGE_STAR)).unwrap(),
			MultipartFormDataField::text("body"),
		]
);

Works:

let upload_max: u32 = 3;

let options = MultipartFormDataOptions::with_multipart_form_data_fields(
     vec! [
			MultipartFormDataField::file("URL").
repetition(Repetition::fixed(upload_max))
.content_type_by_string(Some(mime::IMAGE_STAR)).unwrap(),
			MultipartFormDataField::text("body"),
		]
);

If I set the upload max to 3 the code works as expected and will upload the 3 files and finish the routine. If I go to 10 (my desired upload limit) it throws an error stating "The data type of field url is incorrect.".
I looked through the source code a bit to see how the fixed() function works and I don't see anything inherently wrong with it. I also could be using this wrong, but it seems the max for the code was set higher than 10 as well. Any help would be appreciated!

Use a tempfile for file fields

If a file is uploaded by a user, and stored in the file system, it hangs around forever. If the program exits, crashes, or even if the developer ignores the file, it will clutter the temp directory.

I think using tempfile() (or if there are too many issues with unnamed files, NamedTempFile) would deal with the issue effectively.

Optional field

Hi,

I can't find a way to have an optional image file in my MultipartFormDataOptions.

I currently have:

let options = MultipartFormDataOptions::with_multipart_form_data_fields(vec![
        MultipartFormDataField::text("title"),
        MultipartFormDataField::text("description"),
        MultipartFormDataField::file("image")
            .content_type_by_string(Some(mime::IMAGE_STAR))
            .unwrap(),
    ]);

But it fails when no image is provided. If I remove the MultipartFormDataField::file("image"), I cannot fetch the image later when needed…

Is it possible? Did I miss something?

How can I send an array of photos?

Hello!

I want to send array of some photos to my application using JS. For example:

function uploadFile(file, i) { 
  var xhr = new XMLHttpRequest()
  xhr.open('POST', '/upload_multipart', true)
  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
  xhr.upload.addEventListener("progress", function(e) {
    updateProgress(i, (e.loaded * 100.0 / e.total) || 100)
  })
  xhr.addEventListener('readystatechange', function(e) {
    if (xhr.readyState == 4 && xhr.status == 200) {
      updateProgress(i, 100)
    }
    else if (xhr.readyState == 4 && xhr.status != 200) {
      // Error
    }
  })

  var formData = new FormData()
  formData.append('image', file)
  formData.append('image', file)
  xhr.send(formData)
}

And I expect the next Rust code to read the array as RawField::Multiple(raws):

#[post("/upload_multipart", data = "<data>")]
fn upload_multipart(content_type: &ContentType, data: Data) -> RawResponse {
    let mut options = MultipartFormDataOptions::new();
    options.allowed_fields.push(
        MultipartFormDataField::raw("image")
            .size_limit(32 * 1024 * 1024)
            .content_type_by_string(Some(mime::IMAGE_STAR))
            .unwrap(),
    );

    let mut multipart_form_data = match MultipartFormData::parse(content_type, data, options) {
        Ok(multipart_form_data) => multipart_form_data,
        Err(err) => match err {
            MultipartFormDataError::DataTooLargeError(_) => {
                return RawResponse::from_vec(
                    "Размер файла слишком большой."
                        .bytes()
                        .collect(),
                    "",
                    Some(mime::TEXT_PLAIN_UTF_8),
                )
            }
            MultipartFormDataError::DataTypeError(_) => {
                return RawResponse::from_vec(
                    "Вы отправили не изображение."
                        .bytes()
                        .collect(),
                    "",
                    Some(mime::TEXT_PLAIN_UTF_8),
                )
            }
            _ => {
                return RawResponse::from_vec(
                    "Произошла ошибка при загрузке файла."
                        .bytes()
                        .collect(),
                    "",
                    Some(mime::TEXT_PLAIN_UTF_8),
                )
            }
        },
    };

    let image = multipart_form_data.raw.remove(&"image".to_string());

    match image {
        Some(image) => match image {
            RawField::Single(raw) => {
                let content_type = raw.content_type;
                let file_name = raw.file_name.unwrap_or("Image".to_string());
                let data = raw.raw;

                let mut file =
                    File::create(Path::new("upload").join(&file_name).to_str().unwrap()).unwrap();
                file.write_all(&data).unwrap();

                RawResponse::from_vec(data, file_name, content_type)
            }
            RawField::Multiple(raws) => {
                for raw in raws {
                    //let content_type = raw.content_type;
                    let file_name = raw.file_name.unwrap_or("Image".to_string());
                    let data = raw.raw;

                    let mut file =
                        File::create(Path::new("upload").join(&file_name).to_str().unwrap())
                            .unwrap();
                    file.write_all(&data).unwrap();

                    //RawResponse::from_vec(data, file_name, content_type)
                }
                unreachable!()
            }
        },
        None => RawResponse::from_vec(
            "Please input a file.".bytes().collect(),
            "",
            Some(mime::TEXT_PLAIN_UTF_8),
        ),
    }
}

And after xhr.send i have response 'Please input a file.'. What am I doing wrong?

Make a release

Hi. I was investigating why cargo was downloading nickel in my project, and after a while I found out that the code here on master is newer than on crates.io. Since there is no ongoing development, could you upload the code to crates.io as version 0.7.1? Thanks in advance.

Question : Setting form size limit

I cannot find ways to set a size limit to the form data.

I've try through rocket.toml forms limit without success
Any way to do it ?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.