Completed
Pull Request — dev (#265)
by Konstantin
02:32
created

buildRequest(HttpServletRequest)   B

Complexity

Conditions 5

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
c 1
b 0
f 0
dl 0
loc 23
rs 8.8613
1
package easytests.swagger;
2
3
import com.atlassian.oai.validator.SwaggerRequestResponseValidator;
4
import com.atlassian.oai.validator.model.Request;
5
import com.atlassian.oai.validator.model.Response;
6
import com.atlassian.oai.validator.model.SimpleRequest;
7
import com.atlassian.oai.validator.model.SimpleResponse;
8
import com.atlassian.oai.validator.report.ValidationReport;
9
import java.io.IOException;
10
import java.io.Reader;
11
import java.util.*;
12
import javax.annotation.Nonnull;
13
import javax.servlet.http.HttpServletRequest;
14
import org.apache.commons.io.IOUtils;
15
import org.apache.commons.lang3.StringUtils;
16
import org.springframework.core.io.support.EncodedResource;
17
import org.springframework.web.util.ContentCachingResponseWrapper;
18
import org.springframework.web.util.UriComponents;
19
import org.springframework.web.util.UriComponentsBuilder;
20
21
22
/**
23
 * @author atlassian
24
 */
25
class SwaggerRequestValidationService {
26
27
    private static final String MESSAGE_REQUEST_PATH_MISSING = "validation.request.path.missing";
28
29
    private final SwaggerRequestResponseValidator requestValidator;
30
31
    SwaggerRequestValidationService(final EncodedResource restInterface) throws IOException {
32
        this(SwaggerRequestResponseValidator
33
                .createFor(readReader(restInterface.getReader()))
34
                .build());
35
    }
36
37
    SwaggerRequestValidationService(final SwaggerRequestResponseValidator requestValidator) {
38
        Objects.requireNonNull(requestValidator, "A request validator is required.");
39
        this.requestValidator = requestValidator;
40
    }
41
42
    /**
43
     * @param servletRequest the {@link HttpServletRequest}
44
     * @return the build {@link Request} created out of given {@link HttpServletRequest}
45
     * @throws IOException if the request body can't be read
46
     */
47
    Request buildRequest(final HttpServletRequest servletRequest) throws IOException {
48
        Objects.requireNonNull(servletRequest, "A request is required.");
49
        final Request.Method method = Request.Method.valueOf(servletRequest.getMethod());
50
        final String requestUri = getCompleteRequestUri(servletRequest);
51
        final UriComponents uriComponents = UriComponentsBuilder
52
                .fromUriString(requestUri)
53
                .build();
54
        final String path = uriComponents.getPath();
55
        final SimpleRequest.Builder builder = new SimpleRequest.Builder(method, path);
56
        final String body = readReader(servletRequest.getReader());
57
        // The content length of a request does not need to be set. It might by "-1" and
58
        // there is still a body. Only in conjunction with an empty / unset body it was
59
        // really empty.
60
        if (servletRequest.getContentLength() >= 0 || (body != null && !body.isEmpty())) {
61
            builder.withBody(body);
62
        }
63
        for (final Map.Entry<String, List<String>> entry : uriComponents.getQueryParams().entrySet()) {
64
            builder.withQueryParam(entry.getKey(), entry.getValue());
65
        }
66
        for (final String headerName : Collections.list(servletRequest.getHeaderNames())) {
67
            builder.withHeader(headerName, Collections.list(servletRequest.getHeaders(headerName)));
68
        }
69
        return builder.build();
70
    }
71
72
    /**
73
     * @param servletResponse the {@link ContentCachingResponseWrapper}
74
     * @return the build {@link Response} created out of given {@link ContentCachingResponseWrapper}
75
     * @throws IOException if the response body can't be write
76
     */
77
    Response buildResponse(final ContentCachingResponseWrapper servletResponse) throws IOException {
78
        final SimpleResponse.Builder builder = new SimpleResponse.Builder(servletResponse.getStatus());
79
80
        builder.withBody(new String(servletResponse.getContentAsByteArray()));
81
82
        for (final String headerName : servletResponse.getHeaderNames()) {
83
            builder.withHeader(headerName, new ArrayList(servletResponse.getHeaders(headerName)));
84
        }
85
86
        return builder.build();
87
    }
88
89
    /**
90
     * @param request the {@link Request} to validate against the Swagger schema
91
     * @return the {@link ValidationReport} for the validated {@link Request}
92
     */
93
    ValidationReport validateRequest(final Request request) {
94
        return requestValidator.validateRequest(request);
95
    }
96
97
    ValidationReport validateResponse(@Nonnull String path, @Nonnull Request.Method method, final Response response) {
98
        return requestValidator.validateResponse(path, method, response);
99
    }
100
101
102
    /**
103
     * @param validationReport the {@link ValidationReport}
104
     * @return {@code true} if the validated request is defined in the Swagger schema, otherwise {@code false}
105
     */
106
    boolean isDefinedSwaggerRequest(final ValidationReport validationReport) {
107
        for (final ValidationReport.Message message : validationReport.getMessages()) {
108
            if (MESSAGE_REQUEST_PATH_MISSING.equals(message.getKey())) {
109
                return false;
110
            }
111
        }
112
        return true;
113
    }
114
115
    private static String readReader(final Reader reader) throws IOException {
116
        return IOUtils.toString(reader);
117
    }
118
119
    private static String getCompleteRequestUri(final HttpServletRequest servletRequest) {
120
        if (StringUtils.isBlank(servletRequest.getQueryString())) {
121
            return servletRequest.getRequestURI();
122
        }
123
        return servletRequest.getRequestURI() + "?" + servletRequest.getQueryString();
124
    }
125
}
126