Merge pull request #6788 from libgit2/ethomson/user_agent

Allow more control over the user-agent
This commit is contained in:
Edward Thomson
2024-04-18 21:02:59 +01:00
committed by GitHub
10 changed files with 603 additions and 448 deletions

View File

@@ -228,7 +228,9 @@ typedef enum {
GIT_OPT_SET_SERVER_CONNECT_TIMEOUT,
GIT_OPT_GET_SERVER_CONNECT_TIMEOUT,
GIT_OPT_SET_SERVER_TIMEOUT,
GIT_OPT_GET_SERVER_TIMEOUT
GIT_OPT_GET_SERVER_TIMEOUT,
GIT_OPT_SET_USER_AGENT_PRODUCT,
GIT_OPT_GET_USER_AGENT_PRODUCT
} git_libgit2_opt_t;
/**
@@ -337,11 +339,35 @@ typedef enum {
*
* * opts(GIT_OPT_SET_USER_AGENT, const char *user_agent)
*
* > Set the value of the User-Agent header. This value will be
* > appended to "git/1.0", for compatibility with other git clients.
* > Set the value of the comment section of the User-Agent header.
* > This can be information about your product and its version.
* > By default this is "libgit2" followed by the libgit2 version.
* >
* > - `user_agent` is the value that will be delivered as the
* > User-Agent header on HTTP requests.
* > This value will be appended to User-Agent _product_, which
* > is typically set to "git/2.0".
* >
* > Set to the empty string ("") to not send any information in the
* > comment section, or set to NULL to restore the default.
*
* * opts(GIT_OPT_GET_USER_AGENT, git_buf *out)
*
* > Get the value of the User-Agent header.
* > The User-Agent is written to the `out` buffer.
*
* * opts(GIT_OPT_SET_USER_AGENT_PRODUCT, const char *user_agent_product)
*
* > Set the value of the product portion of the User-Agent header.
* > This defaults to "git/2.0", for compatibility with other git
* > clients. It is recommended to keep this as git/<version> for
* > compatibility with servers that do user-agent detection.
* >
* > Set to the empty string ("") to not send any user-agent string,
* > or set to NULL to restore the default.
*
* * opts(GIT_OPT_GET_USER_AGENT_PRODUCT, git_buf *out)
*
* > Get the value of the User-Agent product header.
* > The User-Agent product is written to the `out` buffer.
*
* * opts(GIT_OPT_SET_WINDOWS_SHAREMODE, unsigned long value)
*
@@ -377,11 +403,6 @@ typedef enum {
* >
* > - `ciphers` is the list of ciphers that are eanbled.
*
* * opts(GIT_OPT_GET_USER_AGENT, git_buf *out)
*
* > Get the value of the User-Agent header.
* > The User-Agent is written to the `out` buffer.
*
* * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled)
*
* > Enable or disable the use of "offset deltas" when creating packfiles,

View File

@@ -5,25 +5,19 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "libgit2.h"
#include <git2.h>
#include "alloc.h"
#include "buf.h"
#include "cache.h"
#include "common.h"
#include "filter.h"
#include "grafts.h"
#include "hash.h"
#include "index.h"
#include "merge_driver.h"
#include "pool.h"
#include "mwindow.h"
#include "object.h"
#include "odb.h"
#include "oid.h"
#include "rand.h"
#include "refs.h"
#include "runtime.h"
#include "settings.h"
#include "sysdir.h"
#include "thread.h"
#include "git2/global.h"
@@ -31,40 +25,12 @@
#include "streams/mbedtls.h"
#include "streams/openssl.h"
#include "streams/socket.h"
#include "transports/smart.h"
#include "transports/http.h"
#include "transports/ssh_libssh2.h"
#ifdef GIT_WIN32
# include "win32/w32_leakcheck.h"
#endif
/* Declarations for tuneable settings */
extern size_t git_mwindow__window_size;
extern size_t git_mwindow__mapped_limit;
extern size_t git_mwindow__file_limit;
extern size_t git_indexer__max_objects;
extern bool git_disable_pack_keep_file_checks;
extern int git_odb__packed_priority;
extern int git_odb__loose_priority;
extern int git_socket_stream__connect_timeout;
extern int git_socket_stream__timeout;
char *git__user_agent;
char *git__ssl_ciphers;
static void libgit2_settings_global_shutdown(void)
{
git__free(git__user_agent);
git__free(git__ssl_ciphers);
git_repository__free_extensions();
}
static int git_libgit2_settings_global_init(void)
{
return git_runtime_shutdown_register(libgit2_settings_global_shutdown);
}
int git_libgit2_init(void)
{
static git_runtime_init_fn init_fns[] = {
@@ -87,17 +53,12 @@ int git_libgit2_init(void)
git_mbedtls_stream_global_init,
git_mwindow_global_init,
git_pool_global_init,
git_libgit2_settings_global_init
git_settings_global_init
};
return git_runtime_init(init_fns, ARRAY_SIZE(init_fns));
}
int git_libgit2_init_count(void)
{
return git_runtime_init_count();
}
int git_libgit2_shutdown(void)
{
return git_runtime_shutdown();
@@ -134,350 +95,3 @@ int git_libgit2_features(void)
#endif
;
}
static int config_level_to_sysdir(int *out, int config_level)
{
switch (config_level) {
case GIT_CONFIG_LEVEL_SYSTEM:
*out = GIT_SYSDIR_SYSTEM;
return 0;
case GIT_CONFIG_LEVEL_XDG:
*out = GIT_SYSDIR_XDG;
return 0;
case GIT_CONFIG_LEVEL_GLOBAL:
*out = GIT_SYSDIR_GLOBAL;
return 0;
case GIT_CONFIG_LEVEL_PROGRAMDATA:
*out = GIT_SYSDIR_PROGRAMDATA;
return 0;
default:
break;
}
git_error_set(
GIT_ERROR_INVALID, "invalid config path selector %d", config_level);
return -1;
}
const char *git_libgit2__user_agent(void)
{
return git__user_agent;
}
const char *git_libgit2__ssl_ciphers(void)
{
return git__ssl_ciphers;
}
int git_libgit2_opts(int key, ...)
{
int error = 0;
va_list ap;
va_start(ap, key);
switch (key) {
case GIT_OPT_SET_MWINDOW_SIZE:
git_mwindow__window_size = va_arg(ap, size_t);
break;
case GIT_OPT_GET_MWINDOW_SIZE:
*(va_arg(ap, size_t *)) = git_mwindow__window_size;
break;
case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
git_mwindow__mapped_limit = va_arg(ap, size_t);
break;
case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
*(va_arg(ap, size_t *)) = git_mwindow__mapped_limit;
break;
case GIT_OPT_SET_MWINDOW_FILE_LIMIT:
git_mwindow__file_limit = va_arg(ap, size_t);
break;
case GIT_OPT_GET_MWINDOW_FILE_LIMIT:
*(va_arg(ap, size_t *)) = git_mwindow__file_limit;
break;
case GIT_OPT_GET_SEARCH_PATH:
{
int sysdir = va_arg(ap, int);
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
const git_str *tmp;
int level;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = config_level_to_sysdir(&level, sysdir)) < 0 ||
(error = git_sysdir_get(&tmp, level)) < 0 ||
(error = git_str_put(&str, tmp->ptr, tmp->size)) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_SET_SEARCH_PATH:
{
int level;
if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0)
error = git_sysdir_set(level, va_arg(ap, const char *));
}
break;
case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
{
git_object_t type = (git_object_t)va_arg(ap, int);
size_t size = va_arg(ap, size_t);
error = git_cache_set_max_object_size(type, size);
break;
}
case GIT_OPT_SET_CACHE_MAX_SIZE:
git_cache__max_storage = va_arg(ap, ssize_t);
break;
case GIT_OPT_ENABLE_CACHING:
git_cache__enabled = (va_arg(ap, int) != 0);
break;
case GIT_OPT_GET_CACHED_MEMORY:
*(va_arg(ap, ssize_t *)) = git_cache__current_storage.val;
*(va_arg(ap, ssize_t *)) = git_cache__max_storage;
break;
case GIT_OPT_GET_TEMPLATE_PATH:
{
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
const git_str *tmp;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0 ||
(error = git_str_put(&str, tmp->ptr, tmp->size)) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_SET_TEMPLATE_PATH:
error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *));
break;
case GIT_OPT_SET_SSL_CERT_LOCATIONS:
#ifdef GIT_OPENSSL
{
const char *file = va_arg(ap, const char *);
const char *path = va_arg(ap, const char *);
error = git_openssl__set_cert_location(file, path);
}
#elif defined(GIT_MBEDTLS)
{
const char *file = va_arg(ap, const char *);
const char *path = va_arg(ap, const char *);
error = git_mbedtls__set_cert_location(file, path);
}
#else
git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations");
error = -1;
#endif
break;
case GIT_OPT_SET_USER_AGENT:
git__free(git__user_agent);
git__user_agent = git__strdup(va_arg(ap, const char *));
if (!git__user_agent) {
git_error_set_oom();
error = -1;
}
break;
case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION:
git_object__strict_input_validation = (va_arg(ap, int) != 0);
break;
case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_SSL_CIPHERS:
#if (GIT_OPENSSL || GIT_MBEDTLS)
{
git__free(git__ssl_ciphers);
git__ssl_ciphers = git__strdup(va_arg(ap, const char *));
if (!git__ssl_ciphers) {
git_error_set_oom();
error = -1;
}
}
#else
git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers");
error = -1;
#endif
break;
case GIT_OPT_GET_USER_AGENT:
{
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = git_str_puts(&str, git__user_agent)) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_ENABLE_OFS_DELTA:
git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0);
break;
case GIT_OPT_ENABLE_FSYNC_GITDIR:
git_repository__fsync_gitdir = (va_arg(ap, int) != 0);
break;
case GIT_OPT_GET_WINDOWS_SHAREMODE:
#ifdef GIT_WIN32
*(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
#endif
break;
case GIT_OPT_SET_WINDOWS_SHAREMODE:
#ifdef GIT_WIN32
git_win32__createfile_sharemode = va_arg(ap, unsigned long);
#endif
break;
case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_ALLOCATOR:
error = git_allocator_setup(va_arg(ap, git_allocator *));
break;
case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY:
git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_PACK_MAX_OBJECTS:
git_indexer__max_objects = va_arg(ap, size_t);
break;
case GIT_OPT_GET_PACK_MAX_OBJECTS:
*(va_arg(ap, size_t *)) = git_indexer__max_objects;
break;
case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS:
git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0);
break;
case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE:
git_http__expect_continue = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_ODB_PACKED_PRIORITY:
git_odb__packed_priority = va_arg(ap, int);
break;
case GIT_OPT_SET_ODB_LOOSE_PRIORITY:
git_odb__loose_priority = va_arg(ap, int);
break;
case GIT_OPT_SET_EXTENSIONS:
{
const char **extensions = va_arg(ap, const char **);
size_t len = va_arg(ap, size_t);
error = git_repository__set_extensions(extensions, len);
}
break;
case GIT_OPT_GET_EXTENSIONS:
{
git_strarray *out = va_arg(ap, git_strarray *);
char **extensions;
size_t len;
if ((error = git_repository__extensions(&extensions, &len)) < 0)
break;
out->strings = extensions;
out->count = len;
}
break;
case GIT_OPT_GET_OWNER_VALIDATION:
*(va_arg(ap, int *)) = git_repository__validate_ownership;
break;
case GIT_OPT_SET_OWNER_VALIDATION:
git_repository__validate_ownership = (va_arg(ap, int) != 0);
break;
case GIT_OPT_GET_HOMEDIR:
{
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
const git_str *tmp;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = git_sysdir_get(&tmp, GIT_SYSDIR_HOME)) < 0 ||
(error = git_str_put(&str, tmp->ptr, tmp->size)) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_SET_HOMEDIR:
error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *));
break;
case GIT_OPT_GET_SERVER_CONNECT_TIMEOUT:
*(va_arg(ap, int *)) = git_socket_stream__connect_timeout;
break;
case GIT_OPT_SET_SERVER_CONNECT_TIMEOUT:
{
int timeout = va_arg(ap, int);
if (timeout < 0) {
git_error_set(GIT_ERROR_INVALID, "invalid connect timeout");
error = -1;
} else {
git_socket_stream__connect_timeout = timeout;
}
}
break;
case GIT_OPT_GET_SERVER_TIMEOUT:
*(va_arg(ap, int *)) = git_socket_stream__timeout;
break;
case GIT_OPT_SET_SERVER_TIMEOUT:
{
int timeout = va_arg(ap, int);
if (timeout < 0) {
git_error_set(GIT_ERROR_INVALID, "invalid timeout");
error = -1;
} else {
git_socket_stream__timeout = timeout;
}
}
break;
default:
git_error_set(GIT_ERROR_INVALID, "invalid option key");
error = -1;
}
va_end(ap);
return error;
}

View File

@@ -1,15 +0,0 @@
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_libgit2_h__
#define INCLUDE_libgit2_h__
extern int git_libgit2_init_count(void);
extern const char *git_libgit2__user_agent(void);
extern const char *git_libgit2__ssl_ciphers(void);
#endif

456
src/libgit2/settings.c Normal file
View File

@@ -0,0 +1,456 @@
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "settings.h"
#include <git2.h>
#include "alloc.h"
#include "buf.h"
#include "cache.h"
#include "common.h"
#include "filter.h"
#include "grafts.h"
#include "hash.h"
#include "index.h"
#include "merge_driver.h"
#include "pool.h"
#include "mwindow.h"
#include "object.h"
#include "odb.h"
#include "rand.h"
#include "refs.h"
#include "runtime.h"
#include "sysdir.h"
#include "thread.h"
#include "git2/global.h"
#include "streams/registry.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
#include "streams/socket.h"
#include "transports/smart.h"
#include "transports/http.h"
#include "transports/ssh_libssh2.h"
#ifdef GIT_WIN32
# include "win32/w32_leakcheck.h"
#endif
/* Declarations for tuneable settings */
extern size_t git_mwindow__window_size;
extern size_t git_mwindow__mapped_limit;
extern size_t git_mwindow__file_limit;
extern size_t git_indexer__max_objects;
extern bool git_disable_pack_keep_file_checks;
extern int git_odb__packed_priority;
extern int git_odb__loose_priority;
extern int git_socket_stream__connect_timeout;
extern int git_socket_stream__timeout;
char *git__user_agent;
char *git__user_agent_product;
char *git__ssl_ciphers;
static void settings_global_shutdown(void)
{
git__free(git__user_agent);
git__free(git__user_agent_product);
git__free(git__ssl_ciphers);
git_repository__free_extensions();
}
int git_settings_global_init(void)
{
return git_runtime_shutdown_register(settings_global_shutdown);
}
static int config_level_to_sysdir(int *out, int config_level)
{
switch (config_level) {
case GIT_CONFIG_LEVEL_SYSTEM:
*out = GIT_SYSDIR_SYSTEM;
return 0;
case GIT_CONFIG_LEVEL_XDG:
*out = GIT_SYSDIR_XDG;
return 0;
case GIT_CONFIG_LEVEL_GLOBAL:
*out = GIT_SYSDIR_GLOBAL;
return 0;
case GIT_CONFIG_LEVEL_PROGRAMDATA:
*out = GIT_SYSDIR_PROGRAMDATA;
return 0;
default:
break;
}
git_error_set(
GIT_ERROR_INVALID, "invalid config path selector %d", config_level);
return -1;
}
const char *git_settings__user_agent_product(void)
{
return git__user_agent_product ? git__user_agent_product :
"git/2.0";
}
const char *git_settings__user_agent(void)
{
return git__user_agent ? git__user_agent :
"libgit2 " LIBGIT2_VERSION;
}
int git_libgit2_opts(int key, ...)
{
int error = 0;
va_list ap;
va_start(ap, key);
switch (key) {
case GIT_OPT_SET_MWINDOW_SIZE:
git_mwindow__window_size = va_arg(ap, size_t);
break;
case GIT_OPT_GET_MWINDOW_SIZE:
*(va_arg(ap, size_t *)) = git_mwindow__window_size;
break;
case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
git_mwindow__mapped_limit = va_arg(ap, size_t);
break;
case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
*(va_arg(ap, size_t *)) = git_mwindow__mapped_limit;
break;
case GIT_OPT_SET_MWINDOW_FILE_LIMIT:
git_mwindow__file_limit = va_arg(ap, size_t);
break;
case GIT_OPT_GET_MWINDOW_FILE_LIMIT:
*(va_arg(ap, size_t *)) = git_mwindow__file_limit;
break;
case GIT_OPT_GET_SEARCH_PATH:
{
int sysdir = va_arg(ap, int);
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
const git_str *tmp;
int level;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = config_level_to_sysdir(&level, sysdir)) < 0 ||
(error = git_sysdir_get(&tmp, level)) < 0 ||
(error = git_str_put(&str, tmp->ptr, tmp->size)) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_SET_SEARCH_PATH:
{
int level;
if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0)
error = git_sysdir_set(level, va_arg(ap, const char *));
}
break;
case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
{
git_object_t type = (git_object_t)va_arg(ap, int);
size_t size = va_arg(ap, size_t);
error = git_cache_set_max_object_size(type, size);
break;
}
case GIT_OPT_SET_CACHE_MAX_SIZE:
git_cache__max_storage = va_arg(ap, ssize_t);
break;
case GIT_OPT_ENABLE_CACHING:
git_cache__enabled = (va_arg(ap, int) != 0);
break;
case GIT_OPT_GET_CACHED_MEMORY:
*(va_arg(ap, ssize_t *)) = git_cache__current_storage.val;
*(va_arg(ap, ssize_t *)) = git_cache__max_storage;
break;
case GIT_OPT_GET_TEMPLATE_PATH:
{
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
const git_str *tmp;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0 ||
(error = git_str_put(&str, tmp->ptr, tmp->size)) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_SET_TEMPLATE_PATH:
error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *));
break;
case GIT_OPT_SET_SSL_CERT_LOCATIONS:
#ifdef GIT_OPENSSL
{
const char *file = va_arg(ap, const char *);
const char *path = va_arg(ap, const char *);
error = git_openssl__set_cert_location(file, path);
}
#elif defined(GIT_MBEDTLS)
{
const char *file = va_arg(ap, const char *);
const char *path = va_arg(ap, const char *);
error = git_mbedtls__set_cert_location(file, path);
}
#else
git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations");
error = -1;
#endif
break;
case GIT_OPT_SET_USER_AGENT:
{
const char *new_agent = va_arg(ap, const char *);
git__free(git__user_agent);
if (new_agent) {
git__user_agent= git__strdup(new_agent);
if (!git__user_agent)
error = -1;
} else {
git__user_agent = NULL;
}
}
break;
case GIT_OPT_GET_USER_AGENT:
{
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = git_str_puts(&str, git_settings__user_agent())) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_SET_USER_AGENT_PRODUCT:
{
const char *new_agent = va_arg(ap, const char *);
git__free(git__user_agent_product);
if (new_agent) {
git__user_agent_product = git__strdup(new_agent);
if (!git__user_agent_product)
error = -1;
} else {
git__user_agent_product = NULL;
}
}
break;
case GIT_OPT_GET_USER_AGENT_PRODUCT:
{
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = git_str_puts(&str, git_settings__user_agent_product())) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION:
git_object__strict_input_validation = (va_arg(ap, int) != 0);
break;
case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_SSL_CIPHERS:
#if (GIT_OPENSSL || GIT_MBEDTLS)
{
git__free(git__ssl_ciphers);
git__ssl_ciphers = git__strdup(va_arg(ap, const char *));
if (!git__ssl_ciphers) {
git_error_set_oom();
error = -1;
}
}
#else
git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers");
error = -1;
#endif
break;
case GIT_OPT_ENABLE_OFS_DELTA:
git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0);
break;
case GIT_OPT_ENABLE_FSYNC_GITDIR:
git_repository__fsync_gitdir = (va_arg(ap, int) != 0);
break;
case GIT_OPT_GET_WINDOWS_SHAREMODE:
#ifdef GIT_WIN32
*(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
#endif
break;
case GIT_OPT_SET_WINDOWS_SHAREMODE:
#ifdef GIT_WIN32
git_win32__createfile_sharemode = va_arg(ap, unsigned long);
#endif
break;
case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_ALLOCATOR:
error = git_allocator_setup(va_arg(ap, git_allocator *));
break;
case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY:
git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_PACK_MAX_OBJECTS:
git_indexer__max_objects = va_arg(ap, size_t);
break;
case GIT_OPT_GET_PACK_MAX_OBJECTS:
*(va_arg(ap, size_t *)) = git_indexer__max_objects;
break;
case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS:
git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0);
break;
case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE:
git_http__expect_continue = (va_arg(ap, int) != 0);
break;
case GIT_OPT_SET_ODB_PACKED_PRIORITY:
git_odb__packed_priority = va_arg(ap, int);
break;
case GIT_OPT_SET_ODB_LOOSE_PRIORITY:
git_odb__loose_priority = va_arg(ap, int);
break;
case GIT_OPT_SET_EXTENSIONS:
{
const char **extensions = va_arg(ap, const char **);
size_t len = va_arg(ap, size_t);
error = git_repository__set_extensions(extensions, len);
}
break;
case GIT_OPT_GET_EXTENSIONS:
{
git_strarray *out = va_arg(ap, git_strarray *);
char **extensions;
size_t len;
if ((error = git_repository__extensions(&extensions, &len)) < 0)
break;
out->strings = extensions;
out->count = len;
}
break;
case GIT_OPT_GET_OWNER_VALIDATION:
*(va_arg(ap, int *)) = git_repository__validate_ownership;
break;
case GIT_OPT_SET_OWNER_VALIDATION:
git_repository__validate_ownership = (va_arg(ap, int) != 0);
break;
case GIT_OPT_GET_HOMEDIR:
{
git_buf *out = va_arg(ap, git_buf *);
git_str str = GIT_STR_INIT;
const git_str *tmp;
if ((error = git_buf_tostr(&str, out)) < 0 ||
(error = git_sysdir_get(&tmp, GIT_SYSDIR_HOME)) < 0 ||
(error = git_str_put(&str, tmp->ptr, tmp->size)) < 0)
break;
error = git_buf_fromstr(out, &str);
}
break;
case GIT_OPT_SET_HOMEDIR:
error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *));
break;
case GIT_OPT_GET_SERVER_CONNECT_TIMEOUT:
*(va_arg(ap, int *)) = git_socket_stream__connect_timeout;
break;
case GIT_OPT_SET_SERVER_CONNECT_TIMEOUT:
{
int timeout = va_arg(ap, int);
if (timeout < 0) {
git_error_set(GIT_ERROR_INVALID, "invalid connect timeout");
error = -1;
} else {
git_socket_stream__connect_timeout = timeout;
}
}
break;
case GIT_OPT_GET_SERVER_TIMEOUT:
*(va_arg(ap, int *)) = git_socket_stream__timeout;
break;
case GIT_OPT_SET_SERVER_TIMEOUT:
{
int timeout = va_arg(ap, int);
if (timeout < 0) {
git_error_set(GIT_ERROR_INVALID, "invalid timeout");
error = -1;
} else {
git_socket_stream__timeout = timeout;
}
}
break;
default:
git_error_set(GIT_ERROR_INVALID, "invalid option key");
error = -1;
}
va_end(ap);
return error;
}

View File

@@ -4,8 +4,12 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_settings_h__
#define INCLUDE_settings_h__
extern int git_settings_global_init(void);
extern const char *git_libgit2__user_agent(void);
extern const char *git_libgit2__ssl_ciphers(void);
extern const char *git_settings__user_agent(void);
extern const char *git_settings__user_agent_product(void);
#endif

View File

@@ -36,6 +36,8 @@
# include <openssl/bio.h>
#endif
extern char *git__ssl_ciphers;
SSL_CTX *git__ssl_ctx;
#define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
@@ -105,7 +107,7 @@ static void git_openssl_free(void *mem)
static int openssl_init(void)
{
long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
const char *ciphers = git_libgit2__ssl_ciphers();
const char *ciphers = git__ssl_ciphers;
#ifdef VALGRIND
static bool allocators_initialized = false;
#endif

View File

@@ -15,14 +15,4 @@
extern bool git_http__expect_continue;
GIT_INLINE(int) git_http__user_agent(git_str *buf)
{
const char *ua = git_libgit2__user_agent();
if (!ua)
ua = "libgit2 " LIBGIT2_VERSION;
return git_str_printf(buf, "git/2.0 (%s)", ua);
}
#endif

View File

@@ -651,6 +651,30 @@ static int puts_host_and_port(git_str *buf, git_net_url *url, bool force_port)
return git_str_oom(buf) ? -1 : 0;
}
static int append_user_agent(git_str *buf)
{
const char *product = git_settings__user_agent_product();
const char *comment = git_settings__user_agent();
GIT_ASSERT(product && comment);
if (!*product)
return 0;
git_str_puts(buf, "User-Agent: ");
git_str_puts(buf, product);
if (*comment) {
git_str_puts(buf, " (");
git_str_puts(buf, comment);
git_str_puts(buf, ")");
}
git_str_puts(buf, "\r\n");
return git_str_oom(buf) ? -1 : 0;
}
static int generate_connect_request(
git_http_client *client,
git_http_request *request)
@@ -665,9 +689,7 @@ static int generate_connect_request(
puts_host_and_port(buf, &client->server.url, true);
git_str_puts(buf, " HTTP/1.1\r\n");
git_str_puts(buf, "User-Agent: ");
git_http__user_agent(buf);
git_str_puts(buf, "\r\n");
append_user_agent(buf);
git_str_puts(buf, "Host: ");
puts_host_and_port(buf, &client->server.url, true);
@@ -711,9 +733,7 @@ static int generate_request(
git_str_puts(buf, " HTTP/1.1\r\n");
git_str_puts(buf, "User-Agent: ");
git_http__user_agent(buf);
git_str_puts(buf, "\r\n");
append_user_agent(buf);
git_str_puts(buf, "Host: ");
puts_host_and_port(buf, request->url, false);

View File

@@ -746,6 +746,33 @@ static void CALLBACK winhttp_status(
}
}
static int user_agent(bool *exists, git_str *out)
{
const char *product = git_settings__user_agent_product();
const char *comment = git_settings__user_agent();
GIT_ASSERT(product && comment);
if (!*product) {
*exists = false;
return 0;
}
git_str_puts(out, product);
if (*comment) {
git_str_puts(out, " (");
git_str_puts(out, comment);
git_str_puts(out, ")");
}
if (git_str_oom(out))
return -1;
*exists = true;
return 0;
}
static int winhttp_connect(
winhttp_subtransport *t)
{
@@ -757,6 +784,7 @@ static int winhttp_connect(
int error = -1;
int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
bool has_ua = true;
DWORD protocols =
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
@@ -787,11 +815,11 @@ static int winhttp_connect(
goto on_error;
}
if (git_http__user_agent(&ua) < 0)
if (user_agent(&has_ua, &ua) < 0)
goto on_error;
if (git_utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) {
if (has_ua &&
git_utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) {
git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
goto on_error;
}

View File

@@ -1,17 +1,52 @@
#include "clar_libgit2.h"
#include "settings.h"
void test_core_useragent__get(void)
static git_buf default_ua = GIT_BUF_INIT;
static git_buf default_product = GIT_BUF_INIT;
void test_core_useragent__initialize(void)
{
const char *custom_name = "super duper git";
git_str buf = GIT_STR_INIT;
cl_assert_equal_p(NULL, git_libgit2__user_agent());
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, custom_name));
cl_assert_equal_s(custom_name, git_libgit2__user_agent());
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_USER_AGENT, &buf));
cl_assert_equal_s(custom_name, buf.ptr);
git_str_dispose(&buf);
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_USER_AGENT, &default_ua));
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_USER_AGENT_PRODUCT, &default_product));
}
void test_core_useragent__cleanup(void)
{
git_libgit2_opts(GIT_OPT_SET_USER_AGENT, NULL);
git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, NULL);
git_buf_dispose(&default_ua);
git_buf_dispose(&default_product);
}
void test_core_useragent__get_default(void)
{
cl_assert(default_ua.size);
cl_assert(default_ua.ptr);
cl_assert(git__prefixcmp(default_ua.ptr, "libgit2 ") == 0);
cl_assert(default_product.size);
cl_assert(default_product.ptr);
cl_assert(git__prefixcmp(default_product.ptr, "git/") == 0);
}
void test_core_useragent__set(void)
{
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, "foo bar 4.24"));
cl_assert_equal_s("foo bar 4.24", git_settings__user_agent());
cl_assert_equal_s(default_product.ptr, git_settings__user_agent_product());
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, "baz/2.2.3"));
cl_assert_equal_s("foo bar 4.24", git_settings__user_agent());
cl_assert_equal_s("baz/2.2.3", git_settings__user_agent_product());
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, ""));
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, ""));
cl_assert_equal_s("", git_settings__user_agent());
cl_assert_equal_s("", git_settings__user_agent_product());
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT, NULL));
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_USER_AGENT_PRODUCT, NULL));
cl_assert_equal_s(default_ua.ptr, git_settings__user_agent());
cl_assert_equal_s(default_product.ptr, git_settings__user_agent_product());
}