4267a229创建于 2024年8月2日历史提交
/*
    Copyright (c) [2023] [squallzhao]
    fountain is licensed under APACHE LICENSE, VERSION 2.0.
    You can use this software according to the terms and conditions of the APACHE LICENSE, VERSION 2.0.
    You may obtain a copy of APACHE LICENSE, VERSION 2.0 at: https://www.apache.org/licenses/LICENSE-2.0
*/
package microservice.web.http11
import microservice.web.socket.*
import microservice.exception.*
import std.collection.*
import microservice.trace.*

public class Http11DataProcessor <: IDataProcessor{
    static var sheaderLimit: Int64 = 100000
    static var sbodyLimit: Int64 = 1000000

    public static func setHeaderLimit(limit: Int64){
        sheaderLimit = limit
    }

    public static func setBodyLimit(limit: Int64){
        sbodyLimit = limit
    }

    var data = ArrayList<Rune>()
    var dispatcher: IDispatcher;
    public init(dispatcher: IDispatcher){
        this.dispatcher = dispatcher
    }

    public func process(wrapper: SocketWrapper): Bool {
        var result = innerProcess(wrapper)
        return result
    }

    private func innerProcess(wrapper: SocketWrapper): Bool {
        var headerLimit:Int64 = 0;
        var req = Http11Req()
        var firstLine = readLineSimple(wrapper)
        if (firstLine.y) {
            headerLimit += firstLine.x.size
            req.parseFirstLine(firstLine.x)
        } else{
            return false;
        }

        while(true){
            var line: Pair<String, Bool> = readLineSimple(wrapper)
            if (line.y) {
                if (line.x==""){
                    break
                }
                headerLimit += line.x.size
                req.parseOtherLine(line.x)
            } else{
                return false;
            }
        }
        if (headerLimit>sheaderLimit){
            throw SizeTooBigException("req header too big")
        }

        if (req.getBodyLength()>0){
            var s = readn(wrapper,Int64(req.getBodyLength()))
            if (s == Option<String>.None) {
                return false;
            }
            req.body = s.getOrThrow()    
            if (req.body.size> sbodyLimit){
                throw SizeTooBigException("req body too big")
            }
        }
        
        req.dump()
        
        var res = Http11Res()
        dispatcher.dispatch(req,res)
        var rsp = res.toHttp().toArray()
        wrapper.write(rsp)
        return true;
    }

    func readn(wrapper: SocketWrapper, n: Int64): Option<String>{
        var data = ArrayList<Rune>()
        var nRead = 0
        while(nRead<n){
            var buffer: Array<UInt8> = Array<UInt8>(n-nRead,item:0)
            var len = wrapper.read(buffer)
            if (len>=1){
                for(i in 0..len){
                    data.append(Rune(buffer[i]))
                }
            } else{
                return Option<String>.None;
            }
            nRead +=len
        }
        return String(data)
    }

    func readLineSimple(wrapper: SocketWrapper): Pair<String, Bool>{
        try{
            var data = ArrayList<Rune>()
            var buffer: Array<UInt8> = Array<UInt8>(1,item:0)
            while(true){
                var len = wrapper.read(buffer)
                if (len>=1){
                    if (buffer[0]==b'\n'){
                        return Pair<String,Bool>(String(data),true)
                    } else if (buffer[0]==b'\r'){        
                    } else{
                        data.append(Rune(buffer[0]))
                    }
                }else  {
                    return Pair<String,Bool>("",false)
                }
            }
        } catch(e: Exception){
            Logger.error("readLineSimple: "+ e.message)
            e.printStackTrace()
        }
       
        return Pair<String,Bool>("",false)
    }

    func readLine(wrapper:SocketWrapper) :String{
        var line =""
        for(i in 0..data.size){
            if (data.get(i).toString()=='\r'){
                //line = String(data.toArray(),start:0,length:i)
                line = String(data.toArray()[0..i])
                var origin = data;
                data = ArrayList<Rune>()
                for(j in i+1..data.size){
                    data.append(origin.get(j).getOrThrow())
                }
                return line;
            }
        }

        var buffer: Array<UInt8> = Array<UInt8>(128,item:0)
        var len = wrapper.read(buffer)
        for(i in 0..len){
            if (buffer[i]==b'\r'){
                line = String(data)
                data = ArrayList<Rune>()
                for(j in i+1..len){
                    data.append(Rune(buffer[j]))
                }
                return line;
            } else{
                data.append(Rune(buffer[i]))
            }
        }
        return ""
    }
}