-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttp_server.ion
More file actions
201 lines (167 loc) · 5.27 KB
/
Copy pathhttp_server.ion
File metadata and controls
201 lines (167 loc) · 5.27 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
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// HTTP server on port 8080. FFI sockets, spawn per client, stdin quit shuts down listen socket.
//
// recv and send are Ion keywords; FFI uses recv_sys and send_sys (see ion.toml cflags).
import "stdlib/fmt.ion" as fmt;
import "stdlib/io.ion" as io;
extern "C" {
fn ion_net_init();
fn read(fd: int, buf: *u8, count: int) -> int;
fn socket(domain: int, sock_type: int, protocol: int) -> int;
fn bind(sockfd: &int, addr: &SockAddrIn, addrlen: int) -> int;
fn listen(sockfd: &int, backlog: int) -> int;
fn accept(sockfd: &int, addr: &mut u8, addrlen: &mut int) -> int;
fn recv_sys(sockfd: &int, buf: &mut u8, len: int, flags: int) -> int;
fn send_sys(sockfd: &int, buf: *u8, len: int, flags: int) -> int;
fn close(fd: &int) -> int;
fn htons(hostshort: u16) -> u16;
}
struct SockAddrIn {
sin_family: u16;
sin_port: u16;
sin_addr: u32;
sin_zero: [u8; 8];
}
fn read_line() -> String {
let mut text: String = String::new();
let mut byte_buf: [u8; 1] = [0; 1];
loop {
unsafe {
let n: int = read(0, &byte_buf[0], 1);
if n <= 0 {
return text;
}
}
let ch: u8 = byte_buf[0];
if ch == 10 as u8 {
return text;
}
if ch != 13 as u8 {
String::push_byte(&mut text, ch);
}
}
return text;
}
fn trim_line(s: String) -> String {
let mut out: String = String::new();
let mut skipping: bool = true;
for ch in s {
if skipping && (ch == 32 || ch == 9) {
continue;
}
skipping = false;
String::push_byte(&mut out, ch);
}
return out;
}
fn create_sockaddr_in(port: u16) -> SockAddrIn {
unsafe {
return SockAddrIn {
sin_family: 2,
sin_port: htons(port),
sin_addr: 0,
sin_zero: [0; 8],
};
}
}
fn http_body() -> String {
return String::from("<html><head><title>Ion HTTP Server</title></head><body><h1>Hello from Ion!</h1><p>This is a simple HTTP server written in Ion.</p></body></html>");
}
fn dispatch_peer(peer_fd: int) {
if peer_fd < 0 {
return;
}
spawn {
let _result: int = handle_client(peer_fd);
};
}
fn send_string_bytes(fd: int, text: String) {
let nbytes: int = text.len();
unsafe {
let _sent: int = send_sys(&fd, text.data, nbytes, 0);
}
}
fn handle_client(client_fd: int) -> int {
let mut buffer: [u8; 128] = [0; 128];
unsafe {
let received: int = recv_sys(&client_fd, &mut buffer[0], 128, 0);
if received < 1 {
close(&client_fd);
return 0;
}
let body: String = http_body();
let body_len: int = body.len();
let digits: String = fmt::int_to_string(body_len);
let _sent1: int = send_sys(&client_fd, "HTTP/1.1 200 OK\r\n", 17, 0);
let _sent2: int = send_sys(&client_fd, "Content-Type: text/html\r\n", 25, 0);
let _sent3: int = send_sys(&client_fd, "Content-Length: ", 16, 0);
send_string_bytes(client_fd, digits);
let _sent5: int = send_sys(&client_fd, "\r\n", 2, 0);
let _sent6: int = send_sys(&client_fd, "Connection: close\r\n", 19, 0);
let _sent7: int = send_sys(&client_fd, "\r\n", 2, 0);
send_string_bytes(client_fd, body);
close(&client_fd);
}
return 0;
}
fn listen_and_serve(fd_tx: Sender<int>, stopped_tx: Sender<int>) {
unsafe {
ion_net_init();
let af_inet: int = 2;
let sock_stream: int = 1;
let ipproto_tcp: int = 6;
let server_fd: int = socket(af_inet, sock_stream, ipproto_tcp);
if server_fd < 0 {
send(&stopped_tx, 1);
return;
}
let sockaddr: SockAddrIn = create_sockaddr_in(8080);
let bind_result: int = bind(&server_fd, &sockaddr, 16);
if bind_result < 0 {
close(&server_fd);
send(&stopped_tx, 2);
return;
}
let listen_result: int = listen(&server_fd, 10);
if listen_result < 0 {
close(&server_fd);
send(&stopped_tx, 3);
return;
}
send(&fd_tx, server_fd);
loop {
let mut client_addr: [u8; 16] = [0; 16];
let mut addrlen: int = 16;
let peer_fd: int = accept(&server_fd, &mut client_addr[0], &mut addrlen);
if peer_fd < 0 {
break;
}
dispatch_peer(peer_fd);
}
close(&server_fd);
send(&stopped_tx, 0);
}
}
fn wait_for_quit() {
let trimmed: String = trim_line(read_line());
if trimmed == String::from("quit") {
return;
}
wait_for_quit();
}
fn main() -> int {
let (fd_tx, fd_rx): (Sender<int>, Receiver<int>) = channel<int>();
let (stopped_tx, stopped_rx): (Sender<int>, Receiver<int>) = channel<int>();
spawn {
listen_and_serve(fd_tx, stopped_tx);
};
let mut fd_rx_mut: Receiver<int> = fd_rx;
let server_fd: int = recv(&mut fd_rx_mut);
io::println(String::from("listening on http://127.0.0.1:8080 (type quit)"));
wait_for_quit();
unsafe {
close(&server_fd);
}
let mut stopped_rx_mut: Receiver<int> = stopped_rx;
let status: int = recv(&mut stopped_rx_mut);
return status;
}