Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/debugcommands.py @ 37016:b6a7070e7663
debugcommands: support sending HTTP requests with debugwireproto
We implement an action that can issue an HTTP request. We can define
headers via arguments and specify a file to use for the HTTP request
body.
The request uses the HTTP peer's opener, which is already configured
for auth, etc. This is both good and bad. Good in that we get some
nice behavior out of the box. Bad in that some HTTP request headers
are added automatically.
Differential Revision: https://phab.mercurial-scm.org/D2841
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Tue, 13 Mar 2018 11:17:10 -0700 |
parents | fc8939825632 |
children | d3a9036d9ae9 |
comparison
equal
deleted
inserted
replaced
37015:fc8939825632 | 37016:b6a7070e7663 |
---|---|
12 import difflib | 12 import difflib |
13 import errno | 13 import errno |
14 import operator | 14 import operator |
15 import os | 15 import os |
16 import random | 16 import random |
17 import re | |
17 import socket | 18 import socket |
18 import ssl | 19 import ssl |
19 import stat | 20 import stat |
20 import string | 21 import string |
21 import subprocess | 22 import subprocess |
2690 | 2691 |
2691 Submit previously queued ``command`` blocks as a batch request. | 2692 Submit previously queued ``command`` blocks as a batch request. |
2692 | 2693 |
2693 This action MUST be paired with a ``batchbegin`` action. | 2694 This action MUST be paired with a ``batchbegin`` action. |
2694 | 2695 |
2696 httprequest <method> <path> | |
2697 --------------------------- | |
2698 | |
2699 (HTTP peer only) | |
2700 | |
2701 Send an HTTP request to the peer. | |
2702 | |
2703 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``. | |
2704 | |
2705 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request | |
2706 headers to add to the request. e.g. ``Accept: foo``. | |
2707 | |
2708 The following arguments are special: | |
2709 | |
2710 ``BODYFILE`` | |
2711 The content of the file defined as the value to this argument will be | |
2712 transferred verbatim as the HTTP request body. | |
2713 | |
2695 close | 2714 close |
2696 ----- | 2715 ----- |
2697 | 2716 |
2698 Close the connection to the server. | 2717 Close the connection to the server. |
2699 | 2718 |
2752 | 2771 |
2753 proc = None | 2772 proc = None |
2754 stdin = None | 2773 stdin = None |
2755 stdout = None | 2774 stdout = None |
2756 stderr = None | 2775 stderr = None |
2776 opener = None | |
2757 | 2777 |
2758 if opts['localssh']: | 2778 if opts['localssh']: |
2759 # We start the SSH server in its own process so there is process | 2779 # We start the SSH server in its own process so there is process |
2760 # separation. This prevents a whole class of potential bugs around | 2780 # separation. This prevents a whole class of potential bugs around |
2761 # shared state from interfering with server operation. | 2781 # shared state from interfering with server operation. |
2907 len(batchedcommands)) | 2927 len(batchedcommands)) |
2908 for i, chunk in enumerate(peer._submitbatch(batchedcommands)): | 2928 for i, chunk in enumerate(peer._submitbatch(batchedcommands)): |
2909 ui.status(_('response #%d: %s\n') % (i, util.escapedata(chunk))) | 2929 ui.status(_('response #%d: %s\n') % (i, util.escapedata(chunk))) |
2910 | 2930 |
2911 batchedcommands = None | 2931 batchedcommands = None |
2932 | |
2933 elif action.startswith('httprequest '): | |
2934 if not opener: | |
2935 raise error.Abort(_('cannot use httprequest without an HTTP ' | |
2936 'peer')) | |
2937 | |
2938 request = action.split(' ', 2) | |
2939 if len(request) != 3: | |
2940 raise error.Abort(_('invalid httprequest: expected format is ' | |
2941 '"httprequest <method> <path>')) | |
2942 | |
2943 method, httppath = request[1:] | |
2944 headers = {} | |
2945 body = None | |
2946 for line in lines: | |
2947 line = line.lstrip() | |
2948 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line) | |
2949 if m: | |
2950 headers[m.group(1)] = m.group(2) | |
2951 continue | |
2952 | |
2953 if line.startswith(b'BODYFILE '): | |
2954 with open(line.split(b' ', 1), 'rb') as fh: | |
2955 body = fh.read() | |
2956 else: | |
2957 raise error.Abort(_('unknown argument to httprequest: %s') % | |
2958 line) | |
2959 | |
2960 url = path + httppath | |
2961 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers) | |
2962 | |
2963 try: | |
2964 opener.open(req).read() | |
2965 except util.urlerr.urlerror as e: | |
2966 e.read() | |
2967 | |
2912 elif action == 'close': | 2968 elif action == 'close': |
2913 peer.close() | 2969 peer.close() |
2914 elif action == 'readavailable': | 2970 elif action == 'readavailable': |
2915 if not stdout or not stderr: | 2971 if not stdout or not stderr: |
2916 raise error.Abort(_('readavailable not available on this peer')) | 2972 raise error.Abort(_('readavailable not available on this peer')) |