x.vweb, picoev: fix timeout event (#20377)

This commit is contained in:
Casper Küthe 2024-01-04 11:05:39 +01:00 committed by GitHub
parent 870e6189db
commit 7c310a1bd7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 7 deletions

View file

@ -216,6 +216,12 @@ fn raw_callback(fd int, events int, context voidptr) {
$if trace_fd ? { $if trace_fd ? {
eprintln('timeout ${fd}') eprintln('timeout ${fd}')
} }
if !isnil(pv.raw_cb) {
pv.raw_cb(mut pv, fd, events)
return
}
pv.close_conn(fd) pv.close_conn(fd)
return return
} else if events & picoev.picoev_read != 0 { } else if events & picoev.picoev_read != 0 {

View file

@ -91,8 +91,8 @@ fn test_bigger_content_length() {
data: data data: data
})! })!
assert x.status() == .bad_request // Content-length is larger than the data sent, so the request should timeout
assert x.body == 'Mismatch of body length and Content-Length header' assert x.status() == .request_timeout
} }
fn test_smaller_content_length() { fn test_smaller_content_length() {

View file

@ -57,6 +57,15 @@ pub const http_404 = http.new_response(
).join(headers_close) ).join(headers_close)
) )
pub const http_408 = http.new_response(
status: .request_timeout
body: '408 Request Timeout'
header: http.new_header(
key: .content_type
value: 'text/plain'
).join(headers_close)
)
pub const http_413 = http.new_response( pub const http_413 = http.new_response(
status: .request_entity_too_large status: .request_entity_too_large
body: '413 Request entity is too large' body: '413 Request entity is too large'
@ -256,6 +265,13 @@ mut:
string_responses []StringResponse string_responses []StringResponse
} }
// reset request parameters for `fd`:
// reset content-length index and the http request
pub fn (mut params RequestParams) request_done(fd int) {
params.incomplete_requests[fd] = http.Request{}
params.idx[fd] = 0
}
// run_at - start a new VWeb server, listening only on a specific address `host`, at the specified `port` // run_at - start a new VWeb server, listening only on a specific address `host`, at the specified `port`
// Example: vweb.run_at(new_app(), vweb.RunParams{ host: 'localhost' port: 8099 family: .ip }) or { panic(err) } // Example: vweb.run_at(new_app(), vweb.RunParams{ host: 'localhost' port: 8099 family: .ip }) or { panic(err) }
@[direct_array_access; manualfree] @[direct_array_access; manualfree]
@ -306,7 +322,13 @@ pub fn run_at[A, X](mut global_app A, params RunParams) ! {
fn ev_callback[A, X](mut pv picoev.Picoev, fd int, events int) { fn ev_callback[A, X](mut pv picoev.Picoev, fd int, events int) {
mut params := unsafe { &RequestParams(pv.user_data) } mut params := unsafe { &RequestParams(pv.user_data) }
if events == picoev.picoev_write { if events == picoev.picoev_timeout {
$if trace_picoev_callback ? {
eprintln('> request timeout on file descriptor ${fd}')
}
handle_timeout(mut pv, mut params, fd)
} else if events == picoev.picoev_write {
$if trace_picoev_callback ? { $if trace_picoev_callback ? {
eprintln('> write event on file descriptor ${fd}') eprintln('> write event on file descriptor ${fd}')
} }
@ -320,14 +342,30 @@ fn ev_callback[A, X](mut pv picoev.Picoev, fd int, events int) {
eprintln('[vweb] error: write event on connection should be closed') eprintln('[vweb] error: write event on connection should be closed')
pv.close_conn(fd) pv.close_conn(fd)
} }
} else { } else if events == picoev.picoev_read {
$if trace_picoev_callback ? { $if trace_picoev_callback ? {
eprintln('> read event on file descriptor ${fd}') eprintln('> read event on file descriptor ${fd}')
} }
handle_read[A, X](mut pv, mut params, fd) handle_read[A, X](mut pv, mut params, fd)
} else {
// should never happen
eprintln('[vweb] error: invalid picoev event ${events}')
} }
} }
fn handle_timeout(mut pv picoev.Picoev, mut params RequestParams, fd int) {
mut conn := &net.TcpConn{
sock: net.tcp_socket_from_handle_raw(fd)
handle: fd
is_blocking: false
}
fast_send_resp(mut conn, vweb.http_408) or {}
pv.close_conn(fd)
params.request_done(fd)
}
// handle_write_file reads data from a file and sends that data over the socket. // handle_write_file reads data from a file and sends that data over the socket.
@[direct_array_access; manualfree] @[direct_array_access; manualfree]
fn handle_write_file(mut pv picoev.Picoev, mut params RequestParams, fd int) { fn handle_write_file(mut pv picoev.Picoev, mut params RequestParams, fd int) {
@ -507,9 +545,7 @@ fn handle_read[A, X](mut pv picoev.Picoev, mut params RequestParams, fd int) {
} }
defer { defer {
// reset content-length index, the http request and close the connection params.request_done(fd)
params.incomplete_requests[fd] = http.Request{}
params.idx[fd] = 0
} }
if completed_context := handle_request[A, X](mut conn, req, params) { if completed_context := handle_request[A, X](mut conn, req, params) {