Skip to content

Commit cf7ee48

Browse files
Unique-Usmangitster
authored andcommitted
agent: advertise OS name via agent capability
As some issues that can happen with a Git client can be operating system specific, it can be useful for a server to know which OS a client is using. In the same way it can be useful for a client to know which OS a server is using. Our current agent capability is in the form of "package/version" (e.g., "git/1.8.3.1"). Let's extend it to include the operating system name (os) i.e in the form "package/version-os" (e.g., "git/1.8.3.1-Linux"). Including OS details in the agent capability simplifies implementation, maintains backward compatibility, avoids introducing a new capability, encourages adoption across Git-compatible software, and enhances debugging by providing complete environment information without affecting functionality. The operating system name is retrieved using the 'sysname' field of the `uname(2)` system call or its equivalent. However, there are differences between `uname(1)` (command-line utility) and `uname(2)` (system call) outputs on Windows. These discrepancies complicate testing on Windows platforms. For example: - `uname(1)` output: MINGW64_NT-10.0-20348.3.4.10-87d57229.x86_64\ .2024-02-14.20:17.UTC.x86_64 - `uname(2)` output: Windows.10.0.20348 On Windows, uname(2) is not actually system-supplied but is instead already faked up by Git itself. We could have overcome the test issue on Windows by implementing a new `uname` subcommand in `test-tool` using uname(2), but except uname(2), which would be tested against itself, there would be nothing platform specific, so it's just simpler to disable the tests on Windows. Mentored-by: Christian Couder <[email protected]> Signed-off-by: Usman Akinyemi <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 15ff206 commit cf7ee48

File tree

6 files changed

+62
-6
lines changed

6 files changed

+62
-6
lines changed

Documentation/gitprotocol-v2.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,13 @@ form `agent=X`) to notify the client that the server is running version
184184
the `agent` capability with a value `Y` (in the form `agent=Y`) in its
185185
request to the server (but it MUST NOT do so if the server did not
186186
advertise the agent capability). The `X` and `Y` strings may contain any
187-
printable ASCII characters except space (i.e., the byte range 32 < x <
188-
127), and are typically of the form "package/version" (e.g.,
189-
"git/1.8.3.1"). The agent strings are purely informative for statistics
187+
printable ASCII characters except space (i.e., the byte range 33 <= x <=
188+
126), and are typically of the form "package/version-os" (e.g.,
189+
"git/1.8.3.1-Linux") where `os` is the operating system name (e.g.,
190+
"Linux"). `X` and `Y` can be configured using the GIT_USER_AGENT
191+
environment variable and it takes priority. The `os` is
192+
retrieved using the 'sysname' field of the `uname(2)` system call
193+
or its equivalent. The agent strings are purely informative for statistics
190194
and debugging purposes, and MUST NOT be used to programmatically assume
191195
the presence or absence of particular features.
192196

connect.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ const char *parse_feature_value(const char *feature_list, const char *feature, s
625625
*offset = found + len - orig_start;
626626
return value;
627627
}
628-
/* feature with a value (e.g., "agent=git/1.2.3") */
628+
/* feature with a value (e.g., "agent=git/1.2.3-Linux") */
629629
else if (*value == '=') {
630630
size_t end;
631631

t/t5701-git-serve.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
88
. ./test-lib.sh
99

1010
test_expect_success 'setup to generate files with expected content' '
11-
printf "agent=git/%s\n" "$(git version | cut -d" " -f3)" >agent_capability &&
11+
printf "agent=git/%s" "$(git version | cut -d" " -f3)" >agent_capability &&
1212
1313
test_oid_cache <<-EOF &&
1414
wrong_algo sha1:sha256
1515
wrong_algo sha256:sha1
1616
EOF
1717
18+
if test_have_prereq WINDOWS
19+
then
20+
printf "agent=FAKE\n" >agent_capability
21+
else
22+
printf -- "-%s\n" $(uname -s | test_redact_non_printables) >>agent_capability
23+
fi &&
1824
cat >expect.base <<-EOF &&
1925
version 2
2026
$(cat agent_capability)
@@ -31,6 +37,10 @@ test_expect_success 'setup to generate files with expected content' '
3137
test_expect_success 'test capability advertisement' '
3238
cat expect.base expect.trailer >expect &&
3339
40+
if test_have_prereq WINDOWS
41+
then
42+
GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
43+
fi &&
3444
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
3545
--advertise-capabilities >out &&
3646
test-tool pkt-line unpack <out >actual &&
@@ -361,6 +371,10 @@ test_expect_success 'test capability advertisement with uploadpack.advertiseBund
361371
expect.extra \
362372
expect.trailer >expect &&
363373
374+
if test_have_prereq WINDOWS
375+
then
376+
GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
377+
fi &&
364378
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
365379
--advertise-capabilities >out &&
366380
test-tool pkt-line unpack <out >actual &&

t/test-lib-functions.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,3 +2007,11 @@ test_trailing_hash () {
20072007
test-tool hexdump |
20082008
sed "s/ //g"
20092009
}
2010+
2011+
# Trim and replace each character with ascii code below 32 or above
2012+
# 127 (included) using a dot '.' character.
2013+
# Octal intervals \001-\040 and \177-\377
2014+
# correspond to decimal intervals 1-32 and 127-255
2015+
test_redact_non_printables () {
2016+
tr -d "\n\r" | tr "[\001-\040][\177-\377]" "."
2017+
}

version.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
#define USE_THE_REPOSITORY_VARIABLE
2+
13
#include "git-compat-util.h"
24
#include "version.h"
35
#include "version-def.h"
46
#include "strbuf.h"
5-
#include "sane-ctype.h"
67
#include "gettext.h"
78

89
const char git_version_string[] = GIT_VERSION;
@@ -34,6 +35,27 @@ const char *git_user_agent(void)
3435
return agent;
3536
}
3637

38+
/*
39+
Retrieve, sanitize and cache operating system info for subsequent
40+
calls. Return a pointer to the sanitized operating system info
41+
string.
42+
*/
43+
static const char *os_info(void)
44+
{
45+
static const char *os = NULL;
46+
47+
if (!os) {
48+
struct strbuf buf = STRBUF_INIT;
49+
50+
get_uname_info(&buf, 0);
51+
/* Sanitize the os information immediately */
52+
redact_non_printables(&buf);
53+
os = strbuf_detach(&buf, NULL);
54+
}
55+
56+
return os;
57+
}
58+
3759
const char *git_user_agent_sanitized(void)
3860
{
3961
static const char *agent = NULL;
@@ -42,6 +64,11 @@ const char *git_user_agent_sanitized(void)
4264
struct strbuf buf = STRBUF_INIT;
4365

4466
strbuf_addstr(&buf, git_user_agent());
67+
68+
if (!getenv("GIT_USER_AGENT")) {
69+
strbuf_addch(&buf, '-');
70+
strbuf_addstr(&buf, os_info());
71+
}
4572
redact_non_printables(&buf);
4673
agent = strbuf_detach(&buf, NULL);
4774
}

version.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef VERSION_H
22
#define VERSION_H
33

4+
struct repository;
5+
46
extern const char git_version_string[];
57
extern const char git_built_from_commit_string[];
68

@@ -14,4 +16,5 @@ const char *git_user_agent_sanitized(void);
1416
*/
1517
int get_uname_info(struct strbuf *buf, unsigned int full);
1618

19+
1720
#endif /* VERSION_H */

0 commit comments

Comments
 (0)