##// END OF EJS Templates
serve: use chunked encoding in hgweb responses...
Mads Kiilerich -
r18354:cf5c7601 default
parent child Browse files
Show More
@@ -1,317 +1,329 b''
1 # hgweb/server.py - The standalone hg web server.
1 # hgweb/server.py - The standalone hg web server.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
9 import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
10 from mercurial import util, error
10 from mercurial import util, error
11 from mercurial.hgweb import common
11 from mercurial.hgweb import common
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13
13
14 def _splitURI(uri):
14 def _splitURI(uri):
15 """Return path and query that has been split from uri
15 """Return path and query that has been split from uri
16
16
17 Just like CGI environment, the path is unquoted, the query is
17 Just like CGI environment, the path is unquoted, the query is
18 not.
18 not.
19 """
19 """
20 if '?' in uri:
20 if '?' in uri:
21 path, query = uri.split('?', 1)
21 path, query = uri.split('?', 1)
22 else:
22 else:
23 path, query = uri, ''
23 path, query = uri, ''
24 return urllib.unquote(path), query
24 return urllib.unquote(path), query
25
25
26 class _error_logger(object):
26 class _error_logger(object):
27 def __init__(self, handler):
27 def __init__(self, handler):
28 self.handler = handler
28 self.handler = handler
29 def flush(self):
29 def flush(self):
30 pass
30 pass
31 def write(self, str):
31 def write(self, str):
32 self.writelines(str.split('\n'))
32 self.writelines(str.split('\n'))
33 def writelines(self, seq):
33 def writelines(self, seq):
34 for msg in seq:
34 for msg in seq:
35 self.handler.log_error("HG error: %s", msg)
35 self.handler.log_error("HG error: %s", msg)
36
36
37 class _httprequesthandler(BaseHTTPServer.BaseHTTPRequestHandler):
37 class _httprequesthandler(BaseHTTPServer.BaseHTTPRequestHandler):
38
38
39 url_scheme = 'http'
39 url_scheme = 'http'
40
40
41 @staticmethod
41 @staticmethod
42 def preparehttpserver(httpserver, ssl_cert):
42 def preparehttpserver(httpserver, ssl_cert):
43 """Prepare .socket of new HTTPServer instance"""
43 """Prepare .socket of new HTTPServer instance"""
44 pass
44 pass
45
45
46 def __init__(self, *args, **kargs):
46 def __init__(self, *args, **kargs):
47 self.protocol_version = 'HTTP/1.1'
47 self.protocol_version = 'HTTP/1.1'
48 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
48 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
49
49
50 def _log_any(self, fp, format, *args):
50 def _log_any(self, fp, format, *args):
51 fp.write("%s - - [%s] %s\n" % (self.client_address[0],
51 fp.write("%s - - [%s] %s\n" % (self.client_address[0],
52 self.log_date_time_string(),
52 self.log_date_time_string(),
53 format % args))
53 format % args))
54 fp.flush()
54 fp.flush()
55
55
56 def log_error(self, format, *args):
56 def log_error(self, format, *args):
57 self._log_any(self.server.errorlog, format, *args)
57 self._log_any(self.server.errorlog, format, *args)
58
58
59 def log_message(self, format, *args):
59 def log_message(self, format, *args):
60 self._log_any(self.server.accesslog, format, *args)
60 self._log_any(self.server.accesslog, format, *args)
61
61
62 def log_request(self, code='-', size='-'):
62 def log_request(self, code='-', size='-'):
63 xheaders = [h for h in self.headers.items() if h[0].startswith('x-')]
63 xheaders = [h for h in self.headers.items() if h[0].startswith('x-')]
64 self.log_message('"%s" %s %s%s',
64 self.log_message('"%s" %s %s%s',
65 self.requestline, str(code), str(size),
65 self.requestline, str(code), str(size),
66 ''.join([' %s:%s' % h for h in sorted(xheaders)]))
66 ''.join([' %s:%s' % h for h in sorted(xheaders)]))
67
67
68 def do_write(self):
68 def do_write(self):
69 try:
69 try:
70 self.do_hgweb()
70 self.do_hgweb()
71 except socket.error, inst:
71 except socket.error, inst:
72 if inst[0] != errno.EPIPE:
72 if inst[0] != errno.EPIPE:
73 raise
73 raise
74
74
75 def do_POST(self):
75 def do_POST(self):
76 try:
76 try:
77 self.do_write()
77 self.do_write()
78 except Exception:
78 except Exception:
79 self._start_response("500 Internal Server Error", [])
79 self._start_response("500 Internal Server Error", [])
80 self._write("Internal Server Error")
80 self._write("Internal Server Error")
81 tb = "".join(traceback.format_exception(*sys.exc_info()))
81 tb = "".join(traceback.format_exception(*sys.exc_info()))
82 self.log_error("Exception happened during processing "
82 self.log_error("Exception happened during processing "
83 "request '%s':\n%s", self.path, tb)
83 "request '%s':\n%s", self.path, tb)
84
84
85 def do_GET(self):
85 def do_GET(self):
86 self.do_POST()
86 self.do_POST()
87
87
88 def do_hgweb(self):
88 def do_hgweb(self):
89 path, query = _splitURI(self.path)
89 path, query = _splitURI(self.path)
90
90
91 env = {}
91 env = {}
92 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
92 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
93 env['REQUEST_METHOD'] = self.command
93 env['REQUEST_METHOD'] = self.command
94 env['SERVER_NAME'] = self.server.server_name
94 env['SERVER_NAME'] = self.server.server_name
95 env['SERVER_PORT'] = str(self.server.server_port)
95 env['SERVER_PORT'] = str(self.server.server_port)
96 env['REQUEST_URI'] = self.path
96 env['REQUEST_URI'] = self.path
97 env['SCRIPT_NAME'] = self.server.prefix
97 env['SCRIPT_NAME'] = self.server.prefix
98 env['PATH_INFO'] = path[len(self.server.prefix):]
98 env['PATH_INFO'] = path[len(self.server.prefix):]
99 env['REMOTE_HOST'] = self.client_address[0]
99 env['REMOTE_HOST'] = self.client_address[0]
100 env['REMOTE_ADDR'] = self.client_address[0]
100 env['REMOTE_ADDR'] = self.client_address[0]
101 if query:
101 if query:
102 env['QUERY_STRING'] = query
102 env['QUERY_STRING'] = query
103
103
104 if self.headers.typeheader is None:
104 if self.headers.typeheader is None:
105 env['CONTENT_TYPE'] = self.headers.type
105 env['CONTENT_TYPE'] = self.headers.type
106 else:
106 else:
107 env['CONTENT_TYPE'] = self.headers.typeheader
107 env['CONTENT_TYPE'] = self.headers.typeheader
108 length = self.headers.getheader('content-length')
108 length = self.headers.getheader('content-length')
109 if length:
109 if length:
110 env['CONTENT_LENGTH'] = length
110 env['CONTENT_LENGTH'] = length
111 for header in [h for h in self.headers.keys()
111 for header in [h for h in self.headers.keys()
112 if h not in ('content-type', 'content-length')]:
112 if h not in ('content-type', 'content-length')]:
113 hkey = 'HTTP_' + header.replace('-', '_').upper()
113 hkey = 'HTTP_' + header.replace('-', '_').upper()
114 hval = self.headers.getheader(header)
114 hval = self.headers.getheader(header)
115 hval = hval.replace('\n', '').strip()
115 hval = hval.replace('\n', '').strip()
116 if hval:
116 if hval:
117 env[hkey] = hval
117 env[hkey] = hval
118 env['SERVER_PROTOCOL'] = self.request_version
118 env['SERVER_PROTOCOL'] = self.request_version
119 env['wsgi.version'] = (1, 0)
119 env['wsgi.version'] = (1, 0)
120 env['wsgi.url_scheme'] = self.url_scheme
120 env['wsgi.url_scheme'] = self.url_scheme
121 if env.get('HTTP_EXPECT', '').lower() == '100-continue':
121 if env.get('HTTP_EXPECT', '').lower() == '100-continue':
122 self.rfile = common.continuereader(self.rfile, self.wfile.write)
122 self.rfile = common.continuereader(self.rfile, self.wfile.write)
123
123
124 env['wsgi.input'] = self.rfile
124 env['wsgi.input'] = self.rfile
125 env['wsgi.errors'] = _error_logger(self)
125 env['wsgi.errors'] = _error_logger(self)
126 env['wsgi.multithread'] = isinstance(self.server,
126 env['wsgi.multithread'] = isinstance(self.server,
127 SocketServer.ThreadingMixIn)
127 SocketServer.ThreadingMixIn)
128 env['wsgi.multiprocess'] = isinstance(self.server,
128 env['wsgi.multiprocess'] = isinstance(self.server,
129 SocketServer.ForkingMixIn)
129 SocketServer.ForkingMixIn)
130 env['wsgi.run_once'] = 0
130 env['wsgi.run_once'] = 0
131
131
132 self.saved_status = None
132 self.saved_status = None
133 self.saved_headers = []
133 self.saved_headers = []
134 self.sent_headers = False
134 self.sent_headers = False
135 self.length = None
135 self.length = None
136 self._chunked = None
136 for chunk in self.server.application(env, self._start_response):
137 for chunk in self.server.application(env, self._start_response):
137 self._write(chunk)
138 self._write(chunk)
138 if not self.sent_headers:
139 if not self.sent_headers:
139 self.send_headers()
140 self.send_headers()
141 self._done()
140
142
141 def send_headers(self):
143 def send_headers(self):
142 if not self.saved_status:
144 if not self.saved_status:
143 raise AssertionError("Sending headers before "
145 raise AssertionError("Sending headers before "
144 "start_response() called")
146 "start_response() called")
145 saved_status = self.saved_status.split(None, 1)
147 saved_status = self.saved_status.split(None, 1)
146 saved_status[0] = int(saved_status[0])
148 saved_status[0] = int(saved_status[0])
147 self.send_response(*saved_status)
149 self.send_response(*saved_status)
148 should_close = True
150 self.length = None
151 self._chunked = False
149 for h in self.saved_headers:
152 for h in self.saved_headers:
150 self.send_header(*h)
153 self.send_header(*h)
151 if h[0].lower() == 'content-length':
154 if h[0].lower() == 'content-length':
152 should_close = False
153 self.length = int(h[1])
155 self.length = int(h[1])
154 # The value of the Connection header is a list of case-insensitive
156 if self.length is None:
155 # tokens separated by commas and optional whitespace.
157 self._chunked = (not self.close_connection and
156 if should_close:
158 self.request_version == "HTTP/1.1")
157 self.send_header('Connection', 'close')
159 if self._chunked:
160 self.send_header('Transfer-Encoding', 'chunked')
161 else:
162 self.send_header('Connection', 'close')
158 self.end_headers()
163 self.end_headers()
159 self.sent_headers = True
164 self.sent_headers = True
160
165
161 def _start_response(self, http_status, headers, exc_info=None):
166 def _start_response(self, http_status, headers, exc_info=None):
162 code, msg = http_status.split(None, 1)
167 code, msg = http_status.split(None, 1)
163 code = int(code)
168 code = int(code)
164 self.saved_status = http_status
169 self.saved_status = http_status
165 bad_headers = ('connection', 'transfer-encoding')
170 bad_headers = ('connection', 'transfer-encoding')
166 self.saved_headers = [h for h in headers
171 self.saved_headers = [h for h in headers
167 if h[0].lower() not in bad_headers]
172 if h[0].lower() not in bad_headers]
168 return self._write
173 return self._write
169
174
170 def _write(self, data):
175 def _write(self, data):
171 if not self.saved_status:
176 if not self.saved_status:
172 raise AssertionError("data written before start_response() called")
177 raise AssertionError("data written before start_response() called")
173 elif not self.sent_headers:
178 elif not self.sent_headers:
174 self.send_headers()
179 self.send_headers()
175 if self.length is not None:
180 if self.length is not None:
176 if len(data) > self.length:
181 if len(data) > self.length:
177 raise AssertionError("Content-length header sent, but more "
182 raise AssertionError("Content-length header sent, but more "
178 "bytes than specified are being written.")
183 "bytes than specified are being written.")
179 self.length = self.length - len(data)
184 self.length = self.length - len(data)
185 elif self._chunked and data:
186 data = '%x\r\n%s\r\n' % (len(data), data)
180 self.wfile.write(data)
187 self.wfile.write(data)
181 self.wfile.flush()
188 self.wfile.flush()
182
189
190 def _done(self):
191 if self._chunked:
192 self.wfile.write('0\r\n\r\n')
193 self.wfile.flush()
194
183 class _httprequesthandleropenssl(_httprequesthandler):
195 class _httprequesthandleropenssl(_httprequesthandler):
184 """HTTPS handler based on pyOpenSSL"""
196 """HTTPS handler based on pyOpenSSL"""
185
197
186 url_scheme = 'https'
198 url_scheme = 'https'
187
199
188 @staticmethod
200 @staticmethod
189 def preparehttpserver(httpserver, ssl_cert):
201 def preparehttpserver(httpserver, ssl_cert):
190 try:
202 try:
191 import OpenSSL
203 import OpenSSL
192 OpenSSL.SSL.Context
204 OpenSSL.SSL.Context
193 except ImportError:
205 except ImportError:
194 raise util.Abort(_("SSL support is unavailable"))
206 raise util.Abort(_("SSL support is unavailable"))
195 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
207 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
196 ctx.use_privatekey_file(ssl_cert)
208 ctx.use_privatekey_file(ssl_cert)
197 ctx.use_certificate_file(ssl_cert)
209 ctx.use_certificate_file(ssl_cert)
198 sock = socket.socket(httpserver.address_family, httpserver.socket_type)
210 sock = socket.socket(httpserver.address_family, httpserver.socket_type)
199 httpserver.socket = OpenSSL.SSL.Connection(ctx, sock)
211 httpserver.socket = OpenSSL.SSL.Connection(ctx, sock)
200 httpserver.server_bind()
212 httpserver.server_bind()
201 httpserver.server_activate()
213 httpserver.server_activate()
202
214
203 def setup(self):
215 def setup(self):
204 self.connection = self.request
216 self.connection = self.request
205 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
217 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
206 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
218 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
207
219
208 def do_write(self):
220 def do_write(self):
209 import OpenSSL
221 import OpenSSL
210 try:
222 try:
211 _httprequesthandler.do_write(self)
223 _httprequesthandler.do_write(self)
212 except OpenSSL.SSL.SysCallError, inst:
224 except OpenSSL.SSL.SysCallError, inst:
213 if inst.args[0] != errno.EPIPE:
225 if inst.args[0] != errno.EPIPE:
214 raise
226 raise
215
227
216 def handle_one_request(self):
228 def handle_one_request(self):
217 import OpenSSL
229 import OpenSSL
218 try:
230 try:
219 _httprequesthandler.handle_one_request(self)
231 _httprequesthandler.handle_one_request(self)
220 except (OpenSSL.SSL.SysCallError, OpenSSL.SSL.ZeroReturnError):
232 except (OpenSSL.SSL.SysCallError, OpenSSL.SSL.ZeroReturnError):
221 self.close_connection = True
233 self.close_connection = True
222 pass
234 pass
223
235
224 class _httprequesthandlerssl(_httprequesthandler):
236 class _httprequesthandlerssl(_httprequesthandler):
225 """HTTPS handler based on Pythons ssl module (introduced in 2.6)"""
237 """HTTPS handler based on Pythons ssl module (introduced in 2.6)"""
226
238
227 url_scheme = 'https'
239 url_scheme = 'https'
228
240
229 @staticmethod
241 @staticmethod
230 def preparehttpserver(httpserver, ssl_cert):
242 def preparehttpserver(httpserver, ssl_cert):
231 try:
243 try:
232 import ssl
244 import ssl
233 ssl.wrap_socket
245 ssl.wrap_socket
234 except ImportError:
246 except ImportError:
235 raise util.Abort(_("SSL support is unavailable"))
247 raise util.Abort(_("SSL support is unavailable"))
236 httpserver.socket = ssl.wrap_socket(httpserver.socket, server_side=True,
248 httpserver.socket = ssl.wrap_socket(httpserver.socket, server_side=True,
237 certfile=ssl_cert, ssl_version=ssl.PROTOCOL_SSLv23)
249 certfile=ssl_cert, ssl_version=ssl.PROTOCOL_SSLv23)
238
250
239 def setup(self):
251 def setup(self):
240 self.connection = self.request
252 self.connection = self.request
241 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
253 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
242 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
254 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
243
255
244 try:
256 try:
245 from threading import activeCount
257 from threading import activeCount
246 activeCount() # silence pyflakes
258 activeCount() # silence pyflakes
247 _mixin = SocketServer.ThreadingMixIn
259 _mixin = SocketServer.ThreadingMixIn
248 except ImportError:
260 except ImportError:
249 if util.safehasattr(os, "fork"):
261 if util.safehasattr(os, "fork"):
250 _mixin = SocketServer.ForkingMixIn
262 _mixin = SocketServer.ForkingMixIn
251 else:
263 else:
252 class _mixin(object):
264 class _mixin(object):
253 pass
265 pass
254
266
255 def openlog(opt, default):
267 def openlog(opt, default):
256 if opt and opt != '-':
268 if opt and opt != '-':
257 return open(opt, 'a')
269 return open(opt, 'a')
258 return default
270 return default
259
271
260 class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
272 class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
261
273
262 # SO_REUSEADDR has broken semantics on windows
274 # SO_REUSEADDR has broken semantics on windows
263 if os.name == 'nt':
275 if os.name == 'nt':
264 allow_reuse_address = 0
276 allow_reuse_address = 0
265
277
266 def __init__(self, ui, app, addr, handler, **kwargs):
278 def __init__(self, ui, app, addr, handler, **kwargs):
267 BaseHTTPServer.HTTPServer.__init__(self, addr, handler, **kwargs)
279 BaseHTTPServer.HTTPServer.__init__(self, addr, handler, **kwargs)
268 self.daemon_threads = True
280 self.daemon_threads = True
269 self.application = app
281 self.application = app
270
282
271 handler.preparehttpserver(self, ui.config('web', 'certificate'))
283 handler.preparehttpserver(self, ui.config('web', 'certificate'))
272
284
273 prefix = ui.config('web', 'prefix', '')
285 prefix = ui.config('web', 'prefix', '')
274 if prefix:
286 if prefix:
275 prefix = '/' + prefix.strip('/')
287 prefix = '/' + prefix.strip('/')
276 self.prefix = prefix
288 self.prefix = prefix
277
289
278 alog = openlog(ui.config('web', 'accesslog', '-'), sys.stdout)
290 alog = openlog(ui.config('web', 'accesslog', '-'), sys.stdout)
279 elog = openlog(ui.config('web', 'errorlog', '-'), sys.stderr)
291 elog = openlog(ui.config('web', 'errorlog', '-'), sys.stderr)
280 self.accesslog = alog
292 self.accesslog = alog
281 self.errorlog = elog
293 self.errorlog = elog
282
294
283 self.addr, self.port = self.socket.getsockname()[0:2]
295 self.addr, self.port = self.socket.getsockname()[0:2]
284 self.fqaddr = socket.getfqdn(addr[0])
296 self.fqaddr = socket.getfqdn(addr[0])
285
297
286 class IPv6HTTPServer(MercurialHTTPServer):
298 class IPv6HTTPServer(MercurialHTTPServer):
287 address_family = getattr(socket, 'AF_INET6', None)
299 address_family = getattr(socket, 'AF_INET6', None)
288 def __init__(self, *args, **kwargs):
300 def __init__(self, *args, **kwargs):
289 if self.address_family is None:
301 if self.address_family is None:
290 raise error.RepoError(_('IPv6 is not available on this system'))
302 raise error.RepoError(_('IPv6 is not available on this system'))
291 super(IPv6HTTPServer, self).__init__(*args, **kwargs)
303 super(IPv6HTTPServer, self).__init__(*args, **kwargs)
292
304
293 def create_server(ui, app):
305 def create_server(ui, app):
294
306
295 if ui.config('web', 'certificate'):
307 if ui.config('web', 'certificate'):
296 if sys.version_info >= (2, 6):
308 if sys.version_info >= (2, 6):
297 handler = _httprequesthandlerssl
309 handler = _httprequesthandlerssl
298 else:
310 else:
299 handler = _httprequesthandleropenssl
311 handler = _httprequesthandleropenssl
300 else:
312 else:
301 handler = _httprequesthandler
313 handler = _httprequesthandler
302
314
303 if ui.configbool('web', 'ipv6'):
315 if ui.configbool('web', 'ipv6'):
304 cls = IPv6HTTPServer
316 cls = IPv6HTTPServer
305 else:
317 else:
306 cls = MercurialHTTPServer
318 cls = MercurialHTTPServer
307
319
308 # ugly hack due to python issue5853 (for threaded use)
320 # ugly hack due to python issue5853 (for threaded use)
309 import mimetypes; mimetypes.init()
321 import mimetypes; mimetypes.init()
310
322
311 address = ui.config('web', 'address', '')
323 address = ui.config('web', 'address', '')
312 port = util.getport(ui.config('web', 'port', 8000))
324 port = util.getport(ui.config('web', 'port', 8000))
313 try:
325 try:
314 return cls(ui, app, (address, port), handler)
326 return cls(ui, app, (address, port), handler)
315 except socket.error, inst:
327 except socket.error, inst:
316 raise util.Abort(_("cannot start server at '%s:%d': %s")
328 raise util.Abort(_("cannot start server at '%s:%d': %s")
317 % (address, port, inst.args[1]))
329 % (address, port, inst.args[1]))
@@ -1,281 +1,279 b''
1 Proper https client requires the built-in ssl from Python 2.6.
1 Proper https client requires the built-in ssl from Python 2.6.
2
2
3 $ "$TESTDIR/hghave" serve ssl || exit 80
3 $ "$TESTDIR/hghave" serve ssl || exit 80
4
4
5 Certificates created with:
5 Certificates created with:
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
8 Can be dumped with:
8 Can be dumped with:
9 openssl x509 -in pub.pem -text
9 openssl x509 -in pub.pem -text
10
10
11 $ cat << EOT > priv.pem
11 $ cat << EOT > priv.pem
12 > -----BEGIN PRIVATE KEY-----
12 > -----BEGIN PRIVATE KEY-----
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
20 > HY8gUVkVRVs=
20 > HY8gUVkVRVs=
21 > -----END PRIVATE KEY-----
21 > -----END PRIVATE KEY-----
22 > EOT
22 > EOT
23
23
24 $ cat << EOT > pub.pem
24 $ cat << EOT > pub.pem
25 > -----BEGIN CERTIFICATE-----
25 > -----BEGIN CERTIFICATE-----
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
35 > -----END CERTIFICATE-----
35 > -----END CERTIFICATE-----
36 > EOT
36 > EOT
37 $ cat priv.pem pub.pem >> server.pem
37 $ cat priv.pem pub.pem >> server.pem
38 $ PRIV=`pwd`/server.pem
38 $ PRIV=`pwd`/server.pem
39
39
40 $ cat << EOT > pub-other.pem
40 $ cat << EOT > pub-other.pem
41 > -----BEGIN CERTIFICATE-----
41 > -----BEGIN CERTIFICATE-----
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
51 > -----END CERTIFICATE-----
51 > -----END CERTIFICATE-----
52 > EOT
52 > EOT
53
53
54 pub.pem patched with other notBefore / notAfter:
54 pub.pem patched with other notBefore / notAfter:
55
55
56 $ cat << EOT > pub-not-yet.pem
56 $ cat << EOT > pub-not-yet.pem
57 > -----BEGIN CERTIFICATE-----
57 > -----BEGIN CERTIFICATE-----
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
66 > -----END CERTIFICATE-----
66 > -----END CERTIFICATE-----
67 > EOT
67 > EOT
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
69
69
70 $ cat << EOT > pub-expired.pem
70 $ cat << EOT > pub-expired.pem
71 > -----BEGIN CERTIFICATE-----
71 > -----BEGIN CERTIFICATE-----
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
80 > -----END CERTIFICATE-----
80 > -----END CERTIFICATE-----
81 > EOT
81 > EOT
82 $ cat priv.pem pub-expired.pem > server-expired.pem
82 $ cat priv.pem pub-expired.pem > server-expired.pem
83
83
84 $ hg init test
84 $ hg init test
85 $ cd test
85 $ cd test
86 $ echo foo>foo
86 $ echo foo>foo
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
88 $ echo foo>foo.d/foo
88 $ echo foo>foo.d/foo
89 $ echo bar>foo.d/bAr.hg.d/BaR
89 $ echo bar>foo.d/bAr.hg.d/BaR
90 $ echo bar>foo.d/baR.d.hg/bAR
90 $ echo bar>foo.d/baR.d.hg/bAR
91 $ hg commit -A -m 1
91 $ hg commit -A -m 1
92 adding foo
92 adding foo
93 adding foo.d/bAr.hg.d/BaR
93 adding foo.d/bAr.hg.d/BaR
94 adding foo.d/baR.d.hg/bAR
94 adding foo.d/baR.d.hg/bAR
95 adding foo.d/foo
95 adding foo.d/foo
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
97 $ cat ../hg0.pid >> $DAEMON_PIDS
97 $ cat ../hg0.pid >> $DAEMON_PIDS
98
98
99 cacert not found
99 cacert not found
100
100
101 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
101 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
102 abort: could not find web.cacerts: no-such.pem
102 abort: could not find web.cacerts: no-such.pem
103 [255]
103 [255]
104
104
105 Test server address cannot be reused
105 Test server address cannot be reused
106
106
107 #if windows
107 #if windows
108 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
108 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
109 abort: cannot start server at ':$HGPORT': (glob)
109 abort: cannot start server at ':$HGPORT': (glob)
110 [255]
110 [255]
111 #else
111 #else
112 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
112 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
113 abort: cannot start server at ':$HGPORT': Address already in use
113 abort: cannot start server at ':$HGPORT': Address already in use
114 [255]
114 [255]
115 #endif
115 #endif
116 $ cd ..
116 $ cd ..
117
117
118 clone via pull
118 clone via pull
119
119
120 $ hg clone https://localhost:$HGPORT/ copy-pull
120 $ hg clone https://localhost:$HGPORT/ copy-pull
121 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
121 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
122 requesting all changes
122 requesting all changes
123 adding changesets
123 adding changesets
124 adding manifests
124 adding manifests
125 adding file changes
125 adding file changes
126 added 1 changesets with 4 changes to 4 files
126 added 1 changesets with 4 changes to 4 files
127 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
128 updating to branch default
127 updating to branch default
129 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
128 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
130 $ hg verify -R copy-pull
129 $ hg verify -R copy-pull
131 checking changesets
130 checking changesets
132 checking manifests
131 checking manifests
133 crosschecking files in changesets and manifests
132 crosschecking files in changesets and manifests
134 checking files
133 checking files
135 4 files, 1 changesets, 4 total revisions
134 4 files, 1 changesets, 4 total revisions
136 $ cd test
135 $ cd test
137 $ echo bar > bar
136 $ echo bar > bar
138 $ hg commit -A -d '1 0' -m 2
137 $ hg commit -A -d '1 0' -m 2
139 adding bar
138 adding bar
140 $ cd ..
139 $ cd ..
141
140
142 pull without cacert
141 pull without cacert
143
142
144 $ cd copy-pull
143 $ cd copy-pull
145 $ echo '[hooks]' >> .hg/hgrc
144 $ echo '[hooks]' >> .hg/hgrc
146 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
145 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
147 $ hg pull
146 $ hg pull
148 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
147 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
149 pulling from https://localhost:$HGPORT/
148 pulling from https://localhost:$HGPORT/
150 searching for changes
149 searching for changes
151 adding changesets
150 adding changesets
152 adding manifests
151 adding manifests
153 adding file changes
152 adding file changes
154 added 1 changesets with 1 changes to 1 files
153 added 1 changesets with 1 changes to 1 files
155 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
156 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
154 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
157 (run 'hg update' to get a working copy)
155 (run 'hg update' to get a working copy)
158 $ cd ..
156 $ cd ..
159
157
160 cacert configured in local repo
158 cacert configured in local repo
161
159
162 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
160 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
163 $ echo "[web]" >> copy-pull/.hg/hgrc
161 $ echo "[web]" >> copy-pull/.hg/hgrc
164 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
162 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
165 $ hg -R copy-pull pull --traceback
163 $ hg -R copy-pull pull --traceback
166 pulling from https://localhost:$HGPORT/
164 pulling from https://localhost:$HGPORT/
167 searching for changes
165 searching for changes
168 no changes found
166 no changes found
169 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
167 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
170
168
171 cacert configured globally, also testing expansion of environment
169 cacert configured globally, also testing expansion of environment
172 variables in the filename
170 variables in the filename
173
171
174 $ echo "[web]" >> $HGRCPATH
172 $ echo "[web]" >> $HGRCPATH
175 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
173 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
176 $ P=`pwd` hg -R copy-pull pull
174 $ P=`pwd` hg -R copy-pull pull
177 pulling from https://localhost:$HGPORT/
175 pulling from https://localhost:$HGPORT/
178 searching for changes
176 searching for changes
179 no changes found
177 no changes found
180 $ P=`pwd` hg -R copy-pull pull --insecure
178 $ P=`pwd` hg -R copy-pull pull --insecure
181 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
179 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
182 pulling from https://localhost:$HGPORT/
180 pulling from https://localhost:$HGPORT/
183 searching for changes
181 searching for changes
184 no changes found
182 no changes found
185
183
186 cacert mismatch
184 cacert mismatch
187
185
188 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
186 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
189 abort: 127.0.0.1 certificate error: certificate is for localhost
187 abort: 127.0.0.1 certificate error: certificate is for localhost
190 (configure hostfingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca or use --insecure to connect insecurely)
188 (configure hostfingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca or use --insecure to connect insecurely)
191 [255]
189 [255]
192 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
190 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
193 warning: 127.0.0.1 certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
191 warning: 127.0.0.1 certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
194 pulling from https://127.0.0.1:$HGPORT/
192 pulling from https://127.0.0.1:$HGPORT/
195 searching for changes
193 searching for changes
196 no changes found
194 no changes found
197 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
195 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
198 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
196 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
199 [255]
197 [255]
200 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
198 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
201 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
199 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
202 pulling from https://localhost:$HGPORT/
200 pulling from https://localhost:$HGPORT/
203 searching for changes
201 searching for changes
204 no changes found
202 no changes found
205
203
206 Test server cert which isn't valid yet
204 Test server cert which isn't valid yet
207
205
208 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
206 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
209 $ cat hg1.pid >> $DAEMON_PIDS
207 $ cat hg1.pid >> $DAEMON_PIDS
210 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
208 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
211 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
209 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
212 [255]
210 [255]
213
211
214 Test server cert which no longer is valid
212 Test server cert which no longer is valid
215
213
216 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
214 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
217 $ cat hg2.pid >> $DAEMON_PIDS
215 $ cat hg2.pid >> $DAEMON_PIDS
218 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
216 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
219 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
217 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
220 [255]
218 [255]
221
219
222 Fingerprints
220 Fingerprints
223
221
224 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
222 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
225 $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
223 $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
226 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
224 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
227
225
228 - works without cacerts
226 - works without cacerts
229 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
227 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
230 5fed3813f7f5
228 5fed3813f7f5
231
229
232 - fails when cert doesn't match hostname (port is ignored)
230 - fails when cert doesn't match hostname (port is ignored)
233 $ hg -R copy-pull id https://localhost:$HGPORT1/
231 $ hg -R copy-pull id https://localhost:$HGPORT1/
234 abort: certificate for localhost has unexpected fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
232 abort: certificate for localhost has unexpected fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
235 (check hostfingerprint configuration)
233 (check hostfingerprint configuration)
236 [255]
234 [255]
237
235
238 - ignores that certificate doesn't match hostname
236 - ignores that certificate doesn't match hostname
239 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
237 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
240 5fed3813f7f5
238 5fed3813f7f5
241
239
242 $ while kill `cat hg1.pid` 2>/dev/null; do sleep 0; done
240 $ while kill `cat hg1.pid` 2>/dev/null; do sleep 0; done
243
241
244 Prepare for connecting through proxy
242 Prepare for connecting through proxy
245
243
246 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
244 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
247 $ while [ ! -f proxy.pid ]; do sleep 0; done
245 $ while [ ! -f proxy.pid ]; do sleep 0; done
248 $ cat proxy.pid >> $DAEMON_PIDS
246 $ cat proxy.pid >> $DAEMON_PIDS
249
247
250 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
248 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
251 $ echo "always=True" >> copy-pull/.hg/hgrc
249 $ echo "always=True" >> copy-pull/.hg/hgrc
252 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
250 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
253 $ echo "localhost =" >> copy-pull/.hg/hgrc
251 $ echo "localhost =" >> copy-pull/.hg/hgrc
254
252
255 Test unvalidated https through proxy
253 Test unvalidated https through proxy
256
254
257 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
255 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
258 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
256 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
259 pulling from https://localhost:$HGPORT/
257 pulling from https://localhost:$HGPORT/
260 searching for changes
258 searching for changes
261 no changes found
259 no changes found
262
260
263 Test https with cacert and fingerprint through proxy
261 Test https with cacert and fingerprint through proxy
264
262
265 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
263 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
266 pulling from https://localhost:$HGPORT/
264 pulling from https://localhost:$HGPORT/
267 searching for changes
265 searching for changes
268 no changes found
266 no changes found
269 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
267 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
270 pulling from https://127.0.0.1:$HGPORT/
268 pulling from https://127.0.0.1:$HGPORT/
271 searching for changes
269 searching for changes
272 no changes found
270 no changes found
273
271
274 Test https with cert problems through proxy
272 Test https with cert problems through proxy
275
273
276 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
274 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
277 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
275 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
278 [255]
276 [255]
279 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
277 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
280 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
278 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
281 [255]
279 [255]
General Comments 0
You need to be logged in to leave comments. Login now