Skip to content

Commit 0ec12aa

Browse files
authored
Improve documentation and add more examples. (#152)
1 parent a5702f0 commit 0ec12aa

File tree

6 files changed

+174
-53
lines changed

6 files changed

+174
-53
lines changed

examples/client-get-tls.toit

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (C) 2025 Toitware ApS.
2+
// Use of this source code is governed by a Zero-Clause BSD license that can
3+
// be found in the EXAMPLES_LICENSE file.
4+
5+
import certificate-roots
6+
import http
7+
import net
8+
9+
main:
10+
certificate-roots.install-all-trusted-roots
11+
12+
network := net.open
13+
client := http.Client network
14+
response := client.get --uri="https://www.example.com"
15+
while data := response.body.read:
16+
print data.to-string
17+
18+
client.close

examples/package.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
sdk: ^2.0.0-alpha.91
1+
sdk: ^2.0.0-alpha.150
22
prefixes:
33
certificate_roots: toit-cert-roots
44
http: ..
@@ -7,6 +7,6 @@ packages:
77
path: ..
88
toit-cert-roots:
99
url: github.com/toitware/toit-cert-roots
10-
name: certificate_roots
11-
version: 1.6.1
12-
hash: 55d3be82ed53d8d332338b2de931865cf69fe48b
10+
name: certificate-roots
11+
version: 1.9.0
12+
hash: 1445c4a6cae47689674ae02c5f1dc03660f1df8c

examples/package.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
dependencies:
22
certificate_roots:
33
url: github.com/toitware/toit-cert-roots
4-
version: ^1.6.1
4+
version: ^1.9.0
55
http:
66
path: ..

examples/tls-resume.toit

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (C) 2025 Toitware ApS.
2+
// Use of this source code is governed by a Zero-Clause BSD license that can
3+
// be found in the EXAMPLES_LICENSE file.
4+
5+
import certificate-roots
6+
import http
7+
import net
8+
import system
9+
import system.storage
10+
11+
/**
12+
An example demonstrating the use of the SecurityStore to cache TLS
13+
session state data in RTC memory.
14+
15+
This example is intended to be run on an ESP32.
16+
*/
17+
18+
/**
19+
A security store that saves the TLS session state in RTC memory.
20+
21+
*/
22+
class SecurityStoreRtc extends http.SecurityStore:
23+
// We store the cached session data in RTC memory. This means that
24+
// it survives deep sleeps, but that any loss of power or firmware
25+
// update will clear it.
26+
bucket_/storage.Bucket
27+
28+
constructor path/string:
29+
bucket_ = storage.Bucket.open --ram path
30+
31+
store-session-data host/string port/int data/ByteArray -> none:
32+
bucket_[key_ host port] = data
33+
34+
delete-session-data host/string port/int -> none:
35+
bucket_.remove (key_ host port)
36+
37+
retrieve-session-data host/string port/int -> ByteArray?:
38+
return bucket_.get (key_ host port)
39+
40+
key_ host/string port/int -> string:
41+
return "$host:$port"
42+
43+
main:
44+
// Install common trusted roots.
45+
certificate-roots.install-common-trusted-roots
46+
network := net.open
47+
48+
security-store := SecurityStoreRtc "toitlang.org/pkg-http/example/tls-session-store"
49+
client := http.Client.tls network
50+
--security-store=security-store
51+
52+
response := null
53+
duration := Duration.of:
54+
response = client.get --uri="https://www.example.com"
55+
// Running this program a second time should be faster, as the TLS
56+
// connection could just be resumed.
57+
print "Took $duration to get response."
58+
59+
client.close
60+
network.close

src/client.toit

Lines changed: 73 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,12 @@ import .status-codes
1818
import .web-socket
1919

2020
/**
21-
An HTTP v1.1 client.
22-
23-
This class provides methods to fetch data from HTTP servers.
24-
25-
When the client is no longer needed, resources should be freed up with the
26-
$close method. This is an API incompatibility with version one of the
27-
package, which would automatically close the client after one request.
28-
See the documentation of the constructor for details.
29-
30-
This client has built-in websocket support. The separate websockets package
31-
should no longer be used.
32-
33-
The client caches connections to servers, so a second request to the same
34-
server will use the same socket and may save a lot of CPU time for setting
35-
up TLS connections. It also caches session state for TLS connections, so
36-
subsequent connections to a server will use the session state to speed up
37-
the TLS handshake from about 1000ms to about 150ms (on ESP32).
21+
HTTP Client.
3822
3923
# Get
40-
Use the $get method to fetch data using a $GET request.
24+
Use the $Client.get method to fetch data using a $GET request.
4125
42-
The $get method keeps track of the underlying resources and is thus
26+
The $Client.get method keeps track of the underlying resources and is thus
4327
very easy to use.
4428
4529
Example that takes the incoming data and reads it as JSON:
@@ -53,7 +37,7 @@ PATH ::= "/get"
5337
5438
main:
5539
network := net.open
56-
client := null
40+
client/http.Client := null
5741
try:
5842
client = http.Client network
5943
response := client.get URI PATH
@@ -62,24 +46,53 @@ main:
6246
if client: client.close
6347
```
6448
65-
For https connection use the $Client.tls constructor with the certificate of
66-
the server:
67-
```
68-
client := http.Client.tls network
69-
--root_certificates=[CERTIFICATE]
70-
```
71-
The certificate is server dependendent, and must be obtained before-hand.
72-
Most commonly one uses a combination of inspecting the certificate in Google Chrome,
73-
and the package `certificate_roots`:
74-
https://pkg.toit.io/package/github.com%2Ftoitware%2Ftoit-cert-roots
49+
For https connections either use the $Client.tls constructor or provide
50+
a uri with the https scheme. You need to make sure that the server's
51+
root certificate is installed or provided in the root-certificates list.
52+
For public root certificates see the `certificate_roots` package.
53+
54+
On embedded devices we recommend to provide a $SecurityStore if the server
55+
supports TLS resume. See the tls-resume.toit example.
7556
76-
For example, the `httpbin.org` server uses the `AMAZON_ROOT_CA_1` certificate:
7757
```
78-
import certificate_roots
58+
import certificate-roots
59+
import http
60+
import net
7961
80-
CERTIFICATE ::= certificate_roots.AMAZON_ROOT_CA_1
62+
URI ::= "https://www.example.com"
63+
64+
main:
65+
certificate-roots.install-common-trusted-roots
66+
network := net.open
67+
// On embedded devices consider providing a SecurityStore to speed up
68+
// subsequent connections to the same server.
69+
client := http.Client network
70+
response := client.get --uri=URI
71+
while data := response.body.read:
72+
print data.to-string
73+
client.close
8174
```
8275
*/
76+
77+
/**
78+
An HTTP v1.1 client.
79+
80+
This class provides methods to fetch data from HTTP servers.
81+
82+
When the client is no longer needed, resources should be freed up with the
83+
$close method. This is an API incompatibility with version one of the
84+
package, which would automatically close the client after one request.
85+
See the documentation of the constructor for details.
86+
87+
This client has built-in websocket support. The separate websockets package
88+
should no longer be used.
89+
90+
The client caches connections to servers, so a second request to the same
91+
server will use the same socket and may save a lot of CPU time for setting
92+
up TLS connections. It also caches session state for TLS connections, so
93+
subsequent connections to a server will use the session state to speed up
94+
the TLS handshake from about 1000ms to about 150ms (on ESP32).
95+
*/
8396
class Client:
8497
/**
8598
The maximum number of redirects to follow if 'follow_redirect' is true for $get and $post requests.
@@ -96,39 +109,53 @@ class Client:
96109
security-store_/SecurityStore
97110

98111
/**
99-
Constructs a new client instance over the given interface.
112+
Constructs a new client instance over the given $network.
113+
114+
Use `net.open` to obtain an $network.
115+
116+
Clients that connect to secure servers may provide a $security-store. This
117+
is used to store session state for TLS connections, which can speed up
118+
the TLS handshake from about 1000ms to about 150ms (on ESP32). The
119+
handshake then also uses less memory.
120+
121+
The $root-certificates parameter is nowadays mostly unused, as the
122+
recommended way to provide root certificates is to `install` them
123+
instead.
124+
100125
The client will default to an insecure HTTP connection, but this can be
101-
overridden by a redirect or a URI specifying a secure scheme.
102-
Therefore it can be meaningful to provide certificate roots despite the
126+
overridden by a redirect or a URI specifying a secure scheme. Therefore
127+
it can be meaningful to provide certificate roots despite the
103128
insecure default.
104-
If the client is used for secure connections, the $root-certificates must
105-
contain the root certificate of the server.
129+
130+
If the client is used for secure connections, its root certificate must
131+
be installed or provided in the $root-certificates list.
132+
106133
A client will try to keep a connection open to the last server it
107134
contacted, in the hope that the next request will connect to the same
108135
server. This can save a lot of CPU time for TLS connections which are
109136
expensive to set up, but it also reserves a fairly large amount of
110137
buffer memory for the TLS connection. Call $close (perhaps in a finally
111138
clause) to release the connection.
139+
112140
See the `certificate_roots` package for common roots:
113141
https://pkg.toit.io/package/github.com%2Ftoitware%2Ftoit-cert-roots
114-
Use `net.open` to obtain an interface.
115142
*/
116-
constructor .interface_
143+
constructor network/tcp.Interface
117144
--root-certificates/List=[]
118145
--security-store/SecurityStore=SecurityStoreInMemory:
146+
interface_ = network
119147
security-store_ = security-store
120148
root-certificates_ = root-certificates
121149
add-finalizer this:: this.finalize_
122150

123151
/**
124-
Constructs a new client.
125-
The client will default to a secure HTTPS connection, but this can be
126-
overridden by a redirect or a URI specifying an insecure scheme.
127-
The $root-certificates must contain the root certificate of the server.
128-
See the `certificate_roots` package for common roots:
129-
https://pkg.toit.io/package/github.com%2Ftoitware%2Ftoit-cert-roots
152+
Variant of $constructor.
153+
154+
Constructs a client that defaults to a secure HTTPS connection.
155+
130156
A client $certificate can be specified for the rare case where the client
131157
authenticates itself.
158+
132159
The $server-name can be specified for verifying the TLS certificate. This is
133160
for the rare case where we wish to verify the TLS connections with a
134161
different server name from the one used to establish the connection.

src/server.toit

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import .status-codes
1818
import .web-socket
1919

2020
/**
21-
An HTTP server.
21+
HTTP server.
2222
2323
# Examples
2424
```
@@ -54,6 +54,10 @@ main:
5454
writer.close
5555
```
5656
*/
57+
58+
/**
59+
An HTTP server.
60+
*/
5761
class Server:
5862
static DEFAULT-READ-TIMEOUT/Duration ::= Duration --s=30
5963

@@ -68,10 +72,22 @@ class Server:
6872
// For testing.
6973
call-in-finalizer_/Lambda? := null
7074

75+
/**
76+
Constructs an HTTP server with the given $read-timeout and $max-tasks.
77+
78+
The $max-tasks argument must be tuned to the expected load. More tasks consume
79+
more memory, but can handle more requests concurrently. If the value is not
80+
big enough, then browsers will time out when they try to connect to the server.
81+
*/
7182
constructor --.read-timeout=DEFAULT-READ-TIMEOUT --max-tasks/int=1 --logger=log.default:
7283
logger_ = logger
7384
if max-tasks > 1: semaphore_ = monitor.Semaphore --count=max-tasks
7485

86+
/**
87+
Variant of $constructor.
88+
89+
This variant sets up the server to use TLS with the given $certificate.
90+
*/
7591
constructor.tls
7692
--.read-timeout=DEFAULT-READ-TIMEOUT
7793
--max-tasks/int=1
@@ -111,7 +127,7 @@ class Server:
111127
// Listen on a free port.
112128
tcp_socket := network.tcp_listen 0
113129
print "Server on http://localhost:$tcp_socket.local_address.port/"
114-
server := http.Server
130+
server := http.Server --max-tasks=5
115131
server.listen tcp_socket:: | request/http.Request writer/http.ResponseWriter |
116132
if request.path == "/":
117133
writer.headers.set "Content-Type" "text/html"

0 commit comments

Comments
 (0)