-
-
Notifications
You must be signed in to change notification settings - Fork 3k
std: update websocket server implementation #24969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Raiden1411
wants to merge
3
commits into
ziglang:master
Choose a base branch
from
Raiden1411:websocket_server
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
+273
−62
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24a407e
to
693fe36
Compare
I'm rewriting the implementation for my project to use the new Io Reader and Writer. I've explained more in the issue. So having that for my own testing would be useful, if you would please share it. |
Sure no problem! This was the code used for the test. const std = @import("std");
const Allocator = std.mem.Allocator;
const Server = std.http.Server;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.detectLeaks();
const allocator = gpa.allocator();
var auto = try AutoBanh.init(allocator, 9224);
defer auto.deinit();
auto.serve();
}
const AutoBanh = struct {
gpa: Allocator,
client: std.net.Server,
pub fn init(gpa: Allocator, port: u16) !AutoBanh {
const address = try std.net.Address.parseIp("127.0.0.1", port);
const server = try address.listen(.{ .reuse_address = true });
return .{
.gpa = gpa,
.client = server,
};
}
pub fn serve(self: *AutoBanh) void {
while (true) {
const connection = self.client.accept() catch |err| {
std.log.err("failed to accept connection: {s}", .{@errorName(err)});
return;
};
_ = std.Thread.spawn(.{}, accept, .{ self, connection }) catch |err| {
std.log.err("unable to spawn connection thread: {s}", .{@errorName(err)});
connection.stream.close();
continue;
};
}
}
fn accept(ws: *AutoBanh, connection: std.net.Server.Connection) void {
defer connection.stream.close();
var send_buffer: [4096]u8 = undefined;
var recv_buffer: [8192]u8 = undefined;
var connection_reader = connection.stream.reader(&recv_buffer);
var connection_writer = connection.stream.writer(&send_buffer);
var server: std.http.Server = .init(connection_reader.interface(), &connection_writer.interface);
var request = server.receiveHead() catch |err| switch (err) {
error.HttpConnectionClosing => return,
else => return std.log.err("failed to receive http request: {t}", .{err}),
};
switch (request.upgradeRequested()) {
.websocket => |opt_key| {
const key = opt_key orelse return std.log.err("missing websocket key", .{});
var web_socket = request.respondWebSocket(.{ .key = key, .allocator = ws.gpa }) catch {
return std.log.err("failed to respond web socket: {t}", .{connection_writer.err.?});
};
defer web_socket.deinit();
web_socket.flush() catch {};
return serveWebSocket(&web_socket) catch |err| {
std.log.err("failed to serve websocket: {t}", .{err});
return;
};
},
.other => |name| return std.log.err("unknown upgrade request: {s}", .{name}),
.none => unreachable,
}
}
pub fn deinit(self: *AutoBanh) void {
self.client.deinit();
}
pub fn serveWebSocket(websocket: *std.http.Server.WebSocket) !void {
while (true) {
const message = websocket.readMessage() catch |err| switch (err) {
error.EndOfStream => {
try websocket.writeCloseFrame(.{ .exit_code = 1002 });
return;
},
error.InvalidUtf8Payload => {
try websocket.writeCloseFrame(.{ .exit_code = 1007 });
return err;
},
else => {
try websocket.writeCloseFrame(.{ .exit_code = 1002 });
return err;
},
};
switch (message.opcode) {
.binary,
=> try websocket.writeFrame(message.data, .binary),
.text,
=> try websocket.writeFrame(message.data, .text),
.ping,
=> try websocket.writeFrame(message.data, .pong),
.connection_close,
=> return websocket.writeCloseFrame(.{ .exit_code = 0 }),
// Ignore unsolicited pong messages.
.pong,
=> continue,
else => return error.UnexpectedOpcode,
}
}
}
}; |
Thanks!
…On Tue, Aug 26, 2025, at 8:19 AM, 0xRaiden wrote:
*Raiden1411* left a comment (ziglang/zig#24969) <#24969 (comment)>
@scottredig <https://github.com/scottredig>
—
Reply to this email directly, view it on GitHub <#24969 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/BHGY6JQEVV7P7XK7IFZFMO33PR3JZAVCNFSM6AAAAACEUPXPKKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTEMRUGYZTAMZQGY>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
This commit addresses the ziglang#24937 issue and updates the websocket implementation to support both fragments and longer messages.
693fe36
to
2968e8e
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Closes #24937
This PR updates the websocket server implementation to support larger messages and fragmented ones too.
I have also tested this implementation against the autobahn test suite and it passes on all cases expect the compression tests which this implementation doesn't support. Once
std.compress.flate.Compress
is re-implemented then it can be added too.I can also share the code used for the test if needed.
If you think this PR goes against the original design/goal feel free to close it.