╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ serve.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
239 240 fn runWebListener( 241 io: std.Io, 242 allocator: std.mem.Allocator, 243 net_server: *std.Io.net.Server, 244 tasks: *std.Io.Group, 245 host: web.Host, 246 err: *std.Io.Writer, 247 ) void { 248 const Context = struct { 249 io: std.Io, 250 allocator: std.mem.Allocator, 251 host: web.Host, 252 err: *std.Io.Writer, 253 }; 254 255 const handle = struct { 256 fn h(ctx: Context, stream: std.Io.net.Stream) void { 257 defer stream.close(ctx.io); 258 web.handleConnection(ctx.io, ctx.allocator, stream, ctx.host, ctx.err) catch |request_err| { 259 serve_common.logError(ctx.io, ctx.err, "web ui request failed: {s}\n", .{@errorName(request_err)}); 260 }; 261 } 262 }.h; 263 264 serve_common.runListener(io, net_server, tasks, err, "web ui", Context{ 265 .io = io, 266 .allocator = allocator, 267 .host = host, 268 .err = err, 269 }, handle); 270 } 271 272 // what a listener does with a port that is already taken 273 const PortPolicy = enum { 274 exact, 275 // leave it to whoever holds it and take an OS-assigned port instead 276 fallback, 277 }; 278 279 fn listen(io: std.Io, listen_address: ListenAddress, policy: PortPolicy) !std.Io.net.Server { 280 const address = try std.Io.net.IpAddress.parseIp4(listen_address.host, listen_address.port); 281 return switch (policy) { 282 // so a restart can bind past the old process's connections in TIME_WAIT. 283 // not for fallback, where it would let a second instance share the port. 284 .exact => try address.listen(io, .{ .reuse_address = true }), 285 .fallback => address.listen(io, .{}) catch |listen_err| switch (listen_err) { 286 error.AddressInUse => blk: { 287 const any_port = try std.Io.net.IpAddress.parseIp4(listen_address.host, 0); 288 break :blk try any_port.listen(io, .{}); 289 }, 290 else => |e| return e, 291 }, 292 }; 293 } 294 295 fn parseListenAddress(value: []const u8) !ListenAddress { 296 const colon = std.mem.lastIndexOfScalar(u8, value, ':') orelse return error.InvalidListenAddress; 297 if (colon == 0 or colon + 1 >= value.len) return error.InvalidListenAddress; 298 const port = try std.fmt.parseInt(u16, value[colon + 1 ..], 10); 299 return .{ .host = value[0..colon], .port = port }; 300 } 301