View Javadoc
1   /**
2    * This file is part of Waarp Project.
3    * 
4    * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the
5    * COPYRIGHT.txt in the distribution for a full listing of individual contributors.
6    * 
7    * All Waarp Project is free software: you can redistribute it and/or modify it under the terms of
8    * the GNU General Public License as published by the Free Software Foundation, either version 3 of
9    * the License, or (at your option) any later version.
10   * 
11   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
12   * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13   * Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License along with Waarp . If not, see
16   * <http://www.gnu.org/licenses/>.
17   */
18  package org.waarp.gateway.ftp.adminssl;
19  
20  import java.io.IOException;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Random;
24  import java.util.Set;
25  import java.util.concurrent.ConcurrentHashMap;
26  
27  import io.netty.buffer.ByteBuf;
28  import io.netty.buffer.Unpooled;
29  import io.netty.channel.Channel;
30  import io.netty.channel.ChannelFuture;
31  import io.netty.channel.ChannelHandlerContext;
32  import io.netty.channel.SimpleChannelInboundHandler;
33  import io.netty.handler.codec.http.DefaultFullHttpResponse;
34  import io.netty.handler.codec.http.FullHttpRequest;
35  import io.netty.handler.codec.http.FullHttpResponse;
36  import io.netty.handler.codec.http.HttpHeaderNames;
37  import io.netty.handler.codec.http.HttpHeaderValues;
38  import io.netty.handler.codec.http.HttpMethod;
39  import io.netty.handler.codec.http.HttpResponse;
40  import io.netty.handler.codec.http.HttpResponseStatus;
41  import io.netty.handler.codec.http.HttpUtil;
42  import io.netty.handler.codec.http.HttpVersion;
43  import io.netty.handler.codec.http.QueryStringDecoder;
44  import io.netty.handler.codec.http.cookie.Cookie;
45  import io.netty.handler.codec.http.cookie.DefaultCookie;
46  import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
47  import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
48  import io.netty.handler.traffic.TrafficCounter;
49  
50  import org.waarp.common.command.ReplyCode;
51  import org.waarp.common.command.exception.CommandAbstractException;
52  import org.waarp.common.crypto.ssl.WaarpSslUtility;
53  import org.waarp.common.database.DbAdmin;
54  import org.waarp.common.database.DbPreparedStatement;
55  import org.waarp.common.database.DbSession;
56  import org.waarp.common.database.exception.WaarpDatabaseException;
57  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
58  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
59  import org.waarp.common.logging.WaarpLogger;
60  import org.waarp.common.logging.WaarpLoggerFactory;
61  import org.waarp.common.utility.WaarpStringUtils;
62  import org.waarp.ftp.core.file.FtpDir;
63  import org.waarp.ftp.core.session.FtpSession;
64  import org.waarp.ftp.core.utils.FtpChannelUtils;
65  import org.waarp.gateway.ftp.config.FileBasedConfiguration;
66  import org.waarp.gateway.ftp.control.FtpConstraintLimitHandler;
67  import org.waarp.gateway.ftp.database.DbConstant;
68  import org.waarp.gateway.ftp.database.data.DbTransferLog;
69  import org.waarp.gateway.ftp.file.FileBasedAuth;
70  import org.waarp.gateway.ftp.utils.Version;
71  import org.waarp.gateway.kernel.exec.AbstractExecutor;
72  import org.waarp.gateway.kernel.exec.AbstractExecutor.CommandExecutor;
73  import org.waarp.gateway.kernel.http.HttpWriteCacheEnable;
74  
75  /**
76   * @author Frederic Bregier
77   * @author Bruno Carlin
78   *
79   */
80  public class HttpSslHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
81      /**
82       * Internal Logger
83       */
84      private static final WaarpLogger logger = WaarpLoggerFactory
85              .getLogger(HttpSslHandler.class);
86      /**
87       * Session Management
88       */
89      private static final ConcurrentHashMap<String, FileBasedAuth> sessions = new ConcurrentHashMap<String, FileBasedAuth>();
90      private static final ConcurrentHashMap<String, DbSession> dbSessions = new ConcurrentHashMap<String, DbSession>();
91      private static final Random random = new Random();
92  
93      private FtpSession ftpSession =
94              new FtpSession(FileBasedConfiguration.fileBasedConfiguration,
95                      null);
96      private FileBasedAuth authentHttp =
97              new FileBasedAuth(ftpSession);
98  
99      private FullHttpRequest request;
100     private volatile boolean newSession = false;
101     private volatile Cookie admin = null;
102     private final StringBuilder responseContent = new StringBuilder();
103     private String uriRequest;
104     private Map<String, List<String>> params;
105     private QueryStringDecoder queryStringDecoder;
106     private volatile boolean forceClose = false;
107     private volatile boolean shutdown = false;
108 
109     private static final String FTPSESSION = "FTPSESSION";
110 
111     private static enum REQUEST {
112         Logon("Logon.html"),
113         index("index.html"),
114         error("error.html"),
115         Transfer("Transfer_head.html", "Transfer_body.html", "Transfer_end.html"),
116         Rule("Rule.html"),
117         User("User_head.html", "User_body.html", "User_end.html"),
118         System("System.html");
119 
120         private String header;
121         private String body;
122         private String end;
123 
124         /**
125          * Constructor for a unique file
126          * 
127          * @param uniquefile
128          */
129         private REQUEST(String uniquefile) {
130             this.header = uniquefile;
131             this.body = null;
132             this.end = null;
133         }
134 
135         /**
136          * @param header
137          * @param body
138          * @param end
139          */
140         private REQUEST(String header, String body, String end) {
141             this.header = header;
142             this.body = body;
143             this.end = end;
144         }
145 
146         /**
147          * Reader for a unique file
148          * 
149          * @return the content of the unique file
150          */
151         public String readFileUnique() {
152             return WaarpStringUtils
153                     .readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath
154                             + this.header);
155         }
156 
157         public String readHeader() {
158             return WaarpStringUtils
159                     .readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath
160                             + this.header);
161         }
162 
163         public String readBody() {
164             return WaarpStringUtils
165                     .readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath
166                             + this.body);
167         }
168 
169         public String readEnd() {
170             return WaarpStringUtils
171                     .readFile(FileBasedConfiguration.fileBasedConfiguration.httpBasePath + this.end);
172         }
173     }
174 
175     public static final int LIMITROW = 48;// better if it can be divided by 4
176 
177     /**
178      * The Database connection attached to this NetworkChannel shared among all associated
179      * LocalChannels in the session
180      */
181     private DbSession dbSession = null;
182     /**
183      * Does this dbSession is private and so should be closed
184      */
185     private volatile boolean isPrivateDbSession = false;
186 
187     private String getTrimValue(String varname) {
188         String value = params.get(varname).get(0).trim();
189         if (value.length() == 0) {
190             value = null;
191         }
192         return value;
193     }
194 
195     private String index() {
196         String index = REQUEST.index.readFileUnique();
197         StringBuilder builder = new StringBuilder(index);
198         WaarpStringUtils.replace(builder, "XXXLOCALXXX",
199                 Integer.toString(
200                         FileBasedConfiguration.fileBasedConfiguration.
201                                 getFtpInternalConfiguration().getNumberSessions())
202                         + " " + Thread.activeCount());
203         TrafficCounter trafficCounter =
204                 FileBasedConfiguration.fileBasedConfiguration.getFtpInternalConfiguration()
205                         .getGlobalTrafficShapingHandler().trafficCounter();
206         WaarpStringUtils.replace(builder, "XXXBANDWIDTHXXX",
207                 "IN:" + (trafficCounter.lastReadThroughput() / 131072) +
208                         "Mbits&nbsp;<br>&nbsp;OUT:" +
209                         (trafficCounter.lastWriteThroughput() / 131072) + "Mbits");
210         WaarpStringUtils.replaceAll(builder, "XXXHOSTIDXXX",
211                 FileBasedConfiguration.fileBasedConfiguration.HOST_ID);
212         WaarpStringUtils.replaceAll(builder, "XXXADMINXXX",
213                 "Administrator Connected");
214         WaarpStringUtils.replace(builder, "XXXVERSIONXXX",
215                 Version.ID);
216         return builder.toString();
217     }
218 
219     private String error(String mesg) {
220         String index = REQUEST.error.readFileUnique();
221         return index.replaceAll("XXXERRORMESGXXX",
222                 mesg);
223     }
224 
225     private String Logon() {
226         return REQUEST.Logon.readFileUnique();
227     }
228 
229     private String System() {
230         getParams();
231         FtpConstraintLimitHandler handler =
232                 FileBasedConfiguration.fileBasedConfiguration.constraintLimitHandler;
233         if (params == null) {
234             String system = REQUEST.System.readFileUnique();
235             StringBuilder builder = new StringBuilder(system);
236             WaarpStringUtils.replace(builder, "XXXXCHANNELLIMITRXXX",
237                     Long.toString(FileBasedConfiguration.fileBasedConfiguration
238                             .getServerGlobalReadLimit()));
239             WaarpStringUtils.replace(builder, "XXXXCPULXXX",
240                     Double.toString(handler.getCpuLimit()));
241             WaarpStringUtils.replace(builder, "XXXXCONLXXX",
242                     Integer.toString(handler.getChannelLimit()));
243             WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
244             return builder.toString();
245         }
246         String extraInformation = null;
247         if (params.containsKey("ACTION")) {
248             List<String> action = params.get("ACTION");
249             for (String act : action) {
250                 if (act.equalsIgnoreCase("Disconnect")) {
251                     String logon = Logon();
252                     newSession = true;
253                     clearSession();
254                     forceClose = true;
255                     return logon;
256                 } else if (act.equalsIgnoreCase("Shutdown")) {
257                     String error = error("Shutdown in progress");
258                     newSession = true;
259                     clearSession();
260                     forceClose = true;
261                     shutdown = true;
262                     return error;
263                 } else if (act.equalsIgnoreCase("Validate")) {
264                     String bglobalr = getTrimValue("BGLOBR");
265                     long lglobal = FileBasedConfiguration.fileBasedConfiguration
266                             .getServerGlobalReadLimit();
267                     if (bglobalr != null) {
268                         lglobal = Long.parseLong(bglobalr);
269                     }
270                     FileBasedConfiguration.fileBasedConfiguration.changeNetworkLimit(lglobal,
271                             lglobal);
272                     bglobalr = getTrimValue("CPUL");
273                     double dcpu = handler.getCpuLimit();
274                     if (bglobalr != null) {
275                         dcpu = Double.parseDouble(bglobalr);
276                     }
277                     handler.setCpuLimit(dcpu);
278                     bglobalr = getTrimValue("CONL");
279                     int iconn = handler.getChannelLimit();
280                     if (bglobalr != null) {
281                         iconn = Integer.parseInt(bglobalr);
282                     }
283                     handler.setChannelLimit(iconn);
284                     extraInformation = "Configuration Saved";
285                 }
286             }
287         }
288         String system = REQUEST.System.readFileUnique();
289         StringBuilder builder = new StringBuilder(system);
290         WaarpStringUtils.replace(builder, "XXXXCHANNELLIMITRXXX",
291                 Long.toString(FileBasedConfiguration.fileBasedConfiguration
292                         .getServerGlobalReadLimit()));
293         WaarpStringUtils.replace(builder, "XXXXCPULXXX",
294                 Double.toString(handler.getCpuLimit()));
295         WaarpStringUtils.replace(builder, "XXXXCONLXXX",
296                 Integer.toString(handler.getChannelLimit()));
297         if (extraInformation != null) {
298             WaarpStringUtils.replace(builder, "XXXRESULTXXX", extraInformation);
299         } else {
300             WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
301         }
302         return builder.toString();
303     }
304 
305     private String Rule() {
306         getParams();
307         if (params == null) {
308             String system = REQUEST.Rule.readFileUnique();
309             StringBuilder builder = new StringBuilder(system);
310             CommandExecutor exec = AbstractExecutor.getCommandExecutor();
311             WaarpStringUtils.replace(builder, "XXXSTCXXX",
312                     exec.getStorType() + " " + exec.pstorCMD);
313             WaarpStringUtils.replace(builder, "XXXSTDXXX",
314                     Long.toString(exec.pstorDelay));
315             WaarpStringUtils.replace(builder, "XXXRTCXXX",
316                     exec.getRetrType() + " " + exec.pretrCMD);
317             WaarpStringUtils.replace(builder, "XXXRTDXXX",
318                     Long.toString(exec.pretrDelay));
319             WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
320             return builder.toString();
321         }
322         String extraInformation = null;
323         if (params.containsKey("ACTION")) {
324             List<String> action = params.get("ACTION");
325             for (String act : action) {
326                 if (act.equalsIgnoreCase("Update")) {
327                     CommandExecutor exec = AbstractExecutor.getCommandExecutor();
328                     String bglobalr = getTrimValue("std");
329                     long lglobal = exec.pstorDelay;
330                     if (bglobalr != null) {
331                         lglobal = Long.parseLong(bglobalr);
332                     }
333                     exec.pstorDelay = lglobal;
334                     bglobalr = getTrimValue("rtd");
335                     lglobal = exec.pretrDelay;
336                     if (bglobalr != null) {
337                         lglobal = Long.parseLong(bglobalr);
338                     }
339                     exec.pretrDelay = lglobal;
340                     bglobalr = getTrimValue("stc");
341                     String store = exec.getStorType() + " " + exec.pstorCMD;
342                     if (bglobalr != null) {
343                         store = bglobalr;
344                     }
345                     bglobalr = getTrimValue("rtc");
346                     String retr = exec.getRetrType() + " " + exec.pretrCMD;
347                     if (bglobalr != null) {
348                         retr = bglobalr;
349                     }
350                     AbstractExecutor.initializeExecutor(retr, exec.pretrDelay,
351                             store, exec.pstorDelay);
352                     extraInformation = "Configuration Saved";
353                 }
354             }
355         }
356         String system = REQUEST.Rule.readFileUnique();
357         StringBuilder builder = new StringBuilder(system);
358         CommandExecutor exec = AbstractExecutor.getCommandExecutor();
359         WaarpStringUtils.replace(builder, "XXXSTCXXX",
360                 exec.getStorType() + " " + exec.pstorCMD);
361         WaarpStringUtils.replace(builder, "XXXSTDXXX",
362                 Long.toString(exec.pstorDelay));
363         WaarpStringUtils.replace(builder, "XXXRTCXXX",
364                 exec.getRetrType() + " " + exec.pretrCMD);
365         WaarpStringUtils.replace(builder, "XXXRTDXXX",
366                 Long.toString(exec.pretrDelay));
367         if (extraInformation != null) {
368             WaarpStringUtils.replace(builder, "XXXRESULTXXX", extraInformation);
369         } else {
370             WaarpStringUtils.replace(builder, "XXXRESULTXXX", "");
371         }
372         return builder.toString();
373     }
374 
375     private String Transfer() {
376         getParams();
377         String head = REQUEST.Transfer.readHeader();
378         String end = REQUEST.Transfer.readEnd();
379         String body = REQUEST.Transfer.readBody();
380         if (params == null || (!DbConstant.gatewayAdmin.isActive())) {
381             end = end.replace("XXXRESULTXXX", "");
382             body = FileBasedConfiguration.fileBasedConfiguration.getHtmlTransfer(body, LIMITROW);
383             return head + body + end;
384         }
385         String message = "";
386         List<String> parms = params.get("ACTION");
387         if (parms != null) {
388             String parm = parms.get(0);
389             boolean purgeAll = false;
390             boolean purgeCorrect = false;
391             boolean delete = false;
392             if ("PurgeCorrectTransferLogs".equalsIgnoreCase(parm)) {
393                 purgeCorrect = true;
394             } else if ("PurgeAllTransferLogs".equalsIgnoreCase(parm)) {
395                 purgeAll = true;
396             } else if ("Delete".equalsIgnoreCase(parm)) {
397                 delete = true;
398             }
399             if (purgeCorrect || purgeAll) {
400                 DbPreparedStatement preparedStatement = null;
401                 ReplyCode status = null;
402                 String action = "purgeAll";
403 
404                 if (purgeCorrect) {
405                     status = ReplyCode.REPLY_226_CLOSING_DATA_CONNECTION;
406                     action = "purge";
407                 }
408                 try {
409                     preparedStatement =
410                             DbTransferLog.getStatusPrepareStament(dbSession,
411                                     status, 0);
412                 } catch (WaarpDatabaseNoConnectionException e) {
413                     message = "Error during " + action;
414                 } catch (WaarpDatabaseSqlException e) {
415                     message = "Error during " + action;
416                 }
417                 if (preparedStatement != null) {
418                     try {
419                         FileBasedConfiguration config = FileBasedConfiguration.fileBasedConfiguration;
420                         String filename =
421                                 config.getBaseDirectory() +
422                                         FtpDir.SEPARATOR + config.ADMINNAME + FtpDir.SEPARATOR +
423                                         config.HOST_ID + "_logs_" + System.currentTimeMillis()
424                                         + ".xml";
425                         message = DbTransferLog.saveDbTransferLogFile(preparedStatement, filename);
426                     } finally {
427                         preparedStatement.realClose();
428                     }
429                 }
430             } else if (delete) {
431                 String user = getTrimValue("user");
432                 String acct = getTrimValue("account");
433                 String specid = getTrimValue("specialid");
434                 long specialId = Long.parseLong(specid);
435                 try {
436                     DbTransferLog log = new DbTransferLog(dbSession, user, acct, specialId);
437                     FileBasedConfiguration config = FileBasedConfiguration.fileBasedConfiguration;
438                     String filename =
439                             config.getBaseDirectory() +
440                                     FtpDir.SEPARATOR + config.ADMINNAME + FtpDir.SEPARATOR +
441                                     config.HOST_ID + "_log_" + System.currentTimeMillis() + ".xml";
442                     message = log.saveDbTransferLog(filename);
443                 } catch (WaarpDatabaseException e) {
444                     message = "Error during delete 1 Log";
445                 }
446             } else {
447                 message = "No Action";
448             }
449             end = end.replace("XXXRESULTXXX", message);
450         }
451         end = end.replace("XXXRESULTXXX", "");
452         body = FileBasedConfiguration.fileBasedConfiguration.getHtmlTransfer(body, LIMITROW);
453         return head + body + end;
454     }
455 
456     private String User() {
457         getParams();
458         String head = REQUEST.User.readHeader();
459         String end = REQUEST.User.readEnd();
460         String body = REQUEST.User.readBody();
461         FileBasedConfiguration config = FileBasedConfiguration.fileBasedConfiguration;
462         String filedefault = config.getBaseDirectory() +
463                 FtpDir.SEPARATOR + config.ADMINNAME +
464                 FtpDir.SEPARATOR + "authentication.xml";
465         if (params == null) {
466             end = end.replace("XXXRESULTXXX", "");
467             end = end.replace("XXXFILEXXX", filedefault);
468             body = FileBasedConfiguration.fileBasedConfiguration.getHtmlAuth(body);
469             return head + body + end;
470         }
471         List<String> parms = params.get("ACTION");
472         if (parms != null) {
473             String parm = parms.get(0);
474             if ("ImportExport".equalsIgnoreCase(parm)) {
475                 String file = getTrimValue("file");
476                 String exportImport = getTrimValue("export");
477                 String message = "";
478                 boolean purge = false;
479                 purge = params.containsKey("purge");
480                 boolean replace = false;
481                 replace = params.containsKey("replace");
482                 if (file == null) {
483                     file = filedefault;
484                 }
485                 end = end.replace("XXXFILEXXX", file);
486                 if (exportImport.equalsIgnoreCase("import")) {
487                     if (!config.initializeAuthent(file, purge)) {
488                         message += "Cannot initialize Authentication from " + file;
489                     } else {
490                         message += "Initialization of Authentication OK from " + file;
491                         if (replace) {
492                             if (!config.saveAuthenticationFile(
493                                     config.getAuthenticationFile())) {
494                                 message += " but cannot replace server authenticationFile";
495                             } else {
496                                 message += " and replacement done";
497                             }
498                         }
499                     }
500                 } else {
501                     // export
502                     if (!config.saveAuthenticationFile(file)) {
503                         message += "Authentications CANNOT be saved into " + file;
504                     } else {
505                         message += "Authentications saved into " + file;
506                     }
507                 }
508                 end = end.replace("XXXRESULTXXX", message);
509             } else {
510                 end = end.replace("XXXFILEXXX", filedefault);
511             }
512         }
513         end = end.replace("XXXRESULTXXX", "");
514         body = FileBasedConfiguration.fileBasedConfiguration.getHtmlAuth(body);
515         return head + body + end;
516     }
517 
518     private void getParams() {
519         if (request.method() == HttpMethod.GET) {
520             params = null;
521         } else if (request.method() == HttpMethod.POST) {
522             ByteBuf content = request.content();
523             if (content.isReadable()) {
524                 String param = content.toString(WaarpStringUtils.UTF8);
525                 QueryStringDecoder queryStringDecoder2 = new QueryStringDecoder("/?" + param);
526                 params = queryStringDecoder2.parameters();
527             } else {
528                 params = null;
529             }
530         }
531     }
532 
533     private void clearSession() {
534         if (admin != null) {
535             FileBasedAuth auth = sessions.remove(admin.value());
536             DbSession ldbsession = dbSessions.remove(admin.value());
537             admin = null;
538             if (auth != null) {
539                 auth.clear();
540             }
541             if (ldbsession != null) {
542                 ldbsession.disconnect();
543                 DbAdmin.decHttpSession();
544             }
545         }
546     }
547 
548     private void checkAuthent(ChannelHandlerContext ctx) {
549         newSession = true;
550         if (request.method() == HttpMethod.GET) {
551             String logon = Logon();
552             responseContent.append(logon);
553             clearSession();
554             writeResponse(ctx);
555             return;
556         } else if (request.method() == HttpMethod.POST) {
557             getParams();
558             if (params == null) {
559                 String logon = Logon();
560                 responseContent.append(logon);
561                 clearSession();
562                 writeResponse(ctx);
563                 return;
564             }
565         }
566         boolean getMenu = false;
567         if (params.containsKey("Logon")) {
568             String name = null, password = null;
569             List<String> values = null;
570             if (!params.isEmpty()) {
571                 // get values
572                 if (params.containsKey("name")) {
573                     values = params.get("name");
574                     if (values != null) {
575                         name = values.get(0);
576                         if (name == null || name.length() == 0) {
577                             getMenu = true;
578                         }
579                     }
580                 } else {
581                     getMenu = true;
582                 }
583                 // search the nb param
584                 if ((!getMenu) && params.containsKey("passwd")) {
585                     values = params.get("passwd");
586                     if (values != null) {
587                         password = values.get(0);
588                         if (password == null || password.length() == 0) {
589                             getMenu = true;
590                         } else {
591                             getMenu = false;
592                         }
593                     } else {
594                         getMenu = true;
595                     }
596                 } else {
597                     getMenu = true;
598                 }
599             } else {
600                 getMenu = true;
601             }
602             if (!getMenu) {
603                 logger.debug("Name=" + name + " vs "
604                         + name.equals(FileBasedConfiguration.fileBasedConfiguration.ADMINNAME) +
605                         " Passwd=" + password + " vs " +
606                         FileBasedConfiguration.fileBasedConfiguration.checkPassword(password));
607                 if (name.equals(FileBasedConfiguration.fileBasedConfiguration.ADMINNAME) &&
608                         FileBasedConfiguration.fileBasedConfiguration.checkPassword(password)) {
609                     authentHttp
610                             .specialNoSessionAuth(FileBasedConfiguration.fileBasedConfiguration.HOST_ID);
611                 } else {
612                     getMenu = true;
613                 }
614                 if (!authentHttp.isIdentified()) {
615                     logger.debug("Still not authenticated: {}", authentHttp);
616                     getMenu = true;
617                 }
618                 // load DbSession
619                 if (this.dbSession == null) {
620                     try {
621                         if (DbConstant.gatewayAdmin.isActive()) {
622                             this.dbSession = new DbSession(DbConstant.gatewayAdmin, false);
623                             DbAdmin.incHttpSession();
624                             this.isPrivateDbSession = true;
625                         }
626                     } catch (WaarpDatabaseNoConnectionException e1) {
627                         // Cannot connect so use default connection
628                         logger.warn("Use default database connection");
629                         this.dbSession = DbConstant.gatewayAdmin.getSession();
630                     }
631                 }
632             }
633         } else {
634             getMenu = true;
635         }
636         if (getMenu) {
637             String logon = Logon();
638             responseContent.append(logon);
639             clearSession();
640             writeResponse(ctx);
641         } else {
642             String index = index();
643             responseContent.append(index);
644             clearSession();
645             admin = new DefaultCookie(FTPSESSION,
646                     FileBasedConfiguration.fileBasedConfiguration.HOST_ID +
647                             Long.toHexString(random.nextLong()));
648             sessions.put(admin.value(), this.authentHttp);
649             if (this.isPrivateDbSession) {
650                 dbSessions.put(admin.value(), dbSession);
651             }
652             logger.debug("CreateSession: " + uriRequest + ":{}", admin);
653             writeResponse(ctx);
654         }
655     }
656 
657     @Override
658     protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
659         this.request = msg;
660         queryStringDecoder = new QueryStringDecoder(request.uri());
661         uriRequest = queryStringDecoder.path();
662         if (uriRequest.contains("gre/") || uriRequest.contains("img/") ||
663                 uriRequest.contains("res/")) {
664             HttpWriteCacheEnable.writeFile(request,
665                     ctx,
666                     FileBasedConfiguration.fileBasedConfiguration.httpBasePath + uriRequest,
667                     FTPSESSION);
668             return;
669         }
670         checkSession(ctx.channel());
671         if (!authentHttp.isIdentified()) {
672             logger.debug("Not Authent: " + uriRequest + ":{}", authentHttp);
673             checkAuthent(ctx);
674             return;
675         }
676         String find = uriRequest;
677         if (uriRequest.charAt(0) == '/') {
678             find = uriRequest.substring(1);
679         }
680         find = find.substring(0, find.indexOf("."));
681         REQUEST req = REQUEST.index;
682         try {
683             req = REQUEST.valueOf(find);
684         } catch (IllegalArgumentException e1) {
685             req = REQUEST.index;
686             logger.debug("NotFound: " + find + ":" + uriRequest);
687         }
688         switch (req) {
689             case index:
690                 responseContent.append(index());
691                 break;
692             case Logon:
693                 responseContent.append(index());
694                 break;
695             case System:
696                 responseContent.append(System());
697                 break;
698             case Rule:
699                 responseContent.append(Rule());
700                 break;
701             case User:
702                 responseContent.append(User());
703                 break;
704             case Transfer:
705                 responseContent.append(Transfer());
706                 break;
707             default:
708                 responseContent.append(index());
709                 break;
710         }
711         writeResponse(ctx);
712     }
713 
714     private void checkSession(Channel channel) {
715         String cookieString = request.headers().get(HttpHeaderNames.COOKIE);
716         if (cookieString != null) {
717             Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString);
718             if (!cookies.isEmpty()) {
719                 for (Cookie elt : cookies) {
720                     if (elt.name().equalsIgnoreCase(FTPSESSION)) {
721                         admin = elt;
722                         break;
723                     }
724                 }
725             }
726         }
727         if (admin != null) {
728             FileBasedAuth auth = sessions.get(admin.value());
729             if (auth != null) {
730                 authentHttp = auth;
731             }
732             DbSession dbSession = dbSessions.get(admin.value());
733             if (dbSession != null) {
734                 this.dbSession = dbSession;
735             }
736         } else {
737             logger.debug("NoSession: " + uriRequest + ":{}", admin);
738         }
739     }
740 
741     private void handleCookies(HttpResponse response) {
742         String cookieString = request.headers().get(HttpHeaderNames.COOKIE);
743         if (cookieString != null) {
744             Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString);
745             if (!cookies.isEmpty()) {
746                 // Reset the sessions if necessary.
747                 boolean findSession = false;
748                 for (Cookie cookie : cookies) {
749                     if (cookie.name().equalsIgnoreCase(FTPSESSION)) {
750                         if (newSession) {
751                             findSession = false;
752                         } else {
753                             findSession = true;
754                             response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie));
755                         }
756                     } else {
757                         response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie));
758                     }
759                 }
760                 newSession = false;
761                 if (!findSession) {
762                     if (admin != null) {
763                         response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(admin));
764                         logger.debug("AddSession: " + uriRequest + ":{}", admin);
765                     }
766                 }
767             }
768         } else if (admin != null) {
769             logger.debug("AddSession: " + uriRequest + ":{}", admin);
770             response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(admin));
771         }
772     }
773 
774     /**
775      * Write the response
776      * 
777      * @param ctx
778      */
779     private void writeResponse(ChannelHandlerContext ctx) {
780         // Convert the response content to a ByteBuf.
781         ByteBuf buf = Unpooled.copiedBuffer(responseContent.toString(),
782                 WaarpStringUtils.UTF8);
783         responseContent.setLength(0);
784 
785         // Decide whether to close the connection or not.
786         boolean keepAlive = HttpUtil.isKeepAlive(request);
787         boolean close = HttpHeaderValues.CLOSE.contentEqualsIgnoreCase(request
788                 .headers().get(HttpHeaderNames.CONNECTION)) ||
789                 (!keepAlive) || forceClose;
790 
791         // Build the response object.
792         FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
793         response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
794         response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html");
795         if (keepAlive) {
796             response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
797         }
798         if (!close) {
799             // There's no need to add 'Content-Length' header
800             // if this is the last response.
801             response.headers().set(HttpHeaderNames.CONTENT_LENGTH,
802                     String.valueOf(buf.readableBytes()));
803         }
804 
805         handleCookies(response);
806 
807         // Write the response.
808         ChannelFuture future = ctx.writeAndFlush(response);
809         // Close the connection after the write operation is done if necessary.
810         if (close) {
811             future.addListener(WaarpSslUtility.SSLCLOSE);
812         }
813         if (shutdown) {
814             /*
815              * Thread thread = new Thread( new FtpChannelUtils(
816              * FileBasedConfiguration.fileBasedConfiguration)); thread.setDaemon(true);
817              * thread.setName("Shutdown Thread"); thread.start();
818              */
819             FtpChannelUtils.teminateServer(FileBasedConfiguration.fileBasedConfiguration);
820             if (!close) {
821                 future.addListener(WaarpSslUtility.SSLCLOSE);
822             }
823         }
824     }
825 
826     /**
827      * Send an error and close
828      * 
829      * @param ctx
830      * @param status
831      */
832     private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
833         responseContent.setLength(0);
834         responseContent.append(error(status.toString()));
835         FullHttpResponse response = new DefaultFullHttpResponse(
836                 HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(responseContent.toString(), WaarpStringUtils.UTF8));
837         response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
838         response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html");
839         clearSession();
840         // Close the connection as soon as the error message is sent.
841         ctx.channel().writeAndFlush(response).addListener(WaarpSslUtility.SSLCLOSE);
842     }
843 
844     @Override
845     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
846         Throwable e1 = cause;
847         if (!(e1 instanceof CommandAbstractException)) {
848             if (e1 instanceof IOException) {
849                 // Nothing to do
850                 return;
851             }
852             logger.warn("Exception in HttpSslHandler", e1);
853         }
854         if (ctx.channel().isActive()) {
855             sendError(ctx, HttpResponseStatus.BAD_REQUEST);
856         }
857     }
858 
859     @Override
860     public void channelActive(ChannelHandlerContext ctx) throws Exception {
861         Channel channel = ctx.channel();
862         logger.debug("Add channel to ssl");
863         FileBasedConfiguration.fileBasedConfiguration.getHttpChannelGroup().add(channel);
864         super.channelActive(ctx);
865     }
866 }