001/** 002 * Copyright (C) 2006-2018 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.junit.http.internal.impl; 017 018import static java.util.Collections.emptyList; 019import static java.util.Comparator.comparing; 020import static java.util.stream.Collectors.toMap; 021 022import java.io.ByteArrayInputStream; 023import java.io.ByteArrayOutputStream; 024import java.io.IOException; 025import java.io.InputStream; 026import java.nio.charset.StandardCharsets; 027import java.util.List; 028import java.util.Map; 029import java.util.stream.StreamSupport; 030import java.util.zip.GZIPInputStream; 031 032import org.talend.sdk.component.junit.http.api.HttpApiHandler; 033import org.talend.sdk.component.junit.http.api.Response; 034 035import io.netty.handler.codec.http.FullHttpRequest; 036 037import lombok.extern.slf4j.Slf4j; 038 039@Slf4j 040public class DefaultResponseLocatorCapturingHandler extends PassthroughHandler { 041 042 public DefaultResponseLocatorCapturingHandler(final HttpApiHandler api) { 043 super(api); 044 } 045 046 @Override 047 protected void beforeResponse(final String requestUri, final FullHttpRequest request, final Response resp, 048 final Map<String, List<String>> responseHeaderFields) { 049 final DefaultResponseLocator.RequestModel requestModel = new DefaultResponseLocator.RequestModel(); 050 requestModel.setMethod(request.method().name()); 051 requestModel.setUri(requestUri); 052 requestModel.setHeaders(filterHeaders(request.headers())); 053 final DefaultResponseLocator.Model model = new DefaultResponseLocator.Model(); 054 model.setRequest(requestModel); 055 056 final DefaultResponseLocator.ResponseModel responseModel = new DefaultResponseLocator.ResponseModel(); 057 responseModel.setStatus(resp.status()); 058 responseModel.setHeaders(filterHeaders(resp.headers().entrySet())); 059 // todo: support as byte[] for not text responses 060 if (resp.payload() != null) { 061 if (responseHeaderFields.getOrDefault("Content-Encoding", emptyList()).stream().anyMatch( 062 it -> it.contains("gzip"))) { 063 responseModel.setPayload(new String(degzip(resp.payload()), StandardCharsets.UTF_8)); 064 } else { 065 responseModel.setPayload(new String(resp.payload(), StandardCharsets.UTF_8)); 066 } 067 } 068 model.setResponse(responseModel); 069 070 if (DefaultResponseLocator.class.isInstance(api.getResponseLocator())) { 071 DefaultResponseLocator.class.cast(api.getResponseLocator()).addModel(model); 072 } 073 } 074 075 private byte[] degzip(final byte[] payloadBytes) { 076 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 077 final byte[] bytes = new byte[1024 * 8]; 078 int read; 079 try (final InputStream stream = new GZIPInputStream(new ByteArrayInputStream(payloadBytes))) { 080 while ((read = stream.read(bytes)) >= 0) { 081 if (read == 0) { 082 continue; 083 } 084 out.write(bytes, 0, read); 085 } 086 } catch (final IOException e) { 087 throw new IllegalStateException(e); 088 } 089 return out.toByteArray(); 090 } 091 092 private Map<String, String> filterHeaders(final Iterable<Map.Entry<String, String>> headers) { 093 return StreamSupport 094 .stream(headers.spliterator(), false) 095 .filter(h -> !api.getHeaderFilter().test(h.getKey())) 096 .sorted(comparing(Map.Entry::getKey)) 097 .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); 098 } 099}