summaryrefslogtreecommitdiff
path: root/test/web/native.zig
blob: ad113866e936f538b4c96452107f2195df2a9f52 (plain) (blame)
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
//! Native use of the public HTTPS transport, exercised by the browser E2E runner.
const std = @import("std");
const c9 = @import("cloud9");
const Session = struct {
    tunnel: *c9.http.Client,
    client: c9.Client,
    fn ask(s: *Session, request: c9.Client.Request) !c9.Client.Result {
        const tag = try s.client.submit(request);
        try s.tunnel.send(s.client.output());
        s.client.wrote(s.client.output().len);
        var buffer: [65536]u8 = undefined;
        const frame = try s.tunnel.receive(&buffer);
        if (s.client.push(frame) != frame.len) return error.InputFull;
        const done = s.client.take() orelse return error.MissingReply;
        if (done.tag != tag or done.result == .fail) return error.UnexpectedReply;
        return done.result;
    }
};
pub fn main(init: std.process.Init) !void {
    const args = try init.minimal.args.toSlice(init.arena.allocator());
    if (args.len < 3 or args.len > 4) return error.Arguments;
    var http: std.http.Client = .{ .allocator = init.gpa, .io = init.io };
    defer http.deinit();
    if (args.len == 4) {
        http.now = std.Io.Clock.real.now(init.io);
        try http.ca_bundle.addCertsFromFilePathAbsolute(init.gpa, init.io, http.now.?, args[3]);
    }
    var tunnel = try c9.http.Client.connect(&http, args[1], args[2]);
    defer tunnel.deinit();
    var input: [65536]u8 = undefined;
    var output: [65536]u8 = undefined;
    var session: Session = .{ .tunnel = &tunnel, .client = .init(.{ .in = &input, .out = &output }) };
    _ = try session.ask(.{ .version = .{} });
    _ = try session.ask(.{ .attach = .{ .fid = 0, .uname = "user" } });
    _ = try session.ask(.{ .walk = .{ .fid = 0, .newfid = 1, .names = &.{"hello.txt"} } });
    _ = try session.ask(.{ .open = .{ .fid = 1, .mode = c9.oread } });
    const result = try session.ask(.{ .read = .{ .fid = 1, .offset = 0, .count = 1024 } });
    if (!std.mem.eql(u8, result.read, "Hello from 9P.\n")) return error.WrongContents;
    // Two outstanding tags exercise the full-duplex bridge independently of
    // the browser UI's serialized file-operation queue.
    const read_tag = try session.client.submit(.{ .read = .{ .fid = 1, .offset = 0, .count = 1024 } });
    try tunnel.send(session.client.output());
    session.client.wrote(session.client.output().len);
    const stat_tag = try session.client.submit(.{ .stat = .{ .fid = 0 } });
    try tunnel.send(session.client.output());
    session.client.wrote(session.client.output().len);
    var seen_read = false;
    var seen_stat = false;
    var reply_buffer: [65536]u8 = undefined;
    for (0..2) |_| {
        const frame = try tunnel.receive(&reply_buffer);
        if (session.client.push(frame) != frame.len) return error.InputFull;
        const done = session.client.take() orelse return error.MissingReply;
        if (done.tag == read_tag and !seen_read and done.result == .read) {
            if (!std.mem.eql(u8, done.result.read, "Hello from 9P.\n")) return error.WrongContents;
            seen_read = true;
        } else if (done.tag == stat_tag and !seen_stat and done.result == .stat) {
            if (done.result.stat.qid.type & c9.qtdir == 0) return error.WrongStat;
            seen_stat = true;
        } else return error.UnexpectedReply;
    }
    if (!seen_read or !seen_stat) return error.MissingReply;
    _ = try session.ask(.{ .clunk = .{ .fid = 1 } });
    _ = try session.ask(.{ .clunk = .{ .fid = 0 } });
    std.debug.print("native HTTP transport passed\n", .{});
}