Getting error: HttpRequestException: Received an invalid header name: 'Content=Transfer-Encoding'. when using MVC Core to download a file - model-view-controller

I'm trying to have a controller in MVC core (3.1) download an audio file to present to the user but everything I try ends up with the error:
HttpRequestException: Received an invalid header name: 'Content=Transfer-Encoding'.
I have tried webclient, httpclient and just lately webrequest/webresponse. My code looks like this right now (specifics removed for security):
WebRequest downloadRequest = WebRequest.Create({url here});
downloadRequest.Headers.Add("Cookie", "{cookie data here};");
downloadRequest.Headers.Add("Accept", "application/json, text/javascript, */*; q=0.01");
downloadRequest.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0");
downloadRequest.Headers.Add("Sec-Fetch-Dest", "empty");
downloadRequest.Headers.Add("X-Requested-With", "XMLHttpRequest");
using (WebResponse webResponse = await downloadRequest.GetResponseAsync())
{
return File(webResponse.GetResponseStream(), "audio/wav", wavFile + ".txt");
}
The error is on the line
using (WebResponse webResponse = await downloadRequest.GetResponseAsync())
Using fiddler the request looks good and the header it is complaining about is: Content=Transfer-Encoding: binary, it has the file in the content-disposition as an attachement. I have no control at all over the sending server unfortunately but this works fine in a browser. Can anyone tell me what i'm doing wrong please?
Thanks

The incoming request looks malformed. Transfer-Encoding is its own header name. You cannot assign it to the value of another header. And AFAIK, Content isn't even a standard HTTP header name.
Refer to the list at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#Message_body_information for valid Content-* headers. The Transfer-Encoding header is documented at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding.
Edit for framework 4.8 and below
I had to add the following lines to app.config to let the client process invalid responses from the server.
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
The program itself is shown below.
try
{
var httpclient = new HttpClient();
var response = await httpclient.GetAsync("http://localhost:9091");
var attachment = new byte[1024];
foreach (var h in response.Content.Headers)
{
var e = h.Value.GetEnumerator();
e.MoveNext();
attachment = Encoding.UTF8.GetBytes(e.Current); // Convert UTF-8 encoded string into raw bytes
Console.WriteLine($"{h.Key}, {Encoding.UTF8.GetString(attachment)}"); // Save raw bytes to disk instead of converting back to string and writing to Console
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
Edit for dotnet core
try
{
var s = new Socket(SocketType.Stream, ProtocolType.Tcp);
var a = IPAddress.Parse("127.0.0.1");
await s.ConnectAsync(a, 9091);
var request = "GET http://localhost:9091/";
var outBytes = Encoding.UTF8.GetBytes(request);
var outBuffer = new ArraySegment<byte>(outBytes);
await s.SendAsync(outBuffer, SocketFlags.None);
var inBytes = new byte[1024];
var inBuffer = new ArraySegment<byte>(inBytes);
await s.ReceiveAsync(inBuffer, SocketFlags.None);
var r = Encoding.UTF8.GetString(inBuffer.Array);
}
catch (SocketException exception)
{
Console.WriteLine($"Error: {exception.Message}");
}

Related

Getting 502 BadGateway response when posting using HttpClient (.NET) but not when using Postman

I have an API end-point that I need to post to.
Using Postman I do the following:
Set the method to be POST
Add the URL
In the Headers I set: Content-Type to be application/json
In the Body I add my json string
I hit [Send] and get a 200 response with the expected response.
However, in C# .Net Framework 4.8 (LinqPad 5) I do
var c = new HttpClient(); // Disposed of later
c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string data = #"{ ""a"": ""b"", ""c"": ""d"" }"; // copied from Postman.
HttpContent payload = new StringContent(data, Encoding.UTF8, "application/json");
var msg = new HttpRequestMessage(HttpMethod.Post, new Uri("https://the.url"), UriKind.Absolute)
{
Content = payload,
};
var response = c.SendAsync(msg).GetAwaiter().GetResult(); // It's a synchronous flow
And this responds with a 502 Bad Gateway.
What am I missing...?
I should point out that I need to use the HttpClient and not RestSharp.

Delete data from D365 in Batch Request, getting the error 'Content-Type' Header is missing

I am trying to create an Azure function to delete some data from a Dynamics 365 CE instance. The plan is to use the D365 WebAPI and the Batch Operations request to establish this.
Currently encountering an issue while sending a request after creating the batch request.
I have been referring to this documentation from Microsoft:
https://learn.microsoft.com/en-us/powerapps/developer/common-data-service/webapi/execute-batch-operations-using-web-api
The code looks like:
var batchId = Guid.NewGuid().ToString();
log.LogInformation($"Batch Request Id = {batchId}.");
HttpRequestMessage deleteBatchRequestMessage = new HttpRequestMessage(HttpMethod.Post, "$batch");
deleteBatchRequestMessage.Content = new MultipartContent("mixed", "batch_" + batchId);
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(d365Url);
// Default Request Headers needed to be added in the HttpClient Object
client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
client.DefaultRequestHeaders.Add("OData-Version", "4.0");
client.DefaultRequestHeaders.Add("Prefer", "odata.include-annotations=\"OData.Community.Display.V1.FormattedValue\"");
d365HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Set the Authorization header with the Access Token received specifying the Credentials
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", d365Token);
HttpResponseMessage response = await client.SendAsync(deleteBatchRequestMessage);
var ass = await response.Content.ReadAsStringAsync();
But I keep getting the exception:
The 'Content-Type' header is missing. The 'Content-Type' header must be specified for each MIME part of a batch message.","ExceptionMessage":"The 'Content-Type' header is missing. The 'Content-Type' header must be specified for each MIME part of a batch message."
Is there any reason why you use WebApi? You can use the SDK and the IOrganizationService handle Everything. This will make your life very easy
http://www.threadpunter.com/azure/using-azure-functions-to-call-dynamics-365/

Invalid mimetype exception in Spring boot rest call

I am new to both Spring boot and rest calls.
I am trying to consume a rest service and I do not have any information about that rest API except URL. When I hit that URL from a browser I am getting a response as {key:value}. So, I assumed that it is a JSON response.
I am consuming it in spring boot as follows
restTemplate.getForObject(url, String.class) .
This is giving Invalid mime type "content-type: text/plain; charset=ISO-8859-1": Invalid token character ':' in token "content-type: text"
I assume that this error is because response content type is set to text/plain but it is returning JSON format.
EDIT:
Tried this way but did not work.
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>("parameters",headers);
ResponseEntity<String> result = restTemplate.exchange(url,HttpMethod.GET,
entity, String.class);
How to handle and solve it?
You might want to read about the request headers your REST API needs. Content-Type header specifies the media type of the request you're sending to the server. Because you're just getting data from the server you should set the Accept header to the kind of response you want i.e., Accept: application/json.
Unfortunately, you can't set headers using getForObject(). You could try this:
URL url = new URL("Enter the URL of the REST endpoint");
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Accept", "application/json");
if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuffer content = new StringBuffer();
String inputLine;
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
}

the passed param by resttemplate.exchange was not decoded in service side automatically

Below is my REST API code:
#RequestMapping(value = "/get", method = RequestMethod.POST, produces = { "application/json" })
#ApiOperation(value = "get data by key.", notes = "return json string value.")
public JsonObjectResponse<String> get(
#ApiParam(required = true, name = "regionName", value = "region name") #RequestParam("regionName") String regionName,
#ApiParam(required = true, name = "key", value = "region key,Default is uuid") #RequestParam("key") String key) throws UnsupportedEncodingException
{
JsonObjectResponse<String> jr = new JsonObjectResponse<String>();
//key = decodeJsonString(key); // added for junit
String val = adfService.onPath(regionName).get(key);
jr.setState(StateCode.SUCCESS);
jr.setData(JsonObject.create().append(key,val).toJson());
return jr;
}
I'm trying to pass parameters:
regionName=/fusion/table1&key={"fusionTbl1DetailNo":"fusionNo001","pk":"PK0001"}
If I call it via swagger-ui, it calls like this:
http://localhost:8080/service/basic/get?regionName=%2Ffusion%2Ftable1&key=%7B%22fusionTbl1DetailNo%22%3A%22fusionNo001%22%2C%22pk%22%3A%22PK0001%22%7D&token=8652493a-4147-43f4-af3a-bcb117fb7d42`
It encoded the parameters and these parameters also can be decoded automatically in server side correctly.
When I want to add testcase for this API, I use restTemplate.exchange method, code as below:
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
for (Entry<String, String> entry : queryParamMap.entrySet()) {
builder.queryParam(entry.getKey(), entry.getValue());
}
if (uriParamMap != null) {
url = builder.buildAndExpand(uriParamMap).toUriString();
} else {
url = builder.toUriString();
}
if (StringUtils.isEmpty(requestBody)) {
if (bodyParamMap != null) {
requestBody = parseMapToParams(bodyParamMap);
} else {
requestBody = "";
}
}
HttpHeaders headers = new HttpHeaders();
MediaType mediaType = new MediaType("application", "json", Charset.forName("UTF-8"));
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
// headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
// headers.add("Accept", "application/json");
// headers.set(HttpHeaders.ACCEPT, "application/json");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
// headers.add("Accept-Encoding", "gzip, deflate, br");
headers.set("Accept-Charset", "utf-8");
headers.set("Accept-Encoding", "gzip");
headers.add("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6");
headers.add("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
headers.add(TestBase.TOKEN_HEADER, TestBase.getTokenId());
HttpEntity<String> request = new HttpEntity<>(body, headers);
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
ResponseEntity<String> response = restTemplate.exchange(url, httpMethod, request, String.class);
localresponse.set(response);
System.out.println("response:" + response);
return response;
I used UriComponentsBuilder to append the parameters, it will format the url to
http://localhost:8080/service/basic/get?regionName=/fusion/table1&key=%7B%22fusionTbl1DetailNo%22:%22fusionNo001%22,%22pk%22:%22PK0001%22%7D
for method exchange. However, when the server side received the call, it did not decode the param key, it's value still was:
%7B%22fusionTbl1DetailNo%22:%22fusionNo001%22,%22pk%22:%22PK0001%22%7D
Why is that? I compared the header settings from the swagger calling, added additional settings, no effect :(.
Instead of toUriString() use, UriComponentsBuilder.fromUriString(url).queryParam("name","John Doe").build().toString();
Try like the following:
ResponseEntity<String> res = restTemplate.exchange("http://localhost:8080/service/basic/get?regionName={arg1}&key={arg2}", HttpMethod.POST, null, String.class,"/fusion/table1", "{\"fusionTbl1DetailNo\":\"fusionNo001\",\"pk\":\"PK0001\"}");
arg1 and arg2 will be replaced by
"/fusion/table1" and "{\"fusionTbl1DetailNo\":\"fusionNo001\",\"pk\":\"PK0001\"}"
I send null in requestEntity as no request body and request parameters is in uriVariables.
The Spring Documentation on RestTemplate reads:
For each HTTP method there are three variants: two accept a URI
template string and URI variables (array or map) while a third accepts
a URI. Note that for URI templates it is assumed encoding is
necessary, e.g. restTemplate.getForObject("http://example.com/hotel
list") becomes "http://example.com/hotel%20list". This also means if
the URI template or URI variables are already encoded, double encoding
will occur,
It looks like you are using a RestTemplate exchange method that takes a URI template string and you should therefore NOT encode the url-string.
The url-string is first encoded on
builder.toUriString()
And then again on the exchange-call. So the problem seems to be double encoding on the client side, not lack of decoding on the server side

HTTP Request in Xamarin

I wrote the following code in Xamarin to connect the Web Server:
var request = WebRequest.Create( "http://srv21.n-software.de/authentication.json") as HttpWebRequest;
// request.Method = "GET";
request.Method = "POST";
request.Headers.Add("name", "demo");
request.Headers.Add("password", "demo");
request.ContentType = "application/x-www-form-urlencoded";
HttpWebResponse Httpresponse = (HttpWebResponse)request.GetResponse();
It connects to the web server and the web server gets the request for "authentication.json", but doesn't get the parameters of the header ("name" and "password").
What is wrong with my code?
Most likely your parameters need to be in the body of the POST request instead of in the headers. Alternatively you might try to use a GET request instead and provide the parameters through the URL, if your server supports it (i.e. http://srv21.n-software.de/authentication.json?name=demo&password=demo).
This worked for me
using System.Net.Http;
string URL = "http://www.here.com/api/postForm.php";
string DIRECT_POST_CONTENT_TYPE = "application/x-www-form-urlencoded";
HttpClient client = new HttpClient();
string postData = "username=usernameValueHere&password=passwordValueHere");
StringContent content = new StringContent(postData, Encoding.UTF8, DIRECT_POST_CONTENT_TYPE);
HttpResponseMessage response = await client.PostAsync(DIRECT_GATEWAY_URL, content);
string result = await response.Content.ReadAsStringAsync();

Resources