Commit 82b37ea024

Jacob Young <jacobly0@users.noreply.github.com>
2024-01-30 14:06:53
http: support basic access authentication
1 parent d7a27bf
Changed files (1)
lib
std
lib/std/http/Client.zig
@@ -657,7 +657,7 @@ pub const Request = struct {
         };
     }
 
-    pub const SendError = Connection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding };
+    pub const SendError = Allocator.Error || Connection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding };
 
     pub const SendOptions = struct {
         /// Specifies that the uri should be used as is. You guarantee that the uri is already escaped.
@@ -695,6 +695,14 @@ pub const Request = struct {
             try w.writeAll("\r\n");
         }
 
+        if ((req.uri.user != null or req.uri.password != null) and
+            !req.headers.contains("authorization"))
+        {
+            try w.writeAll("Authorization: ");
+            try w.writeAll(try basicAuthorizationValue(req.arena.allocator(), req.uri));
+            try w.writeAll("\r\n");
+        }
+
         if (!req.headers.contains("user-agent")) {
             try w.writeAll("User-Agent: zig/");
             try w.writeAll(builtin.zig_version_string);
@@ -1122,19 +1130,11 @@ pub fn loadDefaultProxies(client: *Client) !void {
             },
         };
 
-        if (uri.user != null and uri.password != null) {
-            const prefix = "Basic ";
-
-            const unencoded = try std.fmt.allocPrint(client.allocator, "{s}:{s}", .{ uri.user.?, uri.password.? });
-            defer client.allocator.free(unencoded);
+        if (uri.user != null or uri.password != null) {
+            const authorization = try basicAuthorizationValue(client.allocator, uri);
+            defer client.allocator.free(authorization);
 
-            const buffer = try client.allocator.alloc(u8, std.base64.standard.Encoder.calcSize(unencoded.len) + prefix.len);
-            defer client.allocator.free(buffer);
-
-            const result = std.base64.standard.Encoder.encode(buffer[prefix.len..], unencoded);
-            @memcpy(buffer[0..prefix.len], prefix);
-
-            try client.http_proxy.?.headers.append("proxy-authorization", result);
+            try client.http_proxy.?.headers.append("proxy-authorization", authorization);
         }
     }
 
@@ -1173,21 +1173,31 @@ pub fn loadDefaultProxies(client: *Client) !void {
             },
         };
 
-        if (uri.user != null and uri.password != null) {
-            const prefix = "Basic ";
+        if (uri.user != null or uri.password != null) {
+            const authorization = try basicAuthorizationValue(client.allocator, uri);
+            defer client.allocator.free(authorization);
 
-            const unencoded = try std.fmt.allocPrint(client.allocator, "{s}:{s}", .{ uri.user.?, uri.password.? });
-            defer client.allocator.free(unencoded);
+            try client.https_proxy.?.headers.append("proxy-authorization", authorization);
+        }
+    }
+}
 
-            const buffer = try client.allocator.alloc(u8, std.base64.standard.Encoder.calcSize(unencoded.len) + prefix.len);
-            defer client.allocator.free(buffer);
+pub fn basicAuthorizationValue(
+    allocator: Allocator,
+    uri: Uri,
+) Allocator.Error![]const u8 {
+    const prefix = "Basic ";
 
-            const result = std.base64.standard.Encoder.encode(buffer[prefix.len..], unencoded);
-            @memcpy(buffer[0..prefix.len], prefix);
+    const unencoded = try std.fmt.allocPrint(allocator, "{s}:{s}", .{ uri.user orelse "", uri.password orelse "" });
+    defer allocator.free(unencoded);
 
-            try client.https_proxy.?.headers.append("proxy-authorization", result);
-        }
-    }
+    const buffer = try allocator.alloc(u8, prefix.len + std.base64.standard.Encoder.calcSize(unencoded.len));
+    errdefer allocator.free(buffer);
+
+    @memcpy(buffer[0..prefix.len], prefix);
+    _ = std.base64.standard.Encoder.encode(buffer[prefix.len..], unencoded);
+
+    return buffer;
 }
 
 pub const ConnectTcpError = Allocator.Error || error{ ConnectionRefused, NetworkUnreachable, ConnectionTimedOut, ConnectionResetByPeer, TemporaryNameServerFailure, NameServerFailure, UnknownHostName, HostLacksNetworkAddresses, UnexpectedConnectFailure, TlsInitializationFailed };