{"thread":{"id":"34344","subject":"[PATCH] config: add support for http.<url>.* settings","startedAt":"2013-07-04T14:19:36Z","lastAt":"2013-07-04T14:19:36Z","messageCount":1,"participants":["Kyle McKay"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"222561","messageId":"279E20D1-6E36-42A0-A733-72C97C15D860@gmail.com","threadId":"34344","inReplyTo":null,"subject":"[PATCH] config: add support for http.<url>.* settings","fromName":"Kyle McKay","fromEmail":"mackyle@gmail.com","sentAt":"2013-07-04T14:19:36Z","receivedAt":"2013-07-04T14:19:36Z","isPatch":true,"sender":{"key":"mackyle@gmail.com","avatar":"https://avatars.githubusercontent.com/u/813346?v=4"},"body":"The <url> value is considered a match to a url if the <url>\nvalue is a prefix of the url which ends on a path component\nboundary ('/').  So \"https://example.com/test\" will match\n\"https://example.com/test\" and \"https://example.com/test/too\"\nbut not \"https://example.com/testextra\".\n\nLonger matches take precedence over shorter matches with\nenvironment variable settings taking precedence over all.\n\nWith this configuration:\n\n[http]\n        useragent = other-agent\n        noEPSV = true\n[http \"https://example.com\"]\n        useragent = example-agent\n        sslVerify = false\n[http \"https://example.com/path\"]\n        useragent = path-agent\n\nThe \"https://other.example.com/\" url will have useragent\n\"other-agent\" and sslVerify will be on.\n\nThe \"https://example.com/\" url will have useragent\n\"example-agent\" and sslVerify will be off.\n\nThe \"https://example.com/path/sub\" url will have useragent\n\"path-agent\" and sslVerify will be off.\n\nAll three of examples will have noEPSV enabled.\n\nSigned-off-by: Kyle J. McKay <mackyle@gmail.com>\n---\n\nThe credentials configuration values already support url-specific\nconfiguration items in the form credential.<url>.*.  This patch\nadds similar support for http configuration values.\n\nDocumentation/config.txt |   8 +++\nhttp.c                   | 125 +++++++++++++++++++++++++++++++++++++++ \n+-------\n2 files changed, 116 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex b4d4887..27d19a1 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1531,6 +1531,14 @@ http.useragent::\n\tof common USER_AGENT strings (but not including those like git/1.7.1).\n\tCan be overridden by the 'GIT_HTTP_USER_AGENT' environment variable.\n\n+http.<url>.*::\n+\tAny of the http.* options above can be applied selectively to some  \nurls.\n+\tFor example \"http.https://example.com.useragent\" would set the user\n+\tagent only for https connections to example.com.  The <url> value\n+\tmatches a url if it is a prefix of the url matching at a '/' boundary.\n+\tLonger <url> matches take precedence over shorter ones with the\n+\tenvironment variable settings taking precedence over all.\n+\ni18n.commitEncoding::\n\tCharacter encoding the commit messages are stored in; Git itself\n\tdoes not care per se, but this information is necessary e.g. when\ndiff --git a/http.c b/http.c\nindex 2d086ae..7ddf9af 100644\n--- a/http.c\n+++ b/http.c\n@@ -30,6 +30,34 @@ static CURL *curl_default;\n\nchar curl_errorstr[CURL_ERROR_SIZE];\n\n+enum http_option_type {\n+\to_post_buffer = 0,\n+\to_min_sessions,\n+#ifdef USE_CURL_MULTI\n+\to_max_requests,\n+#endif\n+\to_ssl_verify,\n+\to_ssl_try,\n+\to_ssl_cert,\n+#if LIBCURL_VERSION_NUM >= 0x070903\n+\to_ssl_key,\n+#endif\n+#if LIBCURL_VERSION_NUM >= 0x070908\n+\to_ssl_capath,\n+#endif\n+\to_ssl_cainfo,\n+\to_low_speed,\n+\to_low_time,\n+\to_no_epsv,\n+\to_http_proxy,\n+\to_cookie_file,\n+\to_user_agent,\n+\to_passwd_req,\n+\to_max\n+};\n+\n+static int http_option_maxlen[o_max];\n+\nstatic int curl_ssl_verify = -1;\nstatic int curl_ssl_try;\nstatic const char *ssl_cert;\n@@ -65,6 +93,23 @@ static struct curl_slist *no_pragma_header;\n\nstatic struct active_request_slot *active_queue_head;\n\n+static int http_options_url_match(const char *url, const char  \n*config_url)\n+{\n+\t/*\n+\t * config option with config_url matches url if config_url is a\n+\t * prefix of url and the match ends on a path component boundary.\n+\t * the return value is the length of the match in characters or\n+\t * 0 for no match.\n+\t */\n+\tsize_t url_len, config_url_len = strlen(config_url);\n+\tif (!config_url || strncmp(url, config_url, config_url_len))\n+\t\treturn 0;\n+\turl_len = strlen(url);\n+\tif (url_len == config_url_len || url[config_url_len - 1] == '/' ||  \nurl[config_url_len] == '/')\n+\t\treturn url[config_url_len - 1] == '/' ? config_url_len - 1 :  \nconfig_url_len;\n+\treturn 0;\n+}\n+\nsize_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void  \n*buffer_)\n{\n\tsize_t size = eltsize * nmemb;\n@@ -143,32 +188,65 @@ static void process_curl_messages(void)\n\nstatic int http_options(const char *var, const char *value, void *cb)\n{\n-\tif (!strcmp(\"http.sslverify\", var)) {\n+#define CHECKLEN(opt) if (http_option_maxlen[opt] > matchlen) return  \n0; \\\n+\t\t      else http_option_maxlen[opt] = matchlen\n+\n+\tconst char *url = (const char *)cb;\n+\tconst char *key, *dot;\n+\tint matchlen = 0;\n+\n+\tkey = skip_prefix(var, \"http.\");\n+\tif (!key)\n+\t\treturn git_default_config(var, value, cb);\n+\n+\tdot = strrchr(key, '.');\n+\tif (dot) {\n+\t\tchar *config_url = xmemdupz(key, dot - key);\n+\t\tmatchlen = http_options_url_match(url, config_url);\n+\t\tfree(config_url);\n+\t\tif (!matchlen)\n+\t\t\treturn git_default_config(var, value, cb);\n+\t\tkey = dot + 1;\n+\t}\n+\n+\tif (!strcmp(\"sslverify\", key)) {\n+\t\tCHECKLEN(o_ssl_verify);\n\t\tcurl_ssl_verify = git_config_bool(var, value);\n\t\treturn 0;\n\t}\n-\tif (!strcmp(\"http.sslcert\", var))\n+\tif (!strcmp(\"sslcert\", key)) {\n+\t\tCHECKLEN(o_ssl_cert);\n\t\treturn git_config_string(&ssl_cert, var, value);\n+\t}\n#if LIBCURL_VERSION_NUM >= 0x070903\n-\tif (!strcmp(\"http.sslkey\", var))\n+\tif (!strcmp(\"sslkey\", key)) {\n+\t\tCHECKLEN(o_ssl_key);\n\t\treturn git_config_string(&ssl_key, var, value);\n+\t}\n#endif\n#if LIBCURL_VERSION_NUM >= 0x070908\n-\tif (!strcmp(\"http.sslcapath\", var))\n+\tif (!strcmp(\"sslcapath\", key)) {\n+\t\tCHECKLEN(o_ssl_capath);\n\t\treturn git_config_string(&ssl_capath, var, value);\n+\t}\n#endif\n-\tif (!strcmp(\"http.sslcainfo\", var))\n+\tif (!strcmp(\"sslcainfo\", key)) {\n+\t\tCHECKLEN(o_ssl_cainfo);\n\t\treturn git_config_string(&ssl_cainfo, var, value);\n-\tif (!strcmp(\"http.sslcertpasswordprotected\", var)) {\n+\t}\n+\tif (!strcmp(\"sslcertpasswordprotected\", key)) {\n+\t\tCHECKLEN(o_passwd_req);\n\t\tif (git_config_bool(var, value))\n\t\t\tssl_cert_password_required = 1;\n\t\treturn 0;\n\t}\n-\tif (!strcmp(\"http.ssltry\", var)) {\n+\tif (!strcmp(\"ssltry\", key)) {\n+\t\tCHECKLEN(o_ssl_try);\n\t\tcurl_ssl_try = git_config_bool(var, value);\n\t\treturn 0;\n\t}\n-\tif (!strcmp(\"http.minsessions\", var)) {\n+\tif (!strcmp(\"minsessions\", key)) {\n+\t\tCHECKLEN(o_min_sessions);\n\t\tmin_curl_sessions = git_config_int(var, value);\n#ifndef USE_CURL_MULTI\n\t\tif (min_curl_sessions > 1)\n@@ -177,42 +255,55 @@ static int http_options(const char *var, const  \nchar *value, void *cb)\n\t\treturn 0;\n\t}\n#ifdef USE_CURL_MULTI\n-\tif (!strcmp(\"http.maxrequests\", var)) {\n+\tif (!strcmp(\"maxrequests\", key)) {\n+\t\tCHECKLEN(o_max_requests);\n\t\tmax_requests = git_config_int(var, value);\n\t\treturn 0;\n\t}\n#endif\n-\tif (!strcmp(\"http.lowspeedlimit\", var)) {\n+\tif (!strcmp(\"lowspeedlimit\", key)) {\n+\t\tCHECKLEN(o_low_speed);\n\t\tcurl_low_speed_limit = (long)git_config_int(var, value);\n\t\treturn 0;\n\t}\n-\tif (!strcmp(\"http.lowspeedtime\", var)) {\n+\tif (!strcmp(\"lowspeedtime\", key)) {\n+\t\tCHECKLEN(o_low_time);\n\t\tcurl_low_speed_time = (long)git_config_int(var, value);\n\t\treturn 0;\n\t}\n\n-\tif (!strcmp(\"http.noepsv\", var)) {\n+\tif (!strcmp(\"noepsv\", key)) {\n+\t\tCHECKLEN(o_no_epsv);\n\t\tcurl_ftp_no_epsv = git_config_bool(var, value);\n\t\treturn 0;\n\t}\n-\tif (!strcmp(\"http.proxy\", var))\n+\tif (!strcmp(\"proxy\", key)) {\n+\t\tCHECKLEN(o_http_proxy);\n\t\treturn git_config_string(&curl_http_proxy, var, value);\n+\t}\n\n-\tif (!strcmp(\"http.cookiefile\", var))\n+\tif (!strcmp(\"cookiefile\", key)) {\n+\t\tCHECKLEN(o_cookie_file);\n\t\treturn git_config_string(&curl_cookie_file, var, value);\n+\t}\n\n-\tif (!strcmp(\"http.postbuffer\", var)) {\n+\tif (!strcmp(\"postbuffer\", key)) {\n+\t\tCHECKLEN(o_post_buffer);\n\t\thttp_post_buffer = git_config_int(var, value);\n\t\tif (http_post_buffer < LARGE_PACKET_MAX)\n\t\t\thttp_post_buffer = LARGE_PACKET_MAX;\n\t\treturn 0;\n\t}\n\n-\tif (!strcmp(\"http.useragent\", var))\n+\tif (!strcmp(\"useragent\", key)) {\n+\t\tCHECKLEN(o_user_agent);\n\t\treturn git_config_string(&user_agent, var, value);\n+\t}\n\n\t/* Fall back on the default ones */\n\treturn git_default_config(var, value, cb);\n+\n+#undef CHECKLEN\n}\n\nstatic void init_curl_http_auth(CURL *result)\n@@ -344,7 +435,7 @@ void http_init(struct remote *remote, const char  \n*url, int proactive_auth)\n\n\thttp_is_verbose = 0;\n\n-\tgit_config(http_options, NULL);\n+\tgit_config(http_options, (void *)url);\n\n\tcurl_global_init(CURL_GLOBAL_ALL);\n\n-- \n1.8.3\n"}]}