Skip to content

Cannot upload plain/text (*.txt) files with rouille::input::post::BufferedFile #291

@osmoma

Description

@osmoma

I have problems uploading multipart form data from HTML/Javascript to my rouille server.
In the server I use the rouille::input::post routines.

It works very well for all kind of files BUT NOT for plain/text files. I cannot make it accept any .txt files.
The input::post::BufferedFile sets the slot (quite often) to None for plain/text files (maybe it lacks info about the file's MIME Type, plain/text).

See the cases when it works and when not.
The test-program:

THESE FAIL:
These curl and httpie commands fail. Server does not recognize the test1.txt file (cannot dertermine its MIME?).

curl -X POST --form "field1=112" --form "field2=Booom" --form "files=@test1.txt" --form "files=@test2.json" http://localhost:8000/post

http --verify=no --form post http://localhost:8000/post  field1=112 field2="Booom!" files@'test1.txt' files@'test2.json'

THESE ARE OK:
These commands work right, the server receives the files and all good. Setting the MIME type manually.
test1.txt; type=plain/text
test2.json; type=application/json

curl --form "field1=112" --form "field2=Booom" --form "files=@test1.txt;type=plain/text" --form "files=@test2.json;type=application/json" http://localhost:8000/post

http --verify=no --form post http://localhost:8000/post  field1=112 field2="Booom!" files@'test1.txt;type=plain/text' files@'test2.json;type=application/octet-stream'

POSTING FROM HTML/JS FAILS TO UPLOAD .TXT:
Also, when I post form-data from HTML/Javascript, the server fails to see the *.txt files. I have not managed to set the MIME type in Javascript. Start the rust-server and navigate your browser to http://localhost:8000
Then pick some files (.txt and other types).

Here is the code and Cargo.toml file:
(Sorry for the bad formatting and tabs... I do not know what happened. wth*)

use rouille::{router, Response, Request};
use rouille::input::post::BufferedFile;

fn main() {
	println!("Navigate to localhost:8000");

	rouille::start_server("localhost:8000", move |req| {

		let resp = router!(req,
			(GET) (/) => {
				rouille::Response::html(get_index_html())
			},

			(POST) (/post) => {
				test_multipart(req)
			},

			_ => rouille::Response::empty_404()
		);

    resp
  });
}

pub fn test_multipart(req: &Request) -> rouille::Response {

	let res = rouille::post_input!(req, {
		field1: Option<u32>,
		field2: Option<String>,
		files: Vec<Option<BufferedFile>>,
	});

	if let Err(e) = res {
		return Response::text(format!("Got error: {}", e));
	}

	let inp  = res.unwrap();
	println!("Formdata, Got data : {:?}", inp);
	println!("------------------------------------");

	let mut count = 0;
	
	for item in inp.files.iter() {
		if let Some(f) = item {
			println!("Filename:{}", f.filename.as_ref().unwrap());
			println!("Mime:{}", f.mime);
			println!("File len:{}", f.data.len());
			
			count += 1;
		
		} else {
			println!("File slot is None !");
		}

		println!("--------");
	}

	let s = format!("The size of BufferedFile vector is:{}. Found {} files. ", inp.files.len(), count);
	println!("{s}");

	Response::text(s)
}
  

  fn get_index_html() -> &'static str  {

		let html = r###"
		<!DOCTYPE html>
		<html lang="en">
		<head>
  		<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1">
			<style>
			.cl {
				margin-bottom: 20px;
			}
			</style>

   </head>
   <body>
			<br>
			<form method="post" action="http://127.0.0.1:8000/post" enctype="multipart/form-data">
				Field1 number: <br>
				<input class="cl"  type="number" name="field1"><br>

				Field2 txt: <br>
				<input class="cl" type="text" name="field2"><br>

				<label for="file">Multiple files:</label><br>
				<input id="some-files" class="cl"  type="file" name="files" multiple/>

				<!-- <input type="file" class="cl"  id="form-files" name="files" accept="image/*,.pdf,.txt" multiple />  -->
				<br>
				<button id="submit-me" class="cl"  style="width:100px; height:50px;">Send data...</button>
				<br>
				<div id="result"></div>
			</form>

  <script>
		const btn_submit = document.getElementById("submit-me");
		btn_submit.addEventListener("click", (event) => {
		   event.preventDefault();
		   send_data();
		});

		const inp_files = document.querySelector("#some-files");
		const div_result = document.querySelector("#result");
        
		async function send_data() {
			const form = new FormData();
	
			form.append("field1", "123");
			form.append("field2", "some text");

			for (i=0; i< inp_files.files.length; i++) {
			   console.log("Adding file:" + inp_files.files[i].name);
			   form.append("files", inp_files.files[i]);
			  //data.append('files', inp_files.files[i], { type: "text/plain" });
			}
    
			fetch("http://localhost:8000/post", {
			   method: "POST",
			   body: form,
			   mode: 'no-cors',
                           headers: {
                             'Access-Control-Allow-Origin' : '*'
                           },
			})
			.then((response) => {
			   return response.text();
			})
			.then((data) => {
			   div_result.innerText = data;
			}) 
			.catch(function(e) {
				div_result.innerText = e;
			}); 
  }
  </script>
  </body>
 </html>"###;

  html
}

Cargo.toml file:

[package]
name = "T1"
version = "0.1.0"
edition = "2024"

[dependencies]
rouille = "3.6.2"

I forgot.
My desktop is Ubuntu Linux 24.10.
Browser is Chrome Version 135.0.7049.52 (Official Build) (64-bit)
Server is Ubuntu too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions