Watson Speech-to-Text register_callback returns only 400s - ibm-cloud

The Watson Speech-to-Text asynchronous HTTP interface allows one to register a callback url through a call to register_callback. This call is clearly not working; for illustration, please see these six lines of code.
# Illustration of how I can't get the Watson Speech-to-Text
# register_callback call to work.
r = requests.post(
"https://stream.watsonplatform.net/speech-to-text/api/v1/register_callback?{0}".format(
urllib.urlencode({ "callback_url": callback_url })),
auth=(watson_username, watson_password),
data="{}")
print(r.status_code)
print(pprint.pformat(r.json()))
# This outputs:
# 400
# {u'code': 400,
# u'code_description': u'Bad Request',
# u'error': u"unable to verify callback url 'https://xuyv2beqpj.execute-api.us-east-1.amazonaws.com/prod/SpeechToTextCallback' , server responded with status code: 400"}
# and no http call is logged on the server.
r = requests.get(
callback_url, params=dict(challenge_string="what does redacted mean?"))
print(r.status_code)
print(r.text)
# This outputs:
# 200
# what does redacted mean?
# and an HTTP GET is logged on the server.
I first call register_callback with a perfectly valid callback_url parameter, in exactly the way the documentation describes. This call returns with a 400 and, according to my callback URL server logs, the callback URL never receives an HTTP request. Then I GET the callback URL myself with a challenge_string. Not only is the callback URL responding with the right output, but a log appears on my server indicating the URL received an HTTP request. I conclude that register_call is not working.

Answer:
We identified the issue on our end: the server that makes the outbound calls to your URL did not support the SSL encryption method that your callback server uses. We have fixed that and we are in the process of pushing to the production environment very soon.
Also FYI:
The error message with 400 indicates the callback URL does not meet
request or does not exist. Please refer to the detail in
Speech-To-Text service API document,
http://www.ibm.com/watson/developercloud/speech-to-text/api/v1/?curl#register_callback
If the service does not receive a response with a response code of 200
and a body that echoes a random alphanumeric challenge string from the
callback URL within 5 seconds, it does not whitelist the URL; it
sends response code 400 in response to the registration request.

we just fixed the issue you reported. The problem was on our end, the servers responsible for making the callback to the server you set up did not support the cipher suites needed for establishing the SSL connection. We just updated the servers and we are happy to learn that it is now working for you: )
Dani

Related

Forwarding a response from another server using JAX-RS

I have an angular client which is making a POST call to my server. This server needs to get a response by calling another server(server2) with a POST call and pass the response from the server2 to the client. I tried the following approaches.
public Response call(){
String server2Url = "http://server2/path"
RestClient restClient = new RestClient();
return Response.fromResponse(restClient.post(server2Url)).build();
}
But in the above case the HTTP status code gets transferred but not the response body. The response body is empty
Then I tried:
public Response call() throws URISyntaxException{
String server2Url = "http://server2/path"
RestClient restClient = new RestClient();
return Response.temporaryRedirect(new URI(server2Url)).build();
}
but the browser client ends up making an OPTIONS call to the server2Url instead of a POST
and I tried.
public Response call() throws URISyntaxException{
String server2Url = "http://server2/path"
RestClient restClient = new RestClient();
return Response.seeOther(new URI(server2Url)).build();
}
but this ends up making a GET call instead of a POST.
How do I make the browser client make a POST call to server2
You can use Html Client from JAX-RS to make your own requests (from server1 to server2) and then return the response from server2 to the angular client.
public Response call() {
String url = "server2 url";
Response response;
try {
response = ClientBuilder
.newClient()
.target(url)
.request()
.post(Entity.json(null), Response.class);
}
catch (Exception e) {
// Whatever you want
return null; // or error
}
// Return the status returned by server 2
return Response.status(response.getStatus()).build();
}
What you are trying to accomplish is covered in the RFC 2616 I just found here.
If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
So it looks like this is out of your hands if you´re not implementing the client.
Edit because I was told that RFC 2616 must not be used any longer.
RFC 7231 states that:
302 Found
The 302 (Found) status code indicates that the target resource
resides temporarily under a different URI. Since the redirection
might be altered on occasion, the client ought to continue to use the
effective request URI for future requests.
The server SHOULD generate a Location header field in the response
containing a URI reference for the different URI. The user agent MAY
use the Location field value for automatic redirection. The server's
response payload usually contains a short hypertext note with a
hyperlink to the different URI(s).
Note: For historical reasons, a user agent MAY change the request
method from POST to GET for the subsequent request. If this
behavior is undesired, the 307 (Temporary Redirect) status code
can be used instead.
What is:
307 Temporary Redirect
The 307 (Temporary Redirect) status code indicates that the target
resource resides temporarily under a different URI and the user agent
MUST NOT change the request method if it performs an automatic
redirection to that URI. Since the redirection can change over time,
the client ought to continue using the original effective request URI
for future requests.
The server SHOULD generate a Location header field in the response
containing a URI reference for the different URI. The user agent MAY
use the Location field value for automatic redirection. The server's
response payload usually contains a short hypertext note with a
hyperlink to the different URI(s).
Note: This status code is similar to 302 (Found), except that it
does not allow changing the request method from POST to GET. This
specification defines no equivalent counterpart for 301 (Moved
Permanently) ([RFC7238], however, defines the status code 308
(Permanent Redirect) for this purpose).

`akka-http` returns `No Response` for request instead of `Custom Response` specified by `withRequestTimeout` directive for https connection

I’m currently trying to setup withRequestTimeout directive for service based on akka-http.
withRequestTimeout(FiniteDuration(1, TimeUnit.SECONDS),req =>
HttpResponse(status = StatusCodes.InternalServerError, entity = "Request timeout"))
For http connection it works fine and returns my custom response, but for https it usually returns No Response and sometimes my custom response. I traced request and it looks like it was cut down before server returned actual response. What can be potential issue that causes it?

Long GET request on REST API, handling server crashes

I have a REST API where the GET request can take 10-20 seconds. So I usually return a 202 code with a location like http://fakeserver/pending/blah where the client can check the status of this request. pending/blah returns a 200 code with "Status: pending" if the request is still pending, and a 303 code when it's done, with a final location for the result: http://fakeserver/finished/blah .
But what if the server crashes during the request processing? Should pending/blah return a 303 code, and then finished/blah returns a 404? How can I alert the client that the resource may be available at a location, but I'm not sure? Assume the requests are persistent, so that when the server reboots, it continues processing the request.
First of all I'll make the state of processed resource an internal field of this resource. This way you can avoid using strange endpoints like: /finished/blah/ or /pending/blah/ and instead of it introduce a single endpoint /resources/blah/ which will among other fields return the state it's currently in.
After changing architecture to the endpoint mentioned above if you ask for blah and server has crashed you can:
return 200 with pending status - client doesn't have necessarily to know about the crash
return 404, simple not found with and extra message that server has crashed.
return 500 and inform the client explicitly what the problem is.
Other useful codes may be also 409 or 503. Returning any 3XX is not a good idea IMO since no redirection applies here. Personally I'd go for 200 or 500(3).

Play 2.3 WS withFollowRedirects(true) does not work

The following code should post a form to an endpoint (which returns 302) and, after following the redirect, parse the url of the page and return some information from there.
val start = System.currentTimeMillis()
val requestHolder = WS.url(conf("login.url"))
.withRequestTimeout(loginRequestTimeOut)
.withFollowRedirects(true) //This appears to have no effect...
requestHolder.post(getMap(username, password))
.map(resp =>{
Logger.debug(resp.status.toString)
val loginResponse = getResponse(resp)
val end = System.currentTimeMillis()
Logger.debug("Login for the user: "+username+", request took: " + (end - start) + " milliseconds.")
loginResponse
})
The problem is that .withFollowRedirects(true) appears to have no effect on the query. The status of the response is 302 and the request does not follow the redirect.
I've gone through the process manually using httpie and following the redirects does lead to the correct page.
Any help or insight would be much appreciated.
POST redirection isn't as well supported as GET redirection. W3 specification says:
If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
Some browsers don't do that, and just ignore. Have a look also at the 307 status:
307 Temporary Redirect (since HTTP/1.1)
In this case, the request should be repeated with another URI; however, future requests should still use the original URI. In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. For instance, a POST request should be repeated using another POST request.
There is also a discussion about this on Programmer Stack Exchange.
I've had a lot of trouble with withFollowRedirects and POST.
At some point, while fighting to make things work, I had .withFollowRedirects(false) in my code, then removed it during cleanups & things broke. My current guess is that if this option is not explicitly made false, the default behavior is to follow redirects (302 in my case) with some faulty mechanism. Perhaps the default mechanism uses POST again with same arguments. But in my case, interacting with Google App Script (GAS), one needs to use GET to retrieve JSON output of a POST.
Whatever the mechanism was doing, I was getting 400 with no further diagnostics.
After wasting hours, I realized that .withFollowRedirects(false) was in fact truly needed: it disabled Play's messing with redirects, I was able to see the 302 response & handle the following GET manually with success.

Single request to jetty interpreted twice with http error code 401

When I send GET http requests to an EJB served by jetty, I often get a 401 response even though the auth parameters are correct.
When I look into jetty logs I see this :
2013-06-27 11:54:11.004:DBUG:oejs.Server:REQUEST /app/general/launch on AsyncHttpConnection#3adf0ddc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-5,l=34,c=0},r=1
2013-06-27 11:54:11.021:DBUG:oejs.Server:RESPONSE /app/general/launch 401
2013-06-27 11:54:11.066:DBUG:oejs.Server:REQUEST /app/general/launch on AsyncHttpConnection#3adf0ddc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-5,l=102,c=0},r=2
I suspect that the request is not fully read (too large request entity or too large headers?)
as it is parsed twice for a single request. Is there a way to fix this ?
what does HttpParser{s=-5,l=34,c=0} and HttpParser{s=-5,l=102,c=0} mean ?
when I desactivate authentication (security constraints using simple jetty realm). the request is only parsed once.
401 means that the server requires authentication credentials that the client either has not sent or the ones sent by the client have not been authorized.
Some client implementations will resend the request if they receive a 401 including the credentials. If your client is doing that, that would explain why you get the request twice on the server.
The HttpParser toString() method returns the current status of the HttpParser. Here's the code:
return String.format("%s{s=%d,l=%d,c=%d}",
getClass().getSimpleName(),
_state,
_length,
_contentLength);
So s is the state. -5 is STATE_HEADER. And l and c represent the length and the contentLength.