authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-01-31 14:33:17+01:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-01-31 15:00:27+01:00
logc1e7d0c08f96f390a641b082b33a8a8717cdd706
treea5a173396150bf73368ba6d7577b707c9f765c7e
parenta111f805cd6cc82952786d0ffccb5a31c68f6353

http: optimize allocations for proxy basic authorization


2 files changed, 52 insertions(+), 14 deletions(-)

lib/std/http/Client.zig+8-4
......@@ -1141,8 +1141,10 @@ pub fn loadDefaultProxies(client: *Client) !void {
11411141 };
11421142
11431143 if (uri.user != null or uri.password != null) {
1144 var authorization: [basic_authorization.max_value_len]u8 = undefined;
1145 try client.http_proxy.?.headers.append("proxy-authorization", basic_authorization.value(uri, &authorization));
1144 const authorization = try client.allocator.alloc(u8, basic_authorization.valueLengthFromUri(uri));
1145 errdefer client.allocator.free(authorization);
1146 std.debug.assert(basic_authorization.value(uri, authorization).len == authorization.len);
1147 try client.http_proxy.?.headers.appendOwned(.{ .unowned = "proxy-authorization" }, .{ .owned = authorization });
11461148 }
11471149 }
11481150
......@@ -1182,8 +1184,10 @@ pub fn loadDefaultProxies(client: *Client) !void {
11821184 };
11831185
11841186 if (uri.user != null or uri.password != null) {
1185 var authorization: [basic_authorization.max_value_len]u8 = undefined;
1186 try client.https_proxy.?.headers.append("proxy-authorization", basic_authorization.value(uri, &authorization));
1187 const authorization = try client.allocator.alloc(u8, basic_authorization.valueLengthFromUri(uri));
1188 errdefer client.allocator.free(authorization);
1189 std.debug.assert(basic_authorization.value(uri, authorization).len == authorization.len);
1190 try client.https_proxy.?.headers.appendOwned(.{ .unowned = "proxy-authorization" }, .{ .owned = authorization });
11871191 }
11881192 }
11891193}
lib/std/http/Headers.zig+44-10
......@@ -91,30 +91,64 @@ pub const Headers = struct {
9191 ///
9292 /// If the `owned` field is true, both name and value will be copied.
9393 pub fn append(headers: *Headers, name: []const u8, value: []const u8) !void {
94 const n = headers.list.items.len;
94 try headers.appendOwned(.{ .unowned = name }, .{ .unowned = value });
95 }
9596
96 const value_duped = if (headers.owned) try headers.allocator.dupe(u8, value) else value;
97 errdefer if (headers.owned) headers.allocator.free(value_duped);
97 pub const OwnedString = union(enum) {
98 /// A string allocated by the `allocator` field.
99 owned: []u8,
100 /// A string to be copied by the `allocator` field.
101 unowned: []const u8,
102 };
98103
99 var entry = Field{ .name = undefined, .value = value_duped };
104 /// Appends a header to the list.
105 ///
106 /// If the `owned` field is true, `name` and `value` will be copied if unowned.
107 pub fn appendOwned(headers: *Headers, name: OwnedString, value: OwnedString) !void {
108 const n = headers.list.items.len;
109 try headers.list.ensureUnusedCapacity(headers.allocator, 1);
110
111 const owned_value = switch (value) {
112 .owned => |owned| owned,
113 .unowned => |unowned| if (headers.owned)
114 try headers.allocator.dupe(u8, unowned)
115 else
116 unowned,
117 };
118 errdefer if (value == .unowned and headers.owned) headers.allocator.free(owned_value);
119
120 var entry = Field{ .name = undefined, .value = owned_value };
121
122 if (headers.index.getEntry(switch (name) {
123 inline else => |string| string,
124 })) |kv| {
125 defer switch (name) {
126 .owned => |owned| headers.allocator.free(owned),
127 .unowned => {},
128 };
100129
101 if (headers.index.getEntry(name)) |kv| {
102130 entry.name = kv.key_ptr.*;
103131 try kv.value_ptr.append(headers.allocator, n);
104132 } else {
105 const name_duped = if (headers.owned) try std.ascii.allocLowerString(headers.allocator, name) else name;
106 errdefer if (headers.owned) headers.allocator.free(name_duped);
133 const owned_name = switch (name) {
134 .owned => |owned| owned,
135 .unowned => |unowned| if (headers.owned)
136 try std.ascii.allocLowerString(headers.allocator, unowned)
137 else
138 unowned,
139 };
140 errdefer if (name == .unowned and headers.owned) headers.allocator.free(owned_name);
107141
108 entry.name = name_duped;
142 entry.name = owned_name;
109143
110144 var new_index = try HeaderIndexList.initCapacity(headers.allocator, 1);
111145 errdefer new_index.deinit(headers.allocator);
112146
113147 new_index.appendAssumeCapacity(n);
114 try headers.index.put(headers.allocator, name_duped, new_index);
148 try headers.index.put(headers.allocator, owned_name, new_index);
115149 }
116150
117 try headers.list.append(headers.allocator, entry);
151 headers.list.appendAssumeCapacity(entry);
118152 }
119153
120154 /// Returns true if this list of headers contains the given name.