Как разобрать составные формы, используя abonander/multipart с Rocket?

Это может быть полезно для меня:

Я понятия не имею, как вы собираетесь разбирать многокомпонентную форму, кроме того, чтобы делать это вручную, используя только необработанную строку данных после ввода

Я постараюсь настроить пример Hyper, но любая помощь будет высоко ценится.

Актуальные вопросы:

1 ответ

Решение

Основная абстракция Ракеты для данных FromData черта характера. Учитывая данные POST и запрос, вы можете создать данный тип:

pub trait FromData: Sized {
    type Error;
    fn from_data(request: &Request, data: Data) -> Outcome<Self, Self::Error>;
}

Затем нужно просто прочитать API для multipart и вставить вкладку A в слот B:

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate multipart;

#[post("/", data = "<upload>")]
fn index(upload: DummyMultipart) -> String {
    format!("I read this: {:?}", upload)
}

#[derive(Debug)]
struct DummyMultipart {
    alpha: String,
    one: i32,
    file: Vec<u8>,
}

use std::io::{Cursor, Read};
use rocket::{Request, Data, Outcome};
use rocket::data::{self, FromData};
use multipart::server::Multipart;

impl FromData for DummyMultipart {
    type Error = ();

    fn from_data(request: &Request, data: Data) -> data::Outcome<Self, Self::Error> {
        // All of these errors should be reported
        let ct = request.headers().get_one("Content-Type").expect("no content-type");
        let idx = ct.find("boundary=").expect("no boundary");
        let boundary = &ct[(idx + "boundary=".len())..];

        let mut d = Vec::new();
        data.stream_to(&mut d).expect("Unable to read");

        let mut mp = Multipart::with_body(Cursor::new(d), boundary);

        // Custom implementation parts

        let mut alpha = None;
        let mut one = None;
        let mut file = None;

        mp.foreach_entry(|mut entry| {
            match entry.name.as_str() {
                "alpha" => {
                    let t = entry.data.as_text().expect("not text");
                    alpha = Some(t.into());
                },
                "one" => {
                    let t = entry.data.as_text().expect("not text");
                    let n = t.parse().expect("not number");
                    one = Some(n);
                },
                "file" => {
                    let mut d = Vec::new();
                    let f = entry.data.as_file().expect("not file");
                    f.read_to_end(&mut d).expect("cant read");
                    file = Some(d);
                },
                other => panic!("No known key {}", other),
            }
        }).expect("Unable to iterate");

        let v = DummyMultipart {
            alpha: alpha.expect("alpha not set"),
            one: one.expect("one not set"),
            file: file.expect("file not set"),
        };

        // End custom

        Outcome::Success(v)
    }
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}

Я никогда не использовал ни один из этих API около часа назад, поэтому нет гарантии, что это хорошая реализация. Фактически, все паники из-за ошибки определенно означают, что это неоптимально. Производственное использование будет обрабатывать все это чисто.

Тем не менее, это работает:

$ curl -X POST -F alpha=omega -F one=2 -F file=@hello http://localhost:8000/
I read this: DummyMultipart { alpha: "omega", one: 2, file: [104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33, 10] }

Усовершенствованная реализация допускает некоторую абстракцию между пользовательскими данными и общими многочастными аспектами. Что-то вроде Multipart<MyForm> было бы здорово.

Автор Rocket указывает, что это решение позволяет злонамеренному конечному пользователю помещать POST файл бесконечного размера, что приведет к тому, что машине не хватит памяти. В зависимости от предполагаемого использования, вы можете установить ограничение на количество прочитанных байтов, что может привести к записи в файловую систему на некоторой точке останова.

Официальная поддержка синтаксического анализа составных форм в Rocket все еще обсуждается. А пока взгляните на официальный пример того, как интегрировать составной ящик с Rocket: https://github.com/abonander/multipart/blob/master/examples/rocket.rs

Другие вопросы по тегам