Skip to content

Commit

Permalink
feat: add default user agent header
Browse files Browse the repository at this point in the history
  • Loading branch information
jiacai2050 committed Sep 17, 2023
1 parent 1963bdd commit afb717e
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 26 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/mirror.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Mirror

on:
push:
branches: [main, master]
workflow_dispatch:

jobs:
codeberg:
if: github.repository_owner == 'jiacai2050'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: pixta-dev/repository-mirroring-action@v1
with:
target_repo_url: https://${{ secrets.CBTOKEN }}@codeberg.org/${{ github.repository }}.git
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

run-examples:
zig build run-basic
zig build run-advanced
zig build run-basic -freference-trace
zig build run-advanced -freference-trace
53 changes: 45 additions & 8 deletions examples/advanced.zig
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
const std = @import("std");
const println = @import("util.zig").println;
const mem = std.mem;
const Allocator = mem.Allocator;
const curl = @import("curl");
const Easy = curl.Easy;

const UA = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0";

const Resposne = struct {
headers: struct {
@"User-Agent": []const u8,
Authorization: []const u8,
},
json: struct {
name: []const u8,
age: usize,
},
method: []const u8,
url: []const u8,
};

fn put_with_custom_header(allocator: Allocator, easy: Easy) !void {
var payload = std.io.fixedBufferStream(
\\{"name": "John", "age": 15}
Expand All @@ -13,11 +29,12 @@ fn put_with_custom_header(allocator: Allocator, easy: Easy) !void {
var h = curl.RequestHeader.init(allocator);
errdefer h.deinit();
try h.add(curl.HEADER_CONTENT_TYPE, "application/json");
try h.add("User-Agent", "zig-curl/0.1.0");
try h.add("user-agent", UA);
try h.add("Authorization", "Basic YWxhZGRpbjpvcGVuc2VzYW1l");
break :blk h;
};
var req = curl.request(
"http://httpbin.org/anything",
"http://httpbin.org/anything/zig-curl",
payload.reader(),
);
req.method = .PUT;
Expand All @@ -32,7 +49,28 @@ fn put_with_custom_header(allocator: Allocator, easy: Easy) !void {
resp.body.items,
});

if (!curl.has_curl_header_support()) {
const parsed = try std.json.parseFromSlice(Resposne, allocator, resp.body.items, .{
.ignore_unknown_fields = true,
});
defer parsed.deinit();

try std.testing.expectEqualDeep(
parsed.value,
.{
.headers = .{
.@"User-Agent" = UA,
.Authorization = "Basic YWxhZGRpbjpvcGVuc2VzYW1l",
},
.json = .{
.name = "John",
.age = 15,
},
.method = "PUT",
.url = "http://httpbin.org/anything/zig-curl",
},
);

if (!curl.has_parse_header_support()) {
return;
}
// Get response header `date`.
Expand All @@ -45,16 +83,15 @@ fn put_with_custom_header(allocator: Allocator, easy: Easy) !void {
}

pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer if (gpa.deinit() != .ok) @panic("leak");
var allocator = gpa.allocator();

const easy = try Easy.init(allocator);
defer easy.deinit();

curl.print_libcurl_version();

const sep = "-" ** 20;
std.debug.print("{s}PUT with custom header demo{s}\n", .{ sep, sep });
println("PUT with custom header demo");
try put_with_custom_header(allocator, easy);
}
12 changes: 6 additions & 6 deletions examples/basic.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const println = @import("util.zig").println;
const mem = std.mem;
const Allocator = mem.Allocator;
const curl = @import("curl");
Expand Down Expand Up @@ -28,17 +29,16 @@ fn post(easy: Easy) !void {
}

pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer if (gpa.deinit() != .ok) @panic("leak");
var allocator = gpa.allocator();

const easy = try Easy.init(allocator);
defer easy.deinit();

const sep = "-" ** 20;
std.debug.print("{s}GET demo{s}\n", .{ sep, sep });
println("GET demo");
try get(easy);

std.debug.print("{s}POST demo{s}\n", .{ sep, sep });
println("POST demo");
try post(easy);
}
7 changes: 7 additions & 0 deletions examples/util.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const std = @import("std");

const SEP = "-" ** 20;

pub fn println(msg: []const u8) void {
std.debug.print("{s}{s}{s}\n", .{ SEP, msg, SEP });
}
4 changes: 2 additions & 2 deletions src/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn print_libcurl_version() void {
}

pub fn polyfill_struct_curl_header() type {
if (has_curl_header_support()) {
if (has_parse_header_support()) {
return *c.struct_curl_header;
} else {
// return a dummy struct to make it compile on old version.
Expand All @@ -54,7 +54,7 @@ pub fn polyfill_struct_curl_header() type {
}
}

pub fn has_curl_header_support() bool {
pub fn has_parse_header_support() bool {
// `curl_header` is officially supported since 7.84.0.
// https://curl.se/libcurl/c/curl_easy_header.html
return c.CURL_AT_LEAST_VERSION(7, 84, 0);
Expand Down
19 changes: 16 additions & 3 deletions src/easy.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const std = @import("std");
const mem = std.mem;
const fmt = std.fmt;

const has_curl_header = @import("c.zig").has_curl_header_support;
const has_curl_header = @import("c.zig").has_parse_header_support;
const polyfill_struct_curl_header = @import("c.zig").polyfill_struct_curl_header;

const Allocator = mem.Allocator;
Expand All @@ -14,8 +14,10 @@ allocator: Allocator,
handle: *c.CURL,
/// The maximum time in milliseconds that the entire transfer operation to take.
timeout_ms: usize = 30_000,
default_user_agent: []const u8 = "zig-curl/0.1.0",

pub const HEADER_CONTENT_TYPE: []const u8 = "Content-Type";
pub const HEADER_USER_AGENT: []const u8 = "User-Agent";

pub const Method = enum {
GET,
Expand Down Expand Up @@ -50,19 +52,30 @@ pub const RequestHeader = struct {
}

// Note: Caller should free returned list (after usage) with `freeCHeader`.
fn asCHeader(self: @This()) !?*c.struct_curl_slist {
fn asCHeader(self: @This(), ua: []const u8) !?*c.struct_curl_slist {
if (self.entries.count() == 0) {
return null;
}

var lst: ?*c.struct_curl_slist = null;
var it = self.entries.iterator();
var has_ua = false;
while (it.next()) |entry| {
if (!has_ua and std.ascii.eqlIgnoreCase(entry.key_ptr.*, HEADER_USER_AGENT)) {
has_ua = true;
}

const kv = try fmt.allocPrintZ(self.allocator, "{s}: {s}", .{ entry.key_ptr.*, entry.value_ptr.* });
defer self.allocator.free(kv);

lst = c.curl_slist_append(lst, kv);
}
if (!has_ua) {
const kv = try fmt.allocPrintZ(self.allocator, "{s}: {s}", .{ HEADER_USER_AGENT, ua });
defer self.allocator.free(kv);

lst = c.curl_slist_append(lst, kv);
}

return lst;
}
Expand Down Expand Up @@ -201,7 +214,7 @@ pub fn do(self: Self, req: anytype) !Response {

var header: ?*c.struct_curl_slist = null;
if (req.header) |h| {
header = try h.asCHeader();
header = try h.asCHeader(self.default_user_agent);
}
defer if (header) |h| RequestHeader.freeCHeader(h);

Expand Down
7 changes: 2 additions & 5 deletions src/main.zig
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
pub const Easy = @import("easy.zig");
// pub const request = Easy.request;
// pub const Request = Easy.Request;
// pub const Response = Easy.Response;

pub usingnamespace Easy;

pub const print_libcurl_version = @import("c.zig").print_libcurl_version;
pub const has_curl_header_support = @import("c.zig").has_curl_header_support;
pub const has_parse_header_support = @import("c.zig").has_parse_header_support;

0 comments on commit afb717e

Please sign in to comment.