7

I wrote an HTTP server in Java and a client in C++ with Poco. This is a part of the C++ client code:

URI uri("http://127.0.0.1:4444");
HTTPClientSession session(uri.getHost(), uri.getPort());

HTTPRequest req(HTTPRequest::HTTP_POST,
                "/pages/page",
                HTTPMessage::HTTP_1_1);

session.sendRequest(req);
HTTPResponse res;
std::istream &is = session.receiveResponse(res);

In the last line I get the following error:

terminate called after throwing an instance of 'Poco::Net::NoMessageException'
  what():  No message received

But I don't understand why. The connection was established successfully and the page requested exists. I tried the same code with known websites (like Wikipedia) and it works without any exception.

I also tried to make the exact same request with cURL (to my server) in command-line and it shows the response of the server, so the server seems fine.

This is the original response of the server in a string form:

"HTTP/1.1 200 OK\r\n" +
"Server: [server name]\r\n" +
"Content-Type: text/xml; charset=utf-8\r\n" +
"Content-Length:" + bodyBytes.length + "\r\n" +
"Resource: " + job.resId + "\r\n\r\n" + 
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><JobRequest><InputRepresentation id=\"0\"/>    <effectsList><cvtColor><code> CV_RGB2GRAY </code></cvtColor><resize><scaleFactorX> 0.5 </scaleFactorX><scaleFactorY> 0.5 </scaleFactorY><interpolation> INTER_LINEAR </interpolation></resize><GaussianBlur><kSize> 3 </kSize><sigmaX> 2 </sigmaX><sigmaY> 2 </sigmaY><borderType> BORDER_REPLICATE </borderType></GaussianBlur></effectsList></JobRequest>"

I have written a simple HTTP server which respond with a fixed response for every request, to test what's wrong. this is the code:

public class Test {
    public static void main(String[] args) {    
        try {
            ServerSocket serverSocket = new ServerSocket(4449);
            Socket clientSocket = serverSocket.accept();

            String body = "ab";
            byte[] bodyBytes = body.getBytes("UTF-8");

            String headers = "HTTP/1.1 200 OK\r\n" + 
                             "Server: Foo\r\n" +
                             "Content-Type: text/plain\r\n" +
                             "Content-Length: " + bodyBytes.length + "\r\n\r\n";

            byte[] headerBytes = headers.getBytes("UTF-8");

            byte[] responseBytes = new byte[headerBytes.length + bodyBytes.length];

            /* Fill responseBytes with the header and body bytes */
            int i = 0;
            for (int j = 0; j < headerBytes.length; ++j) {
                responseBytes[i] = headerBytes[j];
                ++i;
            }
            for (int j = 0; j < bodyBytes.length; ++j) {
                responseBytes[i] = bodyBytes[j];
                ++i;
            }
            clientSocket.getOutputStream().write(responseBytes);

        } catch (IOException e) {}
    }
}

I get the same exception even with this server. So what's wrong here?

marco.m
  • 4,573
  • 2
  • 26
  • 41
Ori Popowski
  • 10,432
  • 15
  • 57
  • 79
  • Most likely, the output of your server violates some protocol rule that cURL tolerates. If you can intercept the raw TCP connection and post the request and the response, that would help. If you just need a quick fix, try HTTP 1.0 instead of 1.1 (in the request) -- there are fewer things to get wrong. – David Schwartz Jan 24 '12 at 00:11
  • Tried it. Got the same exception :( – Ori Popowski Jan 24 '12 at 00:16
  • How can I intercept the raw TCP connection? – Ori Popowski Jan 24 '12 at 00:28
  • It depends on your platform. Wireshark, tcpdump, and similar tools. – David Schwartz Jan 24 '12 at 00:59
  • OK, I am intercepting the connection suing Wireshark. What kind of information can help you? I don't quite understand what's written there. – Ori Popowski Jan 24 '12 at 01:24
  • David, I added the output of the response packet using Wireshark. I'd appreciate if you take a look. – Ori Popowski Jan 24 '12 at 01:34
  • Make sure the content length header contains precisely the number of bytes in the body. (Everything after the \r\n\r\n that ends the header.) – David Schwartz Jan 24 '12 at 02:31
  • I noticed you didn't escape the quotes in the string `"`. Are you sure the data you are sending is what you expect? – David Schwartz Jan 24 '12 at 02:47
  • I didn't escape it because I copied the string from within a `String` object which held this while debugging. So the string is correct. – Ori Popowski Jan 24 '12 at 03:13
  • David, I added a code to a simple HTTP server which respond with a fixed response. Even with this server I get the same exception. Can you find any error in this server? – Ori Popowski Jan 24 '12 at 03:42
  • Other than the fact that it sends a response before it gets a query, it looks fine to me. – David Schwartz Jan 24 '12 at 03:57
  • OK, this is extremely weird. It happens only during debugging of the client. But when I run it, the exception isn't thrown. Why would that happen? – Ori Popowski Jan 24 '12 at 04:37
  • I don't exactly know how this bit works `byte[] headerBytes = headers.getBytes("UTF-8");` but just to make sure there is no BOM, try replacing it `byte[] headerBytes = headers.getBytes("ASCII");`. I think UTF-8 is not permitted in HTTP header anyway. – bronekk Jan 24 '12 at 15:32

2 Answers2

2

Based on experimentation, I've found that it's necessary to include a Content-Length header if you are making an empty POST request. I.e.,

req.add("Content-Length", "0");
rcbilson
  • 183
  • 1
  • 7
0

I had to use the following sequence in my handler code for a minimal response to be received without a No message received error:

resp.setStatus( Poco::Net::HTTPResponse::HTTP_OK );
resp.setContentType( "text/json" );
ostream &out = resp.send();
out << "[]";
out.flush();
M Katz
  • 5,098
  • 3
  • 44
  • 66