Java tutorial
/* * Copyright 2013 The Http Server & Proxy * * The Http Server & Proxy Project licenses this file to you under the Apache License, version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. * See the License for the specific language governing permissions and limitations under the License. */ package com.sohail.alam.http.common.utils; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultHttpResponse; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import java.util.HashMap; import java.util.Map; import static com.sohail.alam.http.common.LoggerManager.LOGGER; import static com.sohail.alam.http.common.utils.LocalFileFetcher.FETCHER; import static com.sohail.alam.http.server.ServerProperties.PROP; import static io.netty.buffer.Unpooled.copiedBuffer; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpResponseStatus.*; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; /** * User: Sohail Alam * Version: 1.0.0 * Date: 22/9/13 * Time: 11:06 PM */ public class HttpResponseSender { /** * Send channel future. * * @param ctx the ctx * @param status the status * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send(ChannelHandlerContext ctx, HttpResponseStatus status, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { final HttpResponse response; // Create the headers map if null if (headersMap == null) { headersMap = new HashMap<String, String>(); } // If data is not null then add content length header and send Full Http Response if (data != null) { ByteBuf dataBuffer = copiedBuffer(data); response = new DefaultFullHttpResponse(HTTP_1_1, status, dataBuffer); // If no content length is supplied then calculate it and add it if (headersMap.get(CONTENT_LENGTH) == null) { headersMap.put(CONTENT_LENGTH, String.valueOf(data.length)); } } // If data is null then add content length header to 0 else { response = new DefaultHttpResponse(HTTP_1_1, status); headersMap.put(CONTENT_LENGTH, String.valueOf(0)); } // Iterate all headers from map and set response headers for (String header : headersMap.keySet()) { response.headers().set(header, headersMap.get(header)); } // Send the response ChannelFuture future = ctx.channel().write(response); // Use default future listener if needed if (useDefaultListener) { future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { LOGGER.debug("Response sent successfully:\n{}", response); } else { LOGGER.debug("FAILED TO SEND RESPONSE!!\n{}", response); } } }); } return future; } /** * Check before send. * * @param ctx the ctx * @param status the status * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * @param defaultMessage the default message * * @return the channel future */ private static ChannelFuture checkBeforeSend(ChannelHandlerContext ctx, HttpResponseStatus status, Map<String, String> headersMap, byte[] data, boolean useDefaultListener, String defaultMessage) { if (data == null) { return send(ctx, status, headersMap, defaultMessage.getBytes(), useDefaultListener); } else { return send(ctx, status, headersMap, data, useDefaultListener); } } /** * Send 200 oK. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send200OK(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return send(ctx, OK, headersMap, data, useDefaultListener); } /** * Send 400 bad request. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send400BadRequest(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return checkBeforeSend(ctx, BAD_REQUEST, headersMap, data, useDefaultListener, "BAD REQUEST"); } /** * Send 401 unauthorized. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send401Unauthorized(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return checkBeforeSend(ctx, UNAUTHORIZED, headersMap, data, useDefaultListener, "UNAUTHORIZED"); } /** * Send 403 forbidden. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send403Forbidden(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return checkBeforeSend(ctx, FORBIDDEN, headersMap, data, useDefaultListener, "FORBIDDEN"); } /** * Send 404 not found. * If the data is null then this method automatically takes care of * sending a default 404 Page if configured and found, * otherwise sends a custom message. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send404NotFound(final ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { final Map<String, String> headers = new HashMap<String, String>(); // If data is null then try to send the default 404 Page if (data == null) { FETCHER.fetch(PROP.DEFAULT_404_PAGE, new LocalFileFetcherCallback() { // Send the default 404 Page if found @Override public void fetchSuccess(String path, byte[] data, String mediaType, long dataLength) { headers.put(CONTENT_TYPE, mediaType); headers.put(CONTENT_LENGTH, String.valueOf(dataLength)); // Send data as 404 Not Found send404NotFound(ctx, headers, data, true); } // Otherwise send a 404 NOT FOUND message @Override public void fileNotFound(String path, Throwable cause) { headers.put(CONTENT_TYPE, MediaType.getType(".html")); send404NotFound(ctx, headers, "404 NOT FOUND".getBytes(), true); } @Override public void exceptionCaught(String path, Throwable cause) { headers.put(CONTENT_TYPE, MediaType.getType(".html")); send404NotFound(ctx, headers, "404 NOT FOUND".getBytes(), true); } }); } return send(ctx, NOT_FOUND, headersMap, data, useDefaultListener); } /** * Send 405 method not allowed. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send405MethodNotAllowed(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return checkBeforeSend(ctx, METHOD_NOT_ALLOWED, headersMap, data, useDefaultListener, "METHOD NOT ALLOWED"); } /** * Send 407 proxy authentication required. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send407ProxyAuthenticationRequired(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return checkBeforeSend(ctx, PROXY_AUTHENTICATION_REQUIRED, headersMap, data, useDefaultListener, "PROXY AUTHENTICATION REQUIRED"); } /** * Send 408 request timeout. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send408RequestTimeout(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return checkBeforeSend(ctx, REQUEST_TIMEOUT, headersMap, data, useDefaultListener, "REQUEST TIMEOUT"); } /** * Send 500 internal server error. * * @param ctx the ctx * @param headersMap the headers map * @param data the data * @param useDefaultListener use default listener * * @return the channel future */ public static ChannelFuture send500InternalServerError(ChannelHandlerContext ctx, Map<String, String> headersMap, byte[] data, boolean useDefaultListener) { return checkBeforeSend(ctx, INTERNAL_SERVER_ERROR, headersMap, data, useDefaultListener, "INTERNAL SERVER ERROR"); } }