{"thread":{"id":"34520","subject":"[PATCH] http: Add http.savecookies option to write out HTTP cookies","startedAt":"2013-07-23T21:07:56Z","lastAt":"2013-07-23T22:40:17Z","messageCount":3,"participants":["dborowitz@google.com","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"224005","messageId":"1374613676-20889-1-git-send-email-dborowitz@google.com","threadId":"34520","inReplyTo":null,"subject":"[PATCH] http: Add http.savecookies option to write out HTTP cookies","fromName":"","fromEmail":"dborowitz@google.com","sentAt":"2013-07-23T21:07:56Z","receivedAt":"2013-07-23T21:07:56Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"From: Dave Borowitz <dborowitz@google.com>\n\nHTTP servers may send Set-Cookie headers in a response and expect them\nto be set on subsequent requests. By default, libcurl behavior is to\nstore such cookies in memory and reuse them across requests within a\nsingle session. However, it may also make sense, depending on the\nserver and the cookies, to store them across sessions. Provide users\nan option to enable this behavior, writing cookies out to the same\nfile specified in http.cookiefile.\n---\n Documentation/config.txt |  6 +++++-\n http.c                   |  7 +++++++\n t/lib-httpd/apache.conf  |  8 ++++++++\n t/t5551-http-fetch.sh    | 18 ++++++++++++++++++\n 4 files changed, 38 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex e0b923f..e935447 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1456,7 +1456,11 @@ http.cookiefile::\n \tof the file to read cookies from should be plain HTTP headers or\n \tthe Netscape/Mozilla cookie file format (see linkgit:curl[1]).\n \tNOTE that the file specified with http.cookiefile is only used as\n-\tinput. No cookies will be stored in the file.\n+\tinput unless http.saveCookies is set.\n+\n+http.savecookies::\n+\tIf set, store cookies received during requests to the file specified by\n+\thttp.cookiefile. Has no effect if http.cookiefile is unset.\n \n http.sslVerify::\n \tWhether to verify the SSL certificate when fetching or pushing\ndiff --git a/http.c b/http.c\nindex 2d086ae..2fbf986 100644\n--- a/http.c\n+++ b/http.c\n@@ -45,6 +45,7 @@ static long curl_low_speed_time = -1;\n static int curl_ftp_no_epsv;\n static const char *curl_http_proxy;\n static const char *curl_cookie_file;\n+static int curl_save_cookies;\n static struct credential http_auth = CREDENTIAL_INIT;\n static int http_proactive_auth;\n static const char *user_agent;\n@@ -200,6 +201,10 @@ static int http_options(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(\"http.cookiefile\", var))\n \t\treturn git_config_string(&curl_cookie_file, var, value);\n+\tif (!strcmp(\"http.savecookies\", var)) {\n+\t\tcurl_save_cookies = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n \n \tif (!strcmp(\"http.postbuffer\", var)) {\n \t\thttp_post_buffer = git_config_int(var, value);\n@@ -513,6 +518,8 @@ struct active_request_slot *get_active_slot(void)\n \tslot->callback_data = NULL;\n \tslot->callback_func = NULL;\n \tcurl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);\n+\tif (curl_save_cookies)\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);\n \tcurl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);\n \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);\ndiff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf\nindex dd17e3a..397c480 100644\n--- a/t/lib-httpd/apache.conf\n+++ b/t/lib-httpd/apache.conf\n@@ -22,6 +22,9 @@ ErrorLog error.log\n <IfModule !mod_version.c>\n \tLoadModule version_module modules/mod_version.so\n </IfModule>\n+<IfModule !mod_headers.c>\n+\tLoadModule headers_module modules/mod_headers.so\n+</IfModule>\n \n <IfVersion < 2.4>\n LockFile accept.lock\n@@ -87,6 +90,11 @@ Alias /auth/dumb/ www/auth/dumb/\n \tSetEnv GIT_HTTP_EXPORT_ALL\n \tSetEnv GIT_NAMESPACE ns\n </LocationMatch>\n+<LocationMatch /smart_cookies/>\n+\tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n+\tSetEnv GIT_HTTP_EXPORT_ALL\n+\tHeader set Set-Cookie name=value\n+</LocationMatch>\n ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1\n ScriptAlias /broken_smart/ broken-smart-http.sh/\n <Directory ${GIT_EXEC_PATH}>\ndiff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh\nindex 55a866a..287d22b 100755\n--- a/t/t5551-http-fetch.sh\n+++ b/t/t5551-http-fetch.sh\n@@ -187,6 +187,24 @@ test_expect_success 'dumb clone via http-backend respects namespace' '\n \ttest_cmp expect actual\n '\n \n+cat >cookies.txt <<EOF\n+127.0.0.1\tFALSE\t/smart_cookies/\tFALSE\t0\tothername\tothervalue\n+EOF\n+cat >expect_cookies.txt <<EOF\n+# Netscape HTTP Cookie File\n+# http://curl.haxx.se/docs/http-cookies.html\n+# This file was generated by libcurl! Edit at your own risk.\n+\n+127.0.0.1\tFALSE\t/smart_cookies/\tFALSE\t0\tothername\tothervalue\n+127.0.0.1\tFALSE\t/smart_cookies/repo.git/info/\tFALSE\t0\tname\tvalue\n+EOF\n+test_expect_success 'cookies stored in http.cookiefile when http.savecookies set' '\n+\tgit config http.cookiefile cookies.txt &&\n+\tgit config http.savecookies true &&\n+\tgit ls-remote $HTTPD_URL/smart_cookies/repo.git master &&\n+\ttest_cmp expect_cookies.txt cookies.txt\n+'\n+\n test -n \"$GIT_TEST_LONG\" && test_set_prereq EXPENSIVE\n \n test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '\n-- \n1.8.3.2\n"},{"id":"224012","messageId":"7vk3kg7vzj.fsf@alter.siamese.dyndns.org","threadId":"34520","inReplyTo":"1374613676-20889-1-git-send-email-dborowitz@google.com","subject":"Re: [PATCH] http: Add http.savecookies option to write out HTTP cookies","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-07-23T22:27:28Z","receivedAt":"2013-07-23T22:27:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"dborowitz@google.com writes:\n\n> From: Dave Borowitz <dborowitz@google.com>\n>\n> HTTP servers may send Set-Cookie headers in a response and expect them\n> to be set on subsequent requests. By default, libcurl behavior is to\n> store such cookies in memory and reuse them across requests within a\n> single session. However, it may also make sense, depending on the\n> server and the cookies, to store them across sessions. Provide users\n> an option to enable this behavior, writing cookies out to the same\n> file specified in http.cookiefile.\n> ---\n\nMakes sense.\n\nI briefly wondered if users want to be able to selectively store\ncookies only from certain sites but not from others.  But if we are\ngoing to build this on top of Kyle J. McKay's \"Per URL http.<url>.* \nconfiguration\" series, that will fall out as a natural consequence,\nI think.\n\nPlease sign-off your patch.  Thanks.\n"},{"id":"224011","messageId":"1374619217-26462-1-git-send-email-dborowitz@google.com","threadId":"34520","inReplyTo":"1374613676-20889-1-git-send-email-dborowitz@google.com","subject":"[PATCH] http: Add http.savecookies option to write out HTTP cookies","fromName":"","fromEmail":"dborowitz@google.com","sentAt":"2013-07-23T22:40:17Z","receivedAt":"2013-07-23T22:40:17Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"From: Dave Borowitz <dborowitz@google.com>\n\nHTTP servers may send Set-Cookie headers in a response and expect them\nto be set on subsequent requests. By default, libcurl behavior is to\nstore such cookies in memory and reuse them across requests within a\nsingle session. However, it may also make sense, depending on the\nserver and the cookies, to store them across sessions. Provide users\nan option to enable this behavior, writing cookies out to the same\nfile specified in http.cookiefile.\n\nSigned-off-by: Dave Borowitz <dborowitz@google.com>\n---\n Documentation/config.txt |  6 +++++-\n http.c                   |  7 +++++++\n t/lib-httpd/apache.conf  |  8 ++++++++\n t/t5551-http-fetch.sh    | 18 ++++++++++++++++++\n 4 files changed, 38 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex e0b923f..e935447 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1456,7 +1456,11 @@ http.cookiefile::\n \tof the file to read cookies from should be plain HTTP headers or\n \tthe Netscape/Mozilla cookie file format (see linkgit:curl[1]).\n \tNOTE that the file specified with http.cookiefile is only used as\n-\tinput. No cookies will be stored in the file.\n+\tinput unless http.saveCookies is set.\n+\n+http.savecookies::\n+\tIf set, store cookies received during requests to the file specified by\n+\thttp.cookiefile. Has no effect if http.cookiefile is unset.\n \n http.sslVerify::\n \tWhether to verify the SSL certificate when fetching or pushing\ndiff --git a/http.c b/http.c\nindex 2d086ae..2fbf986 100644\n--- a/http.c\n+++ b/http.c\n@@ -45,6 +45,7 @@ static long curl_low_speed_time = -1;\n static int curl_ftp_no_epsv;\n static const char *curl_http_proxy;\n static const char *curl_cookie_file;\n+static int curl_save_cookies;\n static struct credential http_auth = CREDENTIAL_INIT;\n static int http_proactive_auth;\n static const char *user_agent;\n@@ -200,6 +201,10 @@ static int http_options(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(\"http.cookiefile\", var))\n \t\treturn git_config_string(&curl_cookie_file, var, value);\n+\tif (!strcmp(\"http.savecookies\", var)) {\n+\t\tcurl_save_cookies = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n \n \tif (!strcmp(\"http.postbuffer\", var)) {\n \t\thttp_post_buffer = git_config_int(var, value);\n@@ -513,6 +518,8 @@ struct active_request_slot *get_active_slot(void)\n \tslot->callback_data = NULL;\n \tslot->callback_func = NULL;\n \tcurl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);\n+\tif (curl_save_cookies)\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);\n \tcurl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);\n \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);\ndiff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf\nindex dd17e3a..397c480 100644\n--- a/t/lib-httpd/apache.conf\n+++ b/t/lib-httpd/apache.conf\n@@ -22,6 +22,9 @@ ErrorLog error.log\n <IfModule !mod_version.c>\n \tLoadModule version_module modules/mod_version.so\n </IfModule>\n+<IfModule !mod_headers.c>\n+\tLoadModule headers_module modules/mod_headers.so\n+</IfModule>\n \n <IfVersion < 2.4>\n LockFile accept.lock\n@@ -87,6 +90,11 @@ Alias /auth/dumb/ www/auth/dumb/\n \tSetEnv GIT_HTTP_EXPORT_ALL\n \tSetEnv GIT_NAMESPACE ns\n </LocationMatch>\n+<LocationMatch /smart_cookies/>\n+\tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n+\tSetEnv GIT_HTTP_EXPORT_ALL\n+\tHeader set Set-Cookie name=value\n+</LocationMatch>\n ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1\n ScriptAlias /broken_smart/ broken-smart-http.sh/\n <Directory ${GIT_EXEC_PATH}>\ndiff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh\nindex 55a866a..287d22b 100755\n--- a/t/t5551-http-fetch.sh\n+++ b/t/t5551-http-fetch.sh\n@@ -187,6 +187,24 @@ test_expect_success 'dumb clone via http-backend respects namespace' '\n \ttest_cmp expect actual\n '\n \n+cat >cookies.txt <<EOF\n+127.0.0.1\tFALSE\t/smart_cookies/\tFALSE\t0\tothername\tothervalue\n+EOF\n+cat >expect_cookies.txt <<EOF\n+# Netscape HTTP Cookie File\n+# http://curl.haxx.se/docs/http-cookies.html\n+# This file was generated by libcurl! Edit at your own risk.\n+\n+127.0.0.1\tFALSE\t/smart_cookies/\tFALSE\t0\tothername\tothervalue\n+127.0.0.1\tFALSE\t/smart_cookies/repo.git/info/\tFALSE\t0\tname\tvalue\n+EOF\n+test_expect_success 'cookies stored in http.cookiefile when http.savecookies set' '\n+\tgit config http.cookiefile cookies.txt &&\n+\tgit config http.savecookies true &&\n+\tgit ls-remote $HTTPD_URL/smart_cookies/repo.git master &&\n+\ttest_cmp expect_cookies.txt cookies.txt\n+'\n+\n test -n \"$GIT_TEST_LONG\" && test_set_prereq EXPENSIVE\n \n test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '\n-- \n1.8.3.2\n"}]}