diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4a51e6a68dadf0d51c1951c645ee5d361f4ec1d8..e8eadde30577dd7a08ef412d24f857638ff47880 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1449,7 +1449,11 @@ http.cookiefile::
of the file to read cookies from should be plain HTTP headers or
the Netscape/Mozilla cookie file format (see linkgit:curl[1]).
NOTE that the file specified with http.cookiefile is only used as
- input. No cookies will be stored in the file.
+ input unless http.saveCookies is set.
+
+http.savecookies::
+ If set, store cookies received during requests to the file specified by
+ http.cookiefile. Has no effect if http.cookiefile is unset.
http.sslVerify::
Whether to verify the SSL certificate when fetching or pushing
diff --git a/http.c b/http.c
index 2d086aedfac9a8ea384c53f3b1963149b880ed31..2fbf986231d0e23b1d2c15c8d9121f1129139097 100644
--- a/http.c
+++ b/http.c
@@ -45,6 +45,7 @@ static long curl_low_speed_time = -1;
static int curl_ftp_no_epsv;
static const char *curl_http_proxy;
static const char *curl_cookie_file;
+static int curl_save_cookies;
static struct credential http_auth = CREDENTIAL_INIT;
static int http_proactive_auth;
static const char *user_agent;
@@ -200,6 +201,10 @@ static int http_options(const char *var, const char *value, void *cb)
if (!strcmp("http.cookiefile", var))
return git_config_string(&curl_cookie_file, var, value);
+ if (!strcmp("http.savecookies", var)) {
+ curl_save_cookies = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp("http.postbuffer", var)) {
http_post_buffer = git_config_int(var, value);
@@ -513,6 +518,8 @@ struct active_request_slot *get_active_slot(void)
slot->callback_data = NULL;
slot->callback_func = NULL;
curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);
+ if (curl_save_cookies)
+ curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index dd17e3a09d728a08c8038c5ce8187ea63112cdf3..397c4804010c7566a4f969822c413e46fe817e53 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -22,6 +22,9 @@ ErrorLog error.log
LoadModule version_module modules/mod_version.so
+
+ LoadModule headers_module modules/mod_headers.so
+
LockFile accept.lock
@@ -87,6 +90,11 @@ Alias /auth/dumb/ www/auth/dumb/
SetEnv GIT_HTTP_EXPORT_ALL
SetEnv GIT_NAMESPACE ns
+
+ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+ SetEnv GIT_HTTP_EXPORT_ALL
+ Header set Set-Cookie name=value
+
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
ScriptAlias /broken_smart/ broken-smart-http.sh/
diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh
index 55a866af803452e164e2c11c421b1e63f62d2e1e..8196af19f68ac3772a81326828f7cdf83ae399a1 100755
--- a/t/t5551-http-fetch.sh
+++ b/t/t5551-http-fetch.sh
@@ -187,6 +187,22 @@ test_expect_success 'dumb clone via http-backend respects namespace' '
test_cmp expect actual
'
+cat >cookies.txt <expect_cookies.txt < cookies_tail.txt
+ test_cmp expect_cookies.txt cookies_tail.txt
+'
+
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '