001/** 002 * Copyright (C) 2006-2019 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 062 .getOrDefault("Content-Encoding", emptyList()) 063 .stream() 064 .anyMatch(it -> it.contains("gzip"))) { 065 responseModel.setPayload(new String(degzip(resp.payload()), StandardCharsets.UTF_8)); 066 } else { 067 responseModel.setPayload(new String(resp.payload(), StandardCharsets.UTF_8)); 068 } 069 } 070 model.setResponse(responseModel); 071 072 if (DefaultResponseLocator.class.isInstance(api.getResponseLocator())) { 073 DefaultResponseLocator.class.cast(api.getResponseLocator()).addModel(model); 074 } 075 } 076 077 private byte[] degzip(final byte[] payloadBytes) { 078 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 079 final byte[] bytes = new byte[1024 * 8]; 080 int read; 081 try (final InputStream stream = new GZIPInputStream(new ByteArrayInputStream(payloadBytes))) { 082 while ((read = stream.read(bytes)) >= 0) { 083 if (read == 0) { 084 continue; 085 } 086 out.write(bytes, 0, read); 087 } 088 } catch (final IOException e) { 089 throw new IllegalStateException(e); 090 } 091 return out.toByteArray(); 092 } 093 094 private Map<String, String> filterHeaders(final Iterable<Map.Entry<String, String>> headers) { 095 return StreamSupport 096 .stream(headers.spliterator(), false) 097 .filter(h -> !api.getHeaderFilter().test(h.getKey())) 098 .sorted(comparing(Map.Entry::getKey)) 099 .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); 100 } 101}