/** * This file is part of Waarp Project. * * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the * COPYRIGHT.txt in the distribution for a full listing of individual contributors. * * All Waarp Project is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with Waarp . If not, see * <http://www.gnu.org/licenses/>. */ package org.waarp.openr66.protocol.http; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.handler.codec.http.cookie.Cookie; import io.netty.handler.codec.http.cookie.DefaultCookie; import io.netty.handler.codec.http.cookie.ServerCookieDecoder; import io.netty.handler.codec.http.cookie.ServerCookieEncoder; import io.netty.handler.traffic.TrafficCounter; import org.waarp.common.database.DbAdmin; import org.waarp.common.database.DbPreparedStatement; import org.waarp.common.database.DbSession; import org.waarp.common.database.data.AbstractDbData.UpdatedInfo; import org.waarp.common.database.exception.WaarpDatabaseException; import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException; import org.waarp.common.database.exception.WaarpDatabaseSqlException; import org.waarp.common.exception.FileTransferException; import org.waarp.common.exception.InvalidArgumentException; import org.waarp.common.logging.WaarpLogger; import org.waarp.common.logging.WaarpLoggerFactory; import org.waarp.common.utility.WaarpStringUtils; import org.waarp.gateway.kernel.http.HttpWriteCacheEnable; import org.waarp.openr66.context.ErrorCode; import org.waarp.openr66.context.R66Session; import org.waarp.openr66.context.task.SpooledInformTask; import org.waarp.openr66.database.DbConstant; import org.waarp.openr66.database.data.DbTaskRunner; import org.waarp.openr66.database.data.DbTaskRunner.TASKSTEP; import org.waarp.openr66.protocol.configuration.Configuration; import org.waarp.openr66.protocol.configuration.Messages; import org.waarp.openr66.protocol.exception.OpenR66Exception; import org.waarp.openr66.protocol.exception.OpenR66ExceptionTrappedFactory; import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessNoWriteBackException; import org.waarp.openr66.protocol.localhandler.LocalChannelReference; /** * Handler for HTTP information support * * @author Frederic Bregier * */ public class HttpFormattedHandler extends SimpleChannelInboundHandler<FullHttpRequest> { /** * Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory .getLogger(HttpFormattedHandler.class); private static enum REQUEST { index("index.html"), active("monitoring_header.html", "monitoring_end.html"), error("monitoring_header.html", "monitoring_end.html"), done("monitoring_header.html", "monitoring_end.html"), all("monitoring_header.html", "monitoring_end.html"), status("monitoring_header.html", "monitoring_end.html"), statusxml(""), statusjson(""); private String header; private String end; /** * Constructor for a unique file * * @param uniquefile */ private REQUEST(String uniquefile) { this.header = uniquefile; this.end = uniquefile; } /** * @param header * @param end */ private REQUEST(String header, String end) { this.header = header; this.end = end; } /** * Reader for a unique file * * @return the content of the unique file */ public String readFileUnique(HttpFormattedHandler handler) { return handler.readFileHeader(Configuration.configuration.getHttpBasePath() + "monitor/" + this.header); } public String readHeader(HttpFormattedHandler handler) { return handler.readFileHeader(Configuration.configuration.getHttpBasePath() + "monitor/" + this.header); } public String readEnd() { return WaarpStringUtils.readFile(Configuration.configuration.getHttpBasePath() + "monitor/" + this.end); } } private static enum REPLACEMENT { XXXHOSTIDXXX, XXXLOCACTIVEXXX, XXXNETACTIVEXXX, XXXBANDWIDTHXXX, XXXDATEXXX, XXXLANGXXX; } public static final int LIMITROW = 60; // better if it can be divided by 4 private static final String I18NEXT = "i18next"; private final R66Session authentHttp = new R66Session(); private String lang = Messages.getSlocale(); private FullHttpRequest request; private final StringBuilder responseContent = new StringBuilder(); private HttpResponseStatus status; private String uriRequest; private static final String sINFO = "INFO", sNB = "NB", sDETAIL = "DETAIL"; /** * The Database connection attached to this NetworkChannelReference shared among all associated * LocalChannels */ private DbSession dbSession = DbConstant.admin.getSession(); /** * Does this dbSession is private and so should be closed */ private boolean isPrivateDbSession = false; private boolean isCurrentRequestXml = false; private boolean isCurrentRequestJson = false; private Map<String, List<String>> params = null; private String readFileHeader(String filename) { String value; try { value = WaarpStringUtils.readFileException(filename); } catch (InvalidArgumentException e) { logger.error("Error while trying to open: " + filename, e); return ""; } catch (FileTransferException e) { logger.error("Error while trying to read: " + filename, e); return ""; } StringBuilder builder = new StringBuilder(value); WaarpStringUtils.replace(builder, REPLACEMENT.XXXDATEXXX.toString(), (new Date()).toString()); WaarpStringUtils.replace(builder, REPLACEMENT.XXXLOCACTIVEXXX.toString(), Integer.toString( Configuration.configuration.getLocalTransaction(). getNumberLocalChannel())); WaarpStringUtils.replace(builder, REPLACEMENT.XXXNETACTIVEXXX.toString(), Integer.toString( DbAdmin.getNbConnection())); WaarpStringUtils.replace(builder, REPLACEMENT.XXXHOSTIDXXX.toString(), Configuration.configuration.getHOST_ID()); TrafficCounter trafficCounter = Configuration.configuration.getGlobalTrafficShapingHandler().trafficCounter(); WaarpStringUtils.replace(builder, REPLACEMENT.XXXBANDWIDTHXXX.toString(), "IN:" + (trafficCounter.lastReadThroughput() / 131072) + "Mbits  OUT:" + (trafficCounter.lastWriteThroughput() / 131072) + "Mbits"); WaarpStringUtils.replace(builder, REPLACEMENT.XXXLANGXXX.toString(), lang); return builder.toString(); } private String getTrimValue(String varname) { String value = null; try { value = params.get(varname).get(0).trim(); } catch (NullPointerException e) { return null; } if (value.isEmpty()) { value = null; } return value; } @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { isCurrentRequestXml = false; isCurrentRequestJson = false; status = HttpResponseStatus.OK; FullHttpRequest request = this.request = msg; QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri()); uriRequest = queryStringDecoder.path(); logger.debug("Msg: " + uriRequest); if (uriRequest.contains("gre/") || uriRequest.contains("img/") || uriRequest.contains("res/") || uriRequest.contains("favicon.ico")) { HttpWriteCacheEnable.writeFile(request, ctx, Configuration.configuration.getHttpBasePath() + uriRequest, "XYZR66NOSESSION"); return; } /*try { if (DbConstant.admin.isActive) { this.dbSession = new DbSession(DbConstant.admin, false); DbAdmin.nbHttpSession++; this.isPrivateDbSession = true; } } catch (WaarpDatabaseNoConnectionException e1) { // Cannot connect so use default connection logger.warn("Use default database connection"); this.dbSession = DbConstant.admin.session; }*/ try { char cval = 'z'; long nb = LIMITROW; // check the URI if (uriRequest.equalsIgnoreCase("/active")) { cval = '0'; } else if (uriRequest.equalsIgnoreCase("/error")) { cval = '1'; } else if (uriRequest.equalsIgnoreCase("/done")) { cval = '2'; } else if (uriRequest.equalsIgnoreCase("/all")) { cval = '3'; } else if (uriRequest.equalsIgnoreCase("/status")) { cval = '4'; } else if (uriRequest.equalsIgnoreCase("/statusxml")) { cval = '5'; nb = 0; // since it could be the default or setup by request isCurrentRequestXml = true; } else if (uriRequest.toLowerCase().startsWith("/spooled")) { cval = '6'; } else if (uriRequest.equalsIgnoreCase("/statusjson")) { cval = '7'; nb = 0; // since it could be the default or setup by request isCurrentRequestJson = true; } // Get the params according to get or post if (request.method() == HttpMethod.GET) { params = queryStringDecoder.parameters(); } else if (request.method() == HttpMethod.POST) { ByteBuf content = request.content(); if (content.isReadable()) { String param = content.toString(WaarpStringUtils.UTF8); queryStringDecoder = new QueryStringDecoder("/?" + param); } else { responseContent.append(REQUEST.index.readFileUnique(this)); writeResponse(ctx); return; } params = queryStringDecoder.parameters(); } boolean getMenu = (cval == 'z'); boolean extraBoolean = false; if (!params.isEmpty()) { // if not uri, from get or post if (getMenu) { String info = getTrimValue(sINFO); if (info != null) { getMenu = false; cval = info.charAt(0); } else { getMenu = true; } } // search the nb param String snb = getTrimValue(sNB); if (snb != null) { try { nb = Long.parseLong(snb); } catch (Exception e1) { } } // search the detail param String sdetail = getTrimValue(sDETAIL); if (sdetail != null) { try { if (Integer.parseInt(sdetail) > 0) { extraBoolean = true; } } catch (Exception e1) { } } String langarg = getTrimValue("setLng"); if (langarg != null && !langarg.isEmpty()) { lang = langarg; } } if (getMenu) { responseContent.append(REQUEST.index.readFileUnique(this)); } else { // Use value 0=Active 1=Error 2=Done 3=All switch (cval) { case '0': active(ctx, (int) nb); break; case '1': error(ctx, (int) nb); break; case '2': done(ctx, (int) nb); break; case '3': all(ctx, (int) nb); break; case '4': status(ctx, (int) nb); break; case '5': statusxml(ctx, nb, extraBoolean); break; case '6': String name = null; if (params.containsKey("name")) { name = getTrimValue("name"); } int istatus = 0; if (params.containsKey("status")) { String status = getTrimValue("status"); try { istatus = Integer.parseInt(status); } catch (NumberFormatException e1) { istatus = 0; } } if (uriRequest.toLowerCase().startsWith("/spooleddetail")) { extraBoolean = true; } spooled(ctx, extraBoolean, name, istatus); break; case '7': statusjson(ctx, nb, extraBoolean); break; default: responseContent.append(REQUEST.index.readFileUnique(this)); } } writeResponse(ctx); } finally { if (this.isPrivateDbSession && dbSession != null) { dbSession.forceDisconnect(); DbAdmin.decHttpSession(); dbSession = null; } } } /** * Add all runners from preparedStatement for type * * @param preparedStatement * @param type * @param nb * @throws WaarpDatabaseNoConnectionException * @throws WaarpDatabaseSqlException */ private void addRunners(DbPreparedStatement preparedStatement, String type, int nb) throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException { try { preparedStatement.executeQuery(); responseContent .append("<style>td{font-size: 8pt;}</style><table border=\"2\">") .append("<tr><td>").append(type).append("</td>") .append(DbTaskRunner.headerHtml()).append("</tr>\r\n"); int i = 0; while (preparedStatement.getNext()) { DbTaskRunner taskRunner = DbTaskRunner .getFromStatement(preparedStatement); responseContent.append("<tr><td>").append(taskRunner.isSender() ? "S" : "R").append("</td>"); LocalChannelReference lcr = Configuration.configuration.getLocalTransaction(). getFromRequest(taskRunner.getKey()); responseContent.append( taskRunner.toHtml( getAuthentHttp(), lcr != null ? Messages.getString("HttpSslHandler.Active") : Messages .getString("HttpSslHandler.NotActive"))) .append("</tr>\r\n"); if (nb > 0) { i++; if (i >= nb) { break; } } } responseContent.append("</table><br>\r\n"); } finally { if (preparedStatement != null) { preparedStatement.realClose(); } } } /** * print all active transfers * * @param ctx * @param nb */ private void active(ChannelHandlerContext ctx, int nb) { responseContent.append(REQUEST.active.readHeader(this)); DbPreparedStatement preparedStatement = null; try { preparedStatement = DbTaskRunner.getStatusPrepareStatement(dbSession, ErrorCode.Running, nb); addRunners(preparedStatement, ErrorCode.Running.mesg, nb); preparedStatement = DbTaskRunner.getSelectFromInfoPrepareStatement( dbSession, UpdatedInfo.INTERRUPTED, true, nb); DbTaskRunner.finishSelectOrCountPrepareStatement(preparedStatement); addRunners(preparedStatement, UpdatedInfo.INTERRUPTED.name(), nb); preparedStatement = DbTaskRunner.getSelectFromInfoPrepareStatement( dbSession, UpdatedInfo.TOSUBMIT, true, nb); DbTaskRunner.finishSelectOrCountPrepareStatement(preparedStatement); addRunners(preparedStatement, UpdatedInfo.TOSUBMIT.name(), nb); preparedStatement = DbTaskRunner.getStatusPrepareStatement(dbSession, ErrorCode.InitOk, nb); addRunners(preparedStatement, ErrorCode.InitOk.mesg, nb); preparedStatement = DbTaskRunner.getStatusPrepareStatement(dbSession, ErrorCode.PreProcessingOk, nb); addRunners(preparedStatement, ErrorCode.PreProcessingOk.mesg, nb); preparedStatement = DbTaskRunner.getStatusPrepareStatement(dbSession, ErrorCode.TransferOk, nb); addRunners(preparedStatement, ErrorCode.TransferOk.mesg, nb); preparedStatement = DbTaskRunner.getStatusPrepareStatement(dbSession, ErrorCode.PostProcessingOk, nb); addRunners(preparedStatement, ErrorCode.PostProcessingOk.mesg, nb); preparedStatement = null; } catch (WaarpDatabaseException e) { if (preparedStatement != null) { preparedStatement.realClose(); } logger.warn("OpenR66 Web Error {}", e.getMessage()); sendError(ctx, HttpResponseStatus.SERVICE_UNAVAILABLE); return; } responseContent.append(REQUEST.active.readEnd()); } /** * print all transfers in error * * @param ctx * @param nb */ private void error(ChannelHandlerContext ctx, int nb) { responseContent.append(REQUEST.error.readHeader(this)); DbPreparedStatement preparedStatement = null; try { preparedStatement = DbTaskRunner.getSelectFromInfoPrepareStatement( dbSession, UpdatedInfo.INERROR, true, nb / 2); DbTaskRunner.finishSelectOrCountPrepareStatement(preparedStatement); addRunners(preparedStatement, UpdatedInfo.INERROR.name(), nb / 2); preparedStatement = DbTaskRunner.getSelectFromInfoPrepareStatement( dbSession, UpdatedInfo.INTERRUPTED, true, nb / 2); DbTaskRunner.finishSelectOrCountPrepareStatement(preparedStatement); addRunners(preparedStatement, UpdatedInfo.INTERRUPTED.name(), nb / 2); preparedStatement = DbTaskRunner.getStepPrepareStatement(dbSession, TASKSTEP.ERRORTASK, nb / 4); addRunners(preparedStatement, TASKSTEP.ERRORTASK.name(), nb / 4); } catch (WaarpDatabaseException e) { if (preparedStatement != null) { preparedStatement.realClose(); } logger.warn("OpenR66 Web Error {}", e.getMessage()); sendError(ctx, HttpResponseStatus.SERVICE_UNAVAILABLE); return; } responseContent.append(REQUEST.error.readEnd()); } /** * Print all done transfers * * @param ctx * @param nb */ private void done(ChannelHandlerContext ctx, int nb) { responseContent.append(REQUEST.done.readHeader(this)); DbPreparedStatement preparedStatement = null; try { preparedStatement = DbTaskRunner.getStatusPrepareStatement(dbSession, ErrorCode.CompleteOk, nb); addRunners(preparedStatement, ErrorCode.CompleteOk.mesg, nb); } catch (WaarpDatabaseException e) { if (preparedStatement != null) { preparedStatement.realClose(); } logger.warn("OpenR66 Web Error {}", e.getMessage()); sendError(ctx, HttpResponseStatus.SERVICE_UNAVAILABLE); return; } responseContent.append(REQUEST.done.readEnd()); } /** * Print all nb last transfers * * @param ctx * @param nb */ private void all(ChannelHandlerContext ctx, int nb) { responseContent.append(REQUEST.all.readHeader(this)); DbPreparedStatement preparedStatement = null; try { preparedStatement = DbTaskRunner.getStatusPrepareStatement(dbSession, null, nb);// means all addRunners(preparedStatement, "ALL RUNNERS: " + nb, nb); } catch (WaarpDatabaseException e) { if (preparedStatement != null) { preparedStatement.realClose(); } logger.warn("OpenR66 Web Error {}", e.getMessage()); sendError(ctx, HttpResponseStatus.SERVICE_UNAVAILABLE); return; } responseContent.append(REQUEST.all.readEnd()); } /** * print only status * * @param ctx * @param nb */ private void status(ChannelHandlerContext ctx, int nb) { responseContent.append(REQUEST.status.readHeader(this)); DbPreparedStatement preparedStatement = null; try { preparedStatement = DbTaskRunner.getSelectFromInfoPrepareStatement( dbSession, UpdatedInfo.INERROR, true, 1); DbTaskRunner.finishSelectOrCountPrepareStatement(preparedStatement); try { preparedStatement.executeQuery(); if (preparedStatement.getNext()) { responseContent.append("<p>Some Transfers are in ERROR</p><br>"); status = HttpResponseStatus.INTERNAL_SERVER_ERROR; } } finally { if (preparedStatement != null) { preparedStatement.realClose(); } } preparedStatement = DbTaskRunner.getSelectFromInfoPrepareStatement( dbSession, UpdatedInfo.INTERRUPTED, true, 1); DbTaskRunner.finishSelectOrCountPrepareStatement(preparedStatement); try { preparedStatement.executeQuery(); if (preparedStatement.getNext()) { responseContent.append("<p>Some Transfers are INTERRUPTED</p><br>"); status = HttpResponseStatus.INTERNAL_SERVER_ERROR; } } finally { if (preparedStatement != null) { preparedStatement.realClose(); } } preparedStatement = DbTaskRunner.getStepPrepareStatement(dbSession, TASKSTEP.ERRORTASK, 1); try { preparedStatement.executeQuery(); if (preparedStatement.getNext()) { responseContent.append("<p>Some Transfers are in ERRORTASK</p><br>"); status = HttpResponseStatus.INTERNAL_SERVER_ERROR; } } finally { if (preparedStatement != null) { preparedStatement.realClose(); } } if (status != HttpResponseStatus.INTERNAL_SERVER_ERROR) { responseContent.append("<p>No problem is found in Transfers</p><br>"); } } catch (WaarpDatabaseException e) { if (preparedStatement != null) { preparedStatement.realClose(); } logger.warn("OpenR66 Web Error {}", e.getMessage()); sendError(ctx, HttpResponseStatus.SERVICE_UNAVAILABLE); return; } responseContent.append(REQUEST.status.readEnd()); } /** * print only status * * @param ctx * @param nb */ private void statusxml(ChannelHandlerContext ctx, long nb, boolean detail) { Configuration.configuration.getMonitoring().run(nb, detail); responseContent.append(Configuration.configuration.getMonitoring().exportXml(detail)); } /** * print only status * * @param ctx * @param nb */ private void statusjson(ChannelHandlerContext ctx, long nb, boolean detail) { Configuration.configuration.getMonitoring().run(nb, detail); responseContent.append(Configuration.configuration.getMonitoring().exportJson(detail)); } private void spooled(ChannelHandlerContext ctx, boolean detail, String name, int istatus) { responseContent .append(REQUEST.status.readHeader(this)) .append("<p><table border='0' cellpadding='0' cellspacing='0' >") .append("<tr style='background-image:url(gre/gresm.png);background-repeat:repeat-x;background-position:left top;'><td class='col_MenuHaut'>") .append("<a data-i18n='menu2.sous-menu4a' href='Spooled.html' style='display:block;width:100%;height:100%;line-height:15px;'>") .append("SPOOLED DIRECTORY no detail</a></td><td></td><td><img src='gre/gre11.png' height='15' width='1' style='border: none; display: block;' alt='' /></td>") .append("<td></td><td class='col_MenuHaut'><a data-i18n='menu2.sous-menu4c' href='Spooled.html?status=-1' style='display:block;width:100%;height:100%;line-height:15px;'>") .append("SPOOLED DIRECTORY no detail KO</a></td><td></td><td><img src='gre/gre11.png' height='15' width='1' style='border: none; display: block;' alt='' /></td>") .append("<td></td><td class='col_MenuHaut'><a data-i18n='menu2.sous-menu4d' href='Spooled.html?status=1' style='display:block;width:100%;height:100%;line-height:15px;'>") .append("SPOOLED DIRECTORY no detail OK</a></td></tr><tr style='background-image:url(gre/gre11.png);background-repeat:repeat-x;background-position:left top;'>") .append("<td><img src='gre/gre11.png' height='1' width='100%' style='border: none; display: block;' alt='' /></td></tr>") .append("<tr style='background-image:url(gre/gresm.png);background-repeat:repeat-x;background-position:left top;'>") .append("<td class='col_MenuHaut'><a data-i18n='menu2.sous-menu4b' href='SpooledDetailed.html' style='display:block;width:100%;height:100%;line-height:15px;'>") .append("SPOOLED DIRECTORY detailed</a></td><td></td><td><img src='gre/gre11.png' height='15' width='1' style='border: none; display: block;' alt='' /></td>") .append("<td></td><td class='col_MenuHaut'><a data-i18n='menu2.sous-menu4e' href='SpooledDetailed.html?status=-1' style='display:block;width:100%;height:100%;line-height:15px;'>") .append("SPOOLED DIRECTORY detailed KO</a></td><td></td><td><img src='gre/gre11.png' height='15' width='1' style='border: none; display: block;' alt='' /></td>") .append("<td></td><td class='col_MenuHaut'><a data-i18n='menu2.sous-menu4f' href='SpooledDetailed.html?status=1' style='display:block;width:100%;height:100%;line-height:15px;'>") .append("SPOOLED DIRECTORY detailed OK</a></td></tr></table></p>"); String uri = null; if (detail) { uri = "SpooledDetailed.html"; } else { uri = "Spooled.html"; } if (name != null && !name.isEmpty()) { // name is specified uri = request.uri(); if (istatus != 0) { uri += "&status=" + istatus; } responseContent.append(SpooledInformTask.buildSpooledUniqueTable(uri, name)); } else { if (istatus != 0) { uri += "&status=" + istatus; } responseContent.append(SpooledInformTask.buildSpooledTable(detail, istatus, uri)); } responseContent.append(REQUEST.status.readEnd()); } /** * Write the response * * @param ctx */ private void writeResponse(ChannelHandlerContext ctx) { // Convert the response content to a ByteBuf. ByteBuf buf = Unpooled.copiedBuffer(responseContent.toString(), WaarpStringUtils.UTF8); responseContent.setLength(0); // Decide whether to close the connection or not. boolean keepAlive = HttpUtil.isKeepAlive(request); boolean close = HttpHeaderValues.CLOSE.contentEqualsIgnoreCase(request .headers().get(HttpHeaderNames.CONNECTION)) || (!keepAlive); // Build the response object. FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, buf); response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); if (isCurrentRequestXml) { response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/xml"); } else if (isCurrentRequestJson) { response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json"); } else { response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html"); } if (keepAlive) { response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } if (!close) { // There's no need to add 'Content-Length' header // if this is the last response. response.headers().set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(buf.readableBytes())); } String cookieString = request.headers().get(HttpHeaderNames.COOKIE); if (cookieString != null) { Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString); boolean i18nextFound = false; if (!cookies.isEmpty()) { // Reset the cookies if necessary. for (Cookie cookie : cookies) { if (cookie.name().equalsIgnoreCase(I18NEXT)) { i18nextFound = true; cookie.setValue(lang); response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } else { response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } } if (!i18nextFound) { Cookie cookie = new DefaultCookie(I18NEXT, lang); response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } } if (!i18nextFound) { Cookie cookie = new DefaultCookie(I18NEXT, lang); response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } } // Write the response. ChannelFuture future = ctx.writeAndFlush(response); // Close the connection after the write operation is done if necessary. if (close) { future.addListener(ChannelFutureListener.CLOSE); /*if (this.isPrivateDbSession && dbSession != null) { dbSession.forceDisconnect(); DbAdmin.nbHttpSession--; dbSession = null; }*/ } } /** * Send an error and close * * @param ctx * @param status */ private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { responseContent.setLength(0); responseContent.append(REQUEST.error.readHeader(this)).append("OpenR66 Web Failure: ") .append(status.toString()).append(REQUEST.error.readEnd()); ByteBuf buf = Unpooled.copiedBuffer(responseContent.toString(), WaarpStringUtils.UTF8); FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, buf); response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html"); responseContent.setLength(0); // Close the connection as soon as the error message is sent. ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { OpenR66Exception exception = OpenR66ExceptionTrappedFactory .getExceptionFromTrappedException(ctx.channel(), cause); if (exception != null) { if (!(exception instanceof OpenR66ProtocolBusinessNoWriteBackException)) { if (cause instanceof IOException) { if (this.isPrivateDbSession && dbSession != null) { dbSession.forceDisconnect(); DbAdmin.decHttpSession(); dbSession = null; } // Nothing to do return; } logger.warn("Exception in HttpHandler {}", exception.getMessage()); } if (ctx.channel().isActive()) { sendError(ctx, HttpResponseStatus.BAD_REQUEST); } } else { if (this.isPrivateDbSession && dbSession != null) { dbSession.forceDisconnect(); DbAdmin.decHttpSession(); dbSession = null; } // Nothing to do return; } } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { super.channelInactive(ctx); logger.debug("Closed"); if (this.isPrivateDbSession && dbSession != null) { dbSession.forceDisconnect(); DbAdmin.decHttpSession(); dbSession = null; } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { logger.debug("Connected"); getAuthentHttp().getAuth().specialNoSessionAuth(false, Configuration.configuration.getHOST_ID()); super.channelActive(ctx); ChannelGroup group = Configuration.configuration.getHttpChannelGroup(); if (group != null) { group.add(ctx.channel()); } } /** * @return the authentHttp */ public R66Session getAuthentHttp() { return authentHttp; } }