http: tell server that the client understands v1

Tell a server that protocol v1 can be used by sending the http header 'Git-Protocol' with 'version=1' indicating this. Also teach the apache http server to pass through the 'Git-Protocol' header as an environment variable 'GIT_PROTOCOL'. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Oct 16, 2017 at 10:55 UTC 19113a26b667527dc983920bf526b5c938d475bb
4 files changed +96
cache.h
+2
@@ -452,6 +452,8 @@ static inline enum object_type object_type(unsigned int mode)
452 * ignored.
453 */
454 #define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
455 +/* HTTP header used to handshake the wire protocol */
456 +#define GIT_PROTOCOL_HEADER "Git-Protocol"
457
458 /*
459 * This environment variable is expected to contain a boolean indicating
http.c
+18
@@ -12,6 +12,7 @@
12 #include "gettext.h"
13 #include "transport.h"
14 #include "packfile.h"
15 +#include "protocol.h"
16
17 static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
18 #if LIBCURL_VERSION_NUM >= 0x070a08
@@ -897,6 +898,21 @@ static void set_from_env(const char **var, const char *envname)
898 *var = val;
899 }
900
901 +static void protocol_http_header(void)
902 +{
903 + if (get_protocol_version_config() > 0) {
904 + struct strbuf protocol_header = STRBUF_INIT;
905 +
906 + strbuf_addf(&protocol_header, GIT_PROTOCOL_HEADER ": version=%d",
907 + get_protocol_version_config());
908 +
909 +
910 + extra_http_headers = curl_slist_append(extra_http_headers,
911 + protocol_header.buf);
912 + strbuf_release(&protocol_header);
913 + }
914 +}
915 +
916 void http_init(struct remote *remote, const char *url, int proactive_auth)
917 {
918 char *low_speed_limit;
@@ -927,6 +943,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
943 if (remote)
944 var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);
945
946 + protocol_http_header();
947 +
948 pragma_header = curl_slist_append(http_copy_default_headers(),
949 "Pragma: no-cache");
950 no_pragma_header = curl_slist_append(http_copy_default_headers(),
t/lib-httpd/apache.conf
+7
@@ -67,6 +67,9 @@ LockFile accept.lock
67 <IfModule !mod_unixd.c>
68 LoadModule unixd_module modules/mod_unixd.so
69 </IfModule>
70 +<IfModule !mod_setenvif.c>
71 + LoadModule setenvif_module modules/mod_setenvif.so
72 +</IfModule>
73 </IfVersion>
74
75 PassEnv GIT_VALGRIND
@@ -76,6 +79,10 @@ PassEnv ASAN_OPTIONS
79 PassEnv GIT_TRACE
80 PassEnv GIT_CONFIG_NOSYSTEM
81
82 +<IfVersion >= 2.4>
83 + SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
84 +</IfVersion>
85 +
86 Alias /dumb/ www/
87 Alias /auth/dumb/ www/auth/dumb/
88
t/t5700-protocol-v1.sh
+69
@@ -220,4 +220,73 @@ test_expect_success 'push with ssh:// using protocol v1' '
220 grep "push< version 1" log
221 '
222
223 +# Test protocol v1 with 'http://' transport
224 +#
225 +. "$TEST_DIRECTORY"/lib-httpd.sh
226 +start_httpd
227 +
228 +test_expect_success 'create repo to be served by http:// transport' '
229 + git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
230 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" config http.receivepack true &&
231 + test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one
232 +'
233 +
234 +test_expect_success 'clone with http:// using protocol v1' '
235 + GIT_TRACE_PACKET=1 GIT_TRACE_CURL=1 git -c protocol.version=1 \
236 + clone "$HTTPD_URL/smart/http_parent" http_child 2>log &&
237 +
238 + git -C http_child log -1 --format=%s >actual &&
239 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" log -1 --format=%s >expect &&
240 + test_cmp expect actual &&
241 +
242 + # Client requested to use protocol v1
243 + grep "Git-Protocol: version=1" log &&
244 + # Server responded using protocol v1
245 + grep "git< version 1" log
246 +'
247 +
248 +test_expect_success 'fetch with http:// using protocol v1' '
249 + test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" two &&
250 +
251 + GIT_TRACE_PACKET=1 git -C http_child -c protocol.version=1 \
252 + fetch 2>log &&
253 +
254 + git -C http_child log -1 --format=%s origin/master >actual &&
255 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" log -1 --format=%s >expect &&
256 + test_cmp expect actual &&
257 +
258 + # Server responded using protocol v1
259 + grep "git< version 1" log
260 +'
261 +
262 +test_expect_success 'pull with http:// using protocol v1' '
263 + GIT_TRACE_PACKET=1 git -C http_child -c protocol.version=1 \
264 + pull 2>log &&
265 +
266 + git -C http_child log -1 --format=%s >actual &&
267 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" log -1 --format=%s >expect &&
268 + test_cmp expect actual &&
269 +
270 + # Server responded using protocol v1
271 + grep "git< version 1" log
272 +'
273 +
274 +test_expect_success 'push with http:// using protocol v1' '
275 + test_commit -C http_child three &&
276 +
277 + # Push to another branch, as the target repository has the
278 + # master branch checked out and we cannot push into it.
279 + GIT_TRACE_PACKET=1 git -C http_child -c protocol.version=1 \
280 + push origin HEAD:client_branch && #2>log &&
281 +
282 + git -C http_child log -1 --format=%s >actual &&
283 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" log -1 --format=%s client_branch >expect &&
284 + test_cmp expect actual &&
285 +
286 + # Server responded using protocol v1
287 + grep "git< version 1" log
288 +'
289 +
290 +stop_httpd
291 +
292 test_done