Skip to content

Commit 1015fc0

Browse files
authored
Merge pull request #1170 from lightpanda-io/nikneym/ada-in-web-apis
Use ada-url for URL operations in web APIs
2 parents 1c37b1c + 8d4cf40 commit 1015fc0

File tree

12 files changed

+596
-305
lines changed

12 files changed

+596
-305
lines changed

build.zig

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ fn addDependencies(b: *Build, mod: *Build.Module, opts: *Build.Step.Options) !vo
384384
try buildMbedtls(b, mod);
385385
try buildNghttp2(b, mod);
386386
try buildCurl(b, mod);
387+
try buildAda(b, mod);
387388

388389
switch (target.result.os.tag) {
389390
.macos => {
@@ -849,3 +850,34 @@ fn buildCurl(b: *Build, m: *Build.Module) !void {
849850
},
850851
});
851852
}
853+
854+
pub fn buildAda(b: *Build, m: *Build.Module) !void {
855+
const ada_dep = b.dependency("ada-singleheader", .{});
856+
857+
const ada_mod = b.createModule(.{
858+
.root_source_file = b.path("vendor/ada/root.zig"),
859+
});
860+
861+
const ada_lib = b.addLibrary(.{
862+
.name = "ada",
863+
.root_module = b.createModule(.{
864+
.link_libcpp = true,
865+
.target = m.resolved_target,
866+
.optimize = m.optimize,
867+
}),
868+
.linkage = .static,
869+
});
870+
871+
ada_lib.addCSourceFile(.{
872+
.file = ada_dep.path("ada.cpp"),
873+
.flags = &.{ "-std=c++20", "-O3" },
874+
.language = .cpp,
875+
});
876+
877+
ada_lib.installHeader(ada_dep.path("ada_c.h"), "ada_c.h");
878+
879+
// Link the library to ada module.
880+
ada_mod.linkLibrary(ada_lib);
881+
// Expose ada module to main module.
882+
m.addImport("ada", ada_mod);
883+
}

build.zig.zon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@
99
.hash = "v8-0.0.0-xddH63bVAwBSEobaUok9J0er1FqsvEujCDDVy6ItqKQ5",
1010
},
1111
//.v8 = .{ .path = "../zig-v8-fork" }
12+
.@"ada-singleheader" = .{
13+
.url = "https://github.com/ada-url/ada/releases/download/v3.3.0/singleheader.zip",
14+
.hash = "N-V-__8AAPmhFAAw64ALjlzd5YMtzpSrmZ6KymsT84BKfB4s",
15+
},
1216
},
1317
}

src/browser/html/document.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ pub const HTMLDocument = struct {
4242
// JS funcs
4343
// --------
4444

45-
pub fn get_domain(self: *parser.DocumentHTML, page: *Page) ![]const u8 {
45+
pub fn get_domain(self: *parser.DocumentHTML) ![]const u8 {
4646
// libdom's document_html get_domain always returns null, this is
4747
// the way MDN recommends getting the domain anyways, since document.domain
4848
// is deprecated.
4949
const location = try parser.documentHTMLGetLocation(Location, self) orelse return "";
50-
return location.get_host(page);
50+
return location.get_host();
5151
}
5252

5353
pub fn set_domain(_: *parser.DocumentHTML, _: []const u8) ![]const u8 {

src/browser/html/elements.zig

Lines changed: 101 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -218,36 +218,36 @@ pub const HTMLAnchorElement = struct {
218218
}
219219

220220
pub fn get_href(self: *parser.Anchor) ![]const u8 {
221-
return try parser.anchorGetHref(self);
221+
return parser.anchorGetHref(self);
222222
}
223223

224224
pub fn set_href(self: *parser.Anchor, href: []const u8, page: *const Page) !void {
225225
const full = try urlStitch(page.call_arena, href, page.url.raw, .{});
226-
return try parser.anchorSetHref(self, full);
226+
return parser.anchorSetHref(self, full);
227227
}
228228

229229
pub fn get_hreflang(self: *parser.Anchor) ![]const u8 {
230-
return try parser.anchorGetHrefLang(self);
230+
return parser.anchorGetHrefLang(self);
231231
}
232232

233233
pub fn set_hreflang(self: *parser.Anchor, href: []const u8) !void {
234-
return try parser.anchorSetHrefLang(self, href);
234+
return parser.anchorSetHrefLang(self, href);
235235
}
236236

237237
pub fn get_type(self: *parser.Anchor) ![]const u8 {
238-
return try parser.anchorGetType(self);
238+
return parser.anchorGetType(self);
239239
}
240240

241241
pub fn set_type(self: *parser.Anchor, t: []const u8) !void {
242-
return try parser.anchorSetType(self, t);
242+
return parser.anchorSetType(self, t);
243243
}
244244

245245
pub fn get_rel(self: *parser.Anchor) ![]const u8 {
246-
return try parser.anchorGetRel(self);
246+
return parser.anchorGetRel(self);
247247
}
248248

249249
pub fn set_rel(self: *parser.Anchor, t: []const u8) !void {
250-
return try parser.anchorSetRel(self, t);
250+
return parser.anchorSetRel(self, t);
251251
}
252252

253253
pub fn get_text(self: *parser.Anchor) !?[]const u8 {
@@ -269,182 +269,175 @@ pub const HTMLAnchorElement = struct {
269269
if (try parser.elementGetAttribute(@ptrCast(@alignCast(self)), "href")) |href| {
270270
return URL.constructor(.{ .string = href }, null, page); // TODO inject base url
271271
}
272-
return .empty;
272+
return error.NotProvided;
273273
}
274274

275-
// TODO return a disposable string
276275
pub fn get_origin(self: *parser.Anchor, page: *Page) ![]const u8 {
277276
var u = try url(self, page);
278-
return try u.get_origin(page);
277+
defer u.destructor();
278+
return u.get_origin(page);
279279
}
280280

281-
// TODO return a disposable string
282281
pub fn get_protocol(self: *parser.Anchor, page: *Page) ![]const u8 {
283282
var u = try url(self, page);
284-
return u.get_protocol();
283+
defer u.destructor();
284+
285+
return page.call_arena.dupe(u8, u.get_protocol());
285286
}
286287

287-
pub fn set_protocol(self: *parser.Anchor, v: []const u8, page: *Page) !void {
288-
const arena = page.arena;
288+
pub fn set_protocol(self: *parser.Anchor, protocol: []const u8, page: *Page) !void {
289289
var u = try url(self, page);
290+
defer u.destructor();
291+
try u.set_protocol(protocol);
290292

291-
u.uri.scheme = v;
292-
const href = try u.toString(arena);
293-
try parser.anchorSetHref(self, href);
293+
const href = try u._toString(page);
294+
return parser.anchorSetHref(self, href);
294295
}
295296

296-
// TODO return a disposable string
297297
pub fn get_host(self: *parser.Anchor, page: *Page) ![]const u8 {
298-
var u = try url(self, page);
299-
return try u.get_host(page);
300-
}
301-
302-
pub fn set_host(self: *parser.Anchor, v: []const u8, page: *Page) !void {
303-
// search : separator
304-
var p: ?u16 = null;
305-
var h: []const u8 = undefined;
306-
for (v, 0..) |c, i| {
307-
if (c == ':') {
308-
h = v[0..i];
309-
p = try std.fmt.parseInt(u16, v[i + 1 ..], 10);
310-
break;
311-
}
312-
}
298+
var u = url(self, page) catch return "";
299+
defer u.destructor();
313300

314-
const arena = page.arena;
315-
var u = try url(self, page);
301+
return page.call_arena.dupe(u8, u.get_host());
302+
}
316303

317-
if (p) |pp| {
318-
u.uri.host = .{ .raw = h };
319-
u.uri.port = pp;
320-
} else {
321-
u.uri.host = .{ .raw = v };
322-
u.uri.port = null;
323-
}
304+
pub fn set_host(self: *parser.Anchor, host: []const u8, page: *Page) !void {
305+
var u = try url(self, page);
306+
defer u.destructor();
307+
try u.set_host(host);
324308

325-
const href = try u.toString(arena);
326-
try parser.anchorSetHref(self, href);
309+
const href = try u._toString(page);
310+
return parser.anchorSetHref(self, href);
327311
}
328312

329313
pub fn get_hostname(self: *parser.Anchor, page: *Page) ![]const u8 {
330-
var u = try url(self, page);
331-
return u.get_hostname();
314+
var u = url(self, page) catch return "";
315+
defer u.destructor();
316+
return page.call_arena.dupe(u8, u.get_hostname());
332317
}
333318

334-
pub fn set_hostname(self: *parser.Anchor, v: []const u8, page: *Page) !void {
335-
const arena = page.arena;
319+
pub fn set_hostname(self: *parser.Anchor, hostname: []const u8, page: *Page) !void {
336320
var u = try url(self, page);
337-
u.uri.host = .{ .raw = v };
338-
const href = try u.toString(arena);
339-
try parser.anchorSetHref(self, href);
321+
defer u.destructor();
322+
try u.set_hostname(hostname);
323+
324+
const href = try u._toString(page);
325+
return parser.anchorSetHref(self, href);
340326
}
341327

342-
// TODO return a disposable string
343328
pub fn get_port(self: *parser.Anchor, page: *Page) ![]const u8 {
344-
var u = try url(self, page);
345-
return try u.get_port(page);
329+
var u = url(self, page) catch return "";
330+
defer u.destructor();
331+
return page.call_arena.dupe(u8, u.get_port());
346332
}
347333

348-
pub fn set_port(self: *parser.Anchor, v: ?[]const u8, page: *Page) !void {
349-
const arena = page.arena;
334+
pub fn set_port(self: *parser.Anchor, maybe_port: ?[]const u8, page: *Page) !void {
350335
var u = try url(self, page);
336+
defer u.destructor();
351337

352-
if (v != null and v.?.len > 0) {
353-
u.uri.port = try std.fmt.parseInt(u16, v.?, 10);
338+
if (maybe_port) |port| {
339+
try u.set_port(port);
354340
} else {
355-
u.uri.port = null;
341+
u.clearPort();
356342
}
357343

358-
const href = try u.toString(arena);
359-
try parser.anchorSetHref(self, href);
344+
const href = try u._toString(page);
345+
return parser.anchorSetHref(self, href);
360346
}
361347

362-
// TODO return a disposable string
363348
pub fn get_username(self: *parser.Anchor, page: *Page) ![]const u8 {
364-
var u = try url(self, page);
365-
return u.get_username();
349+
var u = url(self, page) catch return "";
350+
defer u.destructor();
351+
352+
const username = u.get_username();
353+
if (username.len == 0) {
354+
return "";
355+
}
356+
357+
return page.call_arena.dupe(u8, username);
366358
}
367359

368-
pub fn set_username(self: *parser.Anchor, v: ?[]const u8, page: *Page) !void {
369-
const arena = page.arena;
360+
pub fn set_username(self: *parser.Anchor, maybe_username: ?[]const u8, page: *Page) !void {
370361
var u = try url(self, page);
362+
defer u.destructor();
371363

372-
if (v) |vv| {
373-
u.uri.user = .{ .raw = vv };
374-
} else {
375-
u.uri.user = null;
376-
}
377-
const href = try u.toString(arena);
364+
const username = if (maybe_username) |username| username else "";
365+
try u.set_username(username);
378366

379-
try parser.anchorSetHref(self, href);
367+
const href = try u._toString(page);
368+
return parser.anchorSetHref(self, href);
380369
}
381370

382-
// TODO return a disposable string
383371
pub fn get_password(self: *parser.Anchor, page: *Page) ![]const u8 {
384-
var u = try url(self, page);
385-
return try page.arena.dupe(u8, u.get_password());
372+
var u = url(self, page) catch return "";
373+
defer u.destructor();
374+
375+
return page.call_arena.dupe(u8, u.get_password());
386376
}
387377

388-
pub fn set_password(self: *parser.Anchor, v: ?[]const u8, page: *Page) !void {
389-
const arena = page.arena;
378+
pub fn set_password(self: *parser.Anchor, maybe_password: ?[]const u8, page: *Page) !void {
390379
var u = try url(self, page);
380+
defer u.destructor();
391381

392-
if (v) |vv| {
393-
u.uri.password = .{ .raw = vv };
394-
} else {
395-
u.uri.password = null;
396-
}
397-
const href = try u.toString(arena);
382+
const password = if (maybe_password) |password| password else "";
383+
try u.set_password(password);
398384

399-
try parser.anchorSetHref(self, href);
385+
const href = try u._toString(page);
386+
return parser.anchorSetHref(self, href);
400387
}
401388

402-
// TODO return a disposable string
403389
pub fn get_pathname(self: *parser.Anchor, page: *Page) ![]const u8 {
404-
var u = try url(self, page);
405-
return u.get_pathname();
390+
var u = url(self, page) catch return "";
391+
defer u.destructor();
392+
393+
return page.call_arena.dupe(u8, u.get_pathname());
406394
}
407395

408-
pub fn set_pathname(self: *parser.Anchor, v: []const u8, page: *Page) !void {
409-
const arena = page.arena;
396+
pub fn set_pathname(self: *parser.Anchor, pathname: []const u8, page: *Page) !void {
410397
var u = try url(self, page);
411-
u.uri.path = .{ .raw = v };
412-
const href = try u.toString(arena);
398+
defer u.destructor();
399+
400+
try u.set_pathname(pathname);
413401

414-
try parser.anchorSetHref(self, href);
402+
const href = try u._toString(page);
403+
return parser.anchorSetHref(self, href);
415404
}
416405

417406
pub fn get_search(self: *parser.Anchor, page: *Page) ![]const u8 {
418-
var u = try url(self, page);
419-
return try u.get_search(page);
407+
var u = url(self, page) catch return "";
408+
defer u.destructor();
409+
// This allocates in page arena so no need to dupe.
410+
return u.get_search(page);
420411
}
421412

422413
pub fn set_search(self: *parser.Anchor, v: ?[]const u8, page: *Page) !void {
423414
var u = try url(self, page);
415+
defer u.destructor();
424416
try u.set_search(v, page);
425417

426-
const href = try u.toString(page.call_arena);
427-
try parser.anchorSetHref(self, href);
418+
const href = try u._toString(page);
419+
return parser.anchorSetHref(self, href);
428420
}
429421

430-
// TODO return a disposable string
431422
pub fn get_hash(self: *parser.Anchor, page: *Page) ![]const u8 {
432-
var u = try url(self, page);
433-
return try u.get_hash(page);
423+
var u = url(self, page) catch return "";
424+
defer u.destructor();
425+
426+
return page.call_arena.dupe(u8, u.get_hash());
434427
}
435428

436-
pub fn set_hash(self: *parser.Anchor, v: ?[]const u8, page: *Page) !void {
437-
const arena = page.arena;
429+
pub fn set_hash(self: *parser.Anchor, maybe_hash: ?[]const u8, page: *Page) !void {
438430
var u = try url(self, page);
431+
defer u.destructor();
439432

440-
if (v) |vv| {
441-
u.uri.fragment = .{ .raw = vv };
433+
if (maybe_hash) |hash| {
434+
try u.set_hash(hash);
442435
} else {
443-
u.uri.fragment = null;
436+
u.clearHash();
444437
}
445-
const href = try u.toString(arena);
446438

447-
try parser.anchorSetHref(self, href);
439+
const href = try u._toString(page);
440+
return parser.anchorSetHref(self, href);
448441
}
449442
};
450443

0 commit comments

Comments
 (0)