Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion index.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ pub(all) struct Mocket {
ws_clients : Map[String, Unit]
ws_channels : Map[String, Map[String, Unit]]
ws_client_port : Map[String, Int]
max_body_size : Int
}

///|
pub fn new(base_path? : String = "") -> Mocket {
pub fn new(base_path? : String = "", max_body_size? : Int = 1048576) -> Mocket {
{
base_path,
mappings: {},
Expand All @@ -40,6 +41,7 @@ pub fn new(base_path? : String = "") -> Mocket {
ws_clients: {},
ws_channels: {},
ws_client_port: {},
max_body_size,
}
}

Expand Down
22 changes: 18 additions & 4 deletions mocket.js.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,27 @@ pub fn listen_ffi(mocket : Mocket, address : String) -> Unit {
// 如果是 post,先等待 data 事件
if event.req.http_method == "POST" {
let buffer = Buffer()
suspend(fn(res, _) {
let mut total_size = 0
let mut exceeded = false
(try? suspend(fn(res, _) {
req.on("data", data => {
buffer.write_bytes(node_body_chunk_to_bytes(data))
if !exceeded {
let chunk = node_body_chunk_to_bytes(data)
total_size = total_size + chunk.length()
if mocket.max_body_size > 0 && total_size > mocket.max_body_size {
exceeded = true
} else {
buffer.write_bytes(chunk)
}
}
})
req.on("end", _ => res(()))
}) catch {
_ => ()
}))
|> ignore
if exceeded {
res.write_head(413, @js.Object::new().to_value())
res.end(@js.Value::cast_from("Request body too large"))
return
}
event.req.raw_body = buffer.to_bytes()
}
Expand Down
40 changes: 39 additions & 1 deletion mocket.native.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,19 @@ async fn handle_http_request(
conn : @http.ServerConnection,
) -> Unit {
let raw_body = if request_has_body(request) {
body_reader.read_all().binary()
let content_length = request.headers
.get("content-length")
.map(s => try { @string.parse_int(s.trim()) } catch { _ => 0 })
.unwrap_or(0)
if mocket.max_body_size > 0 && content_length > mocket.max_body_size {
let err_response = HttpResponse::new(
RequestEntityTooLarge,
raw_body=b"Request body too large",
)
send_native_response(request, conn, err_response)
return
}
read_body_limited(body_reader, mocket.max_body_size)
} else {
b""
}
Expand All @@ -396,6 +408,32 @@ async fn handle_http_request(
send_native_response(request, conn, response)
}

///|
async fn read_body_limited(reader : &@io.Reader, max_size : Int) -> Bytes {
if max_size <= 0 {
return reader.read_all().binary()
}
let buf = Buffer()
let chunk_size = 8192
let chunk = FixedArray::make(chunk_size, b'\x00')
for total = 0 {
let n = try { reader.read(chunk) } catch { _ => break }
if n <= 0 {
break
}
if total + n > max_size {
break
}
let arr : Array[Byte] = []
for i = 0; i < n; i = i + 1 {
arr.push(chunk[i])
}
buf.write_bytes(Bytes::from_array(arr))
continue total + n
}
buf.to_bytes()
}

///|
async fn handle_websocket_request(
port : Int,
Expand Down
Loading