Month: December 2014

Creating HTTP Server with Java

Introduction

After a busy period I got a chance to look something different from usual work. This time its about HTTP server implementation using Java. Most of Java programmers have implemented TCP socket servers when stepping in to Java world. Thereafter developers compare Java with other languages, and think that implementing a server with Java is pretty hard. This is because they are not aware about Java HttpServer [1]. Also you may wonder that there are use-cases which you can easily accomplish with HttpServer while need more effort on alternative methods. So in this post, I’m going to introduce a very simple use-case of it.

Usecase

The example following explains implementing a HTTP server which accepts POST request containing data and send the same payload back to the client (a basic version of a echo server).
A sample request :
————————————–
POST /test HTTP/1.1
Host: localhost:8080
Cache-Control: no-cache

TEST DATA HERE
————————————–

Implementation

Implementation of the usecase contains only 3 high-level steps.

  1. Create a HttpServer object with suitable port number
  2. Add Context suites for your needs (will describe soon)
  3. Start the server

Adding a Context

A context describes the pattern in request url for a matching Handler. A Handler is responsible for further processing of the request. For that a Handler should implement a HttpHandler with overriding ‘handle(HttpExchange he)’ method. Within this handle method, you can extract request and build the response.
Working with HttpExchange in handle method should follow the following sequence [2]:

  1. getRequestMethod() to determine the command
  2. getRequestHeaders() to examine the request headers (if needed)
  3. getRequestBody() returns a InputStream for reading the request body. After reading the request body, the stream is close.
  4. getResponseHeaders() to set any response headers, except content-length
  5. sendResponseHeaders(int,long) to send the response headers. Must be called before next step.
  6. getResponseBody() to get a OutputStream to send the response body. When the response body has been written, the stream must be closed to terminate the exchange.

 

In addition to that HttpExchange [2] contains several additional methods to extract more information from the request and change the response.

Sample

Now let’s move on to the implementation of the above mentioned use-case.


import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author BUDDHIMA
 */
public class ServerTest {

    public static void main(String[] args) {
        try {

            // Bind to port 8080
            HttpServer httpServer = HttpServer.create(new InetSocketAddress(8080), 0);

            // Adding '/test' context
            httpServer.createContext("/test", new TestHandler());

            // Start the server
            httpServer.start();

        } catch (IOException ex) {
            Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    // Handler for '/test' context
    static class TestHandler implements HttpHandler {

        @Override
        public void handle(HttpExchange he) throws IOException {
            System.out.println("Serving the request");

            // Serve for POST requests only
            if (he.getRequestMethod().equalsIgnoreCase("POST")) {

                try {

                    // REQUEST Headers
                    Headers requestHeaders = he.getRequestHeaders();
                    Set<Map.Entry<String, List<String>>> entries = requestHeaders.entrySet();

                    int contentLength = Integer.parseInt(requestHeaders.getFirst("Content-length"));

                    // REQUEST Body
                    InputStream is = he.getRequestBody();

                    byte[] data = new byte[contentLength];
                    int length = is.read(data);

                    // RESPONSE Headers
                    Headers responseHeaders = he.getResponseHeaders();

                    // Send RESPONSE Headers
                    he.sendResponseHeaders(HttpURLConnection.HTTP_OK, contentLength);

                    // RESPONSE Body
                    OutputStream os = he.getResponseBody();

                    os.write(data);

                    he.close();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

Conclusion

Through this post I wanted to give a very brief introduction to Java HttpServer, which is not popular among many developers. I believe this will help you to build embedded HTTP servers and quickly create a backend servers according for your needs.

References

[1] Documentation on HttpServer class : http://docs.oracle.com/javase/7/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpServer.html
[2] Documentation on HttpExchange class : http://docs.oracle.com/javase/7/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpExchange.html
[3] Sample with extracting parameters from a request : http://www.rgagnon.com/javadetails/java-get-url-parameters-using-jdk-http-server.html
[4] Sample of a file download : http://www.rgagnon.com/javadetails/java-have-a-simple-http-server.html

Advertisements