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

org.zodiac.sdk.nio.http.common.HTTPResponse Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.sdk.nio.http.common;

import io.vavr.control.Either;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.zodiac.sdk.nio.http.NioHttpConstants;
import org.zodiac.sdk.toolkit.util.StringUtil;

//@Builder(toBuilder = true)
public final class HTTPResponse {

    private static final String STATUS_LINE_REGEX = "^HTTP/\\d.\\d (\\d+) (.*)\r?$";

    private HTTPRequest request;

    private String statusCode;

    private String statusMessage;

    private HttpHeaders headers;

    private String body;

    public HTTPResponse() {
        super();
    }

    public HTTPResponse(final HTTPRequest request, final String messageHeader, final String messageBody) {
        this.request = request;
        body = messageBody;

        /*
        final Stream statusLine = Arrays.stream(messageHeader.split("\n"))
            .filter(e -> e.matches(STATUS_LINE_REGEX))
            .map(e -> Pattern.compile(STATUS_LINE_REGEX).matcher(e).results().map(ee -> ee.group(0)).findFirst().orElse(null))
            .filter(Objects::nonNull)
            .findFirst()
            .orElse(null);
        statusCode = Pattern.compile(STATUS_LINE_REGEX)
            .matcher(Objects.requireNonNullElse(statusLine, ""))
            .results()
            .map(e -> e.group(1))
            .map(String::trim)
            .findFirst()
            .orElse(null);
        statusMessage = Pattern.compile(STATUS_LINE_REGEX)
            .matcher(Objects.requireNonNullElse(statusLine, ""))
            .results()
            .map(e -> e.group(2))
            .map(String::trim)
            .findFirst()
            .orElse(null);
        headers = Arrays.stream(messageHeader.split("\n"))
            .filter(e -> e.contains(":"))
            .map(e -> e.split(": "))
            .collect(Collectors.toMap(e -> e[0], e -> e[1], (value1, value2) -> {
                System.err.println("Duplicate key found. Discarding value: " + value1);
                return value2;
            }));
        */
        final String statusLine = Arrays.stream(messageHeader.split("\n"))
            .filter(e -> e.matches(STATUS_LINE_REGEX))
            .map(e -> {
                Matcher matcher = Pattern.compile(STATUS_LINE_REGEX).matcher(e);
                return matcher;
            })
            .map(m -> m.group(0))
            .filter(Objects::nonNull)
            .findFirst()
            .orElse(null);
        statusCode = Arrays.stream(new String[] {Pattern.compile(STATUS_LINE_REGEX)
            .matcher(Optional.ofNullable(statusLine).orElse("")).group(1)})
            .map(String::trim)
            .findFirst()
            .orElse(null);
            
        statusMessage = Arrays.stream(new String[] {Pattern.compile(STATUS_LINE_REGEX)
            .matcher(Optional.ofNullable(statusLine).orElse("")).group(2)})
            .map(String::trim)
            .findFirst()
            .orElse(null);
        headers = new HttpHeaders(Arrays.stream(messageHeader.split("\n"))
            .filter(e -> e.contains(":"))
            .map(e -> e.split(": "))
            .collect(Collectors.toMap(e -> e[0], e -> Arrays.asList(e[1]), (value1, value2) -> {
                System.err.println("Duplicate key found. Discarding value: " + value1);
                return value2;
            })));
    }

    public HTTPResponse(HTTPRequest request, String statusCode, String statusMessage, HttpHeaders headers,
        String body) {
        this.request = request;
        this.statusCode = statusCode;
        this.statusMessage = statusMessage;
        this.headers = headers;
        this.body = body;
    }

    public HTTPRequest getRequest() {
        return request;
    }

    public String getStatusCode() {
        return statusCode;
    }

    public String getStatusMessage() {
        return statusMessage;
    }

    public HttpHeaders getHeaders() {
        return headers;
    }

    public String getBody() {
        return body;
    }

    public HTTPResponse setRequest(HTTPRequest request) {
        this.request = request;
        return this;
    }

    public HTTPResponse setStatusCode(HttpResponseStatusEnum httpResponseStatus) {
        if (null != httpResponseStatus)
            this.statusCode = String.valueOf(httpResponseStatus.value());
        return this;
    }

    public HTTPResponse setStatusMessage(HttpResponseStatusEnum httpResponseStatus) {
        if (null != httpResponseStatus)
            this.statusMessage = httpResponseStatus.getReasonPhrase();
        return this;
    }

    public HTTPResponse setHeaders(HttpHeaders headers) {
        this.headers = headers;
        return this;
    }

    public HTTPResponse setBody(String body) {
        this.body = body;
        return this;
    }

    public Either valid() {
        if (statusCode == null) {
            return Either.right("statusCode was null");
        }

        if (statusMessage == null) {
            return Either.right("statusMessage was null");
        }

        if (headers == null) {
            return Either.right("headers were null");
        }

        return validBody();
    }

    private Either validBody() {
        if (headers != null) {
            final String contentLength = headers.getFirstOrDefault(HttpHeaders.CONTENT_LENGTH, "0");
            final String bodyLength = String.valueOf(body != null ? body.length() : 0);
            if (!contentLength.equals(bodyLength)) {
                return Either.right(String.format(
                    "Content-Length header value (%s) did not match body's length parsed (%s)",
                    contentLength,
                    bodyLength));
            }
        }
        return Either.left(true);
    }

    public String statusLine() {
        return HttpProtocolVersion.HTTP_1_0.getText() + " " + statusCode + " " + statusMessage;
    }

    public String messageHeader() {
        if (headers == null) {
            return "";
        }
        return statusLine() + NioHttpConstants.CRLF + headers.entrySet()
            .stream()
            .map(e -> e.getKey() + ": " + e.getValue())
            .collect(Collectors.joining("\n"));
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        boolean contentLengthAdded = false;

        sb.append(String.format("%s %s %s%s", HttpProtocolVersion.HTTP_1_1.getText(), statusCode, statusMessage, NioHttpConstants.CRLF));

        for (final Entry> header : headers.entrySet()) {
            sb.append(String.format("%s: %s%s", header.getKey(), StringUtil.collectionToString(header.getValue()), NioHttpConstants.CRLF));
            if (header.getKey().equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH)) {
                contentLengthAdded = true;
            }
        }

        if (body != null) {
            if (!contentLengthAdded) {
                sb.append(String.format("%s: %s%s", NioHttpConstants.Headers.CONTENT_LENGTH, body.length(), NioHttpConstants.CRLF));
            }
            sb.append(NioHttpConstants.CRLF);
            sb.append(body);
        } else {
            sb.append(NioHttpConstants.CRLF);
        }

        return sb.toString();
    }

    public static Either of(final HTTPRequest request, final String spec) {
        try {
            final List lines = new ArrayList<>(Arrays.asList(spec.split(NioHttpConstants.CRLF)));
            final int lastLineOfHeaderIndex = indexOfBlankLine(spec);
            if (lastLineOfHeaderIndex == -1) {
                return Either.right("could not parse blank line in HTTP response");
            }
            final List messageHeader = lines.subList(0, lastLineOfHeaderIndex);
            final List messageBody = lines.subList(lastLineOfHeaderIndex + 1, lines.size());
            final HTTPResponse response = new HTTPResponse(request, String.join("\n", messageHeader), String.join("\n", messageBody));

            final Either isValid = response.valid();
            return isValid.isLeft() ? Either.left(response) : Either.right(isValid.get());
        } catch (final Exception e) {
            return Either.right("received IOException: " + e.getMessage());
        }
    }

    private static int indexOfBlankLine(final String text) {
        final List lines = new ArrayList<>(Arrays.asList(text.split("\n")));
        for (int i = 0; i < lines.size(); i++) {
            if (lines.get(i).equals("") || lines.get(i).equals("\r")) {
                return i;
            }
        }
        return -1;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {

        private HTTPRequest request;

        private String statusCode;

        private String statusMessage;

        private HttpHeaders headers;

        private String body;

        public Builder() {
            super();
        }

        public Builder request(HTTPRequest request) {
            this.request = request;
            return this;
        }

        public Builder statusCode(HttpResponseStatusEnum httpResponseStatus) {
            this.statusCode = String.valueOf(httpResponseStatus.value());
            return this;
        }

        public Builder statusMessage(HttpResponseStatusEnum httpResponseStatus) {
            this.statusMessage = httpResponseStatus.getReasonPhrase();
            return this;
        }

        public Builder headers(HttpHeaders headers) {
            this.headers = headers;
            return this;
        }

        public Builder body(String body) {
            this.body = body;
            return this;
        }

        public HTTPResponse build() {
            return new HTTPResponse(request, statusCode, statusMessage, headers, body);
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy