diff --git a/examples/vweb/vweb_example.v b/examples/vweb/vweb_example.v
index cfb46d6700..0808c80755 100644
--- a/examples/vweb/vweb_example.v
+++ b/examples/vweb/vweb_example.v
@@ -31,6 +31,7 @@ pub fn (mut app App) index() vweb.Result {
// app.text('Hello world from vweb')
hello := 'Hello world from vweb'
numbers := [1, 2, 3]
+ app.enable_chunked_transfer(40)
return $vweb.html()
}
diff --git a/vlib/vweb/tests/vweb_test.v b/vlib/vweb/tests/vweb_test.v
index 4ab7558b90..b863b96f5f 100644
--- a/vlib/vweb/tests/vweb_test.v
+++ b/vlib/vweb/tests/vweb_test.v
@@ -106,6 +106,13 @@ fn test_http_client_index() {
assert x.text == 'Welcome to VWeb'
}
+fn test_http_client_chunk_transfer() {
+ x := http.get('http://127.0.0.1:$sport/chunk') or { panic(err) }
+ assert_common_http_headers(x)
+ assert x.headers['Transfer-Encoding'] == 'chunked'
+ assert x.text == 'Lorem ipsum dolor sit amet, consetetur sadipscing'
+}
+
fn test_http_client_404() {
url_404_list := [
'http://127.0.0.1:$sport/zxcnbnm',
diff --git a/vlib/vweb/tests/vweb_test_server.v b/vlib/vweb/tests/vweb_test_server.v
index c587b153cf..08d2a907b0 100644
--- a/vlib/vweb/tests/vweb_test_server.v
+++ b/vlib/vweb/tests/vweb_test_server.v
@@ -56,6 +56,11 @@ pub fn (mut app App) html_page() vweb.Result {
return app.html('
ok
')
}
+pub fn (mut app App) chunk() vweb.Result {
+ app.enable_chunked_transfer(20)
+ return app.html('Lorem ipsum dolor sit amet, consetetur sadipscing')
+}
+
// the following serve custom routes
['/:user/settings']
pub fn (mut app App) settings(username string) vweb.Result {
diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v
index 5d0b8cf71b..2f8eff6716 100644
--- a/vlib/vweb/vweb.v
+++ b/vlib/vweb/vweb.v
@@ -56,6 +56,8 @@ pub mut:
done bool
page_gen_start i64
form_error string
+ chunked_transfer bool
+ max_chunk_len int = 20
}
// declaring init_once in your App struct is optional
@@ -88,10 +90,35 @@ pub fn (mut ctx Context) send_response_to_client(mimetype string, res string) bo
sb.write('HTTP/1.1 $ctx.status')
sb.write('\r\nContent-Type: $mimetype')
sb.write('\r\nContent-Length: $res.len')
+ if ctx.chunked_transfer {
+ sb.write('\r\nTransfer-Encoding: chunked')
+ }
sb.write(ctx.headers)
sb.write('\r\n')
sb.write(headers_close)
- sb.write(res)
+ if ctx.chunked_transfer {
+ mut i := 0
+ mut len := res.len
+ for {
+ if len <= 0 {
+ break
+ }
+ mut chunk := ''
+ if len > ctx.max_chunk_len {
+ chunk = res[i..i + ctx.max_chunk_len]
+ i += ctx.max_chunk_len
+ len -= ctx.max_chunk_len
+ } else {
+ chunk = res[i..]
+ len = 0
+ }
+ sb.write(chunk.len.hex())
+ sb.write('\r\n$chunk\r\n')
+ }
+ sb.write('0\r\n\r\n') // End of chunks
+ } else {
+ sb.write(res)
+ }
s := sb.str()
defer {
s.free()
@@ -140,6 +167,11 @@ pub fn (mut ctx Context) not_found() Result {
return Result{}
}
+pub fn (mut ctx Context) enable_chunked_transfer(max_chunk_len int) {
+ ctx.chunked_transfer = true
+ ctx.max_chunk_len = max_chunk_len
+}
+
pub fn (mut ctx Context) set_cookie(cookie Cookie) {
mut cookie_data := []string{}
mut secure := if cookie.secure { 'Secure;' } else { '' }