/* * Copyright (c) LinkedIn Corporation. All rights reserved. Licensed under the BSD-2 Clause license. * See LICENSE in the project root for license information. */ package com.linkedin.flashback.netty.mapper; import com.google.common.base.Splitter; import com.linkedin.flashback.serializable.RecordedHttpResponse; import io.netty.buffer.ByteBuf; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import java.io.IOException; import java.util.Base64; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import static io.netty.buffer.Unpooled.*; import static io.netty.handler.codec.http.HttpVersion.*; /** * Mapper from RecordedHttpResponse to Netty HttpResponse * * @author shfeng. */ public final class NettyHttpResponseMapper { public static final String SET_COOKIE = "Set-Cookie"; private NettyHttpResponseMapper() { } public static FullHttpResponse from(RecordedHttpResponse recordedHttpResponse) throws IOException { FullHttpResponse fullHttpResponse; HttpResponseStatus status = HttpResponseStatus.valueOf(recordedHttpResponse.getStatus()); if (recordedHttpResponse.hasHttpBody()) { ByteBuf content = wrappedBuffer(createHttpBodyBytes(recordedHttpResponse)); fullHttpResponse = new DefaultFullHttpResponse(HTTP_1_1, status, content); } else { fullHttpResponse = new DefaultFullHttpResponse(HTTP_1_1, status); } for (Map.Entry<String, String> header : recordedHttpResponse.getHeaders().entrySet()) { // Set-Cookie headers might contains something like "Expires=Thu, 23-Mar-2017 18:01:20 GMT; Path=/" // It's hard to find special character to split them properly. However, we don't want encode other // headers becaus we don't want lose readability in the flashback.scene so let's handle Set-Cookie header // differently if (SET_COOKIE.equals(header.getKey())) { fullHttpResponse.headers() .set(header.getKey(), StreamSupport.stream(Splitter.onPattern(",\\s*").split(header.getValue()).spliterator(), false) .map(p -> new String(Base64.getDecoder().decode(p.getBytes()))) .collect(Collectors.toList())); } else { fullHttpResponse.headers().set(header.getKey(), Splitter.onPattern(",\\s*").split(header.getValue())); } } return fullHttpResponse; } private static byte[] createHttpBodyBytes(RecordedHttpResponse recordedHttpResponse) throws IOException { return recordedHttpResponse.getHttpBody().getContent(recordedHttpResponse.getCharset()); } }