package org.voovan.network.messagesplitter;

import org.voovan.network.IoSession;
import org.voovan.network.MessageSplitter;
import org.voovan.tools.TByteBuffer;
import org.voovan.tools.TString;

import java.math.BigInteger;
import java.nio.ByteBuffer;

/**
 * Http 消息分割类
 *
 * @author helyho
 *
 * Voovan Framework.
 * WebSite: https://github.com/helyho/Voovan
 * Licence: Apache v2 License
 */
public class HttpMessageSplitter implements MessageSplitter {

	private static final String	BODY_TAG	= "\r\n\r\n";
	private int result = -1;

	private int contentLength = -1;
    boolean isChunked = false;


    @Override
	public int canSplite(IoSession session, ByteBuffer byteBuffer) {

		if(byteBuffer.limit()==0){
			return -1;
		}

        if( "WebSocket".equals(session.getAttribute(0x1111)) ){
            result = isWebSocketFrame(byteBuffer);
        }else{
            result = isHttpFrame(byteBuffer);

            if(result>0){
                result = 0;
            }else if(result == -1){
                session.close();
            }
        }



        return result;
	}

    private int isHttpFrame(ByteBuffer byteBuffer){
        int bodyTagIndex = 0;
        byte[] buffer = TByteBuffer.toArray(byteBuffer);
        StringBuilder stringBuilder = new StringBuilder();
        String httpHead = null;
        for(int x=0;x<buffer.length-3;x++){
            if(buffer[x] == '\r' && buffer[x+1] == '\n' && buffer[x+2] == '\r' && buffer[x+3] == '\n'){
                bodyTagIndex = x + 3;
                httpHead = stringBuilder.toString();
                break;
            }else{
                stringBuilder.append((char)buffer[x]);
            }
        }

        if(httpHead !=null && isHttpHead(httpHead)) {

            String[] contentLengthLines = TString.searchByRegex(httpHead, "Content-Length: \\d+");
            if (contentLengthLines.length > 1) {
                contentLength = Integer.parseInt(contentLengthLines[0].split(" ")[1].trim());
            }

            isChunked = httpHead.contains("chunked");
            return bodyTagIndex;

        }else{
            return -1;
        }
    }

    private boolean isHttpHead(String str){
        //判断是否是 HTTP 头
        int firstLineIndex = str.indexOf("\r\n");
        if(firstLineIndex != -1) {
            String firstLine = str.substring(0, firstLineIndex);
            if (TString.regexMatch(firstLine, "HTTP\\/\\d\\.\\d\\s\\d{3}\\s.*") <= 0) {
                if (TString.regexMatch(firstLine, "^[A-Z]*\\s.*\\sHTTP\\/\\d\\.\\d") <= 0) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 判断缓冲区中的数据是否是一个 WebSocket 帧
     * @param buffer 缓冲区对象
     * @return WebSocket 帧报文长度,-1不是WebSocket 帧, 大于0 返回的 WebSocket 的长度
     */
    public static int isWebSocketFrame(ByteBuffer buffer) {
        // 接受数据的大小
        int maxpacketsize = buffer.remaining();
        // 期望数据包的实际大小
        int expectPackagesize = 2;
        if (maxpacketsize < expectPackagesize) {
            return -1;
        }
        byte finByte = buffer.get();
        boolean fin = finByte >> 8 != 0;
        byte rsv = (byte) ((finByte & ~(byte) 128) >> 4);
        if (rsv != 0) {
            return -1;
        }
        byte maskByte = buffer.get();
        boolean mask = (maskByte & -128) != 0;
        int payloadlength = (byte) (maskByte & ~(byte) 128);
        int optcode = (byte) (finByte & 15);

        if(optcode < 0 && optcode > 10){
            return -1;
        }

        if (!fin) {
            if (optcode == 9 || optcode == 10 || optcode == 8) {
                return -1;
            }
        }

        if (payloadlength >= 0 && payloadlength <= 125) {
        } else {
            if (optcode == 9 || optcode == 10 || optcode == 8) {
                return -1;
            }
            if (payloadlength == 126) {
                expectPackagesize += 2;
                byte[] sizebytes = new byte[3];
                sizebytes[1] = buffer.get();
                sizebytes[2] = buffer.get();
                payloadlength = new BigInteger(sizebytes).intValue();
            } else {
                expectPackagesize += 8;
                byte[] bytes = new byte[8];
                for (int i = 0; i < 8; i++) {
                    bytes[i] = buffer.get();
                }
                long length = new BigInteger(bytes).longValue();
                if (length <= Integer.MAX_VALUE) {
                    payloadlength = (int) length;
                }
            }
        }

        expectPackagesize += (mask ? 4 : 0);
        expectPackagesize += payloadlength;

        // 如果实际接受的数据小于数据包的大小则报错
        if (maxpacketsize < expectPackagesize) {
            buffer.position(0);
            return -1;
        } else {
            buffer.position(0);
            return expectPackagesize;
        }
    }
}

@@ -452,17 +452,20 @@
 tter %7B%0A%0A
-%09
+    
 private 
@@ -507,17 +507,20 @@
 n%5Cr%5Cn%22;%0A
-%09
+    
 private 
@@ -537,17 +537,20 @@
  = -1;%0A%0A
-%09
+    
 private 
@@ -620,17 +620,20 @@
 verride%0A
-%09
+    
 public i
@@ -690,18 +690,24 @@
 fer) %7B%0A%0A
-%09%09
+        
 if(byteB
@@ -729,11 +729,20 @@
 0)%7B%0A
-%09%09%09
+            
 retu
@@ -752,10 +752,16 @@
 -1;%0A
-%09%09
+        
 %7D%0A%0A 
@@ -1109,17 +1109,20 @@
 result;%0A
-%09
+    
 %7D%0A%0A    p
@@ -1346,16 +1346,151 @@
 = null;%0A
+%0A        //%E9%9D%9E HTTP %E8%AF%B7%E6%B1%82%E7%9B%B4%E6%8E%A5%E5%85%B3%E9%97%AD%E8%BF%9E%E6%8E%A5%0A        if(TByteBuffer.indexOf(byteBuffer, %22HTTP/1.%22.getBytes()) != 0 ) %7B%0A            return -1;%0A        %7D%0A%0A
         
@@ -2269,33 +2269,33 @@
         return -
-1
+2
 ;%0A        %7D%0A    

修复 Http 请求针对异常请求处理的 bug