/*
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 ""
}
}