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

io.restassured.internal.RestAssuredResponseOptionsGroovyImpl.groovy Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright 2016 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 io.restassured.internal

import groovy.xml.StreamingMarkupBuilder
import io.restassured.assertion.CookieMatcher
import io.restassured.config.DecoderConfig
import io.restassured.config.RestAssuredConfig
import io.restassured.filter.log.LogDetail
import io.restassured.filter.time.TimingFilter
import io.restassured.http.Cookie
import io.restassured.http.Cookies
import io.restassured.http.Header
import io.restassured.http.Headers
import io.restassured.internal.http.CharsetExtractor
import io.restassured.internal.mapping.ObjectMapperDeserializationContextImpl
import io.restassured.internal.mapping.ObjectMapping
import io.restassured.internal.print.ResponsePrinter
import io.restassured.internal.support.CloseHTTPClientConnectionInputStreamWrapper
import io.restassured.internal.support.Prettifier
import io.restassured.mapper.DataToDeserialize
import io.restassured.mapper.ObjectMapper
import io.restassured.mapper.ObjectMapperDeserializationContext
import io.restassured.mapper.ObjectMapperType
import io.restassured.path.json.JsonPath
import io.restassured.path.json.config.JsonPathConfig
import io.restassured.path.xml.XmlPath
import io.restassured.path.xml.XmlPath.CompatibilityMode
import io.restassured.path.xml.config.XmlPathConfig
import io.restassured.response.ResponseBody
import io.restassured.response.ResponseBodyData
import io.restassured.response.ResponseOptions
import org.apache.commons.lang3.StringUtils

import java.lang.reflect.Type
import java.nio.charset.Charset
import java.util.concurrent.TimeUnit

import static JsonPathConfig.jsonPathConfig
import static XmlPathConfig.xmlPathConfig
import static io.restassured.internal.assertion.AssertParameter.notNull
import static org.apache.commons.lang3.StringUtils.containsIgnoreCase
import static org.apache.commons.lang3.StringUtils.isBlank

class RestAssuredResponseOptionsGroovyImpl {
  private static final String CANNOT_PARSE_MSG = "Failed to parse response."
  public static final String BINARY = "binary"
  private static final long NO_RESPONSE_TIME = -1

  def responseHeaders
  def Cookies cookies
  def content
  def contentType
  def statusLine
  def statusCode
  def sessionIdName
  def Map filterContextProperties
  def connectionManager;

  def String defaultContentType
  def ResponseParserRegistrar rpr

  def DecoderConfig decoderConfig

  def boolean hasExpectations

  def RestAssuredConfig config

  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();
    content = string
    println string
    string
  }

  String prettyPrint(ResponseOptions responseOptions, ResponseBody responseBody) {
    def body = new Prettifier().getPrettifiedBodyIfPossible(responseOptions, responseBody)
    content = body
    println body
    body
  }

  def peek(ResponseOptions responseOptions, ResponseBody responseBody) {
    ResponsePrinter.print(responseOptions, responseBody, System.out, LogDetail.ALL, false);
  }

  def prettyPeek(ResponseOptions responseOptions, ResponseBody responseBody) {
    ResponsePrinter.print(responseOptions, responseBody, System.out, LogDetail.ALL, true);
  }

  String asString() {
    asString(false)
  }

  def String asString(boolean forcePlatformDefaultCharsetIfNoCharsetIsSpecifiedInResponse) {
    charsetToString(findCharset(forcePlatformDefaultCharsetIfNoCharsetIsSpecifiedInResponse))
  }

  def boolean isInputStream() {
    content instanceof InputStream
  }

  InputStream asInputStream() {
    if (content == null || content instanceof InputStream) {
      new CloseHTTPClientConnectionInputStreamWrapper(config.getConnectionConfig(), connectionManager, content)
    } else {
      content instanceof String ? new ByteArrayInputStream(convertStringToByteArray(content)) : new ByteArrayInputStream(content)
    }
  }

  def byte[] convertStringToByteArray(string) {
    string.getBytes(findCharset())
  }

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

  def  T "as"(Type cls, ResponseBodyData responseBodyData) {
    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(responseBodyData, cls, contentTypeToChose, defaultContentType, charset, null, config.getObjectMapperConfig())
  }

  def  T "as"(Type cls, ObjectMapperType mapperType, ResponseBodyData responseBodyData) {
    notNull mapperType, "Object mapper type"
    def charset = findCharset()
    return ObjectMapping.deserialize(responseBodyData, cls, null, defaultContentType, charset, mapperType, config.getObjectMapperConfig())
  }

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

  def String findCharset() {
    return findCharset(false)
  }

  def String findCharset(boolean forcePlatformDefaultCharsetIfNoCharsetIsSpecifiedInResponse) {
    String charset = CharsetExtractor.getCharsetFromContentType(isBlank(contentType) ? defaultContentType : contentType)

    if (charset == null || charset.trim().equals("")) {
      if (decoderConfig == null || forcePlatformDefaultCharsetIfNoCharsetIsSpecifiedInResponse) {
        return Charset.defaultCharset().toString()
      } else {
        charset = decoderConfig.defaultCharsetForContentType(contentType)
      }
    }

    if (StringUtils.equalsIgnoreCase(charset, BINARY)) {
      charset = decoderConfig.defaultCharsetForContentType(contentType)
    }

    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)
  }

  Headers headers() {
    return responseHeaders ?: new Headers()
  }

  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
  }

  ResponseParserRegistrar getRpr() {
    return rpr
  }

  RestAssuredConfig getConfig() {
    return config
  }

  String getContentType() {
    return contentType
  }

  String statusLine() {
    return statusLine
  }

  int statusCode() {
    return statusCode ?: -1
  }

  String getStatusLine() {
    return statusLine()
  }

  String sessionId() {
    return getSessionId()
  }

  String getSessionId() {
    return cookie(sessionIdName)
  }

  int getStatusCode() {
    return statusCode()
  }

  JsonPath jsonPath() {
    jsonPath(jsonPathConfig().charset(findCharset()).
            jackson1ObjectMapperFactory(config.getObjectMapperConfig().jackson1ObjectMapperFactory()).
            jackson2ObjectMapperFactory(config.getObjectMapperConfig().jackson2ObjectMapperFactory()).
            gsonObjectMapperFactory(config.getObjectMapperConfig().gsonObjectMapperFactory()).
            numberReturnType(config.getJsonConfig().numberReturnType()));
  }

  JsonPath jsonPath(JsonPathConfig config) {
    notNull(config, "JsonPathConfig")
    new JsonPath(asString()).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, String... arguments) {
    notNull path, "Path"
    if (arguments?.length > 0) {
      path = String.format(path, arguments);
    }
    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.")
  }


  def long time() {
    if (filterContextProperties?.containsKey(TimingFilter.RESPONSE_TIME_MILLISECONDS)) {
      filterContextProperties.get(TimingFilter.RESPONSE_TIME_MILLISECONDS)
    } else {
      NO_RESPONSE_TIME
    }
  }

  def long timeIn(TimeUnit timeUnit) {
    notNull timeUnit, TimeUnit.class
    def time = time()
    if (time != NO_RESPONSE_TIME && timeUnit != TimeUnit.MILLISECONDS) {
      time = timeUnit.convert(time, TimeUnit.MILLISECONDS)
    }
    time
  }

  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 static 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.hasCustomParserExcludingDefaultParser(contentType)) {
      contentTypeToChose = rpr.getNonDefaultParser(contentType).contentType
    } else {
      contentTypeToChose = contentType
    }
    return contentTypeToChose
  }

  private def newXmlPath(CompatibilityMode xml) {
    newXmlPath(xml, xmlPathConfig().charset(findCharset()).
            features(config.getXmlConfig().features()).
            properties(config.getXmlConfig().properties()).
            declareNamespaces(config.getXmlConfig().declaredNamespaces()).
            jaxbObjectMapperFactory(config.getObjectMapperConfig().jaxbObjectMapperFactory()))
  }

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

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

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

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

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

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy