╭ changed ────╮ │build.zig.zon│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 3 .version = "0.0.0", │ │ 4 .dependencies = .{ │ │ 5 .xit = .{ │ │ 6 - .url = "git+https://github.com/xit-vcs/xit#ca588e800bf3443adbfa4504ab865e407d72f6a2",│ │ 7 - .hash = "xit-0.0.0-Ub3nDMpZUwGoPxMQg2ZaYvAnXCKTAlySUnS-GkbElHav", │ │ 6 + .url = "git+https://github.com/xit-vcs/xit#765ef0d4b3ad401eb4e5c8b55bb397643eb44e7a",│ │ 7 + .hash = "xit-0.0.0-Ub3nDC5aUwHQBLNPIwVbyJfGk8l70OmtKw26fdYEqMZ7", │ │ 8 }, │ │ 9 }, │ │10 .paths = .{ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/serve_http.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │108 const content_type = try allocator.dupe(u8, findHeader(request, "content-type") orelse ""); │ │109 defer allocator.free(content_type); │ │110 const has_remote_user = findHeader(request, "authorization") != null; │ │111 - const protocol_version = protocolVersionFromHeader(findHeader(request, "git-protocol")); │ │111 + const protocol_version = xit.net_server_common.parseProtocolVersion(findHeader(request, "git-protocol"));│ │112 │ │113 // pushing over HTTP is not supported; pushes go over SSH │ │114 if (isReceivePack(handler, suffix, uri.query)) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │267 │ │268 fn normalizeMethod(method: std.http.Method) std.http.Method { │ │269 return if (method == .HEAD) .GET else method; │ │270 -} │ │271 - │ │272 -fn protocolVersionFromHeader(header: ?[]const u8) xit.net_server_common.ProtocolVersion {│ │273 - const git_protocol = header orelse return .v0; │ │274 - var version: xit.net_server_common.ProtocolVersion = .v0; │ │275 - var iter = std.mem.splitScalar(u8, git_protocol, ':'); │ │276 - while (iter.next()) |entry| { │ │277 - const value = std.mem.trimStart(u8, entry, " "); │ │278 - if (std.mem.startsWith(u8, value, "version=")) { │ │279 - const v = value["version=".len..]; │ │280 - if (std.mem.eql(u8, v, "2")) { │ │281 - version = .v2; │ │282 - } else if (std.mem.eql(u8, v, "1") and version != .v2) { │ │283 - version = .v1; │ │284 - } │ │285 - } │ │286 - } │ │287 - return version; │ │270 } │ │271 │ │272 fn findHeader(request: *std.http.Server.Request, name: []const u8) ?[]const u8 { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭───────────────────────────────────────────────────────────╮ │47 sess.exemptFromIdleTimeout(); │ │48 try runTuiSession(self, sess, pty); │ │49 }, │ │50 - .exec => |command| { │ │51 - try runGitSession(self, sess, command);│ │50 + .exec => |exec| { │ │51 + try runGitSession(self, sess, exec); │ │52 }, │ │53 } │ │54 } │ ╰───────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │358 } │ │359 }; │ │360 │ │361 -fn runGitSession(handler: *const SessionHandler, sess: *ssh.SessionCtx, command: []const u8) !void { │ │361 +fn runGitSession(handler: *const SessionHandler, sess: *ssh.SessionCtx, exec: ssh.Request.Exec) !void { │ │362 const allocator = sess.conn.allocator; │ │363 const io = sess.conn.io; │ │364 + const protocol_version = xit.net_server_common.parseProtocolVersion(exec.git_protocol); │ │365 │ │365 - const parsed = parseGitCommand(allocator, command) catch return writeError(sess, "unsupported command (expected git-upload-pack or git-receive-pack)"); │ │366 + const parsed = parseGitCommand(allocator, exec.command) catch return writeError(sess, "unsupported command (expected git-upload-pack or git-receive-pack)");│ │367 defer parsed.deinit(allocator); │ │368 const path = std.mem.trimStart(u8, parsed.dir, "/"); │ │369 const fork_prefix = "fork/"; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │398 var writer = ssh.SessionWriter.init(sess, &writer_buf); │ │399 if (parsed.service == .upload_pack) { │ │400 switch (draft) { │ │400 - inline else => |*repo| try repo.uploadPack(io, allocator, &reader.interface, &writer.interface, .{}), │ │401 + inline else => |*repo| try repo.uploadPack(io, allocator, &reader.interface, &writer.interface, .{ .protocol_version = protocol_version }), │ │402 } │ │403 } else { │ │404 const target = (try evt.Repo.readByOwnerAndName(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &admin_arena, owner_repo.owner, owner_repo.name)) orelse│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │446 }; │ │447 defer allocator.free(repo_path); │ │448 │ │448 - if (try serveIfExists(repo_path, handler.repo_root_path, sess, io, allocator, parsed.service, handler.err)) { │ │449 + if (try serveIfExists(repo_path, handler.repo_root_path, sess, io, allocator, parsed.service, protocol_version, handler.err)) {│ │450 try sess.exit(0); │ │451 return; │ │452 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │456 // create the on-disk repo for the just-minted event and serve the push │ │457 var repo = try createRepo(any_repo_opts.toRepoOpts(), io, allocator, repo_path); │ │458 defer repo.deinit(io, allocator); │ │458 - try servePack(repo.self_repo_opts, &repo, handler.repo_root_path, sess, io, allocator, parsed.service, handler.err); │ │459 + try servePack(repo.self_repo_opts, &repo, handler.repo_root_path, sess, io, allocator, parsed.service, protocol_version, handler.err);│ │460 try sess.exit(0); │ │461 } │ │462 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │468 io: std.Io, │ │469 allocator: std.mem.Allocator, │ │470 service: GitService, │ │471 + protocol_version: xit.net_server_common.ProtocolVersion, │ │472 error_writer: *std.Io.Writer, │ │473 ) !bool { │ │474 // a bare open() creates the directory while probing for the repo, so only│ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │483 defer any_repo.deinit(io, allocator); │ │484 │ │485 switch (any_repo) { │ │484 - inline else => |*repo| try servePack(repo.self_repo_opts, repo, repo_root_path, sess, io, allocator, service, error_writer), │ │486 + inline else => |*repo| try servePack(repo.self_repo_opts, repo, repo_root_path, sess, io, allocator, service, protocol_version, error_writer),│ │487 } │ │488 return true; │ │489 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯