4

I am having a weird problem with a small restlet service that I am building as an exercise. The application is supposed to respond with some XML (specifically TwiML, as it is meant for Twilio) on an HTTP POST, and it worked well for standalone requests. However, when requested by Twilio, the response never completes and it times out. After comparing the traffic coming from Twilio with the one that is working (using a fake HTML form), I isolated the issue to the "Connection: close" header and can reproduce it using nothing but curl command-line. Here is the request that works:

curl -i -H 'Connection: keep-alive' -X POST -d "name=value" http://localhost:8020/hello

and here is the one that just hangs:

curl -i -H 'Connection: close' -X POST -d "name=value" http://localhost:8020/hello

If I kill the server then curl says "(52) Empty reply from server". Here is the code that I am using in the ServerResource:

@Post
public Representation hello(Representation repr)
{
    Representation result = new StringRepresentation(("<Response>\n"+
            "   <Say>Hello. This is a test.</Say>\n"+
            "</Response>"), MediaType.APPLICATION_XML);
    return result;
}

Is something obviously wrong with what I am doing here? I am using restlet-2.0, but also tried with 2.1m1 with the same result. I would really appreciate a quick response as I am on a deadline to finish the exercise.

Victor2748
  • 4,149
  • 13
  • 52
  • 89
haridsv
  • 9,065
  • 4
  • 62
  • 65

2 Answers2

4

not sure if you found a solution for your error, but I came across the same problem in Restlet V 2.0.4.

When running the restlet using the default server. Here the server does assume that the response stream is not writable and thus will not respond with an entity.

As a quick fix I located

  org.restlet.engine.http.connector.Connection

and changed the the canWrite() method to

public boolean canWrite() { 
    return (
             (getState() == ConnectionState.OPEN) 
                     || (getState() == ConnectionState.CLOSING)) 
            && !isOutboundBusy() 
            && (getOutboundMessages().size() > 0); 
} 

from the original

public boolean canWrite() { 
    return (getState() == ConnectionState.OPEN) && !isOutboundBusy() 
            && (getOutboundMessages().size() > 0); 
}

Not sure if that is a good fix, but after recompiling the restlet module it now seems to work fine. It seems to be the issue that when specifying the HTTP Header 'Connection: close' the stream is by default in closing state.

Hope that helps

Joey

See here for the problem on the restlet forum

http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2698048

Joey
  • 1,349
  • 14
  • 26
  • Thanks for sharing. Does this mean, restlet never worked well with a connection that has "Connection: close" header (which would be a significant bug)? – haridsv Jan 14 '11 at 04:13
  • Well it seems to be an artefact of the standard restlet server that comes bundled with restlet. I would assume that if you deploy your restlet within a different container (Jetty for example) it would not hit this issue. But agreed, it's definitively a bug. – Joey Jan 14 '11 at 13:13
  • Three years after it has been opened the bug is still there ... Thanks for the diagnostic and the workaround. – Cyrille Ka Nov 27 '13 at 17:38
  • Seems to be fixed in the latest version - I had an older version of this library with this bug, upgrading to the latest .jar fixed it. – Peteris Jan 26 '14 at 18:06
0

Not sure this is it, but here's something to consider:

Restlet very carefully and accurately implements the REST architectural style. One of the key REST principles it implements is the uniform interface. In an HTTP-based web service, the uniform interface leverages the HTTP GET, PUT, POST, DELETE (and other) operations the way they were originally intended to. So to create a resource on the server when you assign its resource name, you use PUT. To update that resource, you again use PUT. To read it, you use GET. To delete it, use DELETE. POST is reserved for creating a resource when the server assigns the resource name.

So this may somehow be due to a mismatch in expectations. A POST generally has a representation you're sending to the server, but this POST does not. Are you reading in the full request and closing the connection properly on the server-side?

Jim Ferrans
  • 30,582
  • 12
  • 56
  • 83
  • Other than creating an Application and a Component, I don't particularly do anything specific to connections, and I expected restlet to take care of it. Regarding the representation, I am not very clear how it works, and I had trouble finding straight-forward documentation (I admit, I am in a hurry right now), but since I am not sending any representation, do I have to do anything special? I will check if not reading form parameters is somehow causing restlet to go in a wait state. I checked the stack dump, none of the stacks point to even restlet code. – haridsv Dec 20 '10 at 18:33