File: 02-Server.md

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (113 lines) | stat: -rw-r--r-- 3,057 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
HTTP Server
===========

The class [stormname:http.Server] implements a basic server. The server handles receiving incoming
HTTP connections, parsing them, and sending responses to them. To generate responses, it calls one
of the abstract functions below. As such, to use the server, you need to create a class that
inherits from [stormname:http.Server] and overrides the functions below. It is also possible to use
[stormname:http.RoutingServer] to solve routing automatically.

The server is threaded, using Storm's [user threads](md:/Language_Reference/Storm/Threading_Model).
A new thread is created for each client that connects to the server, and the created thread handles
connections in parallell. Note, however, that user threads are scheduled cooperatively. As such,
this model is not too dissimilar from webservers that utilize a few threads to handle requests in a
multiplexed way.

The members that need to be overridden are the following:

```stormdoc
@http.Server
- .onRequest(*)
- .onServerError(*)
- .onError(*)
```

The server also provides the following members that are relevant to be aware of:

```stormdoc
@http.Server
- .__init()
- .timeout(*)
- .run(core.Nat)
- .close()
- .prepareResponse(*)
```


Routing
-------

The class [stormname:http.RoutingServer] extends [stormname:http.Server] and provides routing. That
way, the server is usable without subclassing.

At a conceptual level, the routing server associates each path with a function that will be called
whenever a client visits that particular path. Wildcards are supported. As such, if one path
component is `*`, then any contents of that component will be considered a match. Note that wildcard
components are always matched last.

Routes are added by calling the function `add`:

```stormdoc
@http.RoutingServer
- .add(*)
```

It is also possible to add a default handler that will be called whenever a more specific route does
not exist. The default behavior of this handler is to provide a basic "page not found" message:

```stormdoc
@http.RoutingServer
- .default(*)
```

Example
-------

Below is an example of using the HTTP library to create a simple server:


```bs
use core:net;
use core:io;
use http;
use core:lang;

private Str baseSite() {
    str {
        <!DOCTYPE html>
        <html>
        <body>
            <h1>Hello</h1>
            <p>Example page</p>
        </body>
        </html>
    };
}

private Str picturesSite() {
    str {
        <!DOCTYPE html>
        <html>
        <body>
            <h1>Pictures</h1>
            <p>Pictures page</p>
        </body>
        </html>
    };
}

void main() {
    RoutingServer server;

    // Sleep for 20 seconds, then call close to cause 'server.run' to return.
    spawn (() => { sleep(20 s); server.close; }).call();

    // Add a handler for the route /pictures/<anything>
    server.route(["pictures", "*"], (request) => Response(picturesSite));
    // Add a default handler.
    server.default((request) => Response(baseSite));

    // Run the server on port 1234.
    server.run(1234);
}
```