mirror of
				https://github.com/lightpanda-io/browser.git
				synced 2025-10-29 15:13:28 +00:00 
			
		
		
		
	connect proxy
This commit is contained in:
		| @@ -33,9 +33,8 @@ pub const App = struct { | ||||
|         run_mode: RunMode, | ||||
|         platform: ?*const Platform = null, | ||||
|         tls_verify_host: bool = true, | ||||
|         http_proxy: ?std.Uri = null, | ||||
|         proxy_type: ?Http.ProxyType = null, | ||||
|         proxy_auth: ?Http.ProxyAuth = null, | ||||
|         http_proxy: ?[:0]const u8 = null, | ||||
|         proxy_bearer_token: ?[:0]const u8 = null, | ||||
|     }; | ||||
|  | ||||
|     pub fn init(allocator: Allocator, config: Config) !*App { | ||||
| @@ -53,7 +52,9 @@ pub const App = struct { | ||||
|  | ||||
|         var http = try Http.init(allocator, .{ | ||||
|             .max_concurrent_transfers = 3, | ||||
|             .http_proxy = config.http_proxy, | ||||
|             .tls_verify_host = config.tls_verify_host, | ||||
|             .proxy_bearer_token = config.proxy_bearer_token, | ||||
|         }); | ||||
|         errdefer http.deinit(); | ||||
|  | ||||
|   | ||||
| @@ -57,7 +57,7 @@ blocking_active: if (builtin.mode == .Debug) bool else void = if (builtin.mode = | ||||
|  | ||||
| const RequestQueue = std.DoublyLinkedList(Request); | ||||
|  | ||||
| pub fn init(allocator: Allocator, ca_blob: c.curl_blob, opts: Http.Opts) !*Client { | ||||
| pub fn init(allocator: Allocator, ca_blob: ?c.curl_blob, opts: Http.Opts) !*Client { | ||||
|     var transfer_pool = std.heap.MemoryPool(Transfer).init(allocator); | ||||
|     errdefer transfer_pool.deinit(); | ||||
|  | ||||
| @@ -70,10 +70,10 @@ pub fn init(allocator: Allocator, ca_blob: c.curl_blob, opts: Http.Opts) !*Clien | ||||
|     const multi = c.curl_multi_init() orelse return error.FailedToInitializeMulti; | ||||
|     errdefer _ = c.curl_multi_cleanup(multi); | ||||
|  | ||||
|     var handles = try Handles.init(allocator, client, ca_blob, opts); | ||||
|     var handles = try Handles.init(allocator, client, ca_blob, &opts); | ||||
|     errdefer handles.deinit(allocator); | ||||
|  | ||||
|     var blocking = try Handle.init(client, ca_blob, opts); | ||||
|     var blocking = try Handle.init(client, ca_blob, &opts); | ||||
|     errdefer blocking.deinit(); | ||||
|  | ||||
|     client.* = .{ | ||||
| @@ -104,7 +104,7 @@ pub fn deinit(self: *Client) void { | ||||
|  | ||||
| pub fn abort(self: *Client) void { | ||||
|     while (self.handles.in_use.first) |node| { | ||||
|         var transfer = Transfer.fromEasy(node.data.easy) catch |err| { | ||||
|         var transfer = Transfer.fromEasy(node.data.conn.easy) catch |err| { | ||||
|             log.err(.http, "get private info", .{ .err = err, .source = "abort" }); | ||||
|             continue; | ||||
|         }; | ||||
| @@ -173,19 +173,19 @@ pub fn blockingRequest(self: *Client, req: Request) !void { | ||||
| } | ||||
|  | ||||
| fn makeRequest(self: *Client, handle: *Handle, req: Request) !void { | ||||
|     const easy = handle.easy; | ||||
|     const conn = handle.conn; | ||||
|     const easy = conn.easy; | ||||
|  | ||||
|     const header_list = blk: { | ||||
|         errdefer self.handles.release(handle); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_URL, req.url.ptr)); | ||||
|         try conn.setMethod(req.method); | ||||
|         try conn.setURL(req.url); | ||||
|  | ||||
|         try Http.setMethod(easy, req.method); | ||||
|         if (req.body) |b| { | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_POSTFIELDS, b.ptr)); | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_POSTFIELDSIZE, @as(c_long, @intCast(b.len)))); | ||||
|             try conn.setBody(b); | ||||
|         } | ||||
|  | ||||
|         var header_list = c.curl_slist_append(null, "User-Agent: Lightpanda/1.0"); | ||||
|         var header_list = conn.commonHeaders(); | ||||
|         errdefer c.curl_slist_free_all(header_list); | ||||
|  | ||||
|         if (req.content_type) |ct| { | ||||
| @@ -269,7 +269,7 @@ fn endTransfer(self: *Client, transfer: *Transfer) void { | ||||
|     transfer.deinit(); | ||||
|     self.transfer_pool.destroy(transfer); | ||||
|  | ||||
|     errorMCheck(c.curl_multi_remove_handle(self.multi, handle.easy)) catch |err| { | ||||
|     errorMCheck(c.curl_multi_remove_handle(self.multi, handle.conn.easy)) catch |err| { | ||||
|         log.fatal(.http, "Failed to abort", .{ .err = err }); | ||||
|     }; | ||||
|  | ||||
| @@ -284,7 +284,8 @@ const Handles = struct { | ||||
|  | ||||
|     const HandleList = std.DoublyLinkedList(*Handle); | ||||
|  | ||||
|     fn init(allocator: Allocator, client: *Client, ca_blob: c.curl_blob, opts: Http.Opts) !Handles { | ||||
|     // pointer to opts is not stable, don't hold a reference to it! | ||||
|     fn init(allocator: Allocator, client: *Client, ca_blob: ?c.curl_blob, opts: *const Http.Opts) !Handles { | ||||
|         const count = opts.max_concurrent_transfers; | ||||
|         std.debug.assert(count > 0); | ||||
|  | ||||
| @@ -340,22 +341,16 @@ const Handles = struct { | ||||
|  | ||||
| // wraps a c.CURL (an easy handle) | ||||
| const Handle = struct { | ||||
|     easy: *c.CURL, | ||||
|     client: *Client, | ||||
|     conn: Http.Connection, | ||||
|     node: ?Handles.HandleList.Node, | ||||
|  | ||||
|     fn init(client: *Client, ca_blob: c.curl_blob, opts: Http.Opts) !Handle { | ||||
|         const easy = c.curl_easy_init() orelse return error.FailedToInitializeEasy; | ||||
|         errdefer _ = c.curl_easy_cleanup(easy); | ||||
|     // pointer to opts is not stable, don't hold a reference to it! | ||||
|     fn init(client: *Client, ca_blob: ?c.curl_blob, opts: *const Http.Opts) !Handle { | ||||
|         const conn = try Http.Connection.init(ca_blob, opts); | ||||
|         errdefer conn.deinit(); | ||||
|  | ||||
|         // timeouts | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_TIMEOUT_MS, @as(c_long, @intCast(opts.timeout_ms)))); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CONNECTTIMEOUT_MS, @as(c_long, @intCast(opts.connect_timeout_ms)))); | ||||
|  | ||||
|         // redirect behavior | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_MAXREDIRS, @as(c_long, @intCast(opts.max_redirects)))); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_FOLLOWLOCATION, @as(c_long, 2))); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_REDIR_PROTOCOLS_STR, "HTTP,HTTPS")); // remove FTP and FTPS from the default | ||||
|         const easy = conn.easy; | ||||
|  | ||||
|         // callbacks | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HEADERDATA, easy)); | ||||
| @@ -363,30 +358,15 @@ const Handle = struct { | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_WRITEDATA, easy)); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_WRITEFUNCTION, Transfer.dataCallback)); | ||||
|  | ||||
|         // tls | ||||
|         if (opts.tls_verify_host) { | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CAINFO_BLOB, ca_blob)); | ||||
|         } else { | ||||
|             // Verify peer checks that the cert is signed by a CA, verify host makes sure the | ||||
|             // cert contains the server name. | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYPEER, @as(c_long, 0))); | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYHOST, @as(c_long, 0))); | ||||
|         } | ||||
|  | ||||
|         // debug | ||||
|         if (comptime Http.ENABLE_DEBUG) { | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_VERBOSE, @as(c_long, 1))); | ||||
|         } | ||||
|  | ||||
|         return .{ | ||||
|             .easy = easy, | ||||
|             .conn = conn, | ||||
|             .node = null, | ||||
|             .client = client, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     fn deinit(self: *const Handle) void { | ||||
|         _ = c.curl_easy_cleanup(self.easy); | ||||
|         self.conn.deinit(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -38,8 +38,8 @@ const Http = @This(); | ||||
|  | ||||
| opts: Opts, | ||||
| client: *Client, | ||||
| ca_blob: c.curl_blob, | ||||
| cert_arena: ArenaAllocator, | ||||
| ca_blob: ?c.curl_blob, | ||||
| arena: ArenaAllocator, | ||||
|  | ||||
| pub fn init(allocator: Allocator, opts: Opts) !Http { | ||||
|     try errorCheck(c.curl_global_init(c.CURL_GLOBAL_SSL)); | ||||
| @@ -49,41 +49,58 @@ pub fn init(allocator: Allocator, opts: Opts) !Http { | ||||
|         std.debug.print("curl version: {s}\n\n", .{c.curl_version()}); | ||||
|     } | ||||
|  | ||||
|     var cert_arena = ArenaAllocator.init(allocator); | ||||
|     errdefer cert_arena.deinit(); | ||||
|     const ca_blob = try loadCerts(allocator, cert_arena.allocator()); | ||||
|     var arena = ArenaAllocator.init(allocator); | ||||
|     errdefer arena.deinit(); | ||||
|  | ||||
|     var client = try Client.init(allocator, ca_blob, opts); | ||||
|     var adjusted_opts = opts; | ||||
|     if (opts.proxy_bearer_token) |bt| { | ||||
|         adjusted_opts.proxy_bearer_token = try std.fmt.allocPrintZ( | ||||
|             arena.allocator(), | ||||
|             "Proxy-Authorization: Bearer {s}", | ||||
|             .{bt}, | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     var ca_blob: ?c.curl_blob = null; | ||||
|     if (opts.tls_verify_host) { | ||||
|         ca_blob = try loadCerts(allocator, arena.allocator()); | ||||
|     } | ||||
|  | ||||
|     var client = try Client.init(allocator, ca_blob, adjusted_opts); | ||||
|     errdefer client.deinit(); | ||||
|  | ||||
|     return .{ | ||||
|         .opts = opts, | ||||
|         .arena = arena, | ||||
|         .client = client, | ||||
|         .ca_blob = ca_blob, | ||||
|         .cert_arena = cert_arena, | ||||
|         .opts = adjusted_opts, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| pub fn deinit(self: *Http) void { | ||||
|     self.client.deinit(); | ||||
|     c.curl_global_cleanup(); | ||||
|     self.cert_arena.deinit(); | ||||
|     self.arena.deinit(); | ||||
| } | ||||
|  | ||||
| pub fn newConnection(self: *Http) !Connection { | ||||
|     return Connection.init(self.ca_blob, self.opts); | ||||
|     return Connection.init(self.ca_blob, &self.opts); | ||||
| } | ||||
|  | ||||
| pub const Connection = struct { | ||||
|     easy: *c.CURL, | ||||
|     opts: Connection.Opts, | ||||
|  | ||||
|     // Is called by Handles when already partially initialized. Done like this | ||||
|     // so that we have a stable pointer to error_buffer. | ||||
|     pub fn init(ca_blob: c.curl_blob, opts: Opts) !Connection { | ||||
|     const Opts = struct { | ||||
|         proxy_bearer_token: ?[:0]const u8, | ||||
|     }; | ||||
|  | ||||
|     // pointer to opts is not stable, don't hold a reference to it! | ||||
|     pub fn init(ca_blob_: ?c.curl_blob, opts: *const Http.Opts) !Connection { | ||||
|         const easy = c.curl_easy_init() orelse return error.FailedToInitializeEasy; | ||||
|         errdefer _ = c.curl_easy_cleanup(easy); | ||||
|  | ||||
|         // timeouts | ||||
|       // timeouts | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_TIMEOUT_MS, @as(c_long, @intCast(opts.timeout_ms)))); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CONNECTTIMEOUT_MS, @as(c_long, @intCast(opts.connect_timeout_ms)))); | ||||
|  | ||||
| @@ -92,10 +109,36 @@ pub const Connection = struct { | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_FOLLOWLOCATION, @as(c_long, 2))); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_REDIR_PROTOCOLS_STR, "HTTP,HTTPS")); // remove FTP and FTPS from the default | ||||
|  | ||||
|         // proxy | ||||
|         if (opts.http_proxy) |proxy| { | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY, proxy.ptr)); | ||||
|         } | ||||
|  | ||||
|         // tls | ||||
|         // try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYHOST, @as(c_long, 0))); | ||||
|         // try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYPEER, @as(c_long, 0))); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CAINFO_BLOB, ca_blob)); | ||||
|         if (ca_blob_) |ca_blob| { | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CAINFO_BLOB, ca_blob)); | ||||
|             if (opts.http_proxy != null) { | ||||
|                 // Note, this can be difference for the proxy and for the main | ||||
|                 // request. Might be something worth exposting as command | ||||
|                 // line arguments at some point. | ||||
|                 try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY_CAINFO_BLOB , ca_blob)); | ||||
|             } | ||||
|         } else { | ||||
|             std.debug.assert(opts.tls_verify_host == false); | ||||
|  | ||||
|             // Verify peer checks that the cert is signed by a CA, verify host makes sure the | ||||
|             // cert contains the server name. | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYHOST, @as(c_long, 0))); | ||||
|             try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_SSL_VERIFYPEER, @as(c_long, 0))); | ||||
|  | ||||
|             if (opts.http_proxy != null) { | ||||
|                 // Note, this can be difference for the proxy and for the main | ||||
|                 // request. Might be something worth exposting as command | ||||
|                 // line arguments at some point. | ||||
|                 try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY_SSL_VERIFYHOST, @as(c_long, 0))); | ||||
|                 try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY_SSL_VERIFYPEER , @as(c_long, 0))); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // debug | ||||
|         if (comptime Http.ENABLE_DEBUG) { | ||||
| @@ -104,6 +147,9 @@ pub const Connection = struct { | ||||
|  | ||||
|         return .{ | ||||
|             .easy = easy, | ||||
|             .opts = .{ | ||||
|                 .proxy_bearer_token = opts.proxy_bearer_token, | ||||
|             }, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
| @@ -116,7 +162,15 @@ pub const Connection = struct { | ||||
|     } | ||||
|  | ||||
|     pub fn setMethod(self: *const Connection, method: Method) !void { | ||||
|         try Http.setMethod(self.easy, method); | ||||
|         const easy = self.easy; | ||||
|         switch (method) { | ||||
|             .GET => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPGET, @as(c_long, 1))), | ||||
|             .POST => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPPOST, @as(c_long, 1))), | ||||
|             .PUT => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "put")), | ||||
|             .DELETE => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "delete")), | ||||
|             .HEAD => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "head")), | ||||
|             .OPTIONS => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "options")), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn setBody(self: *const Connection, body: []const u8) !void { | ||||
| @@ -125,10 +179,24 @@ pub const Connection = struct { | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_POSTFIELDS, body.ptr)); | ||||
|     } | ||||
|  | ||||
|     pub fn commonHeaders(self: *const Connection) *c.curl_slist { | ||||
|         var header_list = c.curl_slist_append(null, "User-Agent: Lightpanda/1.0"); | ||||
|         if (self.opts.proxy_bearer_token) |hdr| { | ||||
|             header_list = c.curl_slist_append(header_list, hdr); | ||||
|         } | ||||
|         return header_list; | ||||
|     } | ||||
|  | ||||
|     pub fn request(self: *const Connection) !u16 { | ||||
|         try errorCheck(c.curl_easy_perform(self.easy)); | ||||
|         const easy = self.easy; | ||||
|  | ||||
|         const header_list = self.commonHeaders(); | ||||
|         defer c.curl_slist_free_all(header_list); | ||||
|         try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPHEADER, header_list)); | ||||
|  | ||||
|         try errorCheck(c.curl_easy_perform(easy)); | ||||
|         var http_code: c_long = undefined; | ||||
|         try errorCheck(c.curl_easy_getinfo(self.easy, c.CURLINFO_RESPONSE_CODE, &http_code)); | ||||
|         try errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_RESPONSE_CODE, &http_code)); | ||||
|         if (http_code < 0 or http_code > std.math.maxInt(u16)) { | ||||
|             return 0; | ||||
|         } | ||||
| @@ -136,17 +204,6 @@ pub const Connection = struct { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| // used by Connection and Handle | ||||
| pub fn setMethod(easy: *c.CURL, method: Method) !void { | ||||
|     switch (method) { | ||||
|         .GET => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPGET, @as(c_long, 1))), | ||||
|         .POST => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPPOST, @as(c_long, 1))), | ||||
|         .PUT => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "put")), | ||||
|         .DELETE => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "delete")), | ||||
|         .HEAD => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "head")), | ||||
|         .OPTIONS => try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_CUSTOMREQUEST, "options")), | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn errorCheck(code: c.CURLcode) errors.Error!void { | ||||
|     if (code == c.CURLE_OK) { | ||||
| @@ -173,6 +230,8 @@ pub const Opts = struct { | ||||
|     tls_verify_host: bool = true, | ||||
|     connect_timeout_ms: u31 = 5000, | ||||
|     max_concurrent_transfers: u8 = 5, | ||||
|     http_proxy: ?[:0]const u8 = null, | ||||
|     proxy_bearer_token: ?[:0]const u8 = null, | ||||
| }; | ||||
|  | ||||
| pub const Method = enum { | ||||
| @@ -184,16 +243,6 @@ pub const Method = enum { | ||||
|     OPTIONS, | ||||
| }; | ||||
|  | ||||
| pub const ProxyType = enum { | ||||
|     forward, | ||||
|     connect, | ||||
| }; | ||||
|  | ||||
| pub const ProxyAuth = union(enum) { | ||||
|     basic: struct { user_pass: []const u8 }, | ||||
|     bearer: struct { token: []const u8 }, | ||||
| }; | ||||
|  | ||||
| // TODO: on BSD / Linux, we could just read the PEM file directly. | ||||
| // This whole rescan + decode is really just needed for MacOS. On Linux | ||||
| // bundle.rescan does find the .pem file(s) which could be in a few different | ||||
|   | ||||
							
								
								
									
										70
									
								
								src/main.zig
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								src/main.zig
									
									
									
									
									
								
							| @@ -85,8 +85,7 @@ fn run(alloc: Allocator) !void { | ||||
|         .run_mode = args.mode, | ||||
|         .platform = &platform, | ||||
|         .http_proxy = args.httpProxy(), | ||||
|         .proxy_type = args.proxyType(), | ||||
|         .proxy_auth = args.proxyAuth(), | ||||
|         .proxy_bearer_token = args.proxyBearerToken(), | ||||
|         .tls_verify_host = args.tlsVerifyHost(), | ||||
|     }); | ||||
|     defer app.deinit(); | ||||
| @@ -156,23 +155,16 @@ const Command = struct { | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     fn httpProxy(self: *const Command) ?std.Uri { | ||||
|     fn httpProxy(self: *const Command) ?[:0]const u8 { | ||||
|         return switch (self.mode) { | ||||
|             inline .serve, .fetch => |opts| opts.common.http_proxy, | ||||
|             else => unreachable, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     fn proxyType(self: *const Command) ?Http.ProxyType { | ||||
|     fn proxyBearerToken(self: *const Command) ?[:0]const u8 { | ||||
|         return switch (self.mode) { | ||||
|             inline .serve, .fetch => |opts| opts.common.proxy_type, | ||||
|             else => unreachable, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     fn proxyAuth(self: *const Command) ?Http.ProxyAuth { | ||||
|         return switch (self.mode) { | ||||
|             inline .serve, .fetch => |opts| opts.common.proxy_auth, | ||||
|             inline .serve, .fetch => |opts| opts.common.proxy_bearer_token, | ||||
|             else => unreachable, | ||||
|         }; | ||||
|     } | ||||
| @@ -221,9 +213,8 @@ const Command = struct { | ||||
|     }; | ||||
|  | ||||
|     const Common = struct { | ||||
|         http_proxy: ?std.Uri = null, | ||||
|         proxy_type: ?Http.ProxyType = null, | ||||
|         proxy_auth: ?Http.ProxyAuth = null, | ||||
|         http_proxy: ?[:0]const u8 = null, | ||||
|         proxy_bearer_token: ?[:0]const u8 = null, | ||||
|         tls_verify_host: bool = true, | ||||
|         log_level: ?log.Level = null, | ||||
|         log_format: ?log.Format = null, | ||||
| @@ -242,21 +233,10 @@ const Command = struct { | ||||
|             \\--http_proxy    The HTTP proxy to use for all HTTP requests. | ||||
|             \\                Defaults to none. | ||||
|             \\ | ||||
|             \\--proxy_type   The type of proxy: connect, forward. | ||||
|             \\               'connect' creates a tunnel through the proxy via | ||||
|             \\               and initial CONNECT request. | ||||
|             \\               'forward' sends the full URL in the request target | ||||
|             \\               and expects the proxy to MITM the request. | ||||
|             \\               Defaults to connect when --http_proxy is set. | ||||
|             \\ | ||||
|             \\--proxy_bearer_token | ||||
|             \\               The token to send for bearer authentication with the proxy | ||||
|             \\               The <token> to send for bearer authentication with the proxy | ||||
|             \\               Proxy-Authorization: Bearer <token> | ||||
|             \\ | ||||
|             \\--proxy_basic_auth | ||||
|             \\               The user:password to send for basic authentication with the proxy | ||||
|             \\               Proxy-Authorization: Basic <base64(user:password)> | ||||
|             \\ | ||||
|             \\--log_level     The log level: debug, info, warn, error or fatal. | ||||
|             \\                Defaults to | ||||
|         ++ (if (builtin.mode == .Debug) " info." else "warn.") ++ | ||||
| @@ -521,48 +501,16 @@ fn parseCommonArg( | ||||
|             log.fatal(.app, "missing argument value", .{ .arg = "--http_proxy" }); | ||||
|             return error.InvalidArgument; | ||||
|         }; | ||||
|         common.http_proxy = try std.Uri.parse(try allocator.dupe(u8, str)); | ||||
|         if (common.http_proxy.?.host == null) { | ||||
|             log.fatal(.app, "invalid http proxy", .{ .arg = "--http_proxy", .hint = "missing scheme?" }); | ||||
|             return error.InvalidArgument; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     if (std.mem.eql(u8, "--proxy_type", opt)) { | ||||
|         const str = args.next() orelse { | ||||
|             log.fatal(.app, "missing argument value", .{ .arg = "--proxy_type" }); | ||||
|             return error.InvalidArgument; | ||||
|         }; | ||||
|         common.proxy_type = std.meta.stringToEnum(Http.ProxyType, str) orelse { | ||||
|             log.fatal(.app, "invalid option choice", .{ .arg = "--proxy_type", .value = str }); | ||||
|             return error.InvalidArgument; | ||||
|         }; | ||||
|         common.http_proxy = try allocator.dupeZ(u8, str); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     if (std.mem.eql(u8, "--proxy_bearer_token", opt)) { | ||||
|         if (common.proxy_auth != null) { | ||||
|             log.fatal(.app, "proxy auth already set", .{ .arg = "--proxy_bearer_token" }); | ||||
|             return error.InvalidArgument; | ||||
|         } | ||||
|         const str = args.next() orelse { | ||||
|             log.fatal(.app, "missing argument value", .{ .arg = "--proxy_bearer_token" }); | ||||
|             return error.InvalidArgument; | ||||
|         }; | ||||
|         common.proxy_auth = .{ .bearer = .{ .token = str } }; | ||||
|         return true; | ||||
|     } | ||||
|     if (std.mem.eql(u8, "--proxy_basic_auth", opt)) { | ||||
|         if (common.proxy_auth != null) { | ||||
|             log.fatal(.app, "proxy auth already set", .{ .arg = "--proxy_basic_auth" }); | ||||
|             return error.InvalidArgument; | ||||
|         } | ||||
|         const str = args.next() orelse { | ||||
|             log.fatal(.app, "missing argument value", .{ .arg = "--proxy_basic_auth" }); | ||||
|             return error.InvalidArgument; | ||||
|         }; | ||||
|         common.proxy_auth = .{ .basic = .{ .user_pass = str } }; | ||||
|         common.proxy_bearer_token = try allocator.dupeZ(u8, str); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Karl Seguin
					Karl Seguin