/**
* 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.gateway.ftp.adminssl;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
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.HttpResponse;
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.command.ReplyCode;
import org.waarp.common.command.exception.CommandAbstractException;
import org.waarp.common.crypto.ssl.WaarpSslUtility;
import org.waarp.common.database.DbAdmin;
import org.waarp.common.database.DbPreparedStatement;
import org.waarp.common.database.DbSession;
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.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.common.utility.WaarpStringUtils;
import org.waarp.ftp.core.file.FtpDir;
import org.waarp.ftp.core.session.FtpSession;
import org.waarp.ftp.core.utils.FtpChannelUtils;
import org.waarp.gateway.ftp.config.FileBasedConfiguration;
import org.waarp.gateway.ftp.control.FtpConstraintLimitHandler;
import org.waarp.gateway.ftp.database.DbConstant;
import org.waarp.gateway.ftp.database.data.DbTransferLog;
import org.waarp.gateway.ftp.file.FileBasedAuth;
import org.waarp.gateway.ftp.utils.Version;
import org.waarp.gateway.kernel.exec.AbstractExecutor;
import org.waarp.gateway.kernel.exec.AbstractExecutor.CommandExecutor;
import org.waarp.gateway.kernel.http.HttpWriteCacheEnable;
/**
* @author Frederic Bregier
* @author Bruno Carlin
*
*/
public class HttpSslHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
/**
* Internal Logger
*/
private static final WaarpLogger logger = WaarpLoggerFactory
.getLogger(HttpSslHandler.class);
/**
* Session Management
*/
private static final ConcurrentHashMap<String, FileBasedAuth> sessions = new ConcurrentHashMap<String, FileBasedAuth>();
private static final ConcurrentHashMap<String, DbSession> dbSessions = new ConcurrentHashMap<String, DbSession>();
private static final Random random = new Random();
private FtpSession ftpSession =
new FtpSession(FileBasedConfiguration.fileBasedConfiguration,
null);
private FileBasedAuth authentHttp =
new FileBasedAuth(ftpSession);
private FullHttpRequest request;
private volatile boolean newSession = false;
private volatile Cookie admin = null;
private final StringBuilder responseContent = new StringBuilder();
private String uriRequest;
private Map<String, List<String>> params;
private QueryStringDecoder queryStringDecoder;
private volatile boolean forceClose = false;
private volatile boolean shutdown = false;
private static final String FTPSESSION = "FTPSESSION";
private static enum REQUEST {
Logon("Logon.html"),
index("index.html"),
error("error.html"),
Transfer("Transfer_head.html", "Transfer_body.html", "Transfer_end.html"),
Rule("Rule.html"),
User("User_head.html", "User_body.html", "User_end.html"),
System("System.html");
private String header;
private String body;
private String end;
/**
* Constructor for a unique file
*
* @param uniquefile
*/
private REQUEST(String uniquefile) {
this.header = uniquefile;
this.body = null;
this.end = null;
}
/**
* @param header
* @param body
* @param end
*/
private REQUEST(String header, String body, String end) {
this.header = header;
this.body = body;
this.end = end;
}
/**
* Reader for a unique file
*
* @return the content of the unique file
*/
public String readFileUnique() {
return WaarpStringUtils
.readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath
+ this.header);
}
public String readHeader() {
return WaarpStringUtils
.readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath
+ this.header);
}
public String readBody() {
return WaarpStringUtils
.readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath
+ this.body);
}
public String readEnd() {
return WaarpStringUtils
.readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath + this.end);
}
}
public static final int LIMITROW = 48;// better if it can be divided by 4
/**
* The Database connection attached to this NetworkChannel shared among all associated
* LocalChannels in the session
*/
private DbSession dbSession = null;
/**
* Does this dbSession is private and so should be closed
*/
private volatile boolean isPrivateDbSession = false;
private String getTrimValue(String varname) {
String value = params.get(varname).get(0).trim();
if (value.length() == 0) {
value = null;
}
return value;
}
private String index() {
String index = REQUEST.index.readFileUnique();
StringBuilder builder = new StringBuilder(index);
WaarpStringUtils.replace(builder, "XXXLOCALXXX",
Integer.toString(
FileBasedConfiguration.fileBasedConfiguration.
getFtpInternalConfiguration().getNumberSessions())
+ " " + Thread.activeCount());
TrafficCounter trafficCounter =
FileBasedConfiguration.fileBasedConfiguration.getFtpInternalConfiguration()
.getGlobalTrafficShapingHandler().trafficCounter();
WaarpStringUtils.replace(builder, "XXXBANDWIDTHXXX",
"IN:" + (trafficCounter.lastReadThroughput() / 131072) +
"Mbits <br> OUT:" +
(trafficCounter.lastWriteThroughput() / 131072) + "Mbits");
WaarpStringUtils.replaceAll(builder, "XXXHOSTIDXXX",
FileBasedConfiguration.fileBasedConfiguration.HOST_ID);
WaarpStringUtils.replaceAll(builder, "XXXADMINXXX",
"Administrator Connected");
WaarpStringUtils.replace(builder, "XXXVERSIONXXX",
Version.ID);
return builder.toString();
}
private String error(String mesg) {
String index = REQUEST.error.readFileUnique();
return index.replaceAll("XXXERRORMESGXXX",
mesg);
}
private String Logon() {
return REQUEST.Logon.readFileUnique();
}
private String System() {
getParams();
FtpConstraintLimitHandler handler =
FileBasedConfiguration.fileBasedConfiguration.constraintLimitHandler;
if (params == null) {
String system = REQUEST.System.readFileUnique();
StringBuilder builder = new StringBuilder(system);
WaarpStringUtils.replace(builder, "XXXXCHANNELLIMITRXXX",
Long.toString(FileBasedConfiguration.fileBasedConfiguration
.getServerGlobalReadLimit()));
WaarpStringUtils.replace(builder, "XXXXCPULXXX",
Double.toString(handler.getCpuLimit()));
WaarpStringUtils.replace(builder, "XXXXCONLXXX",
Integer.toString(handler.getChannelLimit()));
WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
return builder.toString();
}
String extraInformation = null;
if (params.containsKey("ACTION")) {
List<String> action = params.get("ACTION");
for (String act : action) {
if (act.equalsIgnoreCase("Disconnect")) {
String logon = Logon();
newSession = true;
clearSession();
forceClose = true;
return logon;
} else if (act.equalsIgnoreCase("Shutdown")) {
String error = error("Shutdown in progress");
newSession = true;
clearSession();
forceClose = true;
shutdown = true;
return error;
} else if (act.equalsIgnoreCase("Validate")) {
String bglobalr = getTrimValue("BGLOBR");
long lglobal = FileBasedConfiguration.fileBasedConfiguration
.getServerGlobalReadLimit();
if (bglobalr != null) {
lglobal = Long.parseLong(bglobalr);
}
FileBasedConfiguration.fileBasedConfiguration.changeNetworkLimit(lglobal,
lglobal);
bglobalr = getTrimValue("CPUL");
double dcpu = handler.getCpuLimit();
if (bglobalr != null) {
dcpu = Double.parseDouble(bglobalr);
}
handler.setCpuLimit(dcpu);
bglobalr = getTrimValue("CONL");
int iconn = handler.getChannelLimit();
if (bglobalr != null) {
iconn = Integer.parseInt(bglobalr);
}
handler.setChannelLimit(iconn);
extraInformation = "Configuration Saved";
}
}
}
String system = REQUEST.System.readFileUnique();
StringBuilder builder = new StringBuilder(system);
WaarpStringUtils.replace(builder, "XXXXCHANNELLIMITRXXX",
Long.toString(FileBasedConfiguration.fileBasedConfiguration
.getServerGlobalReadLimit()));
WaarpStringUtils.replace(builder, "XXXXCPULXXX",
Double.toString(handler.getCpuLimit()));
WaarpStringUtils.replace(builder, "XXXXCONLXXX",
Integer.toString(handler.getChannelLimit()));
if (extraInformation != null) {
WaarpStringUtils.replace(builder, "XXXRESULTXXX", extraInformation);
} else {
WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
}
return builder.toString();
}
private String Rule() {
getParams();
if (params == null) {
String system = REQUEST.Rule.readFileUnique();
StringBuilder builder = new StringBuilder(system);
CommandExecutor exec = AbstractExecutor.getCommandExecutor();
WaarpStringUtils.replace(builder, "XXXSTCXXX",
exec.getStorType() + " " + exec.pstorCMD);
WaarpStringUtils.replace(builder, "XXXSTDXXX",
Long.toString(exec.pstorDelay));
WaarpStringUtils.replace(builder, "XXXRTCXXX",
exec.getRetrType() + " " + exec.pretrCMD);
WaarpStringUtils.replace(builder, "XXXRTDXXX",
Long.toString(exec.pretrDelay));
WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
return builder.toString();
}
String extraInformation = null;
if (params.containsKey("ACTION")) {
List<String> action = params.get("ACTION");
for (String act : action) {
if (act.equalsIgnoreCase("Update")) {
CommandExecutor exec = AbstractExecutor.getCommandExecutor();
String bglobalr = getTrimValue("std");
long lglobal = exec.pstorDelay;
if (bglobalr != null) {
lglobal = Long.parseLong(bglobalr);
}
exec.pstorDelay = lglobal;
bglobalr = getTrimValue("rtd");
lglobal = exec.pretrDelay;
if (bglobalr != null) {
lglobal = Long.parseLong(bglobalr);
}
exec.pretrDelay = lglobal;
bglobalr = getTrimValue("stc");
String store = exec.getStorType() + " " + exec.pstorCMD;
if (bglobalr != null) {
store = bglobalr;
}
bglobalr = getTrimValue("rtc");
String retr = exec.getRetrType() + " " + exec.pretrCMD;
if (bglobalr != null) {
retr = bglobalr;
}
AbstractExecutor.initializeExecutor(retr, exec.pretrDelay,
store, exec.pstorDelay);
extraInformation = "Configuration Saved";
}
}
}
String system = REQUEST.Rule.readFileUnique();
StringBuilder builder = new StringBuilder(system);
CommandExecutor exec = AbstractExecutor.getCommandExecutor();
WaarpStringUtils.replace(builder, "XXXSTCXXX",
exec.getStorType() + " " + exec.pstorCMD);
WaarpStringUtils.replace(builder, "XXXSTDXXX",
Long.toString(exec.pstorDelay));
WaarpStringUtils.replace(builder, "XXXRTCXXX",
exec.getRetrType() + " " + exec.pretrCMD);
WaarpStringUtils.replace(builder, "XXXRTDXXX",
Long.toString(exec.pretrDelay));
if (extraInformation != null) {
WaarpStringUtils.replace(builder, "XXXRESULTXXX", extraInformation);
} else {
WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
}
return builder.toString();
}
private String Transfer() {
getParams();
String head = REQUEST.Transfer.readHeader();
String end = REQUEST.Transfer.readEnd();
String body = REQUEST.Transfer.readBody();
if (params == null || (!DbConstant.gatewayAdmin.isActive())) {
end = end.replace("XXXRESULTXXX", "");
body = FileBasedConfiguration.fileBasedConfiguration.getHtmlTransfer(body, LIMITROW);
return head + body + end;
}
String message = "";
List<String> parms = params.get("ACTION");
if (parms != null) {
String parm = parms.get(0);
boolean purgeAll = false;
boolean purgeCorrect = false;
boolean delete = false;
if ("PurgeCorrectTransferLogs".equalsIgnoreCase(parm)) {
purgeCorrect = true;
} else if ("PurgeAllTransferLogs".equalsIgnoreCase(parm)) {
purgeAll = true;
} else if ("Delete".equalsIgnoreCase(parm)) {
delete = true;
}
if (purgeCorrect || purgeAll) {
DbPreparedStatement preparedStatement = null;
ReplyCode status = null;
String action = "purgeAll";
if (purgeCorrect) {
status = ReplyCode.REPLY_226_CLOSING_DATA_CONNECTION;
action = "purge";
}
try {
preparedStatement =
DbTransferLog.getStatusPrepareStament(dbSession,
status, 0);
} catch (WaarpDatabaseNoConnectionException e) {
message = "Error during " + action;
} catch (WaarpDatabaseSqlException e) {
message = "Error during " + action;
}
if (preparedStatement != null) {
try {
FileBasedConfiguration config = FileBasedConfiguration.fileBasedConfiguration;
String filename =
config.getBaseDirectory() +
FtpDir.SEPARATOR + config.ADMINNAME + FtpDir.SEPARATOR +
config.HOST_ID + "_logs_" + System.currentTimeMillis()
+ ".xml";
message = DbTransferLog.saveDbTransferLogFile(preparedStatement, filename);
} finally {
preparedStatement.realClose();
}
}
} else if (delete) {
String user = getTrimValue("user");
String acct = getTrimValue("account");
String specid = getTrimValue("specialid");
long specialId = Long.parseLong(specid);
try {
DbTransferLog log = new DbTransferLog(dbSession, user, acct, specialId);
FileBasedConfiguration config = FileBasedConfiguration.fileBasedConfiguration;
String filename =
config.getBaseDirectory() +
FtpDir.SEPARATOR + config.ADMINNAME + FtpDir.SEPARATOR +
config.HOST_ID + "_log_" + System.currentTimeMillis() + ".xml";
message = log.saveDbTransferLog(filename);
} catch (WaarpDatabaseException e) {
message = "Error during delete 1 Log";
}
} else {
message = "No Action";
}
end = end.replace("XXXRESULTXXX", message);
}
end = end.replace("XXXRESULTXXX", "");
body = FileBasedConfiguration.fileBasedConfiguration.getHtmlTransfer(body, LIMITROW);
return head + body + end;
}
private String User() {
getParams();
String head = REQUEST.User.readHeader();
String end = REQUEST.User.readEnd();
String body = REQUEST.User.readBody();
FileBasedConfiguration config = FileBasedConfiguration.fileBasedConfiguration;
String filedefault = config.getBaseDirectory() +
FtpDir.SEPARATOR + config.ADMINNAME +
FtpDir.SEPARATOR + "authentication.xml";
if (params == null) {
end = end.replace("XXXRESULTXXX", "");
end = end.replace("XXXFILEXXX", filedefault);
body = FileBasedConfiguration.fileBasedConfiguration.getHtmlAuth(body);
return head + body + end;
}
List<String> parms = params.get("ACTION");
if (parms != null) {
String parm = parms.get(0);
if ("ImportExport".equalsIgnoreCase(parm)) {
String file = getTrimValue("file");
String exportImport = getTrimValue("export");
String message = "";
boolean purge = false;
purge = params.containsKey("purge");
boolean replace = false;
replace = params.containsKey("replace");
if (file == null) {
file = filedefault;
}
end = end.replace("XXXFILEXXX", file);
if (exportImport.equalsIgnoreCase("import")) {
if (!config.initializeAuthent(file, purge)) {
message += "Cannot initialize Authentication from " + file;
} else {
message += "Initialization of Authentication OK from " + file;
if (replace) {
if (!config.saveAuthenticationFile(
config.getAuthenticationFile())) {
message += " but cannot replace server authenticationFile";
} else {
message += " and replacement done";
}
}
}
} else {
// export
if (!config.saveAuthenticationFile(file)) {
message += "Authentications CANNOT be saved into " + file;
} else {
message += "Authentications saved into " + file;
}
}
end = end.replace("XXXRESULTXXX", message);
} else {
end = end.replace("XXXFILEXXX", filedefault);
}
}
end = end.replace("XXXRESULTXXX", "");
body = FileBasedConfiguration.fileBasedConfiguration.getHtmlAuth(body);
return head + body + end;
}
private void getParams() {
if (request.method() == HttpMethod.GET) {
params = null;
} else if (request.method() == HttpMethod.POST) {
ByteBuf content = request.content();
if (content.isReadable()) {
String param = content.toString(WaarpStringUtils.UTF8);
QueryStringDecoder queryStringDecoder2 = new QueryStringDecoder("/?" + param);
params = queryStringDecoder2.parameters();
} else {
params = null;
}
}
}
private void clearSession() {
if (admin != null) {
FileBasedAuth auth = sessions.remove(admin.value());
DbSession ldbsession = dbSessions.remove(admin.value());
admin = null;
if (auth != null) {
auth.clear();
}
if (ldbsession != null) {
ldbsession.disconnect();
DbAdmin.decHttpSession();
}
}
}
private void checkAuthent(ChannelHandlerContext ctx) {
newSession = true;
if (request.method() == HttpMethod.GET) {
String logon = Logon();
responseContent.append(logon);
clearSession();
writeResponse(ctx);
return;
} else if (request.method() == HttpMethod.POST) {
getParams();
if (params == null) {
String logon = Logon();
responseContent.append(logon);
clearSession();
writeResponse(ctx);
return;
}
}
boolean getMenu = false;
if (params.containsKey("Logon")) {
String name = null, password = null;
List<String> values = null;
if (!params.isEmpty()) {
// get values
if (params.containsKey("name")) {
values = params.get("name");
if (values != null) {
name = values.get(0);
if (name == null || name.length() == 0) {
getMenu = true;
}
}
} else {
getMenu = true;
}
// search the nb param
if ((!getMenu) && params.containsKey("passwd")) {
values = params.get("passwd");
if (values != null) {
password = values.get(0);
if (password == null || password.length() == 0) {
getMenu = true;
} else {
getMenu = false;
}
} else {
getMenu = true;
}
} else {
getMenu = true;
}
} else {
getMenu = true;
}
if (!getMenu) {
logger.debug("Name=" + name + " vs "
+ name.equals(FileBasedConfiguration.fileBasedConfiguration.ADMINNAME) +
" Passwd=" + password + " vs " +
FileBasedConfiguration.fileBasedConfiguration.checkPassword(password));
if (name.equals(FileBasedConfiguration.fileBasedConfiguration.ADMINNAME) &&
FileBasedConfiguration.fileBasedConfiguration.checkPassword(password)) {
authentHttp
.specialNoSessionAuth(FileBasedConfiguration.fileBasedConfiguration.HOST_ID);
} else {
getMenu = true;
}
if (!authentHttp.isIdentified()) {
logger.debug("Still not authenticated: {}", authentHttp);
getMenu = true;
}
// load DbSession
if (this.dbSession == null) {
try {
if (DbConstant.gatewayAdmin.isActive()) {
this.dbSession = new DbSession(DbConstant.gatewayAdmin, false);
DbAdmin.incHttpSession();
this.isPrivateDbSession = true;
}
} catch (WaarpDatabaseNoConnectionException e1) {
// Cannot connect so use default connection
logger.warn("Use default database connection");
this.dbSession = DbConstant.gatewayAdmin.getSession();
}
}
}
} else {
getMenu = true;
}
if (getMenu) {
String logon = Logon();
responseContent.append(logon);
clearSession();
writeResponse(ctx);
} else {
String index = index();
responseContent.append(index);
clearSession();
admin = new DefaultCookie(FTPSESSION,
FileBasedConfiguration.fileBasedConfiguration.HOST_ID +
Long.toHexString(random.nextLong()));
sessions.put(admin.value(), this.authentHttp);
if (this.isPrivateDbSession) {
dbSessions.put(admin.value(), dbSession);
}
logger.debug("CreateSession: " + uriRequest + ":{}", admin);
writeResponse(ctx);
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
this.request = msg;
queryStringDecoder = new QueryStringDecoder(request.uri());
uriRequest = queryStringDecoder.path();
if (uriRequest.contains("gre/") || uriRequest.contains("img/") ||
uriRequest.contains("res/")) {
HttpWriteCacheEnable.writeFile(request,
ctx,
FileBasedConfiguration.fileBasedConfiguration.httpBasePath + uriRequest,
FTPSESSION);
return;
}
checkSession(ctx.channel());
if (!authentHttp.isIdentified()) {
logger.debug("Not Authent: " + uriRequest + ":{}", authentHttp);
checkAuthent(ctx);
return;
}
String find = uriRequest;
if (uriRequest.charAt(0) == '/') {
find = uriRequest.substring(1);
}
find = find.substring(0, find.indexOf("."));
REQUEST req = REQUEST.index;
try {
req = REQUEST.valueOf(find);
} catch (IllegalArgumentException e1) {
req = REQUEST.index;
logger.debug("NotFound: " + find + ":" + uriRequest);
}
switch (req) {
case index:
responseContent.append(index());
break;
case Logon:
responseContent.append(index());
break;
case System:
responseContent.append(System());
break;
case Rule:
responseContent.append(Rule());
break;
case User:
responseContent.append(User());
break;
case Transfer:
responseContent.append(Transfer());
break;
default:
responseContent.append(index());
break;
}
writeResponse(ctx);
}
private void checkSession(Channel channel) {
String cookieString = request.headers().get(HttpHeaderNames.COOKIE);
if (cookieString != null) {
Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString);
if (!cookies.isEmpty()) {
for (Cookie elt : cookies) {
if (elt.name().equalsIgnoreCase(FTPSESSION)) {
admin = elt;
break;
}
}
}
}
if (admin != null) {
FileBasedAuth auth = sessions.get(admin.value());
if (auth != null) {
authentHttp = auth;
}
DbSession dbSession = dbSessions.get(admin.value());
if (dbSession != null) {
this.dbSession = dbSession;
}
} else {
logger.debug("NoSession: " + uriRequest + ":{}", admin);
}
}
private void handleCookies(HttpResponse response) {
String cookieString = request.headers().get(HttpHeaderNames.COOKIE);
if (cookieString != null) {
Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString);
if (!cookies.isEmpty()) {
// Reset the sessions if necessary.
boolean findSession = false;
for (Cookie cookie : cookies) {
if (cookie.name().equalsIgnoreCase(FTPSESSION)) {
if (newSession) {
findSession = false;
} else {
findSession = true;
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie));
}
} else {
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie));
}
}
newSession = false;
if (!findSession) {
if (admin != null) {
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(admin));
logger.debug("AddSession: " + uriRequest + ":{}", admin);
}
}
}
} else if (admin != null) {
logger.debug("AddSession: " + uriRequest + ":{}", admin);
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(admin));
}
}
/**
* 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) || forceClose;
// Build the response object.
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
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()));
}
handleCookies(response);
// Write the response.
ChannelFuture future = ctx.writeAndFlush(response);
// Close the connection after the write operation is done if necessary.
if (close) {
future.addListener(WaarpSslUtility.SSLCLOSE);
}
if (shutdown) {
/*
* Thread thread = new Thread( new FtpChannelUtils(
* FileBasedConfiguration.fileBasedConfiguration)); thread.setDaemon(true);
* thread.setName("Shutdown Thread"); thread.start();
*/
FtpChannelUtils.teminateServer(FileBasedConfiguration.fileBasedConfiguration);
if (!close) {
future.addListener(WaarpSslUtility.SSLCLOSE);
}
}
}
/**
* Send an error and close
*
* @param ctx
* @param status
*/
private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
responseContent.setLength(0);
responseContent.append(error(status.toString()));
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(responseContent.toString(), WaarpStringUtils.UTF8));
response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html");
clearSession();
// Close the connection as soon as the error message is sent.
ctx.channel().writeAndFlush(response).addListener(WaarpSslUtility.SSLCLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Throwable e1 = cause;
if (!(e1 instanceof CommandAbstractException)) {
if (e1 instanceof IOException) {
// Nothing to do
return;
}
logger.warn("Exception in HttpSslHandler", e1);
}
if (ctx.channel().isActive()) {
sendError(ctx, HttpResponseStatus.BAD_REQUEST);
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
logger.debug("Add channel to ssl");
FileBasedConfiguration.fileBasedConfiguration.getHttpChannelGroup().add(channel);
super.channelActive(ctx);
}
}