v / vlib / veb / ssl_notd_use_openssl.v
134 lines · 128 sloc · 3.68 KB · 39ee5fb9e80298cdd41330658b492736f52a98b4
Raw
1module veb
2
3import io
4import net
5import net.http
6import net.mbedtls
7import os
8import time
9
10@[params]
11pub struct RunParams {
12pub:
13 // use `family: .ip, host: 'localhost'` when you want it to bind only to 127.0.0.1
14 family net.AddrFamily = .ip6
15 host string
16 port int = default_port
17 nr_workers int = 1
18 show_startup_message bool = true
19 timeout_in_seconds int = 30
20 max_request_buffer_size int = 8192
21 benchmark_page_generation bool // for the "page rendered in X ms"
22 ssl_config mbedtls.SSLConnectConfig
23}
24
25fn run_at_with_ssl[A, X](mut global_app A, params RunParams) ! {
26 routes := generate_routes[A, X](global_app)!
27 controllers_sorted := check_duplicate_routes_in_controllers[A](global_app, routes)!
28 if params.show_startup_message {
29 println('[veb] Running app on https://${startup_host(params)}:${params.port}/')
30 }
31 flush_stdout()
32 mut ssl_listener := mbedtls.new_ssl_listener(listen_addr(params), params.ssl_config)!
33 defer {
34 ssl_listener.shutdown() or {}
35 }
36 ssl_params := &SslRequestParams{
37 global_app: unsafe { voidptr(&global_app) }
38 controllers_sorted: controllers_sorted
39 routes: &routes
40 benchmark_page_generation: params.benchmark_page_generation
41 max_request_buffer_size: if params.max_request_buffer_size > 0 {
42 params.max_request_buffer_size
43 } else {
44 max_read
45 }
46 }
47 $if A is BeforeAcceptApp {
48 global_app.before_accept_loop()
49 }
50 for {
51 mut ssl_conn := ssl_listener.accept() or {
52 eprintln('[veb] accept() failed, reason: ${err}; skipping')
53 continue
54 }
55 ssl_conn.duration = params.timeout_in_seconds * time.second
56 spawn handle_ssl_connection[A, X](mut ssl_conn, ssl_params)
57 }
58}
59
60fn handle_ssl_connection[A, X](mut ssl_conn mbedtls.SSLConn, params &SslRequestParams) {
61 defer {
62 ssl_conn.shutdown() or {}
63 }
64 mut reader := io.new_buffered_reader(
65 reader: ssl_conn
66 cap: params.max_request_buffer_size
67 )
68 defer {
69 unsafe {
70 reader.free()
71 }
72 }
73 for {
74 req := read_request_from_buffered_reader(mut reader) or {
75 if err !is io.Eof {
76 write_ssl_response(mut ssl_conn, http_400) or {}
77 }
78 return
79 }
80 completed_context := handle_ssl_request[A, X](req, params) or {
81 write_ssl_response(mut ssl_conn, http_400) or {}
82 return
83 }
84 if completed_context.takeover_mode != .none {
85 eprintln('[veb] HTTPS connections do not support takeover connections yet; closing the connection after this response.')
86 }
87 write_ssl_context_response(mut ssl_conn, completed_context) or {
88 eprintln('[veb] error sending HTTPS response: ${err}')
89 return
90 }
91 if completed_context.takeover_mode != .none
92 || should_close_connection(completed_context.req, completed_context.res, completed_context.client_wants_to_close) {
93 return
94 }
95 }
96}
97
98fn write_ssl_context_response(mut ssl_conn mbedtls.SSLConn, completed_context &Context) ! {
99 if !completed_context.done && completed_context.return_type == .normal {
100 return error('context did not send a response')
101 }
102 match completed_context.return_type {
103 .normal {
104 write_ssl_response(mut ssl_conn, completed_context.res)!
105 }
106 .file {
107 write_ssl_response(mut ssl_conn, completed_context.res)!
108 if completed_context.return_file == '' {
109 return error('missing file response path')
110 }
111 mut file := os.open(completed_context.return_file)!
112 defer {
113 file.close()
114 }
115 mut buf := []u8{len: max_read}
116 for {
117 n := file.read(mut buf) or {
118 if err is io.Eof {
119 break
120 }
121 return err
122 }
123 if n <= 0 {
124 break
125 }
126 ssl_conn.write(buf[..n])!
127 }
128 }
129 }
130}
131
132fn write_ssl_response(mut ssl_conn mbedtls.SSLConn, resp http.Response) ! {
133 ssl_conn.write(resp.bytes())!
134}
135