-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathclient_info.gleam
More file actions
72 lines (63 loc) 路 2.32 KB
/
Copy pathclient_info.gleam
File metadata and controls
72 lines (63 loc) 路 2.32 KB
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
import ewe
import gleam/erlang/process
import gleam/http
import gleam/http/request
import gleam/http/response
import gleam/int
import logging
pub fn main() {
logging.configure()
logging.set_level(logging.Info)
let listener_name = process.new_name("listener_name")
let connection_factory_name = process.new_name("connection_factory_name")
// A server that logs who every request came from and tells the client its own
// address, the way `curl ifconfig.me` does.
//
let assert Ok(_) =
ewe.new(listener_name:, connection_factory_name:, handler: handle_request)
|> ewe.bind(to: "0.0.0.0")
|> ewe.listening(on: 8080)
|> ewe.start
process.sleep_forever()
}
fn handle_request(
request: request.Request(ewe.Connection),
) -> response.Response(ewe.Body) {
// The connection the request carries is what the client's address is read
// from, so it is `request.body` that goes in here.
let client = describe_client(request.body)
logging.log(
logging.Info,
http.method_to_string(request.method)
<> " "
<> request.path
<> " "
<> client,
)
response.new(200)
|> response.set_header("content-type", "text/plain; charset=utf-8")
|> response.set_body(ewe.Text(client <> "\n"))
}
// Behind a proxy this is the proxy's address and not the browser's. The address
// the proxy puts in `x-forwarded-for` is the one to use there.
//
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For
fn describe_client(connection: ewe.Connection) -> String {
case ewe.get_client_info(connection) {
Ok(ewe.TcpSocketAddress(ip_address:, port:)) -> {
// An IPv6 address is bracketed so the port stays readable next to the
// colons the address itself is full of.
let host = case ip_address {
ewe.IpV6(..) -> "[" <> ewe.ip_address_to_string(ip_address) <> "]"
ewe.IpV4(..) -> ewe.ip_address_to_string(ip_address)
}
host <> ":" <> int.to_string(port)
}
// A unix socket client is unnamed unless it bound a path of its own, which
// clients rarely do, so most of the time there is no path to report.
Ok(ewe.UnixSocketAddress(path: "")) -> "unix socket"
Ok(ewe.UnixSocketAddress(path:)) -> "unix:" <> path
// The socket is already gone, so there is nothing left to report.
Error(Nil) -> "unknown"
}
}