All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.iprogrammerr.bright.server.protocol.HttpOneProtocol Maven / Gradle / Ivy

package com.iprogrammerr.bright.server.protocol;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import com.iprogrammerr.bright.server.binary.Binary;
import com.iprogrammerr.bright.server.binary.OnePacketBinary;
import com.iprogrammerr.bright.server.binary.PacketsBinary;
import com.iprogrammerr.bright.server.header.Header;
import com.iprogrammerr.bright.server.header.HttpHeader;
import com.iprogrammerr.bright.server.request.ParsedRequest;
import com.iprogrammerr.bright.server.request.Request;
import com.iprogrammerr.bright.server.response.Response;

public class HttpOneProtocol implements RequestResponseProtocol {

    private static final String CONNECTION_HEADER = "Connection";
    private static final String CONNECTION_CLOSE = "close";
    private static final String NEW_LINE_SEPARATOR = "\n";
    private static final String HEADER_KEY_VALUE_SEPARATOR = ": ";
    private static final String HEADERS_BODY_PARSED_SEPARATOR = "\r";
    private static final int MIN_VALID_FIRST_LINE_LENGTH = 10;
    private static final int MIN_REQUEST_METHOD_LENGTH = 3;
    private static final String CRLF_CRLF = "\r\n\r\n";
    private static final String URL_SEGMENTS_SEPARATOR = "/";
    private static final String HTTP = "HTTP";
    private static final String RESPONSE_CODE_HTTP_1_1_PREFIX = "HTTP/1.1 ";
    private static final String CONTENT_LENGTH_HEADER = "Content-Length";

    @Override
    public Request read(InputStream inputStream) throws Exception {
	Binary binary = new OnePacketBinary(inputStream);
	String[] requestLines = new String(binary.content()).split(NEW_LINE_SEPARATOR);
	if (requestLines.length < 1 || requestLines[0].length() < MIN_VALID_FIRST_LINE_LENGTH) {
	    throw new Exception("Request is empty");
	}
	String method = readMethod(requestLines[0]);
	String path = readPath(requestLines[0]);
	List
headers = readHeaders(requestLines); int bodyBytes = bodyBytes(headers); if (bodyBytes == 0) { return new ParsedRequest(method, path, headers); } byte[] partOfTheBody = requestLines[requestLines.length - 1].getBytes(); if (partOfTheBody.length == bodyBytes) { return new ParsedRequest(method, path, headers, partOfTheBody); } byte[] body = new PacketsBinary(binary, partOfTheBody, bodyBytes).content(); return new ParsedRequest(method, path, headers, body); } private List
readHeaders(String[] requestLines) throws Exception { List
headers = new ArrayList<>(); for (int i = 1; i < requestLines.length; i++) { String line = requestLines[i]; if (line.equals(HEADERS_BODY_PARSED_SEPARATOR)) { break; } headers.add(readHeader(line)); } return headers; } private int bodyBytes(List
headers) { try { int bodyBytes = 0; for (Header header : headers) { if (header.is(CONTENT_LENGTH_HEADER)) { bodyBytes = Integer.parseInt(header.value()); break; } } return bodyBytes > 0 ? bodyBytes : 0; } catch (NumberFormatException exception) { return 0; } } private String readMethod(String firstLine) throws Exception { int indexOfSeparator = firstLine.indexOf("/"); if (indexOfSeparator <= MIN_REQUEST_METHOD_LENGTH) { throw new Exception("First request line is invalid"); } return firstLine.substring(0, indexOfSeparator - 1); } private String readPath(String firstLine) throws Exception { int indexOfSeparator = firstLine.indexOf(URL_SEGMENTS_SEPARATOR); if (indexOfSeparator <= MIN_REQUEST_METHOD_LENGTH) { throw new Exception("First request line is invalid"); } int indexOfHttp = firstLine.indexOf(HTTP); if (indexOfHttp <= MIN_REQUEST_METHOD_LENGTH) { throw new Exception("First request line is invalid"); } return firstLine.substring(indexOfSeparator + 1, indexOfHttp).trim(); } private Header readHeader(String headerToParse) throws Exception { String[] keyValue = headerToParse.split(HEADER_KEY_VALUE_SEPARATOR); if (keyValue.length < 2) { throw new Exception(keyValue[0] + " is not a proper header"); } return new HttpHeader(keyValue[0].trim(), keyValue[1].trim()); } @Override public void write(OutputStream outputStream, Response response) throws Exception { StringBuilder builder = new StringBuilder(); builder.append(responseCodeToString(response.code())); for (Header header : response.headers()) { builder.append(NEW_LINE_SEPARATOR).append(header.writable()); } outputStream.write(builder.toString().getBytes()); if (response.hasBody()) { outputStream.write(CRLF_CRLF.getBytes()); outputStream.write(response.body()); } } private String responseCodeToString(int responseCode) { return RESPONSE_CODE_HTTP_1_1_PREFIX + responseCode; } @Override public boolean closeConnection(Request request) { boolean close; try { close = !request.hasHeader(CONNECTION_HEADER) || request.header(CONNECTION_HEADER).equalsIgnoreCase(CONNECTION_CLOSE); } catch (Exception exception) { close = true; } return close; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy