Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable base64-encoded filenames in HttpClient/MultipartFormDataContent

I'm using HttpClient to POST MultipartFormDataContent to a Java web application. I'm uploading several StringContents and one file which I add as a StreamContent using MultipartFormDataContent.Add(HttpContent content, String name, String fileName) using the method HttpClient.PostAsync(String, HttpContent).

This works fine, except when I provide a fileName that contains german umlauts (I haven't tested other non-ASCII characters yet). In this case, fileName is being base64-encoded. The result for a file named 99 2 LD 353 Temp Äüöß-1.txt

looks like this:

 __utf-8_B_VGVtcCDvv73vv73vv73vv71cOTkgMiBMRCAzNTMgVGVtcCDvv73vv73vv73vv70tMS50eHQ___

The Java server shows this encoded file name in its UI, which confuses the users. I cannot make any server-side changes.

How do I disable this behavior? Any help would be highly appreciated.

Thanks in advance!

like image 257
Strezz0r Avatar asked Feb 21 '14 08:02

Strezz0r


4 Answers

I just found the same limitation as StrezzOr, as the server that I was consuming didn't respect the filename* standard.

I converted the filename to a byte array of the UTF-8 representation, and the re-armed the bytes as chars of "simple" string (non UTF-8).

This code creates a content stream and add it to a multipart content:

        FileStream fs = File.OpenRead(_fullPath);
        StreamContent streamContent = new StreamContent(fs);
        streamContent.Headers.Add("Content-Type", "application/octet-stream");
        String headerValue = "form-data; name=\"Filedata\"; filename=\"" + _Filename + "\"";
        byte[] bytes = Encoding.UTF8.GetBytes(headerValue);
        headerValue="";
        foreach (byte b in bytes)
        {
            headerValue += (Char)b;
        }
        streamContent.Headers.Add("Content-Disposition", headerValue);
        multipart.Add(streamContent, "Filedata", _Filename);

This is working with spanish accents.

Hope this helps.

like image 136
Ugo Enrico Albarello Avatar answered Nov 16 '22 20:11

Ugo Enrico Albarello


I recently found this issue and I use a workaround here:

At server side:

private static readonly Regex _regexEncodedFileName = new Regex(@"^=\?utf-8\?B\?([a-zA-Z0-9/+]+={0,2})\?=$");

private static string TryToGetOriginalFileName(string fileNameInput) {
    Match match = _regexEncodedFileName.Match(fileNameInput);
    if (match.Success && match.Groups.Count > 1) {
        string base64 = match.Groups[1].Value;
        try {
            byte[] data = Convert.FromBase64String(base64);
            return Encoding.UTF8.GetString(data);
        }
        catch (Exception) {
            //ignored
            return fileNameInput;
        }
    }
    return fileNameInput;
}

And then use this function like this:

string correctedFileName = TryToGetOriginalFileName(fileRequest.FileName);

It works.

like image 34
guogangj Avatar answered Nov 16 '22 18:11

guogangj


In order to pass non-ascii characters in the Content-Disposition header filename attribute it is necessary to use the filename* attribute instead of the regular filename. See spec here.

To do this with HttpClient you can do the following,

   var streamcontent = new StreamContent(stream);
   streamcontent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
      FileNameStar = "99 2 LD 353 Temp Äüöß-1.txt" 
   };
   multipartContent.Add(streamcontent);

The header will then end up looking like this,

  Content-Disposition: attachment; filename*=utf-8''99%202%20LD%20353%20Temp%20%C3%84%C3%BC%C3%B6%C3%9F-1.txt
like image 32
Darrel Miller Avatar answered Nov 16 '22 18:11

Darrel Miller


I finally gave up and solved the task using HttpWebRequest instead of HttpClient. I had to build headers and content manually, but this allowed me to ignore the standards for sending non-ASCII filenames. I ended up cramming unencoded UTF-8 filenames into the filename header, which was the only way the server would accept my request.

like image 1
Strezz0r Avatar answered Nov 16 '22 18:11

Strezz0r