如何使用 abonander/multipart with Rocket 解析多部分形式? [英] How to parse multipart forms using abonander/multipart with Rocket?

查看:41
本文介绍了如何使用 abonander/multipart with Rocket 解析多部分形式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能对我有用:

我不知道您打算如何解析多部分表单除了手动使用原始后数据字符串作为输入之外

I have no idea how you're meant to go about parsing a multipart form besides doing it manually using just the raw post-data string as input

我会尝试调整Hyper example 但任何将不胜感激.

I will try to adjust the Hyper example but any help will be much appreciated.

相关问题:

推荐答案

Rocket 对数据的主要抽象是 FromData 特性.给定 POST 数据和请求,您可以构造给定的类型:

Rocket's primary abstraction for data is the FromData trait. Given the POST data and the request, you can construct a given type:

pub trait FromData<'a>: Sized {
    type Error;
    type Owned: Borrow<Self::Borrowed>;
    type Borrowed: ?Sized;
    fn transform(
        request: &Request, 
        data: Data
    ) -> Transform<Outcome<Self::Owned, Self::Error>>;
    fn from_data(
        request: &Request, 
        outcome: Transformed<'a, Self>
    ) -> Outcome<Self, Self::Error>;
}

然后,只需阅读 API for multipart 并将选项卡 A 插入插槽 B:

Then, it's just a matter of reading the API for multipart and inserting tab A into slot B:

#![feature(proc_macro_hygiene, decl_macro)]

use multipart::server::Multipart; // 0.16.1, default-features = false, features = ["server"]
use rocket::{
    data::{Data, FromData, Outcome, Transform, Transformed},
    post, routes, Request,
}; // 0.4.2
use std::io::Read;

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

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

// All of the errors in these functions should be reported
impl<'a> FromData<'a> for DummyMultipart {
    type Owned = Vec<u8>;
    type Borrowed = [u8];
    type Error = ();

    fn transform(_request: &Request, data: Data) -> Transform<Outcome<Self::Owned, Self::Error>> {
        let mut d = Vec::new();
        data.stream_to(&mut d).expect("Unable to read");

        Transform::Owned(Outcome::Success(d))
    }

    fn from_data(request: &Request, outcome: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
        let d = outcome.owned()?;

        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 mp = Multipart::with_body(&d[..], boundary);

        // Custom implementation parts

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

        mp.foreach_entry(|mut entry| match &*entry.headers.name {
            "alpha" => {
                let mut t = String::new();
                entry.data.read_to_string(&mut t).expect("not text");
                alpha = Some(t);
            }
            "one" => {
                let mut t = String::new();
                entry.data.read_to_string(&mut t).expect("not text");
                let n = t.parse().expect("not number");
                one = Some(n);
            }
            "file" => {
                let mut d = Vec::new();
                entry.data.read_to_end(&mut d).expect("not file");
                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,因此不能保证这是一个好的实现.事实上,所有对错误的恐慌肯定意味着它是次优的.生产用途可以干净地处理所有这些.

I've never used either of these APIs for real, so there's no guarantee that this is a good implementation. In fact, all the panicking on error definitely means it's suboptimal. A production usage would handle all of those cleanly.

但是,它确实有效:

%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 这样的东西会很好.

Rocket 的作者指出该解决方案允许恶意的最终用户 POST 一个无限大小的文件,这将导致机器内存不足.根据预期用途,您可能希望对读取的字节数设置某种上限,可能会在某个断点写入文件系统.

The author of Rocket points out that this solution allows a malicious end user to POST an infinitely sized file, which would cause the machine to run out of memory. Depending on the intended use, you may wish to establish some kind of cap on the number of bytes read, potentially writing to the filesystem at some breakpoint.

这篇关于如何使用 abonander/multipart with Rocket 解析多部分形式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆