Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient uploading MultipartFormData to play 2 framework

I have the following code in a Windows Phone 8 project that uses RestSharp client:

public async Task<string> DoMultiPartPostRequest(String ext, JSonWriter jsonObject, ObservableCollection<Attachment> attachments)
    {
        var client = new RestClient(DefaultUri);
        // client.Authenticator = new HttpBasicAuthenticator(username, password);

        var request = new RestRequest(ext, Method.POST);

        request.RequestFormat = DataFormat.Json;
        request.AddParameter("json", jsonObject.ToString(), ParameterType.GetOrPost);

        // add files to upload
        foreach (var a in attachments)
            request.AddFile("attachment", a.FileBody, "attachment.file", a.ContType);

        var content = await client.GetResponseAsync(request);

        if (content.StatusCode != HttpStatusCode.OK)
            return "error";

        return content.Content;
    }

Fiddler shows the generated header:

POST http://192.168.1.101:9000/rayz/create HTTP/1.1
Content-Type: multipart/form-data; boundary=-----------------------------28947758029299
Content-Length: 71643
Accept-Encoding: identity
Accept: application/json, application/xml, text/json, text/x-json, text/javascript, text/xml
User-Agent: RestSharp 104.1.0.0
Host: 192.168.1.101:9000
Connection: Keep-Alive
Pragma: no-cache

-------------------------------28947758029299
Content-Disposition: form-data; name="json"

{
    "userId": "2D73B43390041E868694A85A65E47A09D50F019C180E93BAACC454488F67A411",
    "latitude": "35.09",
    "longitude": "33.30",
    "accuracy": "99",
    "maxDistance": "dist",
    "Message": "mooohv"
}
-------------------------------28947758029299
Content-Disposition: form-data; name="attachment"; filename="attachment.file"
Content-Type: image/jpeg

?????JFIF??`?`?????C?  $" &0P40,,0bFJ:Ptfzxrfpn????????np????????|????????????C"$$0*0^44^?p??????????????????????????????????????????????????????`?"??????????????
-------------------------------28947758029299

The code above works fine on the Play2 API. However since the RestSharp does not seem to be stable I have decided to use the native HttpClient provided by Microsoft.

Hence I wrote another function that uses HttpClient to do the same job:

public async Task<string> DoMultiPartPostRequest2(String ext, JSonWriter jsonObject,
                                                                 ObservableCollection<Attachment> attachments)
    {
        var client = new HttpClient();

        var content = new MultipartFormDataContent();

        var json = new StringContent(jsonObject.ToString());
        content.Add(json, "json");

        foreach (var a in attachments)
        {
            var fileContent = new StreamContent(new MemoryStream(a.FileBody));
            fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = "attachment",
                FileName = "attachment.file"
            };
            fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(a.ContType);
            content.Add(fileContent);
        }

        var resp = await client.PostAsync(DefaultUri + ext, content);

        if (resp.StatusCode != HttpStatusCode.OK)
            return "error";

        var reponse = await resp.Content.ReadAsStringAsync();

        return reponse;
    }

The header that is generated from that code is the following:

POST http://192.168.1.101:9000/rayz/create HTTP/1.1
Accept: */*
Content-Length: 6633
Accept-Encoding: identity
Content-Type: multipart/form-data; boundary="e01b2196-d24a-47a2-a99b-e82cc4a2f92e"
User-Agent: NativeHost
Host: 192.168.1.101:9000
Connection: Keep-Alive
Pragma: no-cache

--e01b2196-d24a-47a2-a99b-e82cc4a2f92e
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=json

{
    "userId": "2D73B43390041E868694A85A65E47A09D50F019C180E93BAACC454488F67A411",
    "latitude": "35.09",
    "longitude": "33.30",
    "accuracy": "99",
    "maxDistance": "dist",
    "Message": "test"
}
--e01b2196-d24a-47a2-a99b-e82cc4a2f92e
Content-Disposition: form-data; name=attachment; filename=attachment.file
Content-Type: image/jpeg

?????JFIF??`?`?????C?  $" &0P40,,0bFJ:Ptfzxrfpn????????np????????|????????????C"$$0*0^44^?p????????????????????????????????????????????????????????"??????????????
--e01b2196-d24a-47a2-a99b-e82cc4a2f92e--

So far so good. From my point of view the two headers seem to be identical.

However when I debug the Play 2 API after executing Http.MultipartFormData body = request().body().asMultipartFormData(); I noticed that the multipart data are not being parsed correctly.

More specifically the multipart filed in the body variable is as follows:

MultipartFormData(Map(),List(),List(BadPart(Map(ntent-type -> text/plain; charset=utf-8, content-disposition -> form-data; name=json)), BadPart(Map()), BadPart(Map()), BadPart(Map()), BadPart(Map())),List())

As you can notice it has several (actually 5 in this example) BadParts. Example: BadPart(Map(ntent-type -> text/plain; charset=utf-8, content-disposition -> form-data; name=json))

Can anyone see what is going wrong here? Is the header generated by HttpClient wrong?

like image 558
George Nikolaides Avatar asked Aug 07 '26 01:08

George Nikolaides


1 Answers

Here is the solution.. (hack)

There seems to be a problem with Play Framework when the boundary has quotes in it.

So i added the following code after multipart is created in order to remove them:

var content = new MultipartFormDataContent();

foreach (var param in content.Headers.ContentType.Parameters.Where(param => param.Name.Equals("boundary")))
     param.Value = param.Value.Replace("\"", String.Empty);

Finally i had to add quotes "\"" manually to specific values on the header like the following:

Original: Content-Disposition: form-data; name=attachment; filename=attachment.file Changed to: Content-Disposition: form-data; name="attachment"; filename="attachment.file"

and

Original: Content-Disposition: form-data; name=json Changed to: Content-Disposition: form-data; name="json"

I don't think that its a mistake to have quotes or not anywhere in the header and maybe the parsing on play framework should be fixed accordingly.

like image 165
George Nikolaides Avatar answered Aug 08 '26 14:08

George Nikolaides



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!