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

com.turbospaces.resteasy.DefaultHttpClientRequestPrinter Maven / Gradle / Ivy

The newest version!
package com.turbospaces.resteasy;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Consumer;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration;
import org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.robtimus.obfuscation.Obfuscator;
import com.github.robtimus.obfuscation.http.HeaderObfuscator;
import com.github.robtimus.obfuscation.http.RequestParameterObfuscator;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.turbospaces.annotations.ApiEndpoint;
import com.turbospaces.cfg.ApplicationProperties;
import com.turbospaces.http.HttpProto;
import com.turbospaces.resteasy.obfuscate.ObfuscateUtil;

import io.netty.handler.codec.http.QueryStringDecoder;
import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.core.Configuration;
import jakarta.ws.rs.core.Cookie;
import jakarta.ws.rs.core.Form;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.ext.ContextResolver;
import jakarta.ws.rs.ext.RuntimeDelegate;
import jakarta.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DefaultHttpClientRequestPrinter implements HttpClientRequestPrinter {
    private static HeaderDelegate COOKIE_PRINTER = RuntimeDelegate.getInstance().createHeaderDelegate(Cookie.class);

    protected final ApplicationProperties props;
    protected final StringWriter writer = new StringWriter();
    protected final BufferedWriter buffer = new BufferedWriter(writer);
    private final LoadingCache objectMappersWithObfuscation = CacheBuilder.newBuilder()
            .build(new CacheLoader() {
                @Override
                public ObjectMapper load(ObjectMapper key) {
                    return key.copy().registerModule(ObfuscateUtil.LOGGING_OBFUSCATED_MODULE);
                }
            });

    public DefaultHttpClientRequestPrinter(ApplicationProperties props) {
        this.props = Objects.requireNonNull(props);
    }
    @Override
    public void writeStart(ClientRequestContext context) throws IOException {
        buffer.write("Request:");
        buffer.newLine();
    }

    @Override
    public Map> writeUri(ClientRequestContext context) throws IOException {
        ClientInvoker clientInvoker = clientInvoker(context);
        URI uri = context.getUri();
        Map> query = Collections.emptyMap();

        if (StringUtils.isNotEmpty(uri.getRawQuery())) {
            QueryStringDecoder decoder = new QueryStringDecoder(uri.getRawQuery(), false);
            query = decoder.parameters();
        }

        URIBuilder builder = new URIBuilder().setScheme(uri.getScheme()).setHost(uri.getHost()).setPort(uri.getPort());
        builder.setPath(uri.getPath());

        if (BooleanUtils.isFalse(query.isEmpty())) {
            RequestParameterObfuscator.Builder b = addQueryParamsToMask(clientInvoker, RequestParameterObfuscator.builder());

            List l = props.HTTP_QUERY_PARAMS_TO_MASK.get();
            if (CollectionUtils.isNotEmpty(l)) {
                for (String it : l) {
                    b.withParameter(it, Obfuscator.all());
                }
            }

            RequestParameterObfuscator obfuscator = b.build();
            for (Entry> next : query.entrySet()) {
                String name = next.getKey();

                if (CollectionUtils.isNotEmpty(next.getValue())) {
                    for (String value : next.getValue()) {
                        builder.addParameter(name, obfuscator.obfuscateParameter(name, value).toString());
                    }
                }
            }
        }

        context.setProperty(HttpProto.toCtxName(HttpProto.CONTEXT_URI), builder);

        buffer.write(context.getMethod() + ": " + builder);
        buffer.newLine();

        return query;
    }

    @Override
    public void writeQueryParams(ClientRequestContext context, Map> query) throws IOException {
        ClientInvoker clientInvoker = clientInvoker(context);

        if (MapUtils.isNotEmpty(query)) {
            if (BooleanUtils.isFalse(query.isEmpty())) {
                RequestParameterObfuscator.Builder b = addQueryParamsToMask(clientInvoker, RequestParameterObfuscator.builder());

                List l = props.HTTP_QUERY_PARAMS_TO_MASK.get();
                if (CollectionUtils.isNotEmpty(l)) {
                    for (String it : l) {
                        b.withParameter(it, Obfuscator.all());
                    }
                }

                RequestParameterObfuscator obfuscator = b.build();
                for (Entry> next : query.entrySet()) {
                    String name = next.getKey();

                    if (CollectionUtils.isNotEmpty(next.getValue())) {
                        for (String value : next.getValue()) {
                            buffer.write(String.format("Query: %s = %s", name, obfuscator.obfuscateParameter(name, value)));
                            buffer.newLine();
                        }
                    }
                }
            }
        }
    }

    @Override
    public void writeHeaders(ClientRequestContext context) throws IOException {
        ClientInvoker clientInvoker = clientInvoker(context);
        MultivaluedMap headers = context.getStringHeaders();

        if (BooleanUtils.isFalse(headers.isEmpty())) {
            HeaderObfuscator.Builder b = addHeadersToMask(clientInvoker, HeaderObfuscator.builder());

            List l = props.HTTP_HEADERS_TO_MASK.get();
            if (CollectionUtils.isNotEmpty(l)) {
                for (String it : l) {
                    b.withHeader(it, Obfuscator.all());
                }
            }

            HeaderObfuscator obfuscator = b.build();
            for (Entry> next : headers.entrySet()) {
                String name = next.getKey();

                if (CollectionUtils.isNotEmpty(next.getValue())) {
                    for (String value : next.getValue()) {
                        buffer.write(String.format("Header: %s = %s", name, obfuscator.obfuscateHeader(name, value)));
                        buffer.newLine();
                    }
                }
            }
        }
    }

    @Override
    public void writeCookies(ClientRequestContext context) throws IOException {
        Map cookies = context.getCookies();

        if (BooleanUtils.isFalse(cookies.isEmpty())) {
            for (Entry next : cookies.entrySet()) {
                Cookie cookie = next.getValue();
                String value = COOKIE_PRINTER.toString(cookie);
                buffer.write(String.format("Cookie: %s", Obfuscator.all().obfuscateText(value)));
                buffer.newLine();
            }
        }
    }

    @Override
    public void writeBody(ClientRequestContext context) throws IOException {
        String body = getBody(context.getEntity(), context.getConfiguration(), context.getMediaType());
        if (StringUtils.isNotEmpty(body)) {
            buffer.write("Body: " + body);
        }
    }

    private String getBody(Object entity, Configuration config, MediaType mediaType) {
        if (Objects.nonNull(entity)) {
            try {
                ContextResolver resolver = null;
                ObjectMapper mapper = null;
                if (config instanceof ClientConfiguration) {
                    resolver = ((ClientConfiguration) config).getContextResolver(ObjectMapper.class, mediaType);
                }
                if (resolver != null) {
                    mapper = resolver.getContext(ObjectMapper.class);
                }
                if (mapper != null) {
                    return objectMappersWithObfuscation.get(mapper).writeValueAsString(entity);
                }
                if (entity instanceof Form) {
                    StringBuffer str = new StringBuffer();
                    ((Form) entity).asMap().forEach((s, strings) -> str.append(s).append("=").append(String.join(",", strings)).append(";"));
                    return str.toString();
                }
                return entity.toString();
            } catch (Exception e) {
                log.error("Error on preparing request body", e);
            }
        }
        return StringUtils.EMPTY;
    }

    @Override
    public void doOutPut(ClientRequestContext context) {
        try {
            writeStart(context);
            Map> query = writeUri(context);
            writeHeaders(context);
            writeQueryParams(context, query);
            writeCookies(context);
            writeBody(context);
            buffer.flush();

            LOGGING_FILTER_LOGGER.debug(writer.toString());

            buffer.close();
            writer.close();
        } catch (IOException err) {
            log.error(err.getMessage(), err);
        }
    }

    protected RequestParameterObfuscator.Builder addQueryParamsToMask(ClientInvoker invoker, RequestParameterObfuscator.Builder obfuscator) {
        Class resource = invoker.getDeclaring();
        Method method = invoker.getMethod();

        Consumer action = new Consumer() {
            @Override
            public void accept(ApiEndpoint annotation) {
                if (Objects.nonNull(annotation)) {
                    String[] toMask = annotation.queryParamsToMask();
                    if (toMask != null) {
                        for (String param : toMask) {
                            obfuscator.withParameter(param, Obfuscator.all());
                        }
                    }
                }
            }
        };

        action.accept(resource.getAnnotation(ApiEndpoint.class));
        action.accept(method.getAnnotation(ApiEndpoint.class));

        return obfuscator;
    }

    protected HeaderObfuscator.Builder addHeadersToMask(ClientInvoker invoker, HeaderObfuscator.Builder obfuscator) {
        Class resource = invoker.getDeclaring();
        Method method = invoker.getMethod();

        Consumer action = new Consumer() {
            @Override
            public void accept(ApiEndpoint annotation) {
                if (Objects.nonNull(annotation)) {
                    String[] toMask = annotation.headersToMask();
                    if (toMask != null) {
                        for (String param : toMask) {
                            obfuscator.withHeader(param, Obfuscator.all());
                        }
                    }
                }
            }
        };

        action.accept(resource.getAnnotation(ApiEndpoint.class));
        action.accept(method.getAnnotation(ApiEndpoint.class));

        return obfuscator;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy