@@ -108,6 +108,14 @@ fn run(alloc: Allocator) !void {
108108 log .opts .filter_scopes = lfs ;
109109 }
110110
111+ const user_agent = blk : {
112+ const USER_AGENT = "User-Agent: Lightpanda/1.0" ;
113+ if (args .userAgentSuffix ()) | suffix | {
114+ break :blk try std .fmt .allocPrintSentinel (args_arena .allocator (), "{s} {s}" , .{ USER_AGENT , suffix }, 0 );
115+ }
116+ break :blk USER_AGENT ;
117+ };
118+
111119 // _app is global to handle graceful shutdown.
112120 _app = try App .init (alloc , .{
113121 .run_mode = args .mode ,
@@ -118,6 +126,7 @@ fn run(alloc: Allocator) !void {
118126 .http_connect_timeout_ms = args .httpConnectTiemout (),
119127 .http_max_host_open = args .httpMaxHostOpen (),
120128 .http_max_concurrent = args .httpMaxConcurrent (),
129+ .user_agent = user_agent ,
121130 });
122131
123132 const app = _app .? ;
@@ -260,6 +269,13 @@ const Command = struct {
260269 };
261270 }
262271
272+ fn userAgentSuffix (self : * const Command ) ? []const u8 {
273+ return switch (self .mode ) {
274+ inline .serve , .fetch = > | opts | opts .common .user_agent_suffix ,
275+ else = > unreachable ,
276+ };
277+ }
278+
263279 const Mode = union (App .RunMode ) {
264280 help : bool , // false when being printed because of an error
265281 fetch : Fetch ,
@@ -293,6 +309,7 @@ const Command = struct {
293309 log_level : ? log.Level = null ,
294310 log_format : ? log.Format = null ,
295311 log_filter_scopes : ? []log.Scope = null ,
312+ user_agent_suffix : ? []const u8 = null ,
296313 };
297314
298315 fn printUsageAndExit (self : * const Command , success : bool ) void {
@@ -339,6 +356,9 @@ const Command = struct {
339356 \\ Defaults to
340357 ++ (if (builtin .mode == .Debug ) " pretty." else " logfmt." ) ++
341358 \\
359+ \\ --user_agent_suffix
360+ \\ Suffix to append to the Lightpanda/X.Y User-Agent
361+ \\
342362 ;
343363
344364 // MAX_HELP_LEN|
@@ -713,6 +733,21 @@ fn parseCommonArg(
713733 return true ;
714734 }
715735
736+ if (std .mem .eql (u8 , "--user_agent_suffix" , opt )) {
737+ const str = args .next () orelse {
738+ log .fatal (.app , "missing argument value" , .{ .arg = "--user_agent_suffix" });
739+ return error .InvalidArgument ;
740+ };
741+ for (str ) | c | {
742+ if (! std .ascii .isPrint (c )) {
743+ log .fatal (.app , "not printable character" , .{ .arg = "--user_agent_suffix" });
744+ return error .InvalidArgument ;
745+ }
746+ }
747+ common .user_agent_suffix = try allocator .dupe (u8 , str );
748+ return true ;
749+ }
750+
716751 return false ;
717752}
718753
0 commit comments