fujaba/NetworkParser

View on GitHub
src/main/java/de/uniks/networkparser/ext/http/HTTPRequest.java

Summary

Maintainability
F
5 days
Test Coverage
package de.uniks.networkparser.ext.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.net.Socket;

import de.uniks.networkparser.buffer.CharacterBuffer;
import de.uniks.networkparser.interfaces.BaseItem;
import de.uniks.networkparser.interfaces.Condition;
import de.uniks.networkparser.list.SimpleKeyValueList;
import de.uniks.networkparser.list.SimpleList;
import de.uniks.networkparser.xml.HTMLEntity;

public class HTTPRequest implements Comparable<HTTPRequest> {
    public static final String HTTP__NOTFOUND = "HTTP 404";
    public static final String HTTP_OK = "HTTP/1.1 200 OK";
    public static final String HTTP_PERMISSION_DENIED = "HTTP 403";
    public static final String HTTP_CONTENT = "Content-Type:";
    public static final String HTTP_AUTHENTIFICATION = "Authentification";
    public static final String HTTP_REFRESH = "REFRESH";
    public static final String HTTP_CONTENT_HTML = "text/html";
    public static final String HTTP_CHARSET = "charset=UTF-8";
    public static final String HTTP_CONTENT_FORM = "application/x-www-form-urlencoded";
    public static final String HTTP_LENGTH = "Content-Length:";
    public static final String BEARER = "Bearer";
    public static final Character STATIC = 'S';
    public static final Character VARIABLE = 'V';

    private BufferedReader inputStream;
    private PrintWriter outputStream;
    private Condition<Exception> errorListener;
    private Condition<HTTPRequest> updateCondition;
    private Socket socket;
    private String path;
    private SimpleList<String> headers = new SimpleList<String>();
    private String content;

    private String http_Type; /* GET OR POST */
    private String contentType;

    private boolean writeHeader;
    private boolean writeBody;
    private SimpleList<String> partParameter;
    private SimpleList<String> partPath;
    private SimpleList<String> fullPath;
    private SimpleList<Character> pathType;
    private CharacterBuffer bufferResponse;

    private SimpleKeyValueList<String, String> matchVariables = new SimpleKeyValueList<String, String>();
    private boolean matchValid = true;
    private int matchOfRequestPath;

    public void executeExeption(Exception e) {
        if (errorListener != null) {
            errorListener.update(e);
        } else {
            e.printStackTrace();
        }
    }

    HTTPRequest() {
    }

    private HTTPRequest(Socket socket) {
        this.socket = socket;
    }

    public BufferedReader getInput() {
        if (socket != null && this.inputStream == null) {
            try {
                this.inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            } catch (IOException e) {
                executeExeption(e);
            }
        }
        return inputStream;
    }

    public String readType() {
        this.http_Type = readTo(' ');
        return http_Type;
    }

    public String readTo(char splitStr) {
        int c;
        CharacterBuffer buffer = new CharacterBuffer();
        try {
            BufferedReader input = getInput();
            if (input != null) {
                while ((c = getInput().read()) != -1) {
                    if (c == ' ') {
                        break;
                    }
                    buffer.with((char) c);
                }
            }
        } catch (IOException e) {
            executeExeption(e);
        }
        return buffer.toString();
    }

    public PrintWriter getOutput() {
        if (this.socket != null && this.outputStream == null) {
            try {
                this.outputStream = new PrintWriter(socket.getOutputStream(), true);
            } catch (IOException e) {
                executeExeption(e);
            }
        }
        return outputStream;
    }

    public boolean close() {
        if (this.writeBody == false && this.bufferResponse != null) {
            writeBody(this.bufferResponse.toString());
        }
        if (outputStream != null) {
            outputStream.close();
        }
        if (this.socket != null) {
            try {
                this.socket.close();
            } catch (IOException e) {
                executeExeption(e);
                return false;
            }
        }
        return true;
    }

    public static HTTPRequest create(Socket socket) {
        return new HTTPRequest(socket);
    }

    public static HTTPRequest createRouting(String value) {
        HTTPRequest httpRequest = new HTTPRequest();
        if (value != null) {
            StringReader stringReader = new StringReader(value);
            httpRequest.parsingPath(stringReader, "*");
        }
        return httpRequest;
    }

    public void readPath() {
        BufferedReader input = getInput();
        parsingPath(input, null);
    }

    /**
     * Parsing Path
     *
     * bub/bla * bub/:id blub?id=1&name=bla
     * 
     * @param input        Reader
     * @param defaultValue default Fallback
     * @return success
     */
    private boolean parsingPath(Reader input, String defaultValue) {
        this.partPath = new SimpleList<String>();
        this.partParameter = new SimpleList<String>();
        this.pathType = new SimpleList<Character>();
        this.fullPath = new SimpleList<String>();
        if (defaultValue == null) {
            defaultValue = "";
        }
        if (input == null) {
            this.path = defaultValue;
            return false;
        }
        CharacterBuffer buffer = new CharacterBuffer();
        int c;
        CharacterBuffer part = new CharacterBuffer();
        boolean isVariable = false;
        try {
            boolean isFirst = true;
            while ((c = input.read()) != -1) {
                if (c == ' ') {
                    break;
                }
                buffer.with((char) c);
                /* Check for Paramter */
                if (c == ':' && part.length() == 0) {
                    isVariable = true;
                }
                if (c == '?' && isVariable == false) {
                    isVariable = true;
                }
                if (c == '&' && isVariable) {
                    part.withStartPosition(1);
                    String value = part.toString();
                    this.fullPath.add(value);
                    this.partParameter.add(value);
                    this.pathType.add(VARIABLE);
                    part.clear();
                    continue;
                }
                if (c == '/' && isFirst == false) {
                    /* Split for / */
                    if (isVariable) {
                        if (part.startsWith(":")) {
                            part.withStartPosition(1);
                            String value = part.toString();
                            this.fullPath.add(value);
                            this.partParameter.add(part.toString());
                            this.pathType.add(VARIABLE);
                            part.clear();
                            continue;
                        }
                    } else {
                        String value = part.toString();
                        this.fullPath.add(value);
                        if ("*".equals(value)) {
                            this.partParameter.add(value);
                            this.pathType.add(VARIABLE);
                        } else {
                            this.partPath.add(value);
                            this.pathType.add(STATIC);
                        }
                    }
                    part.clear();
                    continue;
                }
                part.with((char) c);
                isFirst = false;
            }
            if (part.length() > 0) {
                if (isVariable) {
                    part.withStartPosition(1);
                    String value = part.toString();
                    this.fullPath.add(value);
                    this.partParameter.add(value);
                    this.pathType.add(VARIABLE);
                } else {
                    String value = part.toString();
                    this.fullPath.add(value);
                    if ("*".equals(value)) {
                        this.partParameter.add(part.toString());
                        this.pathType.add(VARIABLE);
                    } else {
                        this.partPath.add(value);
                        this.pathType.add(STATIC);
                    }
                }
            }
        } catch (IOException e) {
            executeExeption(e);
        }
        if (buffer.charAt(0) == '/') {
            buffer.withStartPosition(1);
        }
        this.path = buffer.toString();
        return true;
    }

    public String getHttp_Type() {
        return http_Type;
    }

    public String getPath() {
        return path;
    }

    public HTTPRequest withPath(String value) {
        this.path = value;
        return this;
    }

    public boolean write(HTMLEntity entity) {
        if (entity == null) {
            return false;
        }
        String content = entity.toString();
        PrintWriter output = getOutput();
        if (output != null) {
            this.writeHeader = true;
            this.writeBody = true;
            output.println(HTTP_OK);
            output.println(HTTP_CONTENT + " " + HTTP_CONTENT_HTML + ";" + HTTP_CHARSET + ";");
            output.println(HTTP_LENGTH + content.length());
            output.write(BaseItem.CRLF);
            output.print(content);
            output.flush();
            return true;
        }
        return false;
    }

    public boolean writeHeader(String... header) {
        PrintWriter output = getOutput();
        if (output != null) {
            if (this.writeHeader == false) {
                output.println(HTTP_OK);
                output.println(HTTP_CONTENT + " " + HTTP_CONTENT_HTML + ";" + HTTP_CHARSET + ";");
                this.writeHeader = true;
            }
            if (header != null) {
                for (String item : header) {
                    if (item != null) {
                        output.println(item);
                    }
                }
            }
        }
        return true;
    }

    public boolean writeBody(String... body) {
        PrintWriter output = getOutput();
        if (output != null) {
            if (this.writeHeader == false) {
                this.writeHeader();
            }
            if (body != null) {
                int len = 0;
                for (String item : body) {
                    len += item.length() + 2;
                }
                output.println(HTTP_LENGTH + len);
                output.write(BaseItem.CRLF);
                for (String item : body) {
                    output.println(item);
                }
                output.flush();
                this.writeHeader = true;
            }
            return true;
        }
        return false;
    }

    public boolean readHeader() {
        BufferedReader input = getInput();
        if (input == null) {
            return false;
        }
        int c, pos = 0;
        boolean isEnd = false;
        CharacterBuffer buffer = new CharacterBuffer();
        int length = 0;
        try {
            while ((c = input.read()) != -1) {
                if (c == 10 && buffer.size() < 1) {
                    continue;
                }
                if (c == HTTP_LENGTH.charAt(pos)) {
                    pos++;
                    if (pos == HTTP_LENGTH.length()) {
                        length = 1;
                        break;
                    }
                } else {
                    pos = 0;
                }
                if (c == 13) {
                    String value = buffer.toString();
                    if (value.length() < 1) {
                        isEnd = true;
                        break;
                    }
                    this.withHeader(value);
                    buffer.clear();
                } else {
                    buffer.with((char) c);
                }
            }
            if (length < 1) {
                this.withHeader(buffer.toString());
            } else {
                length = 0;
                while ((c = input.read()) != -1) {
                    if (c == ' ') {
                        continue;
                    }
                    if (c >= '0' && c <= '9') {
                        length = length * 10 + c - '0';
                    } else {
                        break;
                    }
                }
                this.withHeader(HTTP_LENGTH + " " + length);
                if (c == 13) {
                    c = input.read();
                }
            }
            if (isEnd == false) {
                String line;
                do {
                    line = input.readLine();
                    this.withHeader(line);
                } while (line != null && line.trim().length() > 0);
            }
            if (length > 0) {
                char[] item = new char[length];
                while ((c = input.read()) != -1) {
                    if (c != 13 && c != 10 && c != ' ') {
                        break;
                    }
                }
                item[0] = (char) c;
                input.read(item, 1, item.length - 1);
                CharacterBuffer entry = new CharacterBuffer();
                entry.with(item, 0, item.length);
                this.content = entry.toString();
            }
        } catch (IOException e) {
            executeExeption(e);
        }
        return true;
    }

    public boolean isWriteBody() {
        return writeBody;
    }

    public boolean isWriteHeader() {
        return writeHeader;
    }

    public SimpleKeyValueList<String, String> parseForm() {
        SimpleKeyValueList<String, String> value = new SimpleKeyValueList<String, String>();
        if (HTTP_CONTENT_FORM.equals(this.contentType) && this.content != null) {
            CharacterBuffer buffer = new CharacterBuffer();
            char c;
            String key = null;
            for (int i = 0; i < this.content.length(); i++) {
                c = this.content.charAt(i);
                if (c == '=') {
                    key = buffer.toString();
                    buffer.clear();
                    continue;
                }
                if (c == '&') {
                    value.add(key, buffer.toString());
                    buffer.clear();
                    continue;
                }
                buffer.with(c);
            }
            if (buffer.length() > 0) {
                value.add(key, buffer.toString());
            }
        }
        return value;
    }

    public HTTPRequest withHeader(String value) {
        if (value != null) {
            value = value.trim();
            if (value.length() > 0) {
                if (value.startsWith(HTTP_CONTENT)) {
                    this.contentType = value.substring(HTTP_CONTENT.length() + 1);
                }
                this.headers.add(value);
            }
        }
        return this;
    }

    public String getHeader(String filter) {
        if (filter == null) {
            return null;
        }
        for (String item : headers) {
            if (item != null && item.startsWith(filter)) {
                return item;
            }
        }
        return null;
    }

    public String getContent() {
        return content;
    }

    public HTTPRequest withExceptionListener(Condition<Exception> value) {
        this.errorListener = value;
        return this;
    }

    public boolean writeCookie(String key, String value, int expriration) {
        PrintWriter output = getOutput();
        if (output != null) {
            output.println("Set-Cookie: " + key + "=" + value + "; Max-Age=" + expriration);
            return true;
        }
        return false;
    }

    public SimpleList<String> getPathParts() {
        return this.partPath;
    }

    public SimpleList<String> getPathParameter() {
        return this.partParameter;
    }

    public SimpleList<Character> getPathType() {
        return pathType;
    }

    public int getMatchOfRequestPath() {
        return matchOfRequestPath;
    }

    public boolean isValid() {
        return matchValid;
    }

    @Override
    public int compareTo(HTTPRequest o) {
        if (o == null) {
            return 1;
        }
        if (isValid() && o.isValid() == false) {
            return 1;
        }
        if (isValid() == false && o.isValid()) {
            return -1;
        }
        if (o.getMatchOfRequestPath() < this.matchOfRequestPath) {
            return 1;
        }
        if (this.matchOfRequestPath > o.getMatchOfRequestPath()) {
            return -1;
        }
        return 0;
    }

    public HTTPRequest withBufferRespone(String... values) {
        if (bufferResponse == null) {
            bufferResponse = new CharacterBuffer();
        }
        if (values != null) {
            for (String item : values) {
                if (item != null) {
                    bufferResponse.append(item);
                }
            }
        }
        return this;
    }

    public boolean match(HTTPRequest routing) {
        this.matchOfRequestPath = 0;
        this.matchValid = false;
        this.matchVariables.clear();

        if (routing == null || pathType == null) {
            return false;
        }
        SimpleList<String> paths = routing.getFullPath();
        for (matchOfRequestPath = 0; matchOfRequestPath < this.pathType.size(); matchOfRequestPath++) {
            Character type = this.pathType.get(matchOfRequestPath);
            String currentPathpart = this.fullPath.get(getMatchOfRequestPath());
            if (HTTPRequest.STATIC.equals(type)) {
                if (paths.size() < matchOfRequestPath) {
                    break;
                }
                /* Must be the Same */
                if (currentPathpart.equalsIgnoreCase(paths.get(matchOfRequestPath)) == false) {
                    break;
                }
            } else if (HTTPRequest.VARIABLE.equals(type)) {
                /* NEW ONE */
                this.matchVariables.put(paths.get(matchOfRequestPath), currentPathpart);
            }
        }
        matchValid = matchOfRequestPath == paths.size();
        return true;
    }

    public HTTPRequest withUpdateCondition(Condition<HTTPRequest> condition) {
        this.updateCondition = condition;
        return this;
    }

    public boolean update(HTTPRequest value) {
        if (updateCondition != null) {
            return updateCondition.update(value);
        }
        return false;
    }

    public SimpleList<String> getFullPath() {
        return fullPath;
    }
}