/**
 * ********************************************************************************
 * 프로그램명 : HttpFileUpload_1.java 작 성 자 : 강원중 작 성 일 : 2003. 7.23 최신변경일 : 2013.
 * 1.11
 **********************************************************************************
 */
package kr.co.kihyun.beans.totsys.board;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.co.kihyun.beans.user.HttpSSOLogin;
import kr.co.kihyun.io.FileUtil;
import kr.co.kihyun.io.MultipartRequest;
import kr.co.kihyun.lang.MInteger;
import kr.co.kihyun.lang.MLong;
import kr.co.kihyun.lang.MString;
import kr.co.kihyun.moumi.MoumiConfig;
//import kr.co.kihyun.text.html.ServletUtil;
import kr.co.kihyun.util.MRandom;

import org.apache.commons.fileupload.FileItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebServlet("/servlet/kr.co.kihyun.beans.totsys.board.HttpFileUpload_1")
public class HttpFileUpload_1 extends HttpServlet {

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = LoggerFactory.getLogger(HttpFileUpload_1.class);

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

        res.setContentType("text/html;charset=UTF-8");
        PrintWriter out = res.getWriter();

        MultipartRequest multi = null;
        String svrFilename = "";
        String usrFilename = "";
        String boardGroupID = "";
        String connURL = "";
        String mode = "";
        String usID = HttpSSOLogin.getLoginID(req);
        String dtID = HttpSSOLogin.getDeptID(req);
        Long docID = null;
        Long reportID = null;
        String boardID = "";
        String msg = "";
        String maxSize = "1";
        String checkSize = "";
        boolean isExtNullOk = true;   //7.+++
        boolean isExtFileOk = true;   //7.+++
        boolean isDirectoryOk = true;  //3.+++
        
        String currentFileSize = "";    // 업로드할 파일의 크기(byte)를 저장할 변수. 2014.09.02 by youngjun cho.
        int accumulateFileSize = 0;     // 업로드된 파일들의 총 누적 크기(byte)를 저장할 변수. 2014.09.02 by youngjun cho.
      
        try {

            maxSize = req.getParameter("maxSize");
            if (maxSize == null || maxSize.equals("")) {
                maxSize = "10";
            }
            int tmpSize = Integer.parseInt(maxSize) * 1024 * 1024; //사이즈를 정해준다.
            checkSize = String.valueOf(tmpSize);

            //MultipartRequest.maxSize = Integer.parseInt(maxSize);
            //multi = new MultipartRequest(req);
            multi = new MultipartRequest(req, tmpSize);
            //multi.setMaxSize(Integer.parseInt(maxSize));
            //System.out.println("====> HttpFileUpload_1.java multi.getMaxSize() : " + multi.getMaxSize());
            
            //LOG.debug("req.appendFile: {}", req.getParameter("appendFile"));
            mode = MString.checkNull(multi.getParameter("mode"));
            boardGroupID = multi.getParameter("boardGroupID");
            usrFilename = multi.getParameter("appendFile");
            
            //7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Add by KWON,HAN
            int extIndex = 0 ;
            extIndex = usrFilename.lastIndexOf('.');
            if(extIndex < 0 ) {
                //LOG.debug("7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Not Test / usrFilename: {}", usrFilename);
                isExtNullOk = false;
                //out.print("<script language='javascript'>alert('확장자가 없는 파일입니다.');</script>");   
                return;
            }              
            
            //v2 22.정수형 오버플로우_CWE-190 : Update by YOUNGJUN,CHO
            if (extIndex < Integer.MAX_VALUE) {
                //String file_ext = usrFilename.substring(usrFilename.lastIndexOf('.') + 1); 
                String file_ext = usrFilename.substring(extIndex + 1); 
                
                if( file_ext.equalsIgnoreCase("exe") || file_ext.equalsIgnoreCase("bat") || file_ext.equalsIgnoreCase("sh") ) { 
                    //LOG.debug("7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Not Test / usrFilename: {}", usrFilename);
                    //out.print("<script language='javascript'>alert('확장자가 [exe, bat, sh]는 업로드가 제한된 파일입니다.');</script>"); 
                    isExtFileOk = false;
                    return;
                }
            } else {
                //LOG.debug("v2 22.정수형 오버플로우_CWE-190 : Not Test / usrFilename: {}", usrFilename);
                //out.print("<script language='javascript'>alert('확장자가 [exe, bat, sh]는 업로드가 제한된 파일입니다.');</script>"); 
                isExtFileOk = false;
                return;
            }
            //================================================ v2 22.정수형 오버플로우_CWE-190 : Update by YOUNGJUN,CHO
            //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Add by KWON,HAN
                        
            
            docID = MLong.parseLong(multi.getParameter("docID"));
            reportID = MLong.parseLong(multi.getParameter("reportID"));
            boardID = MString.checkNull(multi.getParameter("boardID"));
            
            // 2014.09.02 by youngjun cho.
            // 업로드된 파일들의 총 누적 크기(byte)를 jsp 의 hidden value 에 저장 후 파라미터로 받아온다.
            accumulateFileSize = MInteger.parseInt(multi.getParameter("accumulateFileSize"));
            //System.out.println("====> before file check accumulateFileSize : " + accumulateFileSize);

            //LOG.debug("docID: {}, boardID: {}, mode: {}", new Object[] {docID, boardID, mode});
            if (!MString.isNull(usrFilename)) {
                String[] usrFilenamePath = usrFilename.split("\\\\");
                usrFilename = usrFilenamePath[usrFilenamePath.length - 1];

                String imsi = "";
//                String[] filter_word = {" ", "\\?", "\\/", "\\~", "\\!", "\\@", "\\#", "\\$", "\\%", "\\^", "\\&", "\\*", "\\(", "\\)", "\\+", "\\=", "\\|", "\\\\", "\\}", "\\]", "\\{", "\\[", "\\\"", "\\'", "\\:", "\\;", "\\<", "\\,", "\\>", "\\?", "\\/"};
                String[] filter_word = {"\\?","\\/","\\~","\\!","\\@","\\#","\\$","\\%","\\^","\\&","\\*","\\+","\\=","\\|","\\\\","\\\"","\\'","\\:","\\;","\\,"};
                for (int ii = 0; ii < filter_word.length; ii++) {
                    imsi = usrFilename.replaceAll(filter_word[ii], "_");
                    usrFilename = imsi;
                }

                LOG.debug("usrFilename: {}", usrFilename);
            }
            svrFilename = FileUtil.getName(usrFilename, Integer.toString(MRandom.getInt(100))); //두자리의 랜덤 수치를 얻음

            File path;
            if (docID != null) {
                path = MoumiConfig.getFileDirectory();
                LOG.debug("MoumiConfig.getFileDirectory(): " + MoumiConfig.getFileDirectory());
            } else if (reportID != null) {
                path = MoumiConfig.getFileDirectory();
                LOG.debug("MoumiConfig.getFileDirectory(): " + MoumiConfig.getFileDirectory());
//			} else if (!MString.isNull(boardID)) {
//				path = new File(MoumiConfig.getBoardFileRoot(), boardID.toString());
//				LOG.debug("MoumiConfig.getBoardFileRoot(): " + MoumiConfig.getBoardFileRoot());
            } else if ("csv".equals(mode)) {
                path = MoumiConfig.getCsvFileRoot();
                LOG.debug("MoumiConfig.getCsvFileRoot(): " + MoumiConfig.getCsvFileRoot());
            } else {
                path = MoumiConfig.getFileDirectory();
                LOG.debug("MoumiConfig.getFileDirectory(): " + MoumiConfig.getFileDirectory());
            }
            if (!path.isDirectory()) {
                if (!path.mkdirs()) {
                    throw new ServletException(path + " is not a directory.");
                }
            }
            FileItem upFile = multi.getFileItem("appendFile");
            LOG.debug("UPFILE: {}", upFile);

            // 업로드할 파일의 크기를 구한다. (2014.09.02 by youngjun cho.)
            currentFileSize = Long.toString(upFile.getSize());
            LOG.debug("UPFILE currentFileSize : {}", currentFileSize);

            //v2 22.정수형 오버플로우_CWE-190 : Update by YOUNGJUN,CHO
            if (accumulateFileSize < Integer.MAX_VALUE) {
                // 업로드된 총 누적 파일의 크기와 현재 업로드할 파일의 크기를 더한다. (2014.09.02 by youngjun cho.)
                accumulateFileSize = accumulateFileSize + Integer.parseInt(currentFileSize);
                //System.out.println("====> after file check accumulateFileSize : " + accumulateFileSize + ", tmpSize : " + tmpSize);
            } else {
                msg = "-66";
                return;
            }
            //================================================

            // 제한용량 이상이면 "-66" 을 리턴한다. (2014.09.02 by youngjun cho.)
            if (tmpSize <= accumulateFileSize) {
                msg = "-66";
                return;
            }

            //3.디렉토리 경로 조작(getParameter)_CWE-22/23/36 : Add by KWON,HAN
            LOG.debug("svrFilename: {}", svrFilename); 
            if(svrFilename.contains("..") || svrFilename. contains("/")) { // 특수문자열 검증
                //LOG.debug("3.디렉토리 경로 조작(getParameter)_CWE-22/23/36 : Test OK {}", svrFilename);
                isDirectoryOk = false;
                return;
            }
            //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
            
            upFile.write(new File(path, svrFilename));
            LOG.debug("UPFILE writed to svrFilename: {}/{}", path, svrFilename);

            svrFilename = URLEncoder.encode(svrFilename, "UTF-8");
            usrFilename = URLEncoder.encode(usrFilename, "UTF-8");

            return;
        } catch (IOException ex) {
            msg = ex.getMessage();
            if (msg.indexOf(checkSize) > 0) {
                msg = "-99";
            } else {
                msg = "-88";
            }
            ex.printStackTrace();
        } catch (Exception ex) {
            msg = ex.getMessage();
            if (msg.indexOf(checkSize) > 0) {
                msg = "-99";
            } else {
                msg = "-88";
            }
            ex.printStackTrace();
        } finally {
            connURL = "/totsys/common/inc/board/doc/write_file_upload_1.jsp?execMode=up&svrFilename="
                    + svrFilename + "&usrFilename=" + usrFilename + "&boardGroupID=" + boardGroupID + "&docID=" + docID
                    + "&reportID=" + reportID + "&boardID=" + boardID + "&mode=" + mode + "&MSG=" + msg + "&maxSize=" + maxSize + "&currentFileSize=" + currentFileSize;
            if (connURL.length() > 2047) {
                msg = "-77";
            }
            if(!isExtNullOk) { 
                msg="-33"; 
            } //7.+++
            if(!isExtFileOk) { 
                msg="-55"; 
            } //7.+++
            if(!isDirectoryOk) { 
                msg="-44"; 
            } //3.+++
            if (!msg.equals("")) {
                svrFilename = "";
                usrFilename = "";
                currentFileSize = "0";  // 에러인 경우 파일이 업로드되지 않으므로 파일 크기를 0으로 리턴한다. (2014.09.02 by youngjun cho.)
            }
            
            //v2. 1.HTTP 응답분할 : Update by KWON,HAN             
//            connURL = "/totsys/common/inc/board/doc/write_file_upload_1.jsp?execMode=up&svrFilename="
//                    + svrFilename + "&usrFilename=" + usrFilename + "&boardGroupID=" + boardGroupID + "&docID=" + docID
//                    + "&reportID=" + reportID + "&boardID=" + boardID + "&mode=" + mode + "&MSG=" + msg + "&maxSize=" + maxSize + "&currentFileSize=" + currentFileSize;
            
            if (svrFilename != null || usrFilename != null) {               
                // 수정 : 외부 입력값 필터링
                String filtered_svrFilename = svrFilename.replaceAll("\r","").replaceAll("\n","");      
                String filtered_usrFilename = usrFilename.replaceAll("\r","").replaceAll("\n","");      
                //LOG.debug("v2 1.HTTP 응답분할 : HttpFileUpload_1.doPost() filtered_svrFilename={} : Test OK", filtered_svrFilename);
                //LOG.debug("v2 1.HTTP 응답분할 : HttpFileUpload_1.doPost() filtered_usrFilename={} : Test OK", filtered_usrFilename);
                
                //v2. 3.신뢰되지 않는 URL 주소로 자동 접속 연결_CWE-601 : Update by KWON,HAN       
//                connURL = "/totsys/common/inc/board/doc/write_file_upload_1.jsp?execMode=up&svrFilename="
//                        + filtered_svrFilename + "&usrFilename=" + filtered_usrFilename + "&boardGroupID=" + boardGroupID + "&docID=" + docID
//                        + "&reportID=" + reportID + "&boardID=" + boardID + "&mode=" + mode + "&MSG=" + msg + "&maxSize=" + maxSize + "&currentFileSize=" + currentFileSize;
                
                // 다른 페이지 이동하는 URL 리스트를 만듬
                String allowURL[] = { "/totsys/common/inc/board/doc/write_file_upload_1.jsp" };
                connURL = allowURL[0] + "?execMode=up&svrFilename="
                        + filtered_svrFilename + "&usrFilename=" + filtered_usrFilename + "&boardGroupID=" + boardGroupID + "&docID=" + docID
                        + "&reportID=" + reportID + "&boardID=" + boardID + "&mode=" + mode + "&MSG=" + msg + "&maxSize=" + maxSize + "&currentFileSize=" + currentFileSize;
                LOG.debug("v2 3.신뢰되지 않는 URL 주소로 자동 접속 연결_CWE-601 : HttpFileUpload_1.doPost() connURL={} : Test OK", connURL);
                //=========================================================================                
            }                        
            //========================================              
            res.sendRedirect(connURL);
        }
    }
}
