create new http client for Ipwhois
This commit is contained in:
parent
f58fc54eb2
commit
90abfbf79f
3 changed files with 20 additions and 9 deletions
|
|
@ -15,7 +15,7 @@ jobs:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Setup Zig
|
- name: Setup Zig
|
||||||
uses: https://codeberg.org/mlugg/setup-zig@v2.2.1
|
uses: https://github.com/mlugg/setup-zig@v2.2.1
|
||||||
- name: Build project
|
- name: Build project
|
||||||
run: zig build --summary all
|
run: zig build --summary all
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ allocator: Allocator,
|
||||||
/// every method that touches a file or the network.
|
/// every method that touches a file or the network.
|
||||||
io: std.Io,
|
io: std.Io,
|
||||||
api_key: ?[]const u8,
|
api_key: ?[]const u8,
|
||||||
http_client: std.http.Client,
|
|
||||||
cache: *Cache,
|
cache: *Cache,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, io: std.Io, api_key: ?[]const u8, cache_path: []const u8) !Self {
|
pub fn init(allocator: Allocator, io: std.Io, api_key: ?[]const u8, cache_path: []const u8) !Self {
|
||||||
|
|
@ -24,7 +23,6 @@ pub fn init(allocator: Allocator, io: std.Io, api_key: ?[]const u8, cache_path:
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.io = io,
|
.io = io,
|
||||||
.api_key = if (api_key) |k| try allocator.dupe(u8, k) else null,
|
.api_key = if (api_key) |k| try allocator.dupe(u8, k) else null,
|
||||||
.http_client = std.http.Client{ .allocator = allocator, .io = io },
|
|
||||||
.cache = cache,
|
.cache = cache,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -32,7 +30,6 @@ pub fn init(allocator: Allocator, io: std.Io, api_key: ?[]const u8, cache_path:
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
self.cache.deinit();
|
self.cache.deinit();
|
||||||
self.allocator.destroy(self.cache);
|
self.allocator.destroy(self.cache);
|
||||||
self.http_client.deinit();
|
|
||||||
if (self.api_key) |k|
|
if (self.api_key) |k|
|
||||||
self.allocator.free(k);
|
self.allocator.free(k);
|
||||||
}
|
}
|
||||||
|
|
@ -106,9 +103,15 @@ fn fetch(self: *Self, ip_str: []const u8) !Location {
|
||||||
if (self.api_key) |key|
|
if (self.api_key) |key|
|
||||||
try w.print("&key={s}", .{key});
|
try w.print("&key={s}", .{key});
|
||||||
|
|
||||||
|
// A fresh client per request, deliberately: a long-lived `std.http.Client`
|
||||||
|
// validates certificates against the time of its first request. See the
|
||||||
|
// matching comment in `IpWhoIs.fetch` for the failure this prevents.
|
||||||
|
var client: std.http.Client = .{ .allocator = self.allocator, .io = self.io };
|
||||||
|
defer client.deinit();
|
||||||
|
|
||||||
var response_buf: [4096]u8 = undefined;
|
var response_buf: [4096]u8 = undefined;
|
||||||
var writer = std.Io.Writer.fixed(&response_buf);
|
var writer = std.Io.Writer.fixed(&response_buf);
|
||||||
const result = try self.http_client.fetch(.{
|
const result = try client.fetch(.{
|
||||||
.location = .{ .url = w.buffered() },
|
.location = .{ .url = w.buffered() },
|
||||||
.method = .GET,
|
.method = .GET,
|
||||||
.response_writer = &writer,
|
.response_writer = &writer,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ const log = std.log.scoped(.ipwhois);
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
/// Zig 0.16 requires an explicit `Io` for filesystem and HTTP work.
|
/// Zig 0.16 requires an explicit `Io` for filesystem and HTTP work.
|
||||||
io: std.Io,
|
io: std.Io,
|
||||||
http_client: std.http.Client,
|
|
||||||
cache: *Cache,
|
cache: *Cache,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, io: std.Io, cache_path: []const u8) !Self {
|
pub fn init(allocator: Allocator, io: std.Io, cache_path: []const u8) !Self {
|
||||||
|
|
@ -21,7 +20,6 @@ pub fn init(allocator: Allocator, io: std.Io, cache_path: []const u8) !Self {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.io = io,
|
.io = io,
|
||||||
.http_client = std.http.Client{ .allocator = allocator, .io = io },
|
|
||||||
.cache = cache,
|
.cache = cache,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +27,6 @@ pub fn init(allocator: Allocator, io: std.Io, cache_path: []const u8) !Self {
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
self.cache.deinit();
|
self.cache.deinit();
|
||||||
self.allocator.destroy(self.cache);
|
self.allocator.destroy(self.cache);
|
||||||
self.http_client.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(self: *Self, ip_str: []const u8) ?Location {
|
pub fn lookup(self: *Self, ip_str: []const u8) ?Location {
|
||||||
|
|
@ -69,9 +66,20 @@ fn fetch(self: *Self, ip_str: []const u8) !Location {
|
||||||
// which cannot be derived from `country` without matching display text.
|
// which cannot be derived from `country` without matching display text.
|
||||||
try w.writeAll("?fields=city,region,country,country_code,latitude,longitude&output=json");
|
try w.writeAll("?fields=city,region,country,country_code,latitude,longitude&output=json");
|
||||||
|
|
||||||
|
// A fresh client per request, deliberately. `std.http.Client` latches the
|
||||||
|
// wall clock into `now` on its first HTTPS request and validates every
|
||||||
|
// later certificate against that frozen time. A client kept for the life of
|
||||||
|
// the server therefore rejects any certificate issued after its first
|
||||||
|
// lookup (`CertificateNotYetValid`, which std reports only as
|
||||||
|
// `TlsInitializationFailed`), so lookups start failing as soon as the
|
||||||
|
// provider rotates its certificate and keep failing until a restart.
|
||||||
|
// Lookups are cached permanently, so the per-request CA bundle scan is rare.
|
||||||
|
var client: std.http.Client = .{ .allocator = self.allocator, .io = self.io };
|
||||||
|
defer client.deinit();
|
||||||
|
|
||||||
var response_buf: [4096]u8 = undefined;
|
var response_buf: [4096]u8 = undefined;
|
||||||
var writer = std.Io.Writer.fixed(&response_buf);
|
var writer = std.Io.Writer.fixed(&response_buf);
|
||||||
const result = try self.http_client.fetch(.{
|
const result = try client.fetch(.{
|
||||||
.location = .{ .url = w.buffered() },
|
.location = .{ .url = w.buffered() },
|
||||||
.method = .GET,
|
.method = .GET,
|
||||||
.response_writer = &writer,
|
.response_writer = &writer,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue