How to read field from http post body with Content-Type multipart/form-data and boundary

I am trying to read field HotelCode from HTTP Body:

POST /collect_bookings HTTP/1.1
Content-Type: multipart/form-data; boundary=----CitWeb4U20KIWWQ
Accept: */*
Accept-Language: en-US,en;q=0.9,sr-Latn-RS;q=0.8,sr-Latn;q=0.6,de-DE;q=0.5,de;q=0.4,sr-Cyrl-RS;q=0.3,sr-Cyrl;q=0.1
User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
Charset: UTF-8
Content-Length: 347
Host: 192.168.1.3:8090

------CitWeb4U20KIWWQ
Content-Disposition: form-data; name="UserName"

my_username
------CitWeb4U20KIWWQ
Content-Disposition: form-data; name="Password"

my_password
------CitWeb4U20KIWWQ
Content-Disposition: form-data; name="HotelCode"

1111
------CitWeb4U20KIWWQ
Content-Disposition: form-data; name="XML"


------CitWeb4U20KIWWQ

HotelCode has value 1111

Here is my code:

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

func main() {

	http.HandleFunc("/", root)
	http.HandleFunc("/collect_bookings", multipart)

	http.ListenAndServe(":8090", nil)
}

func root(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Landed")
}

func multipart(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		io.WriteString(w, "Only POST is supported!")
		return
	}

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Println(err)
	}

	// Calling ParseMultipartForm, with maxMemory = 0. Tried also with 32, 10000 etc. but without success.
	r.ParseMultipartForm(0)
	v := r.FormValue("HotelCode")
	// v is empty
	fmt.Println("HotelCode", v)

	s := string(b)
	fmt.Println(s)
	xml := ""
	if strings.Contains(s, "1111") {
		xml = `<?xml version="1.0"?><Status Code="1111" />`
	} else {
		xml = `<?xml version="1.0"?><Status Code="2222" />`
	}

	w.Header().Set("Content-Type", "text/xml; charset=utf-8")
	io.WriteString(w, xml)
}

I tried to use ParseMultipartForm, but without success. Now I am ended with reading complete body as string, and searching for HotelCode in string.

Why is call to ParseMultipartForm not working, what am I doing wrong?

Thank You.

1 Like

Don’t read the body - after that, ParseMultipartForm cannot read it.
Just use r.FormValue.

Thank You for Your reply.

I changed my code so:

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {

	http.HandleFunc("/", root)
	http.HandleFunc("/collect_bookings", multipart)

	http.ListenAndServe(":8090", nil)
}

func root(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Landed")
}

func multipart(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		io.WriteString(w, "Only POST is supported!")
		return
	}

	// Calling ParseMultipartForm, with maxMemory = 0. Tried also with 32, 10000 etc. but without success.
	r.ParseMultipartForm(4096)
	v := r.FormValue("HotelCode")
	// v is empty
	fmt.Println("HotelCode", v)

	xml := ""
	if v == "1111" {
		xml = `<?xml version="1.0"?><Status Code="1111" />`
	} else {
		xml = `<?xml version="1.0"?><Status Code="2222" />`
	}

	w.Header().Set("Content-Type", "text/xml; charset=utf-8")
	io.WriteString(w, xml)
}

But without success. I also tried to remove r.ParseMultipartForm(4096), but also without success.

Replace r.ParseMultipartForm(4096) with r.ParseForm().

Tried with r.ParseForm() , but it also doesn’t work.

I tried again with r.ParseMultipartForm(4096), but this time I logged error:

	err := r.ParseMultipartForm(0)
	if err != nil {
		fmt.Println(err)
	}
	v := r.FormValue("HotelCode")
	// v is empty
	fmt.Println("HotelCode", v)

Error text is: unexpected EOF

Something must be wrong in the way you’re making the POST request then. I tried doing $ http --form POST http://localhost:8090/collect_bookings HotelCode=1111 and it worked using r.ParseForm(). Here’s an asciicast showing it.

Your request ( at least the posted data ) is simply WRONG.

See https://play.golang.org/p/U86jZi7Fqu for the returned error and a proper fix.

TL;DR; if the boundary is ‘ABC’ in the Content-Type, then it must be ‘–ABC’ between the parts, and ‘–ABC–’ at the end.

3 Likes

Hey, You are right, my POST request was wrong. It missed – on the end:

1111
------CitWeb4U20KIWWQ
Content-Disposition: form-data; name="XML"


------CitWeb4U20KIWWQ--

Now it works, also without r.ParseMultipartForm(0) :

v := req.FormValue("HotelCode")

I must say, this POST request works in production for six months (shame on me :slight_smile: ), without problems. I don’t now which programming language is used on server side, i just see that it is a nginx server. I wanted to have simple small webserver in Go for testing.
But Go complained with reason, so I have now fixed my post request body.

Thank You for your effort to help me.

Yes You are right, my POST request was not properly formatted, it missed – on the end.
Now it works.

Thank You.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.