C# Add Accept header to HttpClient - c#

What is the difference between these two calls? My end goal is to have
Accept: application/json sent over the wire, not to append to some default set of other MIME types.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
vs.
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
My CLR is .NET Core 2.0.
Sniffing the wire reveals no difference:
# just .Add("Accept"...
~ % nc -l 8000
GET / HTTP/1.1
Connection: Keep-Alive
Accept: application/json
[...]
# with MediaTypeWithQualityHeaderValue
~ % nc -l 8000
GET / HTTP/1.1
Connection: Keep-Alive
Accept: application/json
[...]
So, outside the bizarre naming of that type, nothing else to gain here right?

There is no difference.
DefaultRequestHeaders.Accept is a collection of string type, where you can add your header to accept using the new instance of MediaTypeWithQualityHeaderValue.
client.DefaultRequestHeaders is a dictionary that accepts key for and value for the request header and matches the results according to them.
DefaultRequestHeaders
has overloads.
The only thing that differs between them, is the fact that DefaultRequestHeaders.Accept will require you to initialize a new instance of MediaTypeWithQualityHeaderValue class, resulting in another reference type in the heap, while client.DefaultRequestHeaders will add the data to the dictionary, removing the cost of resources and the need to initialize a new instance.
It is really up to the user as to how and what to use.

There's no difference in the end result, as long as the names and values are correct.
The HTTP standard specifies that certain headers have a quality factor, hence the name MediaTypeWithQualityHeaderValue. It's a MediaType header value that can have a Quality factor. You can pass the quality factor if you use the MediaTypeWithQualityHeaderValue Constructor (String, Double) constructor
The Accept header section in the standard shows several examples that use the quality factor. For example,
The example
Accept: audio/*; q=0.2, audio/basic
SHOULD be interpreted as "I prefer audio/basic, but send me any audio type if it is the best available after an 80% mark-down in quality."
You could write that with
var requestAccepts=client.DefaultRequestHeaders.Accept;
requestAccepts.Add(new MediaTypeWithQualityHeaderValue("audio/*",0.2));
requestAccepts.Add(new MediaTypeWithQualityHeaderValue("audio/basic"));
Or you can enter the raw header value with :
client.DefaultRequestHeaders.Add("Accept", "audio/*; q=0.2, audio/basic");

I don't think there is a difference it's just an easier way to add standard headers through properties like Accept, also convenient to add custom headers through the Add method.

Related

Remove Host header in HttpClient request

I'm using the HttpClient class to send some data to specific host. I just want to send a pure header without any additional lines in it like ("Host: http"). So this line is the last to be removed from the header, but I don't know how.
The code:
HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Post, aUrl);
msg.Headers.Clear();
msg.Headers.Remove("Host");
msg.Headers.ExpectContinue = false;
Encoding encoding = ConfiguratorASUST.Instance.Encoding ?? Encoding.GetEncoding(ConfiguratorASUST.ENCODING_DEFAULT);
msg.Content = new StringContent(aStr, encoding);
_client.SendAsync(msg);
The result header in Fiddler:
POST http://http//localhost.fiddler:60001/POS/POSTELESPIS HTTP/1.1
Content-Type: text/plain; charset=windows-1251
Host: http
This line Host: http needs to be removed from the message's header. But how on earth can I do that?! I tried the following:
msg.Headers.Clear();
msg.Headers.Remove("Host");
To no avail. Actually I also see the header Proxy-Connection: Keep-Alive being added.
If you carefully inspect your URL, it looks like your it is wrong anyway: http://http// - is your host really named http, and do you really need two slashes after it? Anyway if you fix that, the Host header will carry localhost.fiddler:60001.
By removing the Host header, you're essentially downgrading your request to HTTP/1.0.
You can set the HTTP version in the HttpRequestMessage as explained in Set HTTP protocol version in HttpClient:
msg.Version = HttpVersion.Version10;
But when using Fiddler, it acts as a proxy, and forwards your request as an HTTP/1.1 request - including the host header again. You can also alter the request in Fiddler. This is explained in How do I prevent fiddler from insering "Host" HTTP header?, but note the bold text, emphasis mine:
Per the RFC, as a HTTP/1.1 proxy, Fiddler is required to add a Host header.
It's not clear why this is problematic-- any server that has a problem with this is, by definition, buggy and should be fixed.
You can remove the header if you'd like (although doing so can cause problems elsewhere). Click Rules > Customize Rules. Scroll to OnBeforeRequest and add the following:
if (oSession.oRequest.headers.HTTPVersion == "HTTP/1.0")
{
oSession["x-overridehost"] = oSession.host;
oSession.oRequest.headers.Remove("Host");
}

How to get RestSharp to properly deflate compressed HTTP response?

I'm using RestSharp to make a call to REST service. My call looks something like this:
var request = new RestRequest("/foo", Method.POST);
request.JsonSerializer.ContentType = "application/json; charset=utf-8";
request.AddJsonBody(new string[] { "param1", "param2" });
var response = this._client.Execute<Foo>(request);
For most other calls this works fine. I'm running into issues when the response is compressed. The headers in the response look (mostly) like this:
HTTP/1.1 200 OK
Uncompressed-Size: 35000
Content-Length: 3019
Content-Encoding: deflate
Content-Type: application/json
The issue is when I call this method with RestSharp I keep getting the error:
Error: Block length does not match with its complement.
I've tried setting the Accept-Encoding header in the request but it still produces the error. I also tried using a custom deserializer but the error is occurring before deserialization. From what I can tell, RestSharp should automatically handle deflation if the Content-Encoding header says deflate (which it does).
How can I get RestSharp to handle the deflation properly?
UPDATE
In the end I was able to have the service changed to look for an Accept-Encoding header in the request with a value of identity. If found, the service was changed to return the data uncompressed.
This is unfortunately not really a solution to the original issue but it does resolve the problem for me. If a better solution is posted I will try it.
According to this post, you should be able to handle it if you won't pass charset=utf-8 in content type.
Please refer to this:
RestSharp compress request while making rest call to server

HttpClient.DefaultRequestHeaders.TryWithoutValidation is automatically adding spaces

When adding an Accept header to a HTTPClient it seems to automatically add spaces, which seems to be a problem for the web service that I am using. They expect a Content-Length of no more than 120. But, because of the spaces being added it's making it 131.
This is my current code:
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
It seems to add spaces as can be seen in Fiddler:
text/html, application/xhtml+xml, application/xml; q=0.9, image/webp, */*; q=0.8
I know in normal cases this shouldn't be a problem for the server, but in my case it is. when the request is sent from a browser, there are no spaces.
Edit: It also does the same for Accept-Language and Accept-Encoding
I had the same problem and this worked for me :
httpRequestMessage.Headers.TryAddWithoutValidation("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

RestSharp Accept header change

I am using RestSharp for developing on the client side. I am also using Ruby Grape gem for my custom API on server side. Grape gem can do versioning by setting Accept HTTP header f.e to application/vnd.twitter-v1+json
And test command via console works perfect
curl -H Accept=application/vnd.twitter-v1+json /statuses/public_timeline
But when I am trying to set up header for RestRequest I am getting error 404 on the server.
I have no idea why so. I have found another issue that server returns 406 error - but in my case 404.
How can I put custom value for Accept header?
You can set a custom Accept header with the AddHeader method...
var client = new RestClient("http://example.com/api");
var request = new RestRequest("statuses/public_timeline", Method.GET);
request.AddHeader("Accept", "application/vnd.twitter-v1+json");
var response = client.Execute(request);
var json = response.Content;
This should work fine if you are willing to deserialize the JSON yourself.
If you want to make use of the generic Execute<T> method, which does automatic deserialization for you, you will run into problems...
From the RestSharp documentation about deserialization:
RestSharp includes deserializers to process XML and JSON. Upon receiving a response, RestClient chooses the correct deserializer to use based on the Content Type returned by the server. The defaults can be overridden (see Customization). The built-in content types supported are:
application/json – JsonDeserializer
application/xml – XmlDeserializer
text/json – JsonDeserializer
text/xml – XmlDeserializer
* – XmlDeserializer (all other content types not specified)
This is saying that, by default, if the response's content type is not one of those listed, RestSharp will attempt to use the XmlDeserializer on your data. This is customizable though with extra work.

If a browser can shows Accept-Encoding of deflate, can it handle .NET gzipped responses?

I'm looking at this method in this HTTPCombiner:
private bool CanGZip(HttpRequest request)
{
string acceptEncoding = request.Headers["Accept-Encoding"];
if (!string.IsNullOrEmpty(acceptEncoding) &&
(acceptEncoding.Contains("gzip") || acceptEncoding.Contains("deflate")))
return true;
return false;
}
If this returns true then the response is compressed using a GZipStream. Is this right?
Those are two different algorithms :
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5
Some code here :
http://www.singular.co.nz/blog/archive/2008/07/06/finding-preferred-accept-encoding-header-in-csharp.aspx
So, according to the protocol, it is not right, as if the browser says "give me the content using deflate", you shouldn't send it back gzipped.
GZip (which is based on Deflate) and Deflate are two different algorithms, so a request for "deflate" should definitely not return gzipped content.
However, this should be easy to fix, by simply using a GZipStream if the accept header contains "gzip" and a DeflateStream for "deflate".
Both are included in System.IO.Compression, so it's not like you'd have to code your own deflate algorithm or use a third party implementation.
Typically most of the browsers understand GZip and Deflate. They tell the server by specifying it in the request header as Accept-Encoding:gzip, deflate. The HTTPCombiner gives preference to GZip. If both the types are present then GZip is given the preference. HttpCombiner will send the content only if the browser requests for Defalte only.

Categories

Resources