I'm creating a pretty simple HTTP service using OpenRasta. For HEAD requests, the HTTP 1.1 spec states that HEAD requests should have the Content-Length set to "the size of the entity-body that would have been sent had the request been a GET" (section 14.13).
However, OpenRasta apparently sees that the response body is empty and automatically sets the Content-Length header to "0".
What is the recommended way to override this behavior?
Thanks-
Faced with exactly this problem my solution was to add an IPipelineContributor to deal with HEAD requests. The contributor was initialized as follows:
public void Initialize(IPipeline pipelineRunner)
{
// We're going to modify the HTTP method, so allow Rasta to have a go first
pipelineRunner.Notify(PreProcessRequest).After<HttpMethodOverriderContributor>();
}
In the pre-process step I swapped the HTTP method from HEAD to GET in order to allow the request to be processed as normal.
static PipelineContinuation PreProcessRequest(ICommunicationContext arg)
{
if (arg.Request.HttpMethod == "HEAD")
{
// Change the method to GET to allow normal processing
arg.Request.HttpMethod = HttpMethod.GET.ToString();
}
return PipelineContinuation.Continue;
}
At the end of the pipeline the response headers get written as expected, but nothing is written to the body.
Related
I have a Jetty http server with some Jersey rest services. Those services are called from a React website that runs on a Node server.
Due to the cross origin nature of this setup, I had to add some HTTP headers. Basically, all my webservices return a createOkResult() which is created as follows.
#POST
#Path("orders/quickfilter")
#Consumes(MediaType.APPLICATION_JSON)
public Response getQuickFilterProductionOrders(String data)
{
...
return createOkResult(json.toString());
}
protected Response createOkResult(Object result)
{
return buildCrossOrigin(Response.ok().entity(result));
}
protected static Response buildCrossOrigin(Response.ResponseBuilder responseBuilder)
{
return responseBuilder.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS")
.build();
}
For the #GET webservices that works fine. But when I create an #POST service, I just can't get it working.
Webbrowsers (chrome and firefox) return these kind of errors:
Access to XMLHttpRequest at 'http://localhost:59187/rs/production/orders/quickfilter' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
So, at first sight I would be tempted to think that the headers are still missing. The thing is, when I test this service with a tool like Postman, then all headers turn out to be in place, and the service even returns the requested data.
This is a screenshot of a POST request.
From my front-end (which runs on the node server), I use the axios API, which uses promises, and my request looks like this:
const url = "http://localhost:59187/rs/production/orders/quickfilter";
const data = JSON.stringify(request);
const headers = { headers: { "Content-Type": "application/json" } };
const promise = axios.post(url, data, headers);
Right now I have a HTTP error 500, If I remove the content type header, I get an unsupported media exception. So, I have reasons to believe that the content type is ok.
Paul Samsotha pointed me in the right direction.
I ended up adding a filter to the ServletContextHandler. Unlike the linked article, I didn't really have to create that filter from scratch. There was an existing filter class that I could use: i.e. org.eclipse.jetty.servlets.CrossOriginFilter.
FilterHolder filterHolder = context.addFilter(CrossOriginFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,PUT,POST,DELETE,OPTIONS");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
filterHolder.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");
Some of the above parameters can probably be left out, as they are default values. But what appeared to be crucial for me, was to set the CHAIN_PREFLIGHT_PARAM to false.
One nice side-effect, is that I can simplify the code of the actual services. They do not longer need to add special headers, by contrast they can now just return Response.ok().entity(result).build();.
I have a main REST web app where I have an endpoint: POST /api/v1/my_endpoint
I want to allow it to be called:
1) via a browser via ajax from my other web apps on different domains
2) from a server side via HTTP client library.
In the case of ajax call - #1 - I'll have to include "Allow-Control-Allow-Origin" and the similar headers to my response to let a browser receive a response.
In the case #2 - I won't need to include those headers.
However, there's no reliable way to distinguish between #1 and #2.
How can I solve that?
On the server, you check for the presence of an Origin header. This header is sent by the browser as part of the CORS protocol. To explain how it works, below is a filter (in other frameworks, this is also known as middleware) used by a Jersey application. Jersey is a Java REST framework. Sorry I don't know Rails. But you should still be able to follow along with this explanation,.
How this filter works is that the ContiainerRequestFilter is called before the backend controller method is called, then the controller method is called, then the ContainerResponseFilter is called. See the commented notes above the methods to see which method are for which.
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
#Override
// ******************************************
// implementation for ContainerRequestFilter
// ******************************************
public void filter(ContainerRequestContext request) throws IOException {
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
#Override
// ******************************************
// implementation for ContainerResponseFilter
// ******************************************
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
if (request.getHeaderString("Origin") == null) {
return;
}
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-Token, " +
"Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
}
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
So when the request comes in, the filter checks to see if it is Preflight request. There are two types of cross origin request: a normal one, and preflight. The preflight request occurs before the actual request is made to the server. This is an OPTIONS request where the browser sends some CORS request headers to check with the server to see if the request is allowed. The server should respond back with CORS response headers telling the server that the request is allowed.
So with this filter, is it a preflight request, we abort the request (the controller method will not be called) and then the code execution goes to the ContainerResponseFilter where we set the CORS response headers. You can see in the code, we check the same isPreflightRequest() method.
If the request is not an OPTIONS request, and the Origin header is present, then it is a "normal" cross origin request, in which case, all that is required in in the response headers is Access-Control-Allow-Origin.
Notice that if there is no Origin header, then no CORS headers are added. This is basically how you will differentiate from an AJAX client and other HTTP clients. Only AJAX requests will add the Origin header, and this is done automatically by the browser when it detects a cross origin request.
I hope you understand everything I am talking about, even though the code is Java. It think it's pretty straight forward though, even if you have never used Java. The naming or methods and variables should make it easy to follow. If you understand the flow of the code, then you should pretty much understand the flow of the CORS protocol.
Aside
As an aside, it doesn't hurt if you add the Access-Control-Allow-Origin header on all responses, whether it be an AJAX request or an HTTP client request. If you want to be lazy and implement it this way, it won't hurt. It is required for the AJAX client, but not for the HTTP client. But if you include it in the HTTP client, nobody will die. The world will go on business as usual.
I have a grails 2.2.4 application. I wanted to enable CORS
So I installed cors plugin by having the following line in build config.
plugins {
runtime ':cors:1.1.8'
}
Then in the config.groovy
cors.headers = ['Access-Control-Allow-Origin': '*']
But after this when I run the application, CORS in not enabled. So I debugged the CORS plugin. The issue seems to be in CorsFilter class in the following method
private boolean checkOrigin(HttpServletRequest req, HttpServletResponse resp) {
String origin = req.getHeader("Origin");
if (origin == null) {
//no origin; per W3C spec, terminate further processing for both preflight and actual requests
return false;
}
The origin parameter in the above line is always null as the request does not have the parameter 'Origin'. Is there something i'm doing wrong? I'm not looking for the answer which says add a manual header with the name "Origin" since that is not exactly a proper fix
I'm quite new to CORS so appriciate the help.
In addition to Access-Control-Allow-Origin, and in addition to setting the Origin header on request, you probably need to specify these response headers as well:
Access-Control-Allow-Headers: accept
Access-Control-Allow-Headers: origin
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Method: GET
Access-Control-Allow-Method: POST
Also make sure you respond to HTTP OPTIONS requests with these headers and a blank 200 OK response.
For now, let's assume that RestClient is sending the Origin header properly. It may still be getting stripped by your application. You can prevent this using the Access-Control-Allow-Headers: Origin header.
Most of the problems I have had with my web services is that the right headers are being sent, but they are stripped from the message by my web server. So I tend to adopt a shotgun approach of "allow everything" and then one by one remove what I don't need. My allow-headers header usually is pretty long and I end up having to include stuff like Content-Type, X-Requested-With and other junk before my requests will finally go through.
I further recommend that you test using something besides RestClient, if only as a sanity check. I use Postman, a free Chrome app, for all my messaging tests. It looks to me like the problem is with RestClient not sending the proper Origin header.
In Delphi, I'm using Indy's TIdHTTPWebBrokerBridge coupled with TIdHTTP to send/receive data via HTTP. On the Server, I don't have any fancy handling, I always just respond with a simple content stream. If there's any issues, I only return information about that issue in the response content (such as authentication failed, invalid request, etc.). So, on the client side, can I assume that every successful request I make to this server will always have a response code of 200 (OK)?
I'm wondering because on the client, the requests are wrapped inside functions which return just a boolean for the success of the request.
Inside this function:
IdHTTP.Get(SomeURL, AStream);
Result:= IdHTTP.ResponseCode = 200;
This function handles any and every request which could possibly fetch data. If there were any issues in the request, This function should return False. In my scenario, since I always return some sort of content on the server, would the client always receive a response code of 200 in this function?
I guess the real question is, if I always return some sort of content and handle all exceptions on the server, then will the server always return status code of 200 to each request?
"Does every successful HTTP request always return status code 200?"
See w3.org: HTTP/1.1 Status Code Definitions (RFC 2616)
The answer is No. All 2xx are considered successful.
That may depend on the HTTP method used.
Should your web-server application always return 200 upon success? That may as well depend on the request method and the signal it intends for the client . e.g.
for PUT method (emphasis is mine):
If an existing resource is modified, either the 200 (OK) or 204 (No
Content) response codes SHOULD be sent to indicate successful
completion of the request.
for POST method:
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see section 14.30). Responses to this method are not
cacheable, unless the response includes appropriate Cache-Control or
Expires header fields. However, the 303 (See Other) response can be
used to direct the user agent to retrieve a cacheable resource.
As you can learn from the RCF, every method SHOULD have it's own success status codes, depending on the implementation.
Your other question:
"can I assume that every successful request I make to this server will always have a response code of 200 (OK)?"
You can always expect Status code 200, if your web server always responds with Status 200. Your web server application controls what response it returns to the client.
That said, Status code 200 is the Standard response for successful HTTP requests (The actual response will depend on the request method used), and in the real world of web servers, SHOULD be set as default upon successful request, unless told otherwise (As explained in Remy's answer).
To answer your specific question:
can I assume that every successful request I make to this server will always have a response code of 200 (OK)?
The answer is Yes, because TIdHTTPWebBrokerBridge wraps TIdHTTPServer, which always sets the default response code to 200 for every request, unless you overwrite it with a different value yourself, or have your server do something that implicitly replies with a different response code (like Redirect() which uses 302, or SmartServeFile() which uses 304), or encounter an error that causes TIdHTTPServer to assign a 4xx or 5xx error response code.
However, in general, what others have told you is true. On the client side, you should handle any possible HTTP success response code, not just 200 by itself. Don't make any assumptions about the server implementation.
In fact, TIdHTTP already handles that for you. If TIdHTTP encounters a response code that it considers to be an error code, it will raise an EIdHTTPProtocolException exception into your code. So if you don't get an exception, assume the response is successful. You don't need to check the response code manually.
If there is a particular response code that normally raises an exception but you do not want it to, you can specify that value in the optional AIgnoreReplies parameter of TIdHTTP.Get() or TIdHTTP.DoRequest(). Or, if you are are using an up-to-date Indy 10 SVN revision, a new hoNoProtocolErrorException flag was recently added to the TIdHTTP.HTTPOptions property so the EIdHTTPProtocolException exception is not raised for any response code.
Successful resposes are 2xx List_of_HTTP_status_codes
i did the following. Process straight all 200`s and LOG exceptions. worked, not a single non 200 - except unauthorized and timeouts (password or sometimes unavaliable server). but many/all responses will be considered for a wide range of mainstream apps.
while (iRedo < 3) do begin
s := Self.HTTPComponent.Get( sUrl );
if self.HTTPComponent.ResponseCode = 200 then begin
break;
end;
// IDEIA - log what happend if not 200
logWhatHappend( s, HTTPComponent ); // then log content, headers, etc
inc( iRedo ); sleep( 5 );
end;
i have an HttpWebRequest that do 'POST' to a web server and get an HTML page In response.
I've been asked how is the best practice to know that the response i got has been changed or not?
I can't relay on the web server headers, they don't have to be.
this will increase performance in a way that i wont be need to parse the response over again and will go to the next request in a half of a sec or so.
thank you in advanced
You can tell your webserver about last modification date. see here. If you can't rely on that you have to parse your response anyway. You could do that quickly using md5. So you "md5" your current response and compare it with the previous.
You shouldn't be attempting to rely on the headers for a POST request, as it shouldn't emit any caching headers anyway.
What you need to do instead is perform a hash/checksum (this can either be CRC(32) for absolute performance or a "real" hash such as md5) on the returned content (this means, everything underneath the \r\n\r\n in the headers) and do a comparison that way.
It should be good enough to store the last request's checksum/hash and compare against that.
For example (psuedo):
int lastChecksum = 0;
bool hasChanged() {
performWebRequest();
string content = stripHeaders();
int checksum = crc32string(content);
if(checksum != lastChecksum) {
lastChecksum = checksum;
return true;
}
return false;
}