File: harbor_http.md

package info (click to toggle)
liquidsoap 2.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 11,912 kB
  • sloc: ml: 67,867; javascript: 24,842; ansic: 273; xml: 114; sh: 96; lisp: 96; makefile: 26
file content (155 lines) | stat: -rw-r--r-- 5,331 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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# Harbor as HTTP server

The harbor server can be used as a HTTP server. We provide two type of APIs for this:

## Simple API

The `harbor.http.register.simple` function provides a simple, easy to use registration API for quick
HTTP response implementation. This function receives a record describing the request and returns
the HTTP response.

The request passed to the function contains all expected information from the underlying HTTP
query.

The `data` method on a request is a _string getter_, that is a function of type: `() -> string`
which returns the empty string `""` when all data has been consumed. You can use this function
to e.g. write the request data to a file using `file.write.stream`.

The `body` method can be used to read all of the request's data and store it in
memory. Make sure to only use it if you know that the response should be small enough!

For convenience, a HTTP response builder is provided via `http.response`. Here's an example:

```{.liquidsoap include="harbor.http.response.liq" from="BEGIN"}

```

where:

- `port` is the port where to receive incoming connections
- `method` is for the http method (or verb), one of: `"GET"`, `"PUT"`, `"POST"`, `"DELETE"`, `"OPTIONS"` and `"HEAD"`
- `path` is the matched path. It can include named fragments, e.g. `"/users/:id/collabs/:cid"`. Named named fragments are passed via `request.query`, for instance: `req.query["cid"]`.

## Node/express API

The `harbor.http.register` function offers a higher-level API for advanced HTTP response implementation.
Its API is very similar to the node/express API. Here's an example:

```{.liquidsoap include="harbor.http.register.liq" from="BEGIN"}

```

where:

- `port` is the port where to receive incoming connections
- `method` is for the http method (or verb), one of: `"GET"`, `"PUT"`, `"POST"`, `"DELETE"`, `"OPTIONS"` and `"HEAD"`
- `path` is the matched path. It can include named fragments, e.g. `"/users/:id/collabs/:cid"`. Matched named fragments are passed via `request.query`, for instance: `req.query["cid"]`.

The handler function receives a record containing all the information about the request and fills
up the details about the response, which is then used to write a proper HTTP response to the client.

Named fragments from the request path are passed to the response `query` list.

Middleware _a la_ node/express are also supported and registered via `http.harbor.middleware.register`. See `http.harbor.middleware.cors` for an example of how to implement one such middleware.

Here's how you would enable the `cors` middleware:

```
harbor.http.middleware.register(harbor.http.middleware.cors(origin="example.com"))
```

## Https support

`https` is supported using either `libssl` or `ocaml-tls`. When compiled with either of them, a `http.transport.ssl` or `http.transport.tls`
is available and can be passed to each `harbor` operator:

```liquidsoap
transport = http.transport.ssl(
  # Server mode: required,
  # client mode: optional, add certificate to trusted pool
  certificate="/path/to/certificate/file",

  # Server mode: required, client mode: ignored
  key="/path/to/secret/key/file",

  # Required if key file requires one.
  # TLS does not support password encrypted keys!
  password="optional password"
)

harbor.http.register(transport=transport, port=8000, ...)

input.harbor(transport=..., port=8000, ...)

output.harbor(transport=..., port=8000, ...)

output.icecast(transport=..., port=8000, ...)
```

A given port can only support one type of transport at a time and registering handlers, sources or outputs on the same port with different transports
will raise a `error.http` error.

## Advanced usage

All registration functions have a `.regexp` counter part, e.g. `harbor.http.register.simple.regexp`. These function accept
a full regular expression for their `path` argument. Named matches on the regular expression are also passed via the request's `query`
parameter.

It is also possible to directly interact with the underlying socket using the `simple` API:

```{.liquidsoap include="harbor-simple.liq"}

```

## Examples

These functions can be used to create your own HTTP interface. Some examples
are:

## Redirect Icecast's pages

Some source clients using the harbor may also request pages that
are served by an icecast server, for instance listeners statistics.
In this case, you can register the following handler:

```{.liquidsoap include="harbor-redirect.liq"}

```

## Get metadata

You can use harbor to register HTTP services to
fecth/set the metadata of a source.

```{.liquidsoap include="harbor-metadata.liq" from="BEGIN"}

```

Once the script is running,
a GET request for `/getmeta` at port `7000`
returns the following:

```
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "genre": "Soul",
  "album": "The Complete Stax-Volt Singles: 1959-1968 (Disc 8)",
  "artist": "Astors",
  "title": "Daddy Didn't Tell Me"
}
```

## Set metadata

Using `insert_metadata`, you can register a GET handler that
updates the metadata of a given source. For instance:

```{.liquidsoap include="harbor-insert-metadata.liq" from="BEGIN"}

```

Now, a request of the form `http://server:7000/setmeta?title=foo`
will update the metadata of source `s` with `[("title","foo")]`. You
can use this handler, for instance, in a custom HTML form.