Why is AWS SNS treating 404 response from subscriber as successful? - amazon-sns

I'm having a hard time understanding how SNS handles response messages. My SNS subscriber is a page that might go down or simply return a 4xx error.
For some reason though, it seems that SNS is treating requests that return 4xx error codes as successful.
How can I make it fail when the response code is 4xx and not only 5xx?
From the logs we can see that the subscriber is returning a status code 404 Not found, but despite that, the status of the request is still SUCCESS.
{
"notification": {
"messageMD5Sum": "fd746e97153916fd99bba*********",
"messageId": "be666c50-8de5-594b-9e77-*********",
"topicArn": "arn:aws:sns:us-east-1:060758096283:*********,
"timestamp": "2021-11-23 14:21:23.778"
},
"delivery": {
"deliveryId": "ef278086-2a70-5512-a191-da90d1534d24",
"redrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:us-east-1:*********:*********-DLQ\"}",
"destination": "*********/subscriber.php",
"providerResponse": "Not Found",
"dwellTimeMs": 80,
"attempts": 1,
"statusCode": 404
},
"status": "SUCCESS"
}
This is causing me issues with monitoring, as It's very hard to know if my requests are actually successful or not without manually looking them up.

SNS's job is to deliver a message to the endpoint. If the endpoint responds with a valid status code (not a 5XX failure), it considers the delivery of the message successful. How that message is responded to is up to the receiving API.
To be precise, only status codes outside of the range 200 - 499 will be considered as a failures and retried according to your retry policy as per https://docs.aws.amazon.com/sns/latest/dg/sns-message-delivery-retries.html. Once the max number of retries has been exhausted, the message will be delivered to a DLQ if one is configured.

Related

What is the use of http_errors in guzzle?

I have read https://docs.guzzlephp.org/en/stable/request-options.html#http-errors documentation. However, I am not getting when to set it true/false.
If anyone can explain it with example, that would be very helpful to me.
Thank you,
Trupti
Take a look at status codes HTTP response status codes
This is what is written in guzzle docs for http errors.
Set to false to disable throwing exceptions on an HTTP protocol errors (i.e., 4xx and 5xx responses). Exceptions are thrown by default when HTTP protocol errors are encountered.
It is not possible that everything is ok when you send a http request for a web uri, you can get different errors like Connection errors, server errors, even client errors.
So in order to handle these there are different status codes used ranging between 400-499 & 500-599.
For requests to be send by guzzle, these are handled by GuzzleException. see the heirarchy of errors here.
So by sending requests with http_errors as false, you are telling that do not bother me throwing the errors of range 400-499(handled by ClientException) and 500-599(ServerException)
$client->request('GET', '/status/500', ['http_errors' => false]);
So guzzle will not inform you if your request has any of these errors(eg 403).

Which HTTP status code should be used for business errors in API design?

Lets say I have an API endpoint that executes some business operation which can result in many different failures that are not connected directly to the request.
The request is correctly formed and I cannot return 4xx failures, but the logic of the application dictates that I return different error messages.
Now I want the client to be able to differentiate these error messages so that different actions can be taken depending on the code. I can return a custom JSON like this e.g.
{
"code": 15,
"message": "Some business error has occurred"
}
Now the question is which HTTP status code should I use for such occasions if no standard code like Conflict or NotFound makes sense.
It seems that 500 InternalServerError is logical, but then how can I additionally flag that this cannot be retried, should it be just documented that given status codes is not possible to retry so one can retry if you don't get one of those?
Consult RFC 7231:
503 Service Unavailable looks like a potential candidate, but the RFC mentions that this is supposed to represent a problem "which will likely be alleviated after some delay." This would indicate to a client that it could try the same call later, maybe after business hours or on the weekend. This is not what you want.
501 Not Implemented could be possible, but the RFC mentions "This
is the appropriate response when the server does not recognize the
request method and is not capable of supporting it for any resource. A 501 response is cacheable by default;" This does not appear to be the case here - the HTTP method itself was presumably valid - the failure here seems to be happening at the business rules layer (e.g. sending in an account number that is not in the database), rather than an HTTP method (GET, POST, etc.) that you never got around to implementing.
That leaves the last serious candidate,
500 Internal Server Error
The 500 (Internal Server Error) status code indicates that the server
encountered an unexpected condition that prevented it from fulfilling
the request.
This is the error code that is normally used for generic "an exception occurred in the app" situations. 500 is the best choice.
As to how to distinguish this from a "temporal internal trouble" error, you can include this as part of the HTTP body - just make sure that your client can parse out the custom codes!

Validation of a user registration request should return 200 or 400

The client sends a perfectly valid request for a user registration, e.g. username & password.
The server finds out that the username is already taken. What's the correct return status - 200 with an error message, or 400? The spec says:
400 implies that something was wrong with the request.
The HyperText Transfer Protocol (HTTP) 400 Bad Request response status
code indicates that the server cannot or will not process the request
due to something that is perceived to be a client error (e.g.,
malformed request syntax, invalid request message framing, or
deceptive request routing).
But technically there's nothing wrong with the request.
What is 'wrong' is that the request was intended to create a new user, but that failed because the username was already taken. This is definitely in the category 'client error'. Rather than seeing 'client error' as 'there is a bug', it's better to think of it was 'for one reason or another the request failed, and it's up to the client to make a correction'.
A typical error code for this specific situation might be 409 Conflict.
If you sent back 200, the client should perceive the result as "My request completed successfully", which is definitely not the case here.

IBM Watson - Conversation API integration returns Resource Not Found error (404)

I am trying to integrate watson from salesforce (Http Callout) and received 404 error. Then I tried the sameusing Postman tool but getting the same result
Added conversation credentials in request header
Request Endpoint
https://gateway.watsonplatform.net/conversation/api/v1/workspaces/883c7704-02c4-41fc-b8a0-aea1d0325c5a/message?version=2016-09-20
Request Body
{
"application/json": {
"input": {
"text": "Hi"
},
"alternate_intents": true
}
}
Response Body
{
"error": "Resource not found"
}
Status
404 Not found
Please let me know what is the issue here. I am not sure whether the way I added version and workspace id in the endpoint went wrong
I had the same issue and I found that it's simply rate limiting that kicks in.
According to the docs here there is no limit for the endpoint, however that turns out to be untrue. If you send a few thousand messages in quick succession, you'll start getting 404 Not Found until the quota resets, which seems to take around 1 hour.
The request body doesn't seem right. It should be JSON with e.g. this structure (see api ref. page in watson conversation service doc.):
{
"input": {
"text": "Hi"
}
}
application/json should be the content type. Sample request with curl:
curl -X POST -u "{username}":"{password}" -H "Content-Type:application/json" --data "{\"input\": {\"text\": \"Hi\"}}" "https://gateway.watsonplatform.net/conversation/api/v1/workspaces/<workspace_id>/message?version=2017-02-10"
See the API Reference for more details: https://www.ibm.com/watson/developercloud/conversation/api/v1/

Is it suitable to use 200 HTTP status code for a forbidden web page?

What is the difference when we use 200 response status code for a forbidden page with an error message saying 'Access Denied' instead of using 403 response status code?
Are there any security implications?
The HTTP Response codes convey information about how the server has processed your request. So, if the server responds with 200, it means: "OK, I have received your request and processed it successfully". If it returns 403, it would mean: "I received your request successfully, but you don't have access to this resource".
However, technically they are both returned in the same format, in the same way in the response HTTP header like this:
HTTP/1.1 200 OK
HTTP/1.1 403 Forbidden
The difference is in the meaning. And the meanings are defined in the standard.
So, when you are responding with code 200, you are telling the client that it is all good and dandy. If you are responding to client with 403, you are saying that the client doesn't have permission to this resource. Remember, there can be different clients: web browsers, crawlers, ajax requests from javascript, etc.
So, if you are sending a login form with 200 code:
Users who are using a web browser would understand that they need to login.
Google crawler will index your members/quality-content URL with the login form and will not understand that actually, the original content is different and it should not index this page with the login form.
Javascript with ajax callback will run success callback, when it should be running error callback function.
So, basically, make us all a favour and follow the standards! :)
Answering your second question, no it does not make your application any less secure.
The reason for this decision might be that error message was not visiable using Internet explorer like described here: How do I suppress "friendly error messages" in Internet Explorer?
Actually the correct way is to use the right HTTP error code and make the error message longer than 512 bytes as described here:
https://support.microsoft.com/en-us/kb/294807
Response status codes are intended to help the client to understand the result of the request. Whenever possible, you should use the proper status codes.
The semantics of the status codes are defined in the RFC 7231, the current reference for HTTP/1.1.
While the 200 status code indicates that the request has succeeded, the 403 status code indicates that the server understood the request but refuses to authorize it:
6.3.1. 200 OK
The 200 (OK) status code indicates that the request has succeeded. The payload sent in a 200 response depends on the request method. [...]
6.5.3. 403 Forbidden
The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it. A server that wishes to make public why the request has been forbidden can describe that reason in the response payload (if any). [...]
Returning 200 will work, for sure. But why would you return 200 if you can return a much more meaningful status code? If is there any good reason, this should be added to your question.

Resources