mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
x.vweb: fix fsanitize-address test for SSE, improve documentation on the usage of takeover_conn
(#20249)
This commit is contained in:
parent
06a536eff2
commit
ada9efd825
6 changed files with 30 additions and 11 deletions
|
@ -805,6 +805,16 @@ When this function is called you are free to do anything you want with the TCP
|
||||||
connection and vweb will not interfere. This means that we are responsible for
|
connection and vweb will not interfere. This means that we are responsible for
|
||||||
sending a response over the connection and closing it.
|
sending a response over the connection and closing it.
|
||||||
|
|
||||||
|
### Empty Result
|
||||||
|
|
||||||
|
Sometimes you want to send the response in another thread, for example when using
|
||||||
|
[Server Sent Events](sse/README.md). When you are sure that a response will be sent
|
||||||
|
over the TCP connection you can return `vweb.no_result()`. This function does nothinng
|
||||||
|
and returns an empty `vweb.Result` struct, letting vweb know that we sent a response ourself.
|
||||||
|
|
||||||
|
> **Note:**
|
||||||
|
> It is important to call `ctx.takeover_conn` before you spawn a thread
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```v
|
```v
|
||||||
module main
|
module main
|
||||||
|
@ -825,11 +835,14 @@ pub fn (app &App) index(mut ctx Context) vweb.Result {
|
||||||
|
|
||||||
@['/long']
|
@['/long']
|
||||||
pub fn (app &App) long_response(mut ctx Context) vweb.Result {
|
pub fn (app &App) long_response(mut ctx Context) vweb.Result {
|
||||||
|
// let vweb know that the connection should not be closed
|
||||||
|
ctx.takeover_conn()
|
||||||
// use spawn to handle the connection in another thread
|
// use spawn to handle the connection in another thread
|
||||||
// if we don't the whole web server will block for 10 seconds,
|
// if we don't the whole web server will block for 10 seconds,
|
||||||
// since vweb is singlethreaded
|
// since vweb is singlethreaded
|
||||||
spawn handle_connection(mut ctx.conn)
|
spawn handle_connection(mut ctx.conn)
|
||||||
return ctx.takeover_conn()
|
// we will send a custom response ourself, so we can safely return an empty result
|
||||||
|
return vweb.no_result()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_connection(mut conn net.TcpConn) {
|
fn handle_connection(mut conn net.TcpConn) {
|
||||||
|
|
|
@ -276,9 +276,8 @@ pub fn (mut ctx Context) set_content_type(mime string) {
|
||||||
// send over the connetion and you can send multiple responses.
|
// send over the connetion and you can send multiple responses.
|
||||||
// This function is usefull when you want to keep the connection alive and/or
|
// This function is usefull when you want to keep the connection alive and/or
|
||||||
// send multiple responses. Like with the SSE.
|
// send multiple responses. Like with the SSE.
|
||||||
pub fn (mut ctx Context) takeover_conn() Result {
|
pub fn (mut ctx Context) takeover_conn() {
|
||||||
ctx.takeover = true
|
ctx.takeover = true
|
||||||
return Result{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// user_agent returns the user-agent header for the current client
|
// user_agent returns the user-agent header for the current client
|
||||||
|
|
|
@ -11,9 +11,9 @@ With SSE we want to keep the connection open, so we are able to
|
||||||
keep sending events to the client. But if we hold the connection open indefinitely
|
keep sending events to the client. But if we hold the connection open indefinitely
|
||||||
vweb isn't able to process any other requests.
|
vweb isn't able to process any other requests.
|
||||||
|
|
||||||
We can let vweb know that it can continue
|
We can let vweb know that it can continue processing other requests and that we will
|
||||||
processing other requests and that we will handle the connection ourself by
|
handle the connection ourself by calling `ctx.takeover_conn()` and and returning an empty result
|
||||||
returning `ctx.takeover_conn()`. Vweb will not close the connection and we can handle
|
with `vweb.no_result()`. Vweb will not close the connection and we can handle
|
||||||
the connection in a seperate thread.
|
the connection in a seperate thread.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
@ -22,10 +22,12 @@ import x.vweb.sse
|
||||||
|
|
||||||
// endpoint handler for SSE connections
|
// endpoint handler for SSE connections
|
||||||
fn (app &App) sse(mut ctx Context) vweb.Result {
|
fn (app &App) sse(mut ctx Context) vweb.Result {
|
||||||
|
// let vweb know that the connection should not be closed
|
||||||
|
ctx.takeover_conn()
|
||||||
// handle the connection in a new thread
|
// handle the connection in a new thread
|
||||||
spawn handle_sse_conn(mut ctx)
|
spawn handle_sse_conn(mut ctx)
|
||||||
// let vweb know that the connection should not be closed
|
// we will send a custom response ourself, so we can safely return an empty result
|
||||||
return ctx.takeover_conn()
|
return vweb.no_result()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_sse_conn(mut ctx Context) {
|
fn handle_sse_conn(mut ctx Context) {
|
||||||
|
|
|
@ -37,7 +37,6 @@ pub mut:
|
||||||
|
|
||||||
// start an SSE connection
|
// start an SSE connection
|
||||||
pub fn start_connection(mut ctx vweb.Context) &SSEConnection {
|
pub fn start_connection(mut ctx vweb.Context) &SSEConnection {
|
||||||
ctx.takeover_conn()
|
|
||||||
ctx.res.header.set(.connection, 'keep-alive')
|
ctx.res.header.set(.connection, 'keep-alive')
|
||||||
ctx.res.header.set(.cache_control, 'no-cache')
|
ctx.res.header.set(.cache_control, 'no-cache')
|
||||||
ctx.send_response_to_client('text/event-stream', '')
|
ctx.send_response_to_client('text/event-stream', '')
|
||||||
|
|
|
@ -14,12 +14,12 @@ pub struct Context {
|
||||||
pub struct App {}
|
pub struct App {}
|
||||||
|
|
||||||
fn (app &App) sse(mut ctx Context) vweb.Result {
|
fn (app &App) sse(mut ctx Context) vweb.Result {
|
||||||
|
ctx.takeover_conn()
|
||||||
spawn handle_sse_conn(mut ctx)
|
spawn handle_sse_conn(mut ctx)
|
||||||
return ctx.takeover_conn()
|
return vweb.no_result()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_sse_conn(mut ctx Context) {
|
fn handle_sse_conn(mut ctx Context) {
|
||||||
// pass vweb.Context
|
|
||||||
mut sse_conn := sse.start_connection(mut ctx.Context)
|
mut sse_conn := sse.start_connection(mut ctx.Context)
|
||||||
|
|
||||||
for _ in 0 .. 3 {
|
for _ in 0 .. 3 {
|
||||||
|
|
|
@ -20,6 +20,12 @@ pub type RawHtml = string
|
||||||
@[noinit]
|
@[noinit]
|
||||||
pub struct Result {}
|
pub struct Result {}
|
||||||
|
|
||||||
|
// no_result does nothing, but returns `vweb.Result`. Only use it when you are sure
|
||||||
|
// a response will be send over the connection, or in combination with `Context.takeover_conn`
|
||||||
|
pub fn no_result() Result {
|
||||||
|
return Result{}
|
||||||
|
}
|
||||||
|
|
||||||
pub const methods_with_form = [http.Method.post, .put, .patch]
|
pub const methods_with_form = [http.Method.post, .put, .patch]
|
||||||
|
|
||||||
pub const headers_close = http.new_custom_header_from_map({
|
pub const headers_close = http.new_custom_header_from_map({
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue