Skip to content

Commit

Permalink
x.vweb, picoev: fix timeout event (#20377)
Browse files Browse the repository at this point in the history
  • Loading branch information
Casper64 committed Jan 4, 2024
1 parent 870e618 commit 7c310a1
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 7 deletions.
6 changes: 6 additions & 0 deletions vlib/picoev/picoev.v
Expand Up @@ -216,6 +216,12 @@ fn raw_callback(fd int, events int, context voidptr) {
$if trace_fd ? {
eprintln('timeout ${fd}')
}

if !isnil(pv.raw_cb) {
pv.raw_cb(mut pv, fd, events)
return
}

pv.close_conn(fd)
return
} else if events & picoev.picoev_read != 0 {
Expand Down
4 changes: 2 additions & 2 deletions vlib/x/vweb/tests/large_payload_test.v
Expand Up @@ -91,8 +91,8 @@ fn test_bigger_content_length() {
data: data
})!

assert x.status() == .bad_request
assert x.body == 'Mismatch of body length and Content-Length header'
// Content-length is larger than the data sent, so the request should timeout
assert x.status() == .request_timeout
}

fn test_smaller_content_length() {
Expand Down
46 changes: 41 additions & 5 deletions vlib/x/vweb/vweb.v
Expand Up @@ -57,6 +57,15 @@ pub const http_404 = http.new_response(
).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(
status: .request_entity_too_large
body: '413 Request entity is too large'
Expand Down Expand Up @@ -256,6 +265,13 @@ mut:
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`
// Example: vweb.run_at(new_app(), vweb.RunParams{ host: 'localhost' port: 8099 family: .ip }) or { panic(err) }
@[direct_array_access; manualfree]
Expand Down Expand Up @@ -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) {
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 ? {
eprintln('> write event on file descriptor ${fd}')
}
Expand All @@ -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')
pv.close_conn(fd)
}
} else {
} else if events == picoev.picoev_read {
$if trace_picoev_callback ? {
eprintln('> read event on file descriptor ${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.
@[direct_array_access; manualfree]
fn handle_write_file(mut pv picoev.Picoev, mut params RequestParams, fd int) {
Expand Down Expand Up @@ -507,9 +545,7 @@ fn handle_read[A, X](mut pv picoev.Picoev, mut params RequestParams, fd int) {
}

defer {
// reset content-length index, the http request and close the connection
params.incomplete_requests[fd] = http.Request{}
params.idx[fd] = 0
params.request_done(fd)
}

if completed_context := handle_request[A, X](mut conn, req, params) {
Expand Down

0 comments on commit 7c310a1

Please sign in to comment.