##// END OF EJS Templates
tests: use 'do sleep 0' instead of 'do true', also on first line of command...
Mads Kiilerich -
r16496:abbabbbe stable
parent child Browse files
Show More
@@ -1,438 +1,437 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # check-code - a style and portability checker for Mercurial
4 4 #
5 5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 import re, glob, os, sys
11 11 import keyword
12 12 import optparse
13 13
14 14 def repquote(m):
15 15 t = re.sub(r"\w", "x", m.group('text'))
16 16 t = re.sub(r"[^\s\nx]", "o", t)
17 17 return m.group('quote') + t + m.group('quote')
18 18
19 19 def reppython(m):
20 20 comment = m.group('comment')
21 21 if comment:
22 22 return "#" * len(comment)
23 23 return repquote(m)
24 24
25 25 def repcomment(m):
26 26 return m.group(1) + "#" * len(m.group(2))
27 27
28 28 def repccomment(m):
29 29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
30 30 return m.group(1) + t + "*/"
31 31
32 32 def repcallspaces(m):
33 33 t = re.sub(r"\n\s+", "\n", m.group(2))
34 34 return m.group(1) + t
35 35
36 36 def repinclude(m):
37 37 return m.group(1) + "<foo>"
38 38
39 39 def rephere(m):
40 40 t = re.sub(r"\S", "x", m.group(2))
41 41 return m.group(1) + t
42 42
43 43
44 44 testpats = [
45 45 [
46 46 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
47 47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
48 48 (r'^function', "don't use 'function', use old style"),
49 49 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
50 50 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
51 51 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
52 52 (r'echo -n', "don't use 'echo -n', use printf"),
53 53 (r'^diff.*-\w*N', "don't use 'diff -N'"),
54 54 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
55 55 (r'head -c', "don't use 'head -c', use 'dd'"),
56 56 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
57 57 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
58 58 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
59 59 (r'printf.*\\x', "don't use printf \\x, use Python"),
60 60 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
61 61 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
62 62 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
63 63 "use egrep for extended grep syntax"),
64 64 (r'/bin/', "don't use explicit paths for tools"),
65 65 (r'\$PWD', "don't use $PWD, use `pwd`"),
66 66 (r'[^\n]\Z', "no trailing newline"),
67 67 (r'export.*=', "don't export and assign at once"),
68 68 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
69 69 (r'^source\b', "don't use 'source', use '.'"),
70 70 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
71 71 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
72 72 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
73 73 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
74 74 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
75 75 (r'^alias\b.*=', "don't use alias, use a function"),
76 76 (r'if\s*!', "don't use '!' to negate exit status"),
77 77 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
78 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
78 79 ],
79 80 # warnings
80 81 []
81 82 ]
82 83
83 84 testfilters = [
84 85 (r"( *)(#([^\n]*\S)?)", repcomment),
85 86 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
86 87 ]
87 88
88 89 uprefix = r"^ \$ "
89 90 uprefixc = r"^ > "
90 91 utestpats = [
91 92 [
92 93 (r'^(\S| $ ).*(\S[ \t]+|^[ \t]+)\n', "trailing whitespace on non-output"),
93 94 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
94 95 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
95 96 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
96 97 (uprefix + r'.*\|\| echo.*(fail|error)',
97 98 "explicit exit code checks unnecessary"),
98 99 (uprefix + r'set -e', "don't use set -e"),
99 100 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
100 101 (uprefixc + r'( *)\t', "don't use tabs to indent"),
101 (uprefixc + r'.*do\s*true;\s*done',
102 "don't use true as loop body, use sleep 0"),
103 102 ],
104 103 # warnings
105 104 []
106 105 ]
107 106
108 107 for i in [0, 1]:
109 108 for p, m in testpats[i]:
110 109 if p.startswith(r'^'):
111 110 p = r"^ \$ (%s)" % p[1:]
112 111 else:
113 112 p = r"^ \$ .*(%s)" % p
114 113 utestpats[i].append((p, m))
115 114
116 115 utestfilters = [
117 116 (r"( *)(#([^\n]*\S)?)", repcomment),
118 117 ]
119 118
120 119 pypats = [
121 120 [
122 121 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
123 122 "tuple parameter unpacking not available in Python 3+"),
124 123 (r'lambda\s*\(.*,.*\)',
125 124 "tuple parameter unpacking not available in Python 3+"),
126 125 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
127 126 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
128 127 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
129 128 (r'^\s*\t', "don't use tabs"),
130 129 (r'\S;\s*\n', "semicolon"),
131 130 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
132 131 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
133 132 (r'\w,\w', "missing whitespace after ,"),
134 133 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
135 134 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
136 135 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
137 136 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'),
138 137 (r'.{85}', "line too long"),
139 138 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
140 139 (r'[^\n]\Z', "no trailing newline"),
141 140 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
142 141 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"),
143 142 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
144 143 "don't use camelcase in identifiers"),
145 144 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
146 145 "linebreak after :"),
147 146 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
148 147 (r'class\s[^( \n]+\(\):',
149 148 "class foo() not available in Python 2.4, use class foo(object)"),
150 149 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
151 150 "Python keyword is not a function"),
152 151 (r',]', "unneeded trailing ',' in list"),
153 152 # (r'class\s[A-Z][^\(]*\((?!Exception)',
154 153 # "don't capitalize non-exception classes"),
155 154 # (r'in range\(', "use xrange"),
156 155 # (r'^\s*print\s+', "avoid using print in core and extensions"),
157 156 (r'[\x80-\xff]', "non-ASCII character literal"),
158 157 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
159 158 (r'^\s*with\s+', "with not available in Python 2.4"),
160 159 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
161 160 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
162 161 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
163 162 (r'(?<!def)\s+(any|all|format)\(',
164 163 "any/all/format not available in Python 2.4"),
165 164 (r'(?<!def)\s+(callable)\(',
166 165 "callable not available in Python 3, use getattr(f, '__call__', None)"),
167 166 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
168 167 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
169 168 "gratuitous whitespace after Python keyword"),
170 169 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
171 170 # (r'\s\s=', "gratuitous whitespace before ="),
172 171 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
173 172 "missing whitespace around operator"),
174 173 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s',
175 174 "missing whitespace around operator"),
176 175 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
177 176 "missing whitespace around operator"),
178 177 (r'[^^+=*/!<>&| -](\s=|=\s)[^= ]',
179 178 "wrong whitespace around ="),
180 179 (r'raise Exception', "don't raise generic exceptions"),
181 180 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
182 181 (r' [=!]=\s+(True|False|None)',
183 182 "comparison with singleton, use 'is' or 'is not' instead"),
184 183 (r'^\s*(while|if) [01]:',
185 184 "use True/False for constant Boolean expression"),
186 185 (r'(?:(?<!def)\s+|\()hasattr',
187 186 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
188 187 (r'opener\([^)]*\).read\(',
189 188 "use opener.read() instead"),
190 189 (r'BaseException', 'not in Py2.4, use Exception'),
191 190 (r'os\.path\.relpath', 'os.path.relpath is not in Py2.5'),
192 191 (r'opener\([^)]*\).write\(',
193 192 "use opener.write() instead"),
194 193 (r'[\s\(](open|file)\([^)]*\)\.read\(',
195 194 "use util.readfile() instead"),
196 195 (r'[\s\(](open|file)\([^)]*\)\.write\(',
197 196 "use util.readfile() instead"),
198 197 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
199 198 "always assign an opened file to a variable, and close it afterwards"),
200 199 (r'[\s\(](open|file)\([^)]*\)\.',
201 200 "always assign an opened file to a variable, and close it afterwards"),
202 201 (r'(?i)descendent', "the proper spelling is descendAnt"),
203 202 (r'\.debug\(\_', "don't mark debug messages for translation"),
204 203 ],
205 204 # warnings
206 205 [
207 206 (r'.{81}', "warning: line over 80 characters"),
208 207 (r'^\s*except:$', "warning: naked except clause"),
209 208 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
210 209 "warning: unwrapped ui message"),
211 210 ]
212 211 ]
213 212
214 213 pyfilters = [
215 214 (r"""(?msx)(?P<comment>\#.*?$)|
216 215 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
217 216 (?P<text>(([^\\]|\\.)*?))
218 217 (?P=quote))""", reppython),
219 218 ]
220 219
221 220 cpats = [
222 221 [
223 222 (r'//', "don't use //-style comments"),
224 223 (r'^ ', "don't use spaces to indent"),
225 224 (r'\S\t', "don't use tabs except for indent"),
226 225 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
227 226 (r'.{85}', "line too long"),
228 227 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
229 228 (r'return\(', "return is not a function"),
230 229 (r' ;', "no space before ;"),
231 230 (r'\w+\* \w+', "use int *foo, not int* foo"),
232 231 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
233 232 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
234 233 (r'\w,\w', "missing whitespace after ,"),
235 234 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
236 235 (r'^#\s+\w', "use #foo, not # foo"),
237 236 (r'[^\n]\Z', "no trailing newline"),
238 237 (r'^\s*#import\b', "use only #include in standard C code"),
239 238 ],
240 239 # warnings
241 240 []
242 241 ]
243 242
244 243 cfilters = [
245 244 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
246 245 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
247 246 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
248 247 (r'(\()([^)]+\))', repcallspaces),
249 248 ]
250 249
251 250 inutilpats = [
252 251 [
253 252 (r'\bui\.', "don't use ui in util"),
254 253 ],
255 254 # warnings
256 255 []
257 256 ]
258 257
259 258 inrevlogpats = [
260 259 [
261 260 (r'\brepo\.', "don't use repo in revlog"),
262 261 ],
263 262 # warnings
264 263 []
265 264 ]
266 265
267 266 checks = [
268 267 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
269 268 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
270 269 ('c', r'.*\.c$', cfilters, cpats),
271 270 ('unified test', r'.*\.t$', utestfilters, utestpats),
272 271 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
273 272 inrevlogpats),
274 273 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
275 274 inutilpats),
276 275 ]
277 276
278 277 class norepeatlogger(object):
279 278 def __init__(self):
280 279 self._lastseen = None
281 280
282 281 def log(self, fname, lineno, line, msg, blame):
283 282 """print error related a to given line of a given file.
284 283
285 284 The faulty line will also be printed but only once in the case
286 285 of multiple errors.
287 286
288 287 :fname: filename
289 288 :lineno: line number
290 289 :line: actual content of the line
291 290 :msg: error message
292 291 """
293 292 msgid = fname, lineno, line
294 293 if msgid != self._lastseen:
295 294 if blame:
296 295 print "%s:%d (%s):" % (fname, lineno, blame)
297 296 else:
298 297 print "%s:%d:" % (fname, lineno)
299 298 print " > %s" % line
300 299 self._lastseen = msgid
301 300 print " " + msg
302 301
303 302 _defaultlogger = norepeatlogger()
304 303
305 304 def getblame(f):
306 305 lines = []
307 306 for l in os.popen('hg annotate -un %s' % f):
308 307 start, line = l.split(':', 1)
309 308 user, rev = start.split()
310 309 lines.append((line[1:-1], user, rev))
311 310 return lines
312 311
313 312 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
314 313 blame=False, debug=False, lineno=True):
315 314 """checks style and portability of a given file
316 315
317 316 :f: filepath
318 317 :logfunc: function used to report error
319 318 logfunc(filename, linenumber, linecontent, errormessage)
320 319 :maxerr: number of error to display before arborting.
321 320 Set to false (default) to report all errors
322 321
323 322 return True if no error is found, False otherwise.
324 323 """
325 324 blamecache = None
326 325 result = True
327 326 for name, match, filters, pats in checks:
328 327 if debug:
329 328 print name, f
330 329 fc = 0
331 330 if not re.match(match, f):
332 331 if debug:
333 332 print "Skipping %s for %s it doesn't match %s" % (
334 333 name, match, f)
335 334 continue
336 335 fp = open(f)
337 336 pre = post = fp.read()
338 337 fp.close()
339 338 if "no-" + "check-code" in pre:
340 339 if debug:
341 340 print "Skipping %s for %s it has no- and check-code" % (
342 341 name, f)
343 342 break
344 343 for p, r in filters:
345 344 post = re.sub(p, r, post)
346 345 if warnings:
347 346 pats = pats[0] + pats[1]
348 347 else:
349 348 pats = pats[0]
350 349 # print post # uncomment to show filtered version
351 350
352 351 if debug:
353 352 print "Checking %s for %s" % (name, f)
354 353
355 354 prelines = None
356 355 errors = []
357 356 for p, msg in pats:
358 357 # fix-up regexes for multiline searches
359 358 po = p
360 359 # \s doesn't match \n
361 360 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
362 361 # [^...] doesn't match newline
363 362 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
364 363
365 364 #print po, '=>', p
366 365
367 366 pos = 0
368 367 n = 0
369 368 for m in re.finditer(p, post, re.MULTILINE):
370 369 if prelines is None:
371 370 prelines = pre.splitlines()
372 371 postlines = post.splitlines(True)
373 372
374 373 start = m.start()
375 374 while n < len(postlines):
376 375 step = len(postlines[n])
377 376 if pos + step > start:
378 377 break
379 378 pos += step
380 379 n += 1
381 380 l = prelines[n]
382 381
383 382 if "check-code" + "-ignore" in l:
384 383 if debug:
385 384 print "Skipping %s for %s:%s (check-code -ignore)" % (
386 385 name, f, n)
387 386 continue
388 387 bd = ""
389 388 if blame:
390 389 bd = 'working directory'
391 390 if not blamecache:
392 391 blamecache = getblame(f)
393 392 if n < len(blamecache):
394 393 bl, bu, br = blamecache[n]
395 394 if bl == l:
396 395 bd = '%s@%s' % (bu, br)
397 396 errors.append((f, lineno and n + 1, l, msg, bd))
398 397 result = False
399 398
400 399 errors.sort()
401 400 for e in errors:
402 401 logfunc(*e)
403 402 fc += 1
404 403 if maxerr and fc >= maxerr:
405 404 print " (too many errors, giving up)"
406 405 break
407 406
408 407 return result
409 408
410 409 if __name__ == "__main__":
411 410 parser = optparse.OptionParser("%prog [options] [files]")
412 411 parser.add_option("-w", "--warnings", action="store_true",
413 412 help="include warning-level checks")
414 413 parser.add_option("-p", "--per-file", type="int",
415 414 help="max warnings per file")
416 415 parser.add_option("-b", "--blame", action="store_true",
417 416 help="use annotate to generate blame info")
418 417 parser.add_option("", "--debug", action="store_true",
419 418 help="show debug information")
420 419 parser.add_option("", "--nolineno", action="store_false",
421 420 dest='lineno', help="don't show line numbers")
422 421
423 422 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
424 423 lineno=True)
425 424 (options, args) = parser.parse_args()
426 425
427 426 if len(args) == 0:
428 427 check = glob.glob("*")
429 428 else:
430 429 check = args
431 430
432 431 ret = 0
433 432 for f in check:
434 433 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
435 434 blame=options.blame, debug=options.debug,
436 435 lineno=options.lineno):
437 436 ret = 1
438 437 sys.exit(ret)
@@ -1,27 +1,27 b''
1 1 $ "$TESTDIR/hghave" serve || exit 80
2 2
3 3 $ hg clone http://localhost:$HGPORT/ copy
4 4 abort: error: Connection refused
5 5 [255]
6 6
7 7 $ test -d copy
8 8 [1]
9 9
10 10 $ cat > dumb.py <<EOF
11 11 > import BaseHTTPServer, SimpleHTTPServer, os, signal
12 12 > def run(server_class=BaseHTTPServer.HTTPServer,
13 13 > handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
14 14 > server_address = ('localhost', int(os.environ['HGPORT']))
15 15 > httpd = server_class(server_address, handler_class)
16 16 > open("listening", "w")
17 17 > httpd.handle_request()
18 18 > run()
19 19 > EOF
20 20
21 21 $ python dumb.py 2> log &
22 22 $ P=$!
23 $ while [ ! -f listening ]; do true; done
23 $ while [ ! -f listening ]; do sleep 0; done
24 24 $ hg clone http://localhost:$HGPORT/foo copy2
25 25 abort: HTTP Error 404: * (glob)
26 26 [255]
27 27 $ wait $P
@@ -1,58 +1,58 b''
1 1 $ "$TESTDIR/hghave" serve || exit 80
2 2
3 3 Test raw style of hgweb
4 4
5 5 $ hg init test
6 6 $ cd test
7 7 $ mkdir sub
8 8 $ cat >'sub/some "text".txt' <<ENDSOME
9 9 > This is just some random text
10 10 > that will go inside the file and take a few lines.
11 11 > It is very boring to read, but computers don't
12 12 > care about things like that.
13 13 > ENDSOME
14 14 $ hg add 'sub/some "text".txt'
15 15 warning: filename contains '"', which is reserved on Windows: 'sub/some "text".txt'
16 16 $ hg commit -d "1 0" -m "Just some text"
17 17
18 18 $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid
19 19
20 20 $ cat hg.pid >> $DAEMON_PIDS
21 21 $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
22 22
23 $ while kill `cat hg.pid` 2>/dev/null; do true; done
23 $ while kill `cat hg.pid` 2>/dev/null; do sleep 0; done
24 24
25 25 $ cat getoutput.txt
26 26 200 Script output follows
27 27 content-type: application/binary
28 28 content-length: 157
29 29 content-disposition: inline; filename="some \"text\".txt"
30 30
31 31 This is just some random text
32 32 that will go inside the file and take a few lines.
33 33 It is very boring to read, but computers don't
34 34 care about things like that.
35 35 $ cat access.log error.log
36 36 127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
37 37
38 38 $ rm access.log error.log
39 39 $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid \
40 40 > --config web.guessmime=True
41 41
42 42 $ cat hg.pid >> $DAEMON_PIDS
43 43 $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
44 $ while kill `cat hg.pid` 2>/dev/null; do true; done
44 $ while kill `cat hg.pid` 2>/dev/null; do sleep 0; done
45 45
46 46 $ cat getoutput.txt
47 47 200 Script output follows
48 48 content-type: text/plain; charset="ascii"
49 49 content-length: 157
50 50 content-disposition: inline; filename="some \"text\".txt"
51 51
52 52 This is just some random text
53 53 that will go inside the file and take a few lines.
54 54 It is very boring to read, but computers don't
55 55 care about things like that.
56 56 $ cat access.log error.log
57 57 127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
58 58
@@ -1,124 +1,124 b''
1 1 $ "$TESTDIR/hghave" serve || exit 80
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo a > a
6 6 $ hg ci -Ama -d '1123456789 0'
7 7 adding a
8 8 $ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
9 9 $ cat hg.pid >> $DAEMON_PIDS
10 10 $ cd ..
11 11 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
12 $ while [ ! -f proxy.pid ]; do true; done
12 $ while [ ! -f proxy.pid ]; do sleep 0; done
13 13 $ cat proxy.pid >> $DAEMON_PIDS
14 14
15 15 url for proxy, stream
16 16
17 17 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b
18 18 streaming all changes
19 19 3 files to transfer, 303 bytes of data
20 20 transferred * bytes in * seconds (*/sec) (glob)
21 21 updating to branch default
22 22 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 23 $ cd b
24 24 $ hg verify
25 25 checking changesets
26 26 checking manifests
27 27 crosschecking files in changesets and manifests
28 28 checking files
29 29 1 files, 1 changesets, 1 total revisions
30 30 $ cd ..
31 31
32 32 url for proxy, pull
33 33
34 34 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
35 35 requesting all changes
36 36 adding changesets
37 37 adding manifests
38 38 adding file changes
39 39 added 1 changesets with 1 changes to 1 files
40 40 updating to branch default
41 41 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 42 $ cd b-pull
43 43 $ hg verify
44 44 checking changesets
45 45 checking manifests
46 46 crosschecking files in changesets and manifests
47 47 checking files
48 48 1 files, 1 changesets, 1 total revisions
49 49 $ cd ..
50 50
51 51 host:port for proxy
52 52
53 53 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
54 54 requesting all changes
55 55 adding changesets
56 56 adding manifests
57 57 adding file changes
58 58 added 1 changesets with 1 changes to 1 files
59 59 updating to branch default
60 60 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 61
62 62 proxy url with user name and password
63 63
64 64 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
65 65 requesting all changes
66 66 adding changesets
67 67 adding manifests
68 68 adding file changes
69 69 added 1 changesets with 1 changes to 1 files
70 70 updating to branch default
71 71 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
72 72
73 73 url with user name and password
74 74
75 75 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
76 76 requesting all changes
77 77 adding changesets
78 78 adding manifests
79 79 adding file changes
80 80 added 1 changesets with 1 changes to 1 files
81 81 updating to branch default
82 82 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 83
84 84 bad host:port for proxy
85 85
86 86 $ http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
87 87 abort: error: Connection refused
88 88 [255]
89 89
90 90 do not use the proxy if it is in the no list
91 91
92 92 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.no=localhost http://localhost:$HGPORT/ g
93 93 requesting all changes
94 94 adding changesets
95 95 adding manifests
96 96 adding file changes
97 97 added 1 changesets with 1 changes to 1 files
98 98 updating to branch default
99 99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 100 $ cat proxy.log
101 101 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
102 102 * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
103 103 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
104 104 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
105 105 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
106 106 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
107 107 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
108 108 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
109 109 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
110 110 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
111 111 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
112 112 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
113 113 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
114 114 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
115 115 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
116 116 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
117 117 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
118 118 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
119 119 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
120 120 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
121 121 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
122 122 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
123 123 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
124 124
@@ -1,275 +1,275 b''
1 1 Proper https client requires the built-in ssl from Python 2.6.
2 2
3 3 $ "$TESTDIR/hghave" serve ssl || exit 80
4 4
5 5 Certificates created with:
6 6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
7 7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
8 8 Can be dumped with:
9 9 openssl x509 -in pub.pem -text
10 10
11 11 $ cat << EOT > priv.pem
12 12 > -----BEGIN PRIVATE KEY-----
13 13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
14 14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
15 15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
16 16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
17 17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
18 18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
19 19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
20 20 > HY8gUVkVRVs=
21 21 > -----END PRIVATE KEY-----
22 22 > EOT
23 23
24 24 $ cat << EOT > pub.pem
25 25 > -----BEGIN CERTIFICATE-----
26 26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
27 27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
28 28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
29 29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
30 30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
31 31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
32 32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
33 33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
34 34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
35 35 > -----END CERTIFICATE-----
36 36 > EOT
37 37 $ cat priv.pem pub.pem >> server.pem
38 38 $ PRIV=`pwd`/server.pem
39 39
40 40 $ cat << EOT > pub-other.pem
41 41 > -----BEGIN CERTIFICATE-----
42 42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
43 43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
44 44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
45 45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
46 46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
47 47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
48 48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
49 49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
50 50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
51 51 > -----END CERTIFICATE-----
52 52 > EOT
53 53
54 54 pub.pem patched with other notBefore / notAfter:
55 55
56 56 $ cat << EOT > pub-not-yet.pem
57 57 > -----BEGIN CERTIFICATE-----
58 58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
59 59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
60 60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
61 61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
62 62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
63 63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
64 64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
65 65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
66 66 > -----END CERTIFICATE-----
67 67 > EOT
68 68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
69 69
70 70 $ cat << EOT > pub-expired.pem
71 71 > -----BEGIN CERTIFICATE-----
72 72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
73 73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
74 74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
75 75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
76 76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
77 77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
78 78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
79 79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
80 80 > -----END CERTIFICATE-----
81 81 > EOT
82 82 $ cat priv.pem pub-expired.pem > server-expired.pem
83 83
84 84 $ hg init test
85 85 $ cd test
86 86 $ echo foo>foo
87 87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
88 88 $ echo foo>foo.d/foo
89 89 $ echo bar>foo.d/bAr.hg.d/BaR
90 90 $ echo bar>foo.d/baR.d.hg/bAR
91 91 $ hg commit -A -m 1
92 92 adding foo
93 93 adding foo.d/bAr.hg.d/BaR
94 94 adding foo.d/baR.d.hg/bAR
95 95 adding foo.d/foo
96 96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
97 97 $ cat ../hg0.pid >> $DAEMON_PIDS
98 98
99 99 cacert not found
100 100
101 101 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
102 102 abort: could not find web.cacerts: no-such.pem
103 103 [255]
104 104
105 105 Test server address cannot be reused
106 106
107 107 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
108 108 abort: cannot start server at ':$HGPORT': Address already in use
109 109 [255]
110 110 $ cd ..
111 111
112 112 clone via pull
113 113
114 114 $ hg clone https://localhost:$HGPORT/ copy-pull
115 115 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)
116 116 requesting all changes
117 117 adding changesets
118 118 adding manifests
119 119 adding file changes
120 120 added 1 changesets with 4 changes to 4 files
121 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 122 updating to branch default
123 123 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 124 $ hg verify -R copy-pull
125 125 checking changesets
126 126 checking manifests
127 127 crosschecking files in changesets and manifests
128 128 checking files
129 129 4 files, 1 changesets, 4 total revisions
130 130 $ cd test
131 131 $ echo bar > bar
132 132 $ hg commit -A -d '1 0' -m 2
133 133 adding bar
134 134 $ cd ..
135 135
136 136 pull without cacert
137 137
138 138 $ cd copy-pull
139 139 $ echo '[hooks]' >> .hg/hgrc
140 140 $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc
141 141 $ hg pull
142 142 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)
143 143 pulling from https://localhost:$HGPORT/
144 144 searching for changes
145 145 adding changesets
146 146 adding manifests
147 147 adding file changes
148 148 added 1 changesets with 1 changes to 1 files
149 149 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)
150 150 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
151 151 (run 'hg update' to get a working copy)
152 152 $ cd ..
153 153
154 154 cacert configured in local repo
155 155
156 156 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
157 157 $ echo "[web]" >> copy-pull/.hg/hgrc
158 158 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
159 159 $ hg -R copy-pull pull --traceback
160 160 pulling from https://localhost:$HGPORT/
161 161 searching for changes
162 162 no changes found
163 163 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
164 164
165 165 cacert configured globally, also testing expansion of environment
166 166 variables in the filename
167 167
168 168 $ echo "[web]" >> $HGRCPATH
169 169 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
170 170 $ P=`pwd` hg -R copy-pull pull
171 171 pulling from https://localhost:$HGPORT/
172 172 searching for changes
173 173 no changes found
174 174 $ P=`pwd` hg -R copy-pull pull --insecure
175 175 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)
176 176 pulling from https://localhost:$HGPORT/
177 177 searching for changes
178 178 no changes found
179 179
180 180 cacert mismatch
181 181
182 182 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
183 183 abort: 127.0.0.1 certificate error: certificate is for localhost
184 184 (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)
185 185 [255]
186 186 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
187 187 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)
188 188 pulling from https://127.0.0.1:$HGPORT/
189 189 searching for changes
190 190 no changes found
191 191 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
192 192 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
193 193 [255]
194 194 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
195 195 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)
196 196 pulling from https://localhost:$HGPORT/
197 197 searching for changes
198 198 no changes found
199 199
200 200 Test server cert which isn't valid yet
201 201
202 202 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
203 203 $ cat hg1.pid >> $DAEMON_PIDS
204 204 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
205 205 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
206 206 [255]
207 207
208 208 Test server cert which no longer is valid
209 209
210 210 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
211 211 $ cat hg2.pid >> $DAEMON_PIDS
212 212 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
213 213 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
214 214 [255]
215 215
216 216 Fingerprints
217 217
218 218 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
219 219 $ 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
220 220 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
221 221
222 222 - works without cacerts
223 223 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
224 224 5fed3813f7f5
225 225
226 226 - fails when cert doesn't match hostname (port is ignored)
227 227 $ hg -R copy-pull id https://localhost:$HGPORT1/
228 228 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
229 229 (check hostfingerprint configuration)
230 230 [255]
231 231
232 232 - ignores that certificate doesn't match hostname
233 233 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
234 234 5fed3813f7f5
235 235
236 $ while kill `cat hg1.pid` 2>/dev/null; do true; done
236 $ while kill `cat hg1.pid` 2>/dev/null; do sleep 0; done
237 237
238 238 Prepare for connecting through proxy
239 239
240 240 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
241 $ while [ ! -f proxy.pid ]; do true; done
241 $ while [ ! -f proxy.pid ]; do sleep 0; done
242 242 $ cat proxy.pid >> $DAEMON_PIDS
243 243
244 244 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
245 245 $ echo "always=True" >> copy-pull/.hg/hgrc
246 246 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
247 247 $ echo "localhost =" >> copy-pull/.hg/hgrc
248 248
249 249 Test unvalidated https through proxy
250 250
251 251 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
252 252 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)
253 253 pulling from https://localhost:$HGPORT/
254 254 searching for changes
255 255 no changes found
256 256
257 257 Test https with cacert and fingerprint through proxy
258 258
259 259 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
260 260 pulling from https://localhost:$HGPORT/
261 261 searching for changes
262 262 no changes found
263 263 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
264 264 pulling from https://127.0.0.1:$HGPORT/
265 265 searching for changes
266 266 no changes found
267 267
268 268 Test https with cert problems through proxy
269 269
270 270 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
271 271 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
272 272 [255]
273 273 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
274 274 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
275 275 [255]
General Comments 0
You need to be logged in to leave comments. Login now