Example of multipart/form-data

HtmlHttpMultipartMultipartform Data

Html Problem Overview


I am wondering if anyone can share with me an example of multipart/form-data that contains:

  1. Some form parameters
  2. Multiple files

Html Solutions


Solution 1 - Html

EDIT: I am maintaining a similar, but more in-depth answer at: https://stackoverflow.com/a/28380690/895245

To see exactly what is happening, use nc -l or an ECHO server and an user agent like a browser or cURL.

Save the form to an .html file:

<form action="http://localhost:8000" method="post" enctype="multipart/form-data">
  <p><input type="text" name="text" value="text default">
  <p><input type="file" name="file1">
  <p><input type="file" name="file2">
  <p><button type="submit">Submit</button>
</form>

Create files to upload:

echo 'Content of a.txt.' > a.txt
echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html

Run:

nc -l localhost 8000

Open the HTML on your browser, select the files and click on submit and check the terminal.

nc prints the request received. Firefox sent:

POST / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: __atuvc=34%7C7; permanent=0; _gitlab_session=226ad8a0be43681acf38c2fab9497240; __profilin=p%3Dt; request_method=GET
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266
Content-Length: 554

-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="text"

text default
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain

Content of a.txt.

-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<!DOCTYPE html><title>Content of a.html.</title>

-----------------------------9051914041544843365972754266--

Aternativelly, cURL should send the same POST request as your a browser form:

nc -l localhost 8000
curl -F "text=default" -F "[email protected]" -F "[email protected]" localhost:8000

You can do multiple tests with:

while true; do printf '' | nc -l localhost 8000; done

Solution 2 - Html

Many thanks to @Ciro Santilli answer! I found that his choice for boundary is quite "unhappy" because all of thoose hyphens: in fact, as @Fake Name commented, when you are using your boundary inside request it comes with two more hyphens on front:

Example:

POST / HTTP/1.1
HOST: host.example.com
Cookie: some_cookies...
Connection: Keep-Alive
Content-Type: multipart/form-data; boundary=12345

--12345
Content-Disposition: form-data; name="sometext"

some text that you wrote in your html form ...
--12345
Content-Disposition: form-data; name="name_of_post_request" filename="filename.xyz"

content of filename.xyz that you upload in your form with input[type=file]
--12345
Content-Disposition: form-data; name="image" filename="picture_of_sunset.jpg"

content of picture_of_sunset.jpg ...
--12345--

I found on this w3.org page that is possible to incapsulate multipart/mixed header in a multipart/form-data, simply choosing another boundary string inside multipart/mixed and using that one to incapsulate data. At the end, you must "close" all boundary used in FILO order to close the POST request (like:

POST / HTTP/1.1
...
Content-Type: multipart/form-data; boundary=12345

--12345
Content-Disposition: form-data; name="sometext"

some text sent via post...
--12345
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=abcde

--abcde
Content-Disposition: file; file="picture.jpg"

content of jpg...
--abcde
Content-Disposition: file; file="test.py"

content of test.py file ....
--abcde--
--12345--

Take a look at the link above.

Solution 3 - Html

There is an example of the multipart data (Angular):

  1. trip-upload.component.html

       <div class="form-group">
         <label for="guide">Guide for the trip:</label>
         <input formControlName="guide" type="file" id="guide" name="guide" (change)="uploadFile($event,'guide')">
       </div>
     
       <div class="form-group">
         <label for="photo">Guide for the trip:</label>
         <input formControlName="photo" type="image" id="photo" name="photo" (change)="uploadFile($event, 'photo')">
       </div>
     
       <div class="form-group">
         <button class="btn">Upload files</button>
       </div>
     </form>
    

2.trip-upload.component.ts

import {Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from "@angular/forms";
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'trip-upload',
  templateUrl: './trip-upload.component.html',
  styleUrls: ['./trip-upload.component.css']
})

export class TripUploadComponent implements OnInit {
  public form: FormGroup;

  constructor(public fb: FormBuilder, private http: HttpClient) {}

  ngOnInit() {
    this.form = this.fb.group({
      name: [''],
      photo: [null],
      guide: [null]
    })
  }

  uploadFile(event, fileType: string) {
    this.updateFileFormControl(event, fileType);
  }

  submitForm() {
    let formData: any = newFormData();
Object.keys(this.form.controls).forEach(formControlName => {
      formData.append(formControlName, this.form.get(formControlName).value);
    });

    this.http.post('http://localhost:4200/api/trip', formData).subscribe(
            (response) =>console.log(response),
            (error) =>console.log(error)
        )
  }

  private updateFileFormControl(event: Event, formControlName: string) {
    const file = (event.target as HTMLInputElement).files[0];
    this.form.controls[formControlName].patchValue([file]);
    this.form.get(formControlName).updateValueAndValidity()
  }
}

3. Multipart response

When Browser understand which enctype you use in your form for HTTP POST requests, user-agent configure list of name/value pairs to the server. Depending on the type and amount of data being transmitted, one of the methods will be more efficient than the other: enter image description here

enter image description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser496949View Question on Stackoverflow
Solution 1 - HtmlCiro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 2 - HtmlpippoView Answer on Stackoverflow
Solution 3 - HtmlVarvara SandakovaView Answer on Stackoverflow