I've built an interface to a thridparty Rest/Json web API, everything is working great with valid test cases, but when I request something invalid from the API, say a job that doesn't exist, the API returns a response where the body = 'null' and has a the content type as "application/json; charset=utf-8". I'm not sure if this is standard practice for a web API, but when I call Execute on the IHttpClient I end up with an Access Violation and the client exits.
Protrace is a follows
Exception code: C0000005 ACCESS_VIOLATION
Fault address: 00007FFC6733DAAD 01:000000000077CAAD C:\Apps\Progress\117\bin\prow.dll
** ABL Stack Trace **
--> Write OpenEdge.Net.HTTP.Filter.Payload.JsonEntityWriter at line 463 (OpenEdge/Net/HTTP/Filter/Payload/JsonEntityWriter.r)
ExtractEntity OpenEdge.Net.HTTP.Lib.ABLSockets.ABLSocketLibrary at line 360 (OpenEdge/Net/HTTP/Lib/ABLSockets/ABLSocketLibrary.r)
Execute OpenEdge.Net.HTTP.Lib.ABLSockets.ABLSocketLibrary at line 312 (OpenEdge/Net/HTTP/Lib/ABLSockets/ABLSocketLibrary.r)
Execute OpenEdge.Net.HTTP.HttpClient at line 154 (OpenEdge/Net/HTTP/HttpClient.r)
TryRest Tempo.TempoApi at line 1264 (D:\_Dev\OnTap-Trunk\rcode\Tempo\TempoApi.r)
ExecuteRest Tempo.TempoApi at line 234 (D:\_Dev\OnTap-Trunk\rcode\Tempo\TempoApi.r)
TryRest is:
METHOD PRIVATE INTEGER TryRest(
INPUT oUri AS URI,
INPUT cType AS CHARACTER,
INPUT cContentType AS CHARACTER,
INPUT oContent AS Object,
OUTPUT oResponse AS IHttpResponse ):
DEFINE VARIABLE result AS INTEGER NO-UNDO.
DEFINE VARIABLE oRequest AS IHttpRequest NO-UNDO.
CASE cType:
WHEN "GET" THEN
oRequest = RequestBuilder:GET(oURI)
:AddHeader("Authorization", "Bearer " + STRING(cAccessToken))
:AcceptJson()
:REQUEST.
END CASE.
oResponse = ResponseBuilder:Build():Response.
oClient:EXECUTE(oRequest,oResponse).
RETURN oResponse:StatusCode.
CATCH e AS Progress.Lang.Error:
UNDO, THROW e.
END CATCH.
END METHOD.
I'm using the latest OpenEdge client, 11.7.2 Windows x64.
My question is, is it normal for a web API to return 'Null' for an invalid request?
And secondly, this is obviously an unhandled exception in OpenEdge.Net.HTTP.Lib, which should not result in client crash.. Any ideas for working around it? I've tried changing AcceptJson() to AcceptAll, and AcceptHTML, but the protrace is the same, crashing in JsonEntityWriter.
Thanks
No, typically RESTful APIs will return a 404 if you make a request to a route that isn't valid. The only exception that I can think of off the top of my head is if you attempt to access a route that has parameters as part of the URI.
Related
Am doing some system testing to URL Sanitation. So I tried rushing the APIs with junk data.Example
http://ipaddress/AppContext/api1?query=%S%n%n%s
If I call this API , my log throws an exception 'Invalid HEX character in escape sequence %n'
How to I catch this in tomcat level and throw a 400 bad request
You can't.
Tomcat doesn't decode the query string until the application requests one or more parameters. The best you can do is write a Filter that always tries to access the query string before the main request processing and returns a 400 response if an exception is thrown.
I am working with Spring Framework about Rest.
I have the scenario about testing when the request is a GET and Accept is either empty or null.
It is closely related with:
#GetMapping is called even when Accept is defined how null
I have read the following:
How to interpret empty HTTP Accept header?
What does 'Accept: /' mean under Client section of Request Headers?
Seems the following options how solutions are valid:
400 Bad Request
406 Not Acceptable
Consider the empty or null value of Accept how */* instead
Three options, that's the reason of this post.
Between the two first, I consider more appropriate 406 Not Acceptable, it because it is specific or tight for Accept. I mean what media type represents empty or null? it is not a known media type such as xml or json
The third option seems illogic, according with the following points (according my own points of view, perhaps I am wrong or missing something):
The server has a handler method for GET that returns either XML or json, such as:
#GetMapping(path="/{id}",
produces={MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public #ResponseBody Persona findOneById(#PathVariable String id){
return personaService.findOneById(id);
}
The client should have clear from the beginning that it would do the request and handle the response either XML or json, according the Accept sent through the request.
Thus, for any reason if the request sent has the Accept how empty (lets assume wrong coding), It is the third point (*/*) that I can't understand: "let the server return any media type"; even with that, lets assume the server returns XML and the client just can handle JSON instead, but of course that Accept how Json wasn't specified from the beginning. So the client once received the response should receive an exception, but observe that the server did the work unnecessarily
Thus: How handle correctly HTTP Accept header when empty or null?
In Sinatra, how can I override the Content-Length header in the response to set my own value?
The last line in my method returns the following:
[200, {'Content-Type' => component.content_type,
'Content-Length' => component.content_length.to_s}, component.content.data]
This way I was hoping to override the content value, but it results in an exception:
Unexpected error while processing request: Content-Length header was 2, but should be 0
I would like to return a different value for the content length. Is there a way to do this?
This error is being raised by the Rack::Lint middleware, so the quick fix would be to not use that piece of middleware. Depending on how you are starting your application that may be tricky though – Rack adds it in certain cases if you use rackup.
A better solution would be to change your client to use a HTTP HEAD request rather than a GET. In Sinatra defining a GET route automatically defines a matching HEAD route. Using HEAD will cause the server to send the headers but not the body, and you should be able to set the Content-Length to whatever you want. It will also avoid the Rack::Lint error.
Here is a gist explaining how to disable Rack::Lint:
module Rack
class Lint
def call(env = nil)
#app.call(env)
end
end
end
(Taken from https://gist.github.com/shtirlic/2146256).
My use case is that I would like to do error handling in sinatra. For this I am setting up the error handler as follows
error 0..600 do
##logger.error("error reason #{env['sinatra.error']}")
end
The sinatra.error variable gets set fine if the error was caused by explicitly raising an exception
get '/' do
raise "Fail the request"
end
But if halt is used to terminate the request then sinatra.error does not get set. Looking into sinatra code this appears to be as expected because throwing :halt causes the control flow to go all the way up to invoke and thus bypassing the setting of sinatra.error variable.
My question is how to use the error handler along with the halt so that I can get the cause of the error in the error handler.
I think the behavior you're seeing stems from the intended purpose of halt. When you call it, you aren't necessarily signaling in error; you just want execution to stop immediately, which can be particularly useful in a filter. If you check Sinatra's README, it says that you use halt to "immediately stop a request within a filter or route use". Granted, you will usually do it because of an error.
It is also interesting to notice that the error handler you defined gets called not only when errors occur, but also when regular requests are served, including ones with status 200. And in those cases, env[sinatra.error] won't be set either.
What you can do in your error handler is to check for an exception and, if it's not available, check the response code. For example (note that this is a classical application):
error 0..600 do
boom = #env['sinatra.error']
status = response.status
case
when boom != nil
puts 'exception: ' + boom
when status != 200
puts 'error: ' + status
end
end
One consequence is that, in this handler, normal requests are indistinguishable from those interrupted by halt, because both generate a 200 status code. However, if you are using halt to report errors, then you should be using an error code like 500 anyway.
I'm writing a REST based web service, and I'm trying to figure out the best way to handle error conditions.
Currently the service is returning HTTP Errors, such as Bad Request, but how can I return extra information to give developers using the web service an idea what they're doing wrong?
For example: creating a user with a null username returns an error of Bad Request. How can I add that the error was caused by a null username parameter?
According to the HTTP spec, the text that comes after the three digit response code, the "Reason-Phrase", can only be replaced with a logical equivalent. So you can't respond with 400 null user and expect anything useful to happen. Indeed, The client is not required to examine or display the Reason- Phrase.
In general, the HTTP response entity (typically the page that accompanies the response) should contain information useful to the client to guide them forward, even when the response is an error. On the web, most such errors are HTML, and are devoid of machine readable information, but most browsers do show the error to the user (and SO's error page is pretty good!).
So for a primarily machine readable resource you have two options:
Pass a human readable message anyway. Return 400 Bad Request with a HTML response, which the client may opt to show to the user. It's dead easy but it's a bit like throwing an unchecked exception, it passes all the hard work to the client, or indeed the end user.
Allow clients to recover. Return 400 Bad Request with a machine readable response which is part of your API, so clients can recover from known error conditions. This is harder, like throwing a checked exception, it becomes part of the API, and it allows clients to recover gracefully if they want to.
You could even make the server support both scenarios by defining a media type for the machie readable error recovery document, and allow clients to "accept" them: Accept: application/atom+xml, application/my.proprietary.errors+json
Clients that forget the mandatory field can opt in to getting machine readable errors or human readable errors by choosing to Accepting the error media type.
It's stated in the HTTP spec that most error codes should return some basic text that gives a clarification of why the error is being returned. The basic Java Servlet Spec defines the HttpServletResponse.sendError(int Code, String message) for this purpose.
String desc = "my Description";
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(desc).type("text/plain").build());