| 1 | import io |
| 2 | import os |
| 3 | import net.mbedtls |
| 4 | |
| 5 | // This example shows a very minimal HTTP server, that supports SNI. |
| 6 | // Server Name Indication (SNI) is defined in RFC 6066. |
| 7 | // See https://mbed-tls.readthedocs.io/en/latest/kb/how-to/use-sni/ |
| 8 | |
| 9 | // Use the following commands, in separate shells, to test that it works, |
| 10 | // after you start the server: |
| 11 | // curl -ik --resolve 1x.dk:8443:0.0.0.0 https://1x.dk:8443/abcd |
| 12 | // curl -ik --resolve example.com:8443:0.0.0.0 https://example.com:8443/xyz |
| 13 | // Both of them should work, and the server should show that it tried to load |
| 14 | // certificates, responding to the given domain name in each of the requests. |
| 15 | |
| 16 | // callback to return the certificates to use for the connection |
| 17 | fn get_cert(mut _listener mbedtls.SSLListener, host string) !&mbedtls.SSLCerts { |
| 18 | println('reading certificates for ${host} ...') |
| 19 | |
| 20 | // For our example, just always use the same certificates. In a real server, |
| 21 | // that should be dependent on the host parameter, and perhaps there should |
| 22 | // be some caching, so that they are not read each time for each request from |
| 23 | // the filesystem. |
| 24 | |
| 25 | cert := os.read_file('cert/server.crt') or { |
| 26 | return error('Failed to read certificate ${host}: ${err}') |
| 27 | } |
| 28 | key := os.read_file('cert/server.key') or { return error('Failed to read key ${host}: ${err}') } |
| 29 | println('read certs for ${host}') |
| 30 | |
| 31 | if mut c := mbedtls.new_sslcerts_in_memory('', cert, key) { |
| 32 | return c |
| 33 | } else { |
| 34 | return error('mbedtls.new_sslcerts_in_memory err: ${err}') |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | fn main() { |
| 39 | mut server := mbedtls.new_ssl_listener('0.0.0.0:8443', mbedtls.SSLConnectConfig{ |
| 40 | verify: os.resource_abs_path('cert/ca.crt') |
| 41 | cert: os.resource_abs_path('cert/server.crt') |
| 42 | cert_key: os.resource_abs_path('cert/server.key') |
| 43 | validate: false |
| 44 | get_certificate: get_cert // set the SNI callback to enable this feature |
| 45 | })! |
| 46 | println('Listening on https://0.0.0.0:8443/ ...') |
| 47 | for { |
| 48 | mut client := server.accept() or { |
| 49 | println('accept error: ${err}') |
| 50 | continue |
| 51 | } |
| 52 | mut reader := io.new_buffered_reader(reader: client) |
| 53 | for { |
| 54 | line := reader.read_line() or { break } |
| 55 | if line.len == 0 { |
| 56 | break |
| 57 | } |
| 58 | println(line) |
| 59 | } |
| 60 | client.write_string('HTTP/1.1 200 OK\r\n') or { continue } |
| 61 | |
| 62 | client.write_string('Content-Type: text/html\r\n') or { continue } |
| 63 | client.write_string('Connection: close\r\n') or { continue } |
| 64 | client.write_string('\r\n') or { continue } |
| 65 | |
| 66 | client.write_string('Hello\n') or { continue } |
| 67 | client.shutdown()! |
| 68 | } |
| 69 | server.shutdown()! |
| 70 | } |
| 71 | |