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

org.zalando.riptide.logbook.LocalRequest Maven / Gradle / Ivy

There is a newer version: 4.1.0
Show newest version
package org.zalando.riptide.logbook;

import com.google.common.collect.Iterables;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.zalando.logbook.HttpHeaders;
import org.zalando.logbook.HttpRequest;
import org.zalando.logbook.Origin;
import org.zalando.riptide.CharsetExtractor;
import org.zalando.riptide.RequestArguments;
import org.zalando.riptide.RequestArguments.Entity;

import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

import static java.util.Collections.emptyList;
import static org.zalando.fauxpas.FauxPas.throwingUnaryOperator;

// TODO remove Entity interface here
@AllArgsConstructor
final class LocalRequest implements HttpRequest {

    private static final CharsetExtractor EXTRACTOR = new CharsetExtractor();

    private final AtomicReference state = new AtomicReference<>(new Unbuffered());

    private final RequestArguments arguments;

    private interface State {

        default State with() {
            return this;
        }

        default State without() {
            return this;
        }

        default State buffer(final Entity entity, final HttpOutputMessage message) throws IOException {
            throw new UnsupportedOperationException();
        }

        default byte[] getBody() {
            return new byte[0];
        }

    }

    private static final class Unbuffered implements State {

        @Override
        public State with() {
            return new Offering();
        }

        @Override
        public State buffer(final Entity entity, final HttpOutputMessage message) throws IOException {
            entity.writeTo(message);
            return new Passing();
        }

    }

    private static final class Offering implements State {

        @Override
        public State without() {
            return new Unbuffered();
        }

        @Override
        public State buffer(
                final Entity entity,
                final HttpOutputMessage message) throws IOException {

            final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            entity.writeTo(new SimpleHttpOutputMessage(
                    message.getHeaders(),
                    new TeeOutputStream(message.getBody(), buffer)));
            return new Buffering(buffer.toByteArray());
        }

    }

    @AllArgsConstructor
    private static final class Buffering implements State {

        private final byte[] body;

        @Override
        public State without() {
            return new Ignoring(body);
        }

        @Override
        public byte[] getBody() {
            return body;
        }

    }

    @AllArgsConstructor
    private static final class Ignoring implements State {

        private final byte[] body;

        @Override
        public State with() {
            return new Buffering(body);
        }

    }

    private static final class Passing implements State {

    }

    @Override
    public HttpRequest withBody() {
        state.updateAndGet(State::with);
        return this;
    }

    @Override
    public HttpRequest withoutBody() {
        state.updateAndGet(State::without);
        return this;
    }

    @Override
    public Origin getOrigin() {
        return Origin.LOCAL;
    }

    @Override
    public String getProtocolVersion() {
        return "HTTP/1.1";
    }

    @Override
    public String getRemote() {
        return "localhost";
    }

    @Override
    public String getMethod() {
        return arguments.getMethod().name();
    }

    @Override
    public String getScheme() {
        return arguments.getRequestUri().getScheme();
    }

    @Override
    public String getHost() {
        return arguments.getRequestUri().getHost();
    }

    @Override
    public Optional getPort() {
        return Optional.of(arguments.getRequestUri().getPort()).filter(p -> p != -1);
    }

    @Override
    public String getPath() {
        return arguments.getRequestUri().getPath();
    }

    @Override
    public String getQuery() {
        return Optional.ofNullable(arguments.getRequestUri().getQuery()).orElse("");
    }

    @Override
    public HttpHeaders getHeaders() {
        return HttpHeaders.of(arguments.getHeaders());
    }

    @Nullable
    @Override
    public String getContentType() {
        return Iterables.getFirst(
                arguments.getHeaders().getOrDefault("Content-Type", emptyList()), null);
    }

    @Override
    public Charset getCharset() {
        return Optional.ofNullable(getContentType())
                .map(MediaType::parseMediaType)
                .flatMap(EXTRACTOR::getCharset)
                .orElse(StandardCharsets.UTF_8);
    }

    void writeTo(final Entity entity, final HttpOutputMessage message) {
        state.updateAndGet(throwingUnaryOperator(state ->
                state.buffer(entity, message)));
    }

    @Override
    public byte[] getBody() {
        return state.get().getBody();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy