annotate tests/dummysmtpd.py @ 37048:fc5e261915b9

wireproto: require POST for all HTTPv2 requests Wire protocol version 1 transfers argument data via request headers by default. This has historically caused problems because servers institute limits on the length of individual HTTP headers as well as the total size of all request headers. Mercurial servers can advertise the maximum length of an individual header. But there's no guarantee any intermediate HTTP agents will accept headers up to that length. In the existing wire protocol, server operators typically also key off the HTTP request method to implement authentication. For example, GET requests translate to read-only requests and can be allowed. But read-write commands must use POST and require authentication. This has typically worked because the only wire protocol commands that use POST modify the repo (e.g. the "unbundle" command). There is an experimental feature to enable clients to transmit argument data via POST request bodies. This is technically a better and more robust solution. But we can't enable it by default because of servers assuming POST means write access. In version 2 of the wire protocol, the permissions of a request are encoded in the URL. And with it being a new protocol in a new URL space, we're not constrained by backwards compatibility requirements. This commit adopts the technically superior mechanism of using HTTP request bodies to send argument data by requiring POST for all commands. Strictly speaking, it may be possible to send request bodies on GET requests. But my experience is that not all HTTP stacks support this. POST pretty much always works. Using POST for read-only operations does sacrifice some RESTful design purity. But this API cares about practicality, not about being in Roy T. Fielding's REST ivory tower. There's a chance we may relax this restriction in the future. But for now, I want to see how far we can get with a POST only API. Differential Revision: https://phab.mercurial-scm.org/D2837
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 13 Mar 2018 11:57:43 -0700
parents ed96d1116302
children 78f1899e4202
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
1 #!/usr/bin/env python
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
2
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
3 """dummy SMTP server for use in tests"""
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
4
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
5 from __future__ import absolute_import
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
6
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
7 import asyncore
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
8 import optparse
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
9 import smtpd
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
10 import ssl
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
11 import sys
35776
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
12 import traceback
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
13
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
14 from mercurial import (
36566
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
15 pycompat,
30506
d9d8d78e6bc9 server: move cmdutil.service() to new module (API)
Yuya Nishihara <yuya@tcha.org>
parents: 29556
diff changeset
16 server,
29556
1b8b6adb2365 tests: use sslutil.wrapserversocket()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29332
diff changeset
17 sslutil,
1b8b6adb2365 tests: use sslutil.wrapserversocket()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29332
diff changeset
18 ui as uimod,
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
19 )
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
20
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
21 def log(msg):
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
22 sys.stdout.write(msg)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
23 sys.stdout.flush()
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
24
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
25 class dummysmtpserver(smtpd.SMTPServer):
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
26 def __init__(self, localaddr):
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
27 smtpd.SMTPServer.__init__(self, localaddr, remoteaddr=None)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
28
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
29 def process_message(self, peer, mailfrom, rcpttos, data):
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
30 log('%s from=%s to=%s\n' % (peer[0], mailfrom, ', '.join(rcpttos)))
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
31
35776
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
32 def handle_error(self):
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
33 # On Windows, a bad SSL connection sometimes generates a WSAECONNRESET.
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
34 # The default handler will shutdown this server, and then both the
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
35 # current connection and subsequent ones fail on the client side with
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
36 # "No connection could be made because the target machine actively
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
37 # refused it". If we eat the error, then the client properly aborts in
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
38 # the expected way, and the server is available for subsequent requests.
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
39 traceback.print_exc()
75bae69747f0 dummysmtpd: don't die on client connection errors
Matt Harbison <matt_harbison@yahoo.com>
parents: 30559
diff changeset
40
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
41 class dummysmtpsecureserver(dummysmtpserver):
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
42 def __init__(self, localaddr, certfile):
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
43 dummysmtpserver.__init__(self, localaddr)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
44 self._certfile = certfile
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
45
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
46 def handle_accept(self):
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
47 pair = self.accept()
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
48 if not pair:
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
49 return
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
50 conn, addr = pair
30559
d83ca854fa21 ui: factor out ui.load() to create a ui without loading configs (API)
Yuya Nishihara <yuya@tcha.org>
parents: 30506
diff changeset
51 ui = uimod.ui.load()
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
52 try:
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
53 # wrap_socket() would block, but we don't care
29556
1b8b6adb2365 tests: use sslutil.wrapserversocket()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29332
diff changeset
54 conn = sslutil.wrapserversocket(conn, ui, certfile=self._certfile)
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
55 except ssl.SSLError:
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
56 log('%s ssl error\n' % addr[0])
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
57 conn.close()
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
58 return
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
59 smtpd.SMTPChannel(self, conn, addr)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
60
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
61 def run():
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
62 try:
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
63 asyncore.loop()
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
64 except KeyboardInterrupt:
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
65 pass
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
66
36566
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
67 def _encodestrsonly(v):
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
68 if isinstance(v, type(u'')):
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
69 return v.encode('ascii')
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
70 return v
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
71
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
72 def bytesvars(obj):
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
73 unidict = vars(obj)
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
74 bd = {k.encode('ascii'): _encodestrsonly(v) for k, v in unidict.items()}
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
75 if bd[b'daemon_postexec'] is not None:
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
76 bd[b'daemon_postexec'] = [
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
77 _encodestrsonly(v) for v in bd[b'daemon_postexec']]
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
78 return bd
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
79
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
80 def main():
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
81 op = optparse.OptionParser()
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
82 op.add_option('-d', '--daemon', action='store_true')
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
83 op.add_option('--daemon-postexec', action='append')
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
84 op.add_option('-p', '--port', type=int, default=8025)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
85 op.add_option('-a', '--address', default='localhost')
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
86 op.add_option('--pid-file', metavar='FILE')
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
87 op.add_option('--tls', choices=['none', 'smtps'], default='none')
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
88 op.add_option('--certificate', metavar='FILE')
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
89
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
90 opts, args = op.parse_args()
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
91 if opts.tls == 'smtps' and not opts.certificate:
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
92 op.error('--certificate must be specified')
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
93
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
94 addr = (opts.address, opts.port)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
95 def init():
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
96 if opts.tls == 'none':
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
97 dummysmtpserver(addr)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
98 else:
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
99 dummysmtpsecureserver(addr, opts.certificate)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
100 log('listening at %s:%d\n' % addr)
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
101
36566
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
102 server.runservice(
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
103 bytesvars(opts), initfn=init, runfn=run,
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
104 runargs=[pycompat.sysexecutable,
ed96d1116302 tests: help dummysmtpd work on python 3
Augie Fackler <augie@google.com>
parents: 35776
diff changeset
105 pycompat.fsencode(__file__)] + pycompat.sysargv[1:])
29332
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
106
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
107 if __name__ == '__main__':
2bb0ddd8267b tests: add dummy SMTP daemon for SSL tests
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
108 main()