Here are the steps, that can be followed to write a web server.
- Create a server socket at a given IPAddress And Port
- Wait for incoming socket request
- read all incoming input data from browser/http-client
- create output data as per request and write it back to the browser/http-client
The implementation is quite simple.
Our server is able to server text file, if the file path is valid.
If the uriPath is a directory then, we look for index.html file in that directoy, and serve the index.html file.
It can be improved for error handling and to serve the images and other file types. But, to keep things simple, server only serves text content.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.channels.*;
import java.net.*;
import java.util.Arrays;
public class HttpServer {
private static final String CRLF = "\r\n";
public static void main(final String... args) throws UnknownHostException, IOException{
System.out.println("Starting Server");
final SocketAddress localAddress = new InetSocketAddress(InetAddress.getLocalHost(), 5432);
System.out.println("Listening at " + localAddress);
final ByteBuffer requestDataBuffer = ByteBuffer.allocate(512);
try(
final ServerSocketChannel serverSocket = ServerSocketChannel.open();
) {
serverSocket.bind(localAddress);
while(true){
try(
final SocketChannel requestChannel = serverSocket.accept();
){
requestDataBuffer.clear();
requestChannel.read(requestDataBuffer);
// prepare for reading
requestDataBuffer.flip();
// Read Method type
final int methodStartIndex = requestDataBuffer.position();
while(requestDataBuffer.get() != 32);
final int methodEndIndex = requestDataBuffer.position() - 1;
final String methodName = new String(requestDataBuffer.array(), methodStartIndex, methodEndIndex - methodStartIndex);
System.out.printf("Method Name : %s.%n", methodName);
// Read Path
final int pathStartIndex = requestDataBuffer.position();
while(requestDataBuffer.get() != 32);
final int pathEndIndex = requestDataBuffer.position() - 1;
final int uriLength = (pathEndIndex - pathStartIndex);
final String uriPath = new String(requestDataBuffer.array(), pathStartIndex, uriLength);
System.out.printf("URI Path : %s.%n", uriPath);
final StringWriter responseWriter = new StringWriter();
// read the content of the file
Path resourcePath = uriLength == 1 ? Path.of("home.html") : Path.of(uriPath.substring(1));
final File resourceFile = new File(resourcePath.toUri());
if(!resourceFile.exists()) {
// handle 404
responseWriter.write("HTTP/1.1 404 Not Found"); responseWriter.write(CRLF);
responseWriter.write("Content-Length: 0"); responseWriter.write(CRLF);
requestChannel.write(ByteBuffer.wrap(responseWriter.toString().getBytes()));
continue;
}
// if the uri path is a directory - then append index.html - by default we will serve
// index.html from a directory
if(resourceFile.isDirectory()) resourcePath = Path.of(uriPath.substring(1) + "/index.html");
final byte[] content = Files.readAllBytes(resourcePath);
final int contentLength = content.length;
// write headers
responseWriter.write("HTTP/1.1 200 OK"); responseWriter.write(CRLF);
responseWriter.write("Content-Type: text/html; charset=utf-8"); responseWriter.write(CRLF);
responseWriter.write("Content-Length: " + contentLength); responseWriter.write(CRLF);
// we need to add this crlf to separate entity headers from entity body
responseWriter.write(CRLF);
responseWriter.write(CRLF);
responseWriter.write(new String(content));
final String headers = responseWriter.toString();
System.out.println("Start Headers ----");
System.out.println(headers);
System.out.println("End Headers ----");
// headers written to the browser
requestChannel.write(ByteBuffer.wrap(headers.getBytes()));
}
}
}
}
}