Code Review Asked by Campos Ilya on December 17, 2021
I’m writing a web server from scratch on pure Java in learning purpose. As a part of request handling, I worked on a class to parse HTTP request, I expect from it to be able to do next things:
The result is:
class HttpRequestParser {
private BufferedReader in;
private int serverPort;
private HttpMethods method;
private InetAddress clientAddr;
private InetAddress serverAddr;
private URL url;
private HashMap<String, String> collectedHeaders;
private long parsingStartTime;
HttpRequestParser(Socket clientSock) throws IOException {
this.in = new BufferedReader(new InputStreamReader(clientSock.getInputStream()));
this.clientAddr = clientSock.getLocalAddress();
this.serverAddr = clientSock.getInetAddress();
this.serverPort = clientSock.getLocalPort();
this.collectedHeaders = new HashMap<>();
}
HttpOneZeroRequest parseAll() throws IOException {
return this.parseAll(this.in);
}
private HttpOneZeroRequest parseAll(BufferedReader inputStream) throws IOException {
this.parsingStartTime = System.currentTimeMillis();
this.waitUntilClientInputReady();
String line = inputStream.readLine();
this.parseTopHeader(line);
this.waitUntilClientInputReady();
while (!(line = inputStream.readLine().trim()).equals("")) {
this.parseCommonHeader(line);
this.waitUntilClientInputReady();
}
byte[] body = {};
if (this.method == HttpMethods.POST || this.method == HttpMethods.PUT || this.method == HttpMethods.PATCH) {
body = this.readBody();
}
return this.prepareRequest(body);
}
private void parseTopHeader(String line) throws HttpException {
String[] parts = line.split("\s+", 3);
if (parts.length != 3
|| !parts[1].startsWith("/")
|| !parts[2].toUpperCase().startsWith("HTTP/")) {
throw new BadRequest();
}
try {
this.url = new URL("http://" + this.getServerNetloc() + parts[1]);
} catch (MalformedURLException e) {
throw new BadRequest();
}
this.method = HttpMethods.cleanMethod(parts[0]);
}
private void parseCommonHeader(String line) throws HttpException {
String[] pair = line.split(":", 2);
if (pair.length != 2) {
throw new BadRequest();
}
String name = pair[0].replaceAll(" ", "");
String value = pair[1].trim();
this.collectedHeaders.put(name, value);
}
private byte[] readBody() throws HttpException, IOException {
ByteArrayOutputStream bodyStream = new ByteArrayOutputStream();
int contentLength = 0; // for now content without Content-Length header are ignored
if (this.collectedHeaders.containsKey("Content-Length")) {
String valueStr = this.collectedHeaders.get("Content-Length");
try {
contentLength = Integer.valueOf(valueStr);
} catch (NumberFormatException e) {
throw new BadRequest();
}
}
int nextByte;
while (bodyStream.size() < contentLength) {
this.waitUntilClientInputReady();
nextByte = this.in.read();
bodyStream.write(nextByte);
}
return bodyStream.toByteArray();
}
private String getServerNetloc() {
String hostname = this.serverAddr.getHostName();
return hostname + ((this.serverPort != 80) ? (":" + this.serverPort) : "");
}
private HttpOneZeroRequest prepareRequest(byte[] body) {
return new HttpOneZeroRequest(
this.method, this.url, this.collectedHeaders, body,
this.clientAddr, this.serverAddr, this.serverPort);
}
private void waitUntilClientInputReady() throws IOException {
long timeout = (long)(120 * 1000);
while (!this.in.ready()) {
if (System.currentTimeMillis() - this.parsingStartTime > timeout) {
throw new RequestTimeout();
}
}
}
}
Can you, please, kindly review my implementation, and give some advises about code formatting and optimization? I have poor (close to zero) experience at Java programming and I’m not sure if I choose proper approach to implement certain parts, especially handling client timeout and extract urls…
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP