thotheolh
thotheolh

Reputation: 7450

Java HTTP Server response incomplete

I am trying to build my own embedded HTTP Server for Java with very specific usage for an internal closed system. Using embedded solution that already exists meant that I need to strip them down to refit them for my internal system's specific use cases.

I have managed to get my Java HTTPD receive HTTP Requests from web browsers but the Requests that the HTTPD receives are incomplete.

Below is the server thread codes (pretending the ServerSocket works perfectly fine):

public class HttpThread implements Runnable {

    private Socket socket;
    private DataInputStream in;
    private PrintStream out;
    private BufferedReader br;
    private String EOF = "\n";
    private String STATUS_200 = "HTTP/1.1 200 OK" + EOF;

    public HttpThread(Socket socket) throws IOException {
        this.socket = socket;
        this.in = new DataInputStream(this.socket.getInputStream());
        this.out = new PrintStream(new BufferedOutputStream(this.socket.getOutputStream()));
    }

    @Override
    public void run() {
        System.out.println("New thread...");
        try {
            processInput();
            //socket.close();
        } catch (IOException ex) {
            Logger.getLogger(HttpThread.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //System.out.println("Thread END...");
    }

    private String processInput() throws IOException {
        String line;
        StringBuilder buff = new StringBuilder();
        br = new BufferedReader(new InputStreamReader(in));
        while ((line = br.readLine()) != null) {
            buff.append(line);
            System.out.println(">>> " + line);
            if (line.trim().isEmpty()) {
                break;
            }
        }
        out.print(STATUS_200);
        out.print("Server: Test Server\n" +
            "Content-Type: text/html; charset=UTF-8\n" +
            "Connection: close");
        out.print(EOF);
        out.print("<html><body>yello</body></html>"); 
        out.print(EOF);
        out.flush();
        System.out.println(STATUS_200);
        return buff.toString();
    }

}

I am using this HTML Script to test the server thread to simulate a POST request:

<html>
<body onLoad="document.test.submit();">
<form action="http://localhost:9999/" method="POST" name="test">
    <input type=hidden name="userid" value="1443"/>
    <input type=hidden name="password" value="1443"/>
</form>
</body>
</html>

When I use the browser to call the HTML codes the Java HTTPD receives an incomplete response:

New thread...
>>> POST / HTTP/1.1
>>> Host: localhost:9999
>>> Connection: keep-alive
>>> Content-Length: 25
>>> Cache-Control: max-age=0
>>> Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
>>> Origin: null
>>> User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36
>>> Content-Type: application/x-www-form-urlencoded
>>> Accept-Encoding: gzip,deflate,sdch
>>> Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
>>> 
HTTP/1.1 200 OK

New thread...
>>> GET /favicon.ico HTTP/1.1
>>> Host: localhost:9999
>>> Connection: keep-alive
>>> Accept: */*
>>> User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36
>>> Accept-Encoding: gzip,deflate,sdch
>>> Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
>>> 
HTTP/1.1 200 OK

It seems that the HTTPD only received the HTTP headers and stopped receiving the POST body. May I know of some solutions to solve the above problem ?

Thanks.

Upvotes: 0

Views: 2787

Answers (2)

thotheolh
thotheolh

Reputation: 7450

I switched out the while loop that does the readline() with the following code:

int i;
byte[] buffer = new byte[2048];
i = in.read(buffer);
for (int j = 0; j < i; j++) {
    buff.append((char) buffer[j]);
}
System.out.println(buff.toString());

and the problem is solved.

Pyranja, thanks for the help.

Thanks to http://kcd.sytes.net/articles/simple_web_server.php IF you follow concisely. Somehow the br.readline() is not fully reading the lines properly after the empty line.

The code fragment should now look like:

private String processInput() throws IOException {
        String line;
        StringBuilder buff = new StringBuilder();
        int i;
        byte[] buffer = new byte[2048];
        i = in.read(buffer);
        for (int j = 0; j < i; j++) {
            buff.append((char) buffer[j]);
        }
        System.out.println(buff.toString());
        out.print(STATUS_200);
        out.print("Server: Test Server\n" +
            "Content-Type: text/html; charset=UTF-8\n" +
            "Connection: close");
        out.print(EOF);
        out.print("<html><body>yello</body></html>"); 
        out.print(EOF);
        out.flush();
        System.out.println(STATUS_200);
        return buff.toString();
}

I guess it's a good experience learning how to build a simple HTTP Server :D .

Upvotes: 0

Pyranja
Pyranja

Reputation: 3589

The HTTP headers and body are separated by an empty line (also see the HTTP RFC, especially the chapter "5 Request"). Your server reads the socket Inputstream but breaks on an empty line :

if (line.trim().isEmpty()) {
   break;
}

Therefore obviously you will not receive the body. You should fully consume the Inputstream instead.

Besides that, I would advise you to use already existing solutions. There is an abundance of HTTP server implementations, that are well tested and proven in real world usage. Save yourself alot of headache and use an existing lightweight server like e.g. Jetty, Netty or similar ones.

Upvotes: 3

Related Questions