HttpClient setting boundary with content-type

user2548513 picture user2548513 · Aug 29, 2013 · Viewed 23.3k times · Source

I am using javascript to communicate with a third party service. As part of their authentication process they need the "multipart/form" body of the post message including an image to be encrypted in md5, this is added to a string including the date, and a few other things and then a HMAc/SHA1 run on it. So in the end they have the multipart body, the date and the authentication hash in order to authenticate and then read the image.

This works fine for all mobile devices except for windowsPhone .. (I know, a problem with IE... who would have thought?). their httpwebrequest does not include a 'Date' header .. so no authentication. This means that I have to go native for windows phone and use the newly released httpclient code in C#. Now I am a C# noob so this is possibly where the easy solution is. I have gotten the authentication to work by passing pretty much everything to c# and just doing the post using c# but they cannot read the body because the only way I have found to send the boundary is when defining the content as multipartformDatacontent and sending the content that way changes the body so the authentication failes.

my javascript is something like:

var boundary = "------------ThIs_Is_tHe_bouNdaRY_";
var part1Array = [];
var part1 = "--"+boundary + "\r\n"+
    "Content-Disposition: form-data; name=\"image\"\r\n"+
    "Content-Type: image/jpg\r\n"+
    "\r\n";
var part3Array = [];
var part3 = "\r\n" + boundary +"--";
for(var p1=0; p1<part1.length; p1++){
    part1Array.push(part1.charCodeAt(p1));
}
for(var p3=0; p3<part3.length; p3++){
    part3Array.push(part3.charCodeAt(p3));
}
var bodyContent = part1Array.concat(imageArray,part3Array);

//hash this

var authMessage = bodyContentHash +"\n"+ contentType +"\n"+ todayString +"\n"+ pathandstuff;
// -hmac -sha1 -base64

and the c# is:

HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, path);

request.Headers.Date = DateTime.ParseExact(todaydate, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'", new CultureInfo("en-US"), DateTimeStyles.AssumeUniversal);
request.Headers.Add("Accept", "application/json; charset=utf-8");
request.Headers.Add("Authorization", auth);

byte[] body = Convert.FromBase64String(bodyData);
request.Content = new ByteArrayContent(body);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
request.Content.Headers.Add("boundary", "------------ThIs_Is_tHe_bouNdaRY_");

HttpResponseMessage response = client.SendAsync(request).Result;
string resultCode = response.StatusCode.ToString();
string responseBodyAsText = await response.Content.ReadAsStringAsync();

This pretty much works.. the body content is correct as are the headers .. all except the content type header which should be:

request.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data, boundary=------------ThIs_Is_tHe_bouNdaRY_");

Except that this throws a System.FormatException error.

Answer

Buzzrick picture Buzzrick · Apr 15, 2014

We solved this by manually clearing and re-adding the content type without validation it seems that the MediaTypeHeaderValue() class doesn't like the boundary tags.

instead of using :

content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data; boundary=----FLICKR_MIME_20140415120129--");

we did the following:

content.Headers.Remove("Content-Type");
content.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=----FLICKR_MIME_20140415120129--");

Once we made this change it all worked correctly.

(Note that this is on WinRT if that makes any difference)