package com.ctriposs.baiji.rpc.server.netty; import com.ctriposs.baiji.rpc.server.HttpResponseWrapper; import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.*; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH; class NettyHttpResponseWrapper implements HttpResponseWrapper { private final ChannelHandlerContext _context; private final FullHttpRequest _request; private final Map<String, String> _headers = new HashMap<String, String>(); private ByteBuf _contentBuffer; private OutputStream _responseStream; private int _status = 200; private boolean _responseSent; NettyHttpResponseWrapper(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) { _context = channelHandlerContext; _request = fullHttpRequest; } @Override public void setHeader(String name, String value) { Preconditions.checkState(!_responseSent, "Header can't be updated after response is sent."); _headers.put(name, value); } @Override public void setStatus(int status) { Preconditions.checkState(!_responseSent, "HTTP status can't be updated after response is sent."); _status = status; } @Override public OutputStream getResponseStream() throws IOException { Preconditions.checkState(!_responseSent, "No data can be written into response stream after response is sent."); if (_responseStream == null) { _contentBuffer = _context.alloc().buffer(); _responseStream = new ByteBufOutputStream(_contentBuffer); } return _responseStream; } @Override public void sendResponse() { ByteBuf content = _contentBuffer; if (content == null) { content = Unpooled.buffer(0); } FullHttpResponse response = new DefaultFullHttpResponse(_request.getProtocolVersion(), HttpResponseStatus.valueOf(_status), content); boolean keepAlive = HttpHeaders.isKeepAlive(_request); if (keepAlive) { response.headers().set(CONTENT_LENGTH, response.content().readableBytes()); response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } for (Map.Entry<String, String> header : _headers.entrySet()) { response.headers().set(header.getKey(), header.getValue()); } ChannelFuture writeFuture = _context.write(response); if (!keepAlive) { writeFuture.addListener(ChannelFutureListener.CLOSE); } } }