I am new to Rust. I am using Rocket.
I have a function for file uploads. The size of the upload is restricted.
Doing an upload of a small file succeeds and returns my JSON success message:
curl --form file='@temp.pdf' http://localhost:8000/upload
{"status":"success"}
Doing an upload of a file that is too large returns some other 400 message.
curl --form file='@/home/ubuntu/out.img' http://localhost:8000/upload
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>400 Bad Request</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>400: Bad Request</h1>
<p>The request could not be understood by the server due to malformed syntax.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Rocket</small>
</div>
</body>
</html>
The server console says:
🚀 Rocket has launched from http://0.0.0.0:8000
POST /upload multipart/form-data:
>> Matched: (upload) POST /upload
>> Outcome: Success
>> Response succeeded.
POST /upload multipart/form-data:
>> Matched: (upload) POST /upload
>> Data guard `Form < FileUploadForm < '_ > >` failed: Errors([Error { name: Some("file"), value: None, kind: Io(Custom { kind: Other, error: field "file" received with incomplete data }), entity: Form }]).
>> Outcome: Failure
>> No 400 catcher registered. Using Rocket default.
>> Response succeeded.
POST /upload multipart/form-data:
>> Matched: (upload) POST /upload
>> Outcome: Success
>> Response succeeded.
POST /upload multipart/form-data:
>> Matched: (upload) POST /upload
>> Outcome: Success
>> Response succeeded.
POST /upload multipart/form-data:
>> Matched: (upload) POST /upload
>> Data guard `Form < FileUploadForm < '_ > >` failed: Errors([Error { name: Some("file"), value: None, kind: Io(Custom { kind: Other, error: field "file" received with incomplete data }), entity: Form }]).
>> Outcome: Failure
>> No 400 catcher registered. Using Rocket default.
>> Response succeeded.
Here is my code:
Can anyone suggest why I cannot send my own 400 error?
thanks!
#[macro_use] extern crate rocket;
mod paste_id;
#[cfg(test)] mod tests;
use std::io;
use rocket::{Request, Route, Catcher, route, catcher};
use rocket::data::{Data, ToByteUnit};
use rocket::http::uri::Absolute;
use rocket::response::content::RawText;
use rocket::tokio::fs::{self, File};
use rocket::form::Form;
use rocket::fs::{FileServer, TempFile, relative};
use rocket::serde::json::{Json, Value, json};
use rocket::serde::{Serialize, Deserialize};
use rocket::serde::uuid::Uuid;
use crate::paste_id::PasteId;
use rocket::response;
use rocket::response::status;
use rocket::data::Capped;
use rocket::http::{Status, ContentType};
use std::io::Cursor;
use rocket::response::{Responder, Response};
const HOST: Absolute<'static> = uri!("http://localhost:8000");
#[derive(FromForm)]
pub struct FileUploadForm<'f> {
#[field(validate = len(1..))]
file: Capped<TempFile<'f>>,
}
#[derive(Debug)]
struct ApiResponse {
json: Value,
status: Status,
}
impl<'r> Responder<'r, 'r> for ApiResponse {
fn respond_to(self, req: &Request) -> response::Result<'r> {
Response::build_from(self.json.respond_to(&req).unwrap())
.status(self.status)
.header(ContentType::JSON)
.ok()
}
}
#[post("/upload", data = "<form>")]
pub async fn upload(mut form: Form<FileUploadForm<'_>>) -> ApiResponse {
if form.file.is_complete() {
form.file.persist_to("file.bin").await;
} else {
return ApiResponse {
json: json!({"status": "application error"}),
status: Status::BadRequest,
}
}
ApiResponse {
json: json!({"status": "success"}),
status: Status::Ok,
}
}
#[launch]
fn rocket() -> _ {
rocket::build()
.mount("/", routes![upload])
}