Hold persistent proxy connection open while fetching clone.bundle

The persistent proxy may choose to present a per-process cookie file
that gets cleaned up after the process exits, to help with the fact
that libcurl cannot save cookies atomically when a cookie file is
shared across processes. We were letting this cleanup happen
immediately by closing stdin as soon as we read the configuration
option, resulting in a nonexistent cookie file by the time we use the
config option.

Work around this by converting the cookie logic to a context manager
method, which closes the process only when we're done with the cookie
file.

Change-Id: I12a88b25cc19621ef8161337144c1b264264211a
This commit is contained in:
Dave Borowitz 2015-01-02 11:12:54 -08:00
parent 42e679b9f6
commit 137d0131bf

View File

@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
from __future__ import print_function from __future__ import print_function
import traceback import contextlib
import errno import errno
import filecmp import filecmp
import os import os
@ -26,6 +26,7 @@ import sys
import tarfile import tarfile
import tempfile import tempfile
import time import time
import traceback
from color import Coloring from color import Coloring
from git_command import GitCommand, git_require from git_command import GitCommand, git_require
@ -1946,7 +1947,7 @@ class Project(object):
os.remove(tmpPath) os.remove(tmpPath)
if 'http_proxy' in os.environ and 'darwin' == sys.platform: if 'http_proxy' in os.environ and 'darwin' == sys.platform:
cmd += ['--proxy', os.environ['http_proxy']] cmd += ['--proxy', os.environ['http_proxy']]
cookiefile = self._GetBundleCookieFile(srcUrl) with self._GetBundleCookieFile(srcUrl) as cookiefile:
if cookiefile: if cookiefile:
cmd += ['--cookie', cookiefile] cmd += ['--cookie', cookiefile]
if srcUrl.startswith('persistent-'): if srcUrl.startswith('persistent-'):
@ -1994,6 +1995,7 @@ class Project(object):
except OSError: except OSError:
return False return False
@contextlib.contextmanager
def _GetBundleCookieFile(self, url): def _GetBundleCookieFile(self, url):
if url.startswith('persistent-'): if url.startswith('persistent-'):
try: try:
@ -2001,7 +2003,7 @@ class Project(object):
['git-remote-persistent-https', '-print_config', url], ['git-remote-persistent-https', '-print_config', url],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
p.stdin.close() # Tell subprocess it's ok to close. try:
prefix = 'http.cookiefile=' prefix = 'http.cookiefile='
cookiefile = None cookiefile = None
for line in p.stdout: for line in p.stdout:
@ -2009,19 +2011,23 @@ class Project(object):
if line.startswith(prefix): if line.startswith(prefix):
cookiefile = line[len(prefix):] cookiefile = line[len(prefix):]
break break
# Leave subprocess open, as cookie file may be transient.
if cookiefile:
yield cookiefile
return
finally:
p.stdin.close()
if p.wait(): if p.wait():
err_msg = p.stderr.read() err_msg = p.stderr.read()
if ' -print_config' in err_msg: if ' -print_config' in err_msg:
pass # Persistent proxy doesn't support -print_config. pass # Persistent proxy doesn't support -print_config.
else: else:
print(err_msg, file=sys.stderr) print(err_msg, file=sys.stderr)
if cookiefile:
return cookiefile
except OSError as e: except OSError as e:
if e.errno == errno.ENOENT: if e.errno == errno.ENOENT:
pass # No persistent proxy. pass # No persistent proxy.
raise raise
return GitConfig.ForUser().GetString('http.cookiefile') yield GitConfig.ForUser().GetString('http.cookiefile')
def _Checkout(self, rev, quiet=False): def _Checkout(self, rev, quiet=False):
cmd = ['checkout'] cmd = ['checkout']