Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# HttpClient file stream content wrong boundary header

I'm trying to simulate HTTP post file exactly like the browser (chrome) does:

HTML:

<form name="fnup" method="post" action="action.shtml" enctype="multipart/form-data">    
         <input name="firmfile" id="firmfile" type="file">
         <input type="submit" id="firmbutton" value="Upgrade" class="othsave">
</form>

C#:

     public async Task<string> UploadFile(string actionUrl, string filePath)
            {
                var httpClient = new HttpClient();
                //Should I need to add all those headers??? it will help me? what is necessary?
                httpClient.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
                httpClient.DefaultRequestHeaders.Add("Origin", "http://" + ip);
                httpClient.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
                httpClient.DefaultRequestHeaders.Add("Pragma", "no-cache");
                httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
                httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
                httpClient.DefaultRequestHeaders.Add("Referer", "http://" + ip + "/");
                httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
                httpClient.DefaultRequestHeaders.Add("Accept-Language", "he,en-US;q=0.9,en;q=0.8");
                httpClient.DefaultRequestHeaders.Add("Cookie", "page=DevSet");
                FileStream paramFileStream = File.OpenRead(filePath);
                HttpContent fileStreamContent = new StreamContent(paramFileStream);
                using (var content = new MultipartFormDataContent())
                {
                    content.Add(fileStreamContent, "firmfile", Path.GetFileName(filePath));
                    HttpResponseMessage response = await httpClient.PostAsync(actionUrl, content);

                    string res = await response.Content.ReadAsStringAsync();
                    return await Task.Run(() => res);
                }
            }

The C# example is not working in my server, and I cannot understand why...

After looking on Wireshark, I've seen some differents:

Chrome:

enter image description here

C#

enter image description here

The questions:

1) How can I delete the "filename*=utf-8''VP445_all_V116.bin" from Content-Disposition
2) Why I cannot see the second line Content-Type: application/octet-stream like in Chrome?
3) Also the Content-length is not the same (even it's the same file)
4) The bottom line is that the C# is not working and chrome is working, and the server side is black-box for me, so I need to guess here what I'm doing wrong in C# post request.

like image 484
cheziHoyzer Avatar asked Jan 03 '23 12:01

cheziHoyzer


1 Answers

Found the solution.

The problem indeed was the 'Content-Type: application/octet-stream'

Why the HttpClient StreamContent is not added it automatically? I really don't know.

The workaround is added it manually

The main idea is from here: https://github.com/paulcbetts/ModernHttpClient/issues/92

Here is the correct C# code:

  public async Task<string> UploadFile(string actionUrl, string filePath)
        {
            var httpClient = new HttpClient();
            httpClient.Timeout = TimeSpan.FromMilliseconds(FileReqTimeout);

            FileStream fileStream = File.OpenRead(filePath);
            var streamContent = new StreamContent(fileStream);
            streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
            streamContent.Headers.ContentDisposition.Name = "\"firmfile\"";
            streamContent.Headers.ContentDisposition.FileName = "\"" + Path.GetFileName(filePath) + "\"";
            streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            string boundary = Guid.NewGuid().ToString();
            var content = new MultipartFormDataContent(boundary);
            content.Headers.Remove("Content-Type");
            content.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary);
            content.Add(streamContent);
            HttpResponseMessage response = null;
            try
            {
                response = await httpClient.PostAsync(actionUrl, content, cts.Token);
            }
            catch (WebException ex)
            {
                // handle web exception
                return null;
            }
            catch (TaskCanceledException ex)
            {
                if (ex.CancellationToken == cts.Token)
                {
                    // a real cancellation, triggered by the caller
                    return null;
                }
                else
                {
                    // a web request timeout (possibly other things!?)
                    return null;
                }
            }

            try
            {
                response.EnsureSuccessStatusCode();
            }
            catch (Exception)
            {
                return null;
            };

            string res = await response.Content.ReadAsStringAsync();
            return await Task.Run(() => res);
        }
    }
like image 59
cheziHoyzer Avatar answered Jan 05 '23 15:01

cheziHoyzer