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

com.jayway.restassured.internal.RestAssuredResponseImpl.groovy Maven / Gradle / Ivy

/*
 * Copyright 2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jayway.restassured.internal

import com.jayway.restassured.assertion.CookieMatcher
import com.jayway.restassured.config.ConnectionConfig
import com.jayway.restassured.config.JsonConfig
import com.jayway.restassured.config.ObjectMapperConfig
import com.jayway.restassured.config.XmlConfig
import com.jayway.restassured.internal.http.CharsetExtractor
import com.jayway.restassured.internal.mapper.ObjectMapperType
import com.jayway.restassured.internal.mapping.ObjectMapperDeserializationContextImpl
import com.jayway.restassured.internal.mapping.ObjectMapping
import com.jayway.restassured.internal.support.CloseHTTPClientConnectionInputStreamWrapper
import com.jayway.restassured.internal.support.Prettifier
import com.jayway.restassured.mapper.DataToDeserialize
import com.jayway.restassured.mapper.ObjectMapper
import com.jayway.restassured.mapper.ObjectMapperDeserializationContext
import com.jayway.restassured.path.json.JsonPath
import com.jayway.restassured.path.json.config.JsonPathConfig
import com.jayway.restassured.path.xml.XmlPath
import com.jayway.restassured.path.xml.XmlPath.CompatibilityMode
import com.jayway.restassured.path.xml.config.XmlPathConfig
import com.jayway.restassured.response.*
import groovy.xml.StreamingMarkupBuilder

import java.nio.charset.Charset

import static com.jayway.restassured.internal.assertion.AssertParameter.notNull
import static com.jayway.restassured.path.json.config.JsonPathConfig.jsonPathConfig
import static com.jayway.restassured.path.xml.config.XmlPathConfig.xmlPathConfig
import static org.apache.commons.lang3.StringUtils.containsIgnoreCase
import static org.apache.commons.lang3.StringUtils.isBlank

class RestAssuredResponseImpl implements Response {
    private static final String CANNOT_PARSE_MSG = "Failed to parse response."
    def responseHeaders
    def Cookies cookies
    def content
    def contentType
    def statusLine
    def statusCode
    def sessionIdName
    def connectionManager;

    def String defaultContentType
    def ResponseParserRegistrar rpr

    def String defaultCharset

    def boolean hasExpectations

    def ObjectMapperConfig objectMapperConfig
    def ConnectionConfig connectionConfig
    def XmlConfig xmlConfig
    def JsonConfig jsonConfig

    public void parseResponse(httpResponse, content, hasBodyAssertions, ResponseParserRegistrar responseParserRegistrar) {
        parseHeaders(httpResponse)
        parseContentType(httpResponse)
        parseCookies()
        parseStatus(httpResponse)
        if (hasBodyAssertions) {
            parseContent(content)
        } else {
            this.content = content
        }
        hasExpectations = hasBodyAssertions
        this.rpr = responseParserRegistrar
        this.defaultContentType = responseParserRegistrar.defaultParser?.getContentType()
    }

    def parseStatus(httpResponse) {
        statusLine = httpResponse.statusLine.toString()
        statusCode = httpResponse.statusLine.statusCode
    }

    def parseContentType(httpResponse) {
        try {
            contentType = httpResponse.contentType?.toString()
        } catch (IllegalArgumentException e) {
            // No content type was found, set it to empty
            contentType = ""
        }
    }

    def parseCookies() {
        if (headers.hasHeaderWithName("Set-Cookie")) {
            cookies = CookieMatcher.getCookies(headers.getValues("Set-Cookie"))
        }
    }

    def parseHeaders(httpResponse) {
        def headerList = [];
        httpResponse.headers.each {
            def name = it.getName()
            def value = it.getValue();
            headerList << new Header(name, value)
        }
        this.responseHeaders = new Headers(headerList)
    }

    private def parseContent(content) {
        try {
            if (content instanceof InputStream) {
                this.content = convertToByteArray(content)
            } else if (content instanceof Writable) {
                this.content = toString(content)
            } else if (content instanceof String) {
                this.content = content
            } else {
                this.content = convertToString(content)
            }
        } catch (IllegalStateException e) {
            throw new IllegalStateException(CANNOT_PARSE_MSG, e)
        }
    }

    // TODO: Handle namespaces ??
    def toString(Writable node) {
        def writer = new StringWriter()
        writer << new StreamingMarkupBuilder().bind {
            // mkp.declareNamespace(dc: "http://purl.org/dc/elements/1.1/")
            mkp.yield node
        }
        return writer.toString();
    }

    String print() {
        def string = asString();
        println string
        string
    }

    String prettyPrint() {
        def body = new Prettifier().getPrettifiedBodyIfPossible(this)
        println body
        body
    }

    String asString() {
        charsetToString(findCharset())
    }

    InputStream asInputStream() {
        if (content == null || content instanceof InputStream) {
            new CloseHTTPClientConnectionInputStreamWrapper(connectionConfig, connectionManager, content)
        } else {
            content instanceof String ? new ByteArrayInputStream(content.getBytes(findCharset())) : new ByteArrayInputStream(content)
        }
    }

    byte[] asByteArray() {
        if (content == null) {
            return new byte[0];
        }
        if (hasExpectations) {
            return content instanceof byte[] ? content : content.getBytes(findCharset())
        } else {
            return convertStreamToByteArray(content)
        }
    }

    def  T "as"(Class cls) {
        def charset = findCharset();
        String contentTypeToChose = findContentType {
            throw new IllegalStateException("""Cannot parse content to $cls because no content-type was present in the response and no default parser has been set.\nYou can specify a default parser using e.g.:\nRestAssured.defaultParser = Parser.JSON;\n
or you can specify an explicit ObjectMapper using as($cls, );""")
        }
        return ObjectMapping.deserialize(this, cls, contentTypeToChose, defaultContentType, charset, null, objectMapperConfig)
    }

    def  T "as"(Class cls, ObjectMapperType mapperType) {
        notNull mapperType, "Object mapper type"
        def charset = findCharset()
        return ObjectMapping.deserialize(this, cls, null, defaultContentType, charset, mapperType, objectMapperConfig)
    }

    def  T "as"(Class cls, ObjectMapper mapper) {
        notNull mapper, "Object mapper"
        def ctx = createObjectMapperDeserializationContext(cls)
        return mapper.deserialize(ctx) as T
    }

    private String findCharset() {
        String charset = CharsetExtractor.getCharsetFromContentType(isBlank(contentType) ? defaultContentType : contentType)

        if (charset == null || charset.trim().equals("")) {
            if (defaultCharset == null) {
                return Charset.defaultCharset()
            } else {
                charset = defaultCharset
            }
        }

        return charset;
    }

    def Cookies detailedCookies() {
        if (cookies == null) {
            return new Cookies()
        }
        return cookies
    }

    def Cookies getDetailedCookies() {
        return detailedCookies()
    }

    def Cookie detailedCookie(String name) {
        return detailedCookies().get(name)
    }

    def Cookie getDetailedCookie(String name) {
        return detailedCookie(name)
    }

    Response andReturn() {
        return this
    }

    ResponseBody body() {
        return this
    }

    Response thenReturn() {
        return this
    }

    ResponseBody getBody() {
        return body()
    }

    Headers headers() {
        return responseHeaders
    }

    Headers getHeaders() {
        return headers()
    }

    String header(String name) {
        notNull(name, "name")
        return responseHeaders.getValue(name)
    }

    String getHeader(String name) {
        return header(name)
    }

    Map cookies() {
        def cookieMap = [:]
        cookies.each { cookie ->
            cookieMap.put(cookie.name, cookie.value)
        }
        return Collections.unmodifiableMap(cookieMap)
    }

    Map getCookies() {
        return cookies()
    }

    String cookie(String name) {
        notNull(name, "name")
        return cookies == null ? null : cookies.getValue(name)
    }

    String getCookie(String name) {
        return cookie(name)
    }

    String contentType() {
        return contentType
    }

    String getContentType() {
        return contentType
    }

    String statusLine() {
        return statusLine
    }

    int statusCode() {
        return statusCode
    }

    String getStatusLine() {
        return statusLine()
    }

    String sessionId() {
        return getSessionId()
    }

    String getSessionId() {
        return cookie(sessionIdName)
    }

    int getStatusCode() {
        return statusCode()
    }

    JsonPath jsonPath() {
        jsonPath(jsonPathConfig().charset(findCharset()).
                jackson1ObjectMapperFactory(objectMapperConfig.jackson1ObjectMapperFactory()).
                jackson2ObjectMapperFactory(objectMapperConfig.jackson2ObjectMapperFactory()).
                gsonObjectMapperFactory(objectMapperConfig.gsonObjectMapperFactory()).
                numberReturnType(jsonConfig.numberReturnType()));
    }

    JsonPath jsonPath(JsonPathConfig config) {
        notNull(config, "JsonPathConfig")
        new JsonPath(asInputStream()).using(config)
    }

    XmlPath xmlPath() {
        xmlPath(CompatibilityMode.XML)
    }

    XmlPath xmlPath(XmlPathConfig config) {
        newXmlPath(CompatibilityMode.XML, config)
    }

    XmlPath xmlPath(CompatibilityMode compatibilityMode) {
        notNull(compatibilityMode, "Compatibility mode")
        newXmlPath(compatibilityMode)
    }

    XmlPath htmlPath() {
        return xmlPath(CompatibilityMode.HTML)
    }

    def  T path(String path) {
        notNull path, "Path"
        def contentType = findContentType {
            throw new IllegalStateException("""Cannot invoke the path method because no content-type was present in the response and no default parser has been set.\n
You can specify a default parser using e.g.:\nRestAssured.defaultParser = Parser.JSON;\n""")
        };
        if (containsIgnoreCase(contentType, "xml")) {
            return xmlPath().get(path)
        } else if (containsIgnoreCase(contentType, "json")) {
            return jsonPath().get(path)
        } else if (containsIgnoreCase(contentType, "html")) {
            return newXmlPath(CompatibilityMode.HTML)
        }
        throw new IllegalStateException("Cannot determine which path implementation to use because the content-type $contentType doesn't map to a path implementation.")
    }

    private convertToByteArray(InputStream stream) {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[16384];

        try {
            while ((nRead = stream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();
        } finally {
            stream.close()
        }
        return buffer.toByteArray();
    }

    private String convertToString(Reader reader) {
        if (reader == null) {
            return "";
        }

        Writer writer = new StringWriter();
        char[] buffer = new char[1024];
        try {
            int n;
            while ((n = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, n);
            }
        } finally {
            reader?.close();
        }
        return writer.toString();
    }

    private String convertStreamToString(InputStream is) throws IOException {
        Writer writer = new StringWriter();
        char[] buffer = new char[1024];
        Reader reader = null;
        try {
            reader = new InputStreamReader(is, findCharset());
            int n;
            while ((n = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, n);
            }
        } finally {
            is?.close();
            reader?.close();
        }
        return writer.toString();
    }

    private byte[] convertStreamToByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        try {
            int nRead;
            byte[] data = new byte[16384];

            while ((nRead = is.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }

            buffer.flush();
        } finally {
            buffer?.close();
            is?.close();
        }

        return buffer.toByteArray();
    }

    private String findContentType(Closure closure) {
        def contentTypeToChose = null
        if (contentType == "") {
            if (defaultContentType != null) {
                contentTypeToChose = defaultContentType
            } else {
                closure.call()
            }
        } else if (rpr.hasCustomParserExludingDefaultParser(contentType)) {
            contentTypeToChose = rpr.getNonDefaultParser(contentType).contentType
        } else {
            contentTypeToChose = contentType
        }
        return contentTypeToChose
    }

    private def newXmlPath(CompatibilityMode xml) {
        newXmlPath(xml, xmlPathConfig().charset(findCharset()).
                features(xmlConfig.features()).
                declareNamespaces(xmlConfig.declaredNamespaces()).
                jaxbObjectMapperFactory(objectMapperConfig.jaxbObjectMapperFactory()))
    }

    private def newXmlPath(CompatibilityMode xml, XmlPathConfig config) {
        notNull(config, "XmlPathConfig")
        new XmlPath(xml, asInputStream()).using(config)
    }

    private def charsetToString(charset) {
        if (content == null) {
            return ""
        }

        if (content instanceof String) {
            content
        } else if (content instanceof byte[]) {
            new String(content, charset)
        } else {
            convertStreamToString(content)
        }
    }

    private ObjectMapperDeserializationContext createObjectMapperDeserializationContext(Class cls) {
        def ctx = new ObjectMapperDeserializationContextImpl()
        ctx.type = cls
        ctx.charset = findCharset()
        ctx.contentType = contentType()
        ctx.dataToDeserialize = new DataToDeserialize() {
            @Override
            String asString() {
                return RestAssuredResponseImpl.this.asString()
            }

            @Override
            byte[] asByteArray() {
                return RestAssuredResponseImpl.this.asByteArray()
            }

            @Override
            InputStream asInputStream() {
                return RestAssuredResponseImpl.this.asInputStream()
            }
        }
        ctx
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy