下面列出了 io.netty.handler.codec.http.HttpResponse # status ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
protected void sanitizeHeadersBeforeEncode(HttpResponse msg, boolean isAlwaysEmpty) {
if (isAlwaysEmpty) {
HttpResponseStatus status = msg.status();
if (status.codeClass() == HttpStatusClass.INFORMATIONAL
|| status.code() == HttpResponseStatus.NO_CONTENT.code()) {
// Stripping Content-Length:
// See https://tools.ietf.org/html/rfc7230#section-3.3.2
msg.headers().remove(HttpHeaderNames.CONTENT_LENGTH);
// Stripping Transfer-Encoding:
// See https://tools.ietf.org/html/rfc7230#section-3.3.1
msg.headers().remove(HttpHeaderNames.TRANSFER_ENCODING);
} else if (status.code() == HttpResponseStatus.RESET_CONTENT.code()) {
// Stripping Transfer-Encoding:
msg.headers().remove(HttpHeaderNames.TRANSFER_ENCODING);
// Set Content-Length: 0
// https://httpstatuses.com/205
msg.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, 0);
}
}
}
@Override
protected boolean isContentAlwaysEmpty(HttpResponse msg) {
// Correctly handle special cases as stated in:
// https://tools.ietf.org/html/rfc7230#section-3.3.3
HttpResponseStatus status = msg.status();
if (status.codeClass() == HttpStatusClass.INFORMATIONAL) {
if (status.code() == HttpResponseStatus.SWITCHING_PROTOCOLS.code()) {
// We need special handling for WebSockets version 00 as it will include an body.
// Fortunally this version should not really be used in the wild very often.
// See https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-1.2
return msg.headers().contains(HttpHeaderNames.SEC_WEBSOCKET_VERSION);
}
return true;
}
return status.code() == HttpResponseStatus.NO_CONTENT.code()
|| status.code() == HttpResponseStatus.NOT_MODIFIED.code()
|| status.code() == HttpResponseStatus.RESET_CONTENT.code();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg;
HttpResponseStatus status = response.status();
this.httpCode = status.code();
}
if (msg instanceof HttpContent) {
buffer.append(((HttpContent) msg).content().toString(StandardCharsets.UTF_8));
if (msg instanceof LastHttpContent) {
ctx.close();
reply.complete(new SimpleHttpResponse(httpCode, buffer.toString()));
}
}
} finally {
ReferenceCountUtil.release(msg);
}
}
@Nullable
@Override
public Integer getResponseHttpStatus(@Nullable HttpResponse response) {
if (response == null) {
return null;
}
HttpResponseStatus statusObj = response.status();
if (statusObj == null) {
return null;
}
return statusObj.code();
}
@Override
@SuppressWarnings("FutureReturnValueIgnored")
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
if (msg instanceof HttpResponse) {
final HttpResponse response = (HttpResponse) msg;
final HttpResponseStatus status = response.status();
if (status.equals(HttpResponseStatus.CONTINUE)) {
//"FutureReturnValueIgnored" this is deliberate
ctx.write(msg, promise);
return;
}
final boolean chunked = HttpUtil.isTransferEncodingChunked(response);
accessLog.status(status.codeAsText())
.chunked(chunked);
if (!chunked) {
accessLog.contentLength(HttpUtil.getContentLength(response, -1));
}
}
if (msg instanceof LastHttpContent) {
accessLog.increaseContentLength(((LastHttpContent) msg).content().readableBytes());
ctx.write(msg, promise.unvoid())
.addListener(future -> {
if (future.isSuccess()) {
accessLog.log();
}
});
return;
}
if (msg instanceof ByteBuf) {
accessLog.increaseContentLength(((ByteBuf) msg).readableBytes());
}
if (msg instanceof ByteBufHolder) {
accessLog.increaseContentLength(((ByteBufHolder) msg).content().readableBytes());
}
//"FutureReturnValueIgnored" this is deliberate
ctx.write(msg, promise);
}
/**
* Writes response metadata to the channel if not already written previously and channel is active.
* @param responseMetadata the {@link HttpResponse} that needs to be written.
* @param listener the {@link GenericFutureListener} that needs to be attached to the write.
* @return {@code true} if response metadata was written to the channel in this call. {@code false} otherwise.
*/
private boolean maybeWriteResponseMetadata(HttpResponse responseMetadata,
GenericFutureListener<ChannelFuture> listener) {
long writeProcessingStartTime = System.currentTimeMillis();
boolean writtenThisTime = false;
if (ctx.channel().isActive() && responseMetadataWriteInitiated.compareAndSet(false, true)) {
// we do some manipulation here for chunking. According to the HTTP spec, we can have either a Content-Length
// or Transfer-Encoding:chunked, never both. So we check for Content-Length - if it is not there, we add
// Transfer-Encoding:chunked on 200 response. Note that sending HttpContent chunks data anyway - we are just
// explicitly specifying this in the header.
if (!HttpUtil.isContentLengthSet(responseMetadata) && (responseMetadata.status().equals(HttpResponseStatus.OK)
|| responseMetadata.status().equals(HttpResponseStatus.PARTIAL_CONTENT))) {
// This makes sure that we don't stomp on any existing transfer-encoding.
HttpUtil.setTransferEncodingChunked(responseMetadata, true);
} else if (HttpUtil.isContentLengthSet(responseMetadata) && HttpUtil.getContentLength(responseMetadata) == 0
&& !(responseMetadata instanceof FullHttpResponse)) {
// if the Content-Length is 0, we can send a FullHttpResponse since there is no content expected.
FullHttpResponse fullHttpResponse =
new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseMetadata.status());
fullHttpResponse.headers().set(responseMetadata.headers());
responseMetadata = fullHttpResponse;
}
logger.trace("Sending response with status {} on channel {}", responseMetadata.status(), ctx.channel());
finalResponseMetadata = responseMetadata;
ChannelPromise writePromise = ctx.newPromise().addListener(listener);
ctx.writeAndFlush(responseMetadata, writePromise);
writtenThisTime = true;
long writeProcessingTime = System.currentTimeMillis() - writeProcessingStartTime;
nettyMetrics.responseMetadataProcessingTimeInMs.update(writeProcessingTime);
if (request != null) {
request.getMetricsTracker().nioMetricsTracker.markFirstByteSent();
}
}
return writtenThisTime;
}
/**
* @param request
* The request to log; will not be null. This is the request that came into the application. WARNING: The
* content may have been released already, so you cannot rely on any of the methods that return the payload
* content in any form.
* @param finalResponseObject
* The {@link HttpResponse} that was the actual final response object sent to the client; may be null. NOTE:
* This should be preferred over {@code responseInfo} whenever both have overlapping data since this argument
* may have been modified by outbound handlers after being initially populated by {@code responseInfo}.
* @param responseInfo
* {@link com.nike.riposte.server.http.ResponseInfo} object that was initially used to build {@code
* finalResponseObject}; may be null. NOTE: {@code finalResponseObject} may have been modified by other outbound
* handlers (e.g. compression/gzip), so if it is non-null it should be preferred over this where possible.
*
* @return String representing the NCSA Combined log format for access logs plus the referrer and user agent: %h %l
* %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}"
*/
protected @NotNull String combinedLogFormatPrefix(
@NotNull RequestInfo<?> request,
@Nullable HttpResponse finalResponseObject,
@Nullable ResponseInfo responseInfo
) {
String ipAddress = "<unknown>";
try {
ipAddress = getLocalIpAddress();
}
catch (UnknownHostException ex) {
logger.warn("Unable to retrieve local IP address.", ex);
}
String method = (request.getMethod() == null) ? "-" : String.valueOf(request.getMethod());
String uriString = request.getUri();
//noinspection ConstantConditions
if (uriString == null) {
uriString = "-";
}
String protocolVersion = (request.getProtocolVersion() == null)
? "-"
: String.valueOf(request.getProtocolVersion());
String url = method + " " + uriString + " " + protocolVersion;
String referer = "-";
String userAgent = "-";
//noinspection ConstantConditions
if (request.getHeaders() != null) {
referer = request.getHeaders().get(REFERER);
if (referer == null) {
referer = "-";
}
userAgent = request.getHeaders().get(USER_AGENT);
if (userAgent == null) {
userAgent = "-";
}
}
String httpStatusCode = "-";
if (finalResponseObject != null && finalResponseObject.status() != null) {
httpStatusCode = String.valueOf(finalResponseObject.status().code());
}
else if (responseInfo != null && responseInfo.getHttpStatusCode() != null) {
httpStatusCode = String.valueOf(responseInfo.getHttpStatusCode());
}
String contentLength = "-";
if (responseInfo != null) {
if (responseInfo.getFinalContentLength() != null && responseInfo.getFinalContentLength() > 0) {
contentLength = String.valueOf(responseInfo.getFinalContentLength());
}
}
return ipAddress +
" - - [" + // remote log name and remote user
getFormattedDateTimeForNcsaCombinedLog(ZonedDateTime.now()) +
"] \"" +
url +
"\" " +
httpStatusCode +
" " +
contentLength +
" \"" +
referer +
"\" \"" +
userAgent +
"\"";
}