Difference between the two Web API headers response.Content.Headers and response.Headers - asp.net-web-api

I find WebAPI separate HTTP response headers into different places, one is in Response.Headers, the other in in Response.Content.Headers. For example, etag is in Response.Headers while lastModified is in the other. What is the reason behind that?

There are a couple of answers to that question. One is because that's the way the HTTP spec defines the headers.
RFC 2616
Content header fields here
https://www.rfc-editor.org/rfc/rfc2616#section-7.1
Request header fields here https://www.rfc-editor.org/rfc/rfc2616#section-5.3
Response header fields here https://www.rfc-editor.org/rfc/rfc2616#section-6.2
The other more practical reason for separating out the content headers is that it is easier write code that processes data into HTTP payloads and sets the related headers, independent of the request/response objects.
Unfortunately, the more recent HTTPbis specification did some reorganization of where they think headers should go and now LastModified and Allow are considered response fields, not content fields.
This means that the headers as defined in System.Net.HttpHeaders will no longer match the spec, which really sucks. It also means that we are probably stuck with LastModified as a HttpContent header and Etag as a response header.
HTTPbis
Content related headers are defined here.
Request headers here.
Response headers here.

Related

Gin-Gonic Content-Type restriction

There is a service written in golang, using gin-gonic framework.
I only ever want to support application/json as a mime-type and it would be great if it always be in UTF-8. The business logic of the service might break if it will get values in different encodings.
Is it a good idea to write a custom middleware that checks if Content-Type header has value "application/json; charset=utf-8" and returns some 4xx status in case it is not?
UPDATE:
Just found out that ctx.ContentType() doesn't return charset part of the header. Is there a way to get it?
Nothing prevents you from simply looking at the "Content-Type" http header directly, to the tune of ctx.Request.Header.Get("Content-Type").
The helper ContentType method is provided by gin-gonic especially for the rather common case of querying the "unadulterated" mime type of incoming data without too much hassle.

Spring MVC response Headers: ETag has double quotes for GET request but not for PUT request

We upgraded our Spring MVC from 4.0 to 4.3 in our service. It caused ETag format change in the response headers for "GET" method. Clients making "GET" calls will get ETags with double quotes in the response headers. Previously ETag in the response headers had no double quotes for "GET" method.
For example:
Now: etag →"TVMzTWFpbmxpbmVEZXZvLTI5ODIxMQ"
Previously: etag →TVMzTWFpbmxpbmVEZXZvLTI5ODIxMQ
The response of "PUT" request does not have double quotes around ETag in Headers, just like before.
Anyone has any ideas why?
Prior to Spring 4.2.x, there was no management for the ETag header. It has been introduced since then in the HttpEntityMethodProcessor. The class has evolved during time and the management of the ETag header respect the RFC (or is close enough).
As you can see in this commit, Spring team fixed an issue with its management:
Fix missing ETag/LastModified headers in responses
Prior to this commit, the HttpEntityMethodProcessor would avoid
writing ETag/Last-Modified response headers before calling
ServletWebRequest to process conditional requests. This was done to
avoid duplicate response header values due to headers being already
written to the underlying servlet response.
This is still necessary for GET/HEAD requests, since this is properly
handled by ServletWebRequest for those cases. But
HttpEntityMethodProcessor should not make that decision for
PUT/PATCH/POST responses since developers are adding response headers on
purpose and should be in control of the situation — whereas
ServletWebRequest does not write those headers in those cases.
The relevant part of modified code is here.
So basically, when you are manually adding an ETag header, in case of a 200 status of a GET or HEAD method, the framework removes it, then recreates it. That is why with a PUT, there are no double quotes.
In HttpEntityMethodProcessor:
if (inputMessage.getMethod() == HttpMethod.GET || inputMessage.getMethod() == HttpMethod.HEAD) {
responseHeaders.remove(HttpHeaders.ETAG);
responseHeaders.remove(HttpHeaders.LAST_MODIFIED);
}
Then in ServletWebRequest:
private String padEtagIfNecessary(String etag) {
if (!StringUtils.hasLength(etag)) {
return etag;
}
if ((etag.startsWith("\"") || etag.startsWith("W/\"")) && etag.endsWith("\"")) {
return etag;
}
return "\"" + etag + "\"";
}
As you can see, this respects the chapter 2.4 of the RFC:
2.4. When to Use Entity-Tags and Last-Modified Dates
In 200 (OK) responses to GET or HEAD, an origin server:
o SHOULD send an entity-tag validator unless it is not feasible to
generate one.
o MAY send a weak entity-tag instead of a strong entity-tag, if
performance considerations support the use of weak entity-tags, or
if it is unfeasible to send a strong entity-tag.
o SHOULD send a Last-Modified value if it is feasible to send one.
In other words, the preferred behavior for an origin server is to
send both a strong entity-tag and a Last-Modified value in successful
responses to a retrieval request.
But I found that it is not backward compatible and breaks what developer could have used prior to these versions, without the possibility to skip/override what they did.
Here is the description of the ETag from the MDN (more clearer).
Hope it helped in comprehension.

What is the "accept" part for?

When connecting to a website using Net::HTTP you can parse the URL and output each of the URL headers by using #.each_header. I understand what the encoding and the user agent and such means, but not what the "accept"=>["*/*"] part is. Is this the accepted payload? Or is it something else?
require 'net/http'
uri = URI('http://www.bible-history.com/subcat.php?id=2')
http://www.bible-history.com/subcat.php?id=2>
http_request = Net::HTTP::Get.new(uri)
http_request.each_header { |header| puts header }
# => {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"], "accept"=>["*/*"], "user-agent"=>["Ruby"], "host"=>["www.bible-history.com"]}
From https://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z3
This field contains a semicolon-separated list of representation schemes ( Content-Type metainformation values) which will be accepted in the response to this request.
Basically, it specifies what kinds of content you can read back. If you write an api client, you may only be interested in application/json, for example (and you couldn't care less about text/html).
In this case, your header would look like this:
Accept: application/json
And the app will know not to send any html your way.
Using the Accept header, the client can specify MIME types they are willing to accept for the requested URL. If the requested resource is e.g. available in multiple representations (e.g an image as PNG, JPG or SVG), the user agent can specify that they want the PNG version only. It is up to the server to honor this request.
In your example, the request header specifies that you are willing to accept any content type.
The header is defined in RFC 2616.

Can I make my OData request in JSON format?

I know OData supports responding in JSON format when it's given the appropriate Accept header:
Accept: application/json
Some articles say you'll need to specify odata verbosity otherwise you'll get the default xml format, but I have not seen this to be actually true. But let me mention it anyway:
Accept: application/json;odata=verbose
But (how) can I make my request using JSON instead of a querystring?
OData doesn't provide a way to specify the query in a request body, it only supports the query in the URL. So the answer is that there's no way to do that in JSON. Note that it applies to GET requests. Modification requests (POST/PUT/...) do accept JSON as the payload (typically representing an entity for example), in which case simply specify the content type of the request in its Content-Type header.
There are java script libraries which let you build the query string using more structured code (as compared to just strings). For example the datajs http://datajs.codeplex.com/.

Overwriting HTTP response headers

Is there a way to overwrite the http response headers returned in Jmeter? I'm testing a web service that returns JSON and when an invalid request is sent, the JSON response returned doesn't contain application/json (or any for that matter) in the response header. If I save the response to a file, I see the actual JSON returned, but looking at the response in a Results tree doesn't show a response. Unless there is a way to load the response from file and parse the error message from the file, I'm hoping to somehow overwrite the HTTP response header and force jmeter to treat the response as JSON.
Any suggestions are welcome!
Using a beanshell post processor, you can write some script that would force the value for the header, or write out to a file.
You can also add a listener that would write the results to file for you. Granted - this is less convenient for debugging then Tree View.
As it turns out JMeter does not support response header overloading. While the response isn't displayed in the Results tree, it is actually available to other assertions. I was able to still provide assertions to validate responses even though the response was missing from the GUI.

Resources