Search code examples
javainputstreamhttpserversimplehttpserverget-request

Unable to retrieve input stream data from httpExchange


I have wrote a code for an http server that suppose to send a respond to the client based on client input.

I have wrote the same code twice, once using simple socket connection and the second one using com.sun.net.httpserver.

The code based on the simple socket works fine and I am able to read the requests coming from the client using:

DataInputStream in = new DataInputStream (threadSocket.getInputStream());
int ln = in.available();
byte [] bytes  = new byte [ln];
in.read(bytes);
String msg = new String(bytes);

However, when I am trying to use the httpserver I can not get any input from the client.

This is the code for the http server hendler:

static class ntripHandler implements HttpHandler {
    public void handle(HttpExchange t){ 
        try {
            int ln = t.getRequestBody().available();
            byte [] bt  = new byte [ln];
            t.getRequestBody().read(bt);
            String msg = new String(bt);
            System.out.println(msg);
        } 
        catch (IOException ex) {System.out.println(ex);}

        //// some operations sholuld be made here .......

    }
}

Currently, I am trying to use the input stream from the HttpExchange.getRequestBody() but it is always null. I have also tried the httpExchange.getRequestURI().getQuery() but it is always null as well.

The input from the client looks like this: GET / HTTP/1.0 User-Agent: NTRIP GnssSurferV1.10 Authorization: Basic

What am I doing wrong and how can I fix it? Any help would be appreciated.


Solution

  • You should close the HttpExchange.

    Also note that the way you use available() is tricky. It returns

    an estimate of the number of bytes that can be read ...

    and:

    Note that while some implementations of {@code InputStream} will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.

    Complete example (not exectly you use case, but it answers your question):

    /**
     * To test: 
     * 
     * ```` bash
     * $ curl -v -H "Content-Type: application/json" \
     *   -d '{"name":"Testing!"}' http://localhost:8000
     * ````
     */
    public static void main(String[] args) throws IOException {
        // Creates a basic HTTP server, with default Executor and system default socket
        // backlog (second parameter in create method, 0)
        final HttpServer server = HttpServer.create(
            new InetSocketAddress("localhost", 8000), 0);
        // context MUST start with "/". Root context is just "/"
        // HttpHandler implemented as lambda, note that HttpHandler#handle() throws an
        // IOException, so no need to catch it
        server.createContext("/", (he) -> {
            try {
                System.out.println(he.getRequestURI());
                final InputStream in = he.getRequestBody();
                final OutputStream out = he.getResponseBody();
    
                // first send header, than response body, if any
                // use default buffer size suited for your use case
                final byte[] buffer = new byte[in.available() == 0 ? 1024 : in.available()];
                System.out.println("buffer size=" + buffer.length);     
    
                // preferrable, specify *exact* size of response body. If not known, use 0
                // < HTTP/1.1 200 OK
                // < Date: Thu, 21 Jul 2016 08:14:25 GMT
                // < Transfer-encoding: chunked
    //            he.sendResponseHeaders(200, 0);
    //            int length;
    //            while ((length = in.read(buffer, 0, buffer.length)) >= 0) {
    //                out.write(buffer, 0, length);
    //            }
    
                // better way of doing it: buffer response body and set content length
                // < HTTP/1.1 200 OK
                // < Date: Thu, 21 Jul 2016 08:11:40 GMT
                // < Content-length: 19
                final ByteArrayOutputStream baos = new ByteArrayOutputStream(buffer.length);
                int length;
                while ((length = in.read(buffer, 0, buffer.length)) >= 0) {
                    baos.write(buffer, 0, length);
                }
                he.sendResponseHeaders(200, baos.size());
                baos.writeTo(out); // no need to close() of flush() ByteArrayOutputStream
    
            } finally {
                // Essential: HttpExchange must be closed
                he.close();
            }
        });
        server.start();
    }