ConnectionHandler.java
package sprout.server;
import sprout.mvc.dispatcher.RequestDispatcher;
import sprout.mvc.http.HttpRequest;
import sprout.mvc.http.HttpResponse;
import sprout.mvc.http.ResponseEntity;
import sprout.mvc.http.parser.HttpRequestParser;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public class ConnectionHandler implements Runnable {
private final Socket socket;
private final RequestDispatcher dispatcher;
private final HttpRequestParser parser;
public ConnectionHandler(Socket socket, RequestDispatcher dispatcher, HttpRequestParser parser) {
this.socket = socket;
this.dispatcher = dispatcher;
this.parser = parser;
}
@Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
String raw = readRawRequest(in);
if (raw.isBlank()) return;
HttpRequest<?> req = parser.parse(raw);
HttpResponse res = new HttpResponse();
dispatcher.dispatch(req, res);
writeResponse(out, res.getResponseEntity());
} catch (Exception e) {
e.printStackTrace();
}
}
private String readRawRequest(BufferedReader in) throws IOException {
StringBuilder sb = new StringBuilder();
String line;
int contentLength = 0;
while ((line = in.readLine()) != null && !line.isEmpty()) {
sb.append(line).append("\r\n");
if (line.toLowerCase().startsWith("content-length:")) {
contentLength = Integer.parseInt(line.substring(line.indexOf(':') + 1).trim());
}
}
sb.append("\r\n");
if (contentLength > 0) {
char[] body = new char[contentLength];
in.read(body, 0, contentLength);
sb.append(body);
}
return sb.toString();
}
private void writeResponse(BufferedWriter out, ResponseEntity<?> res) throws IOException {
if (res == null) return;
String body = res.getBody() != null ? res.getBody().toString() : "";
out.write("HTTP/1.1 " + res.getStatusCode().getCode() + " " + res.getStatusCode().getMessage() + "\r\n");
// Content-Type
out.write("Content-Type: " + res.getContentType() + "\r\n");
// Content-Length
out.write("Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n");
// Custom headers
for (Map.Entry<String, String> header : res.getHeaders().entrySet()) {
out.write(header.getKey() + ": " + header.getValue() + "\r\n");
}
out.write("\r\n");
out.write(body);
out.flush();
}
}