Patchwork D2841: debugcommands: support sending HTTP requests with debugwireproto

login
register
mail settings
Submitter phabricator
Date March 20, 2018, 1:41 a.m.
Message ID <4909f71fc0a9ad2215a8ce9b4391af92@localhost.localdomain>
Download mbox | patch
Permalink /patch/29670/
State Not Applicable
Headers show

Comments

phabricator - March 20, 2018, 1:41 a.m.
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGb6a7070e7663: debugcommands: support sending HTTP requests with debugwireproto (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2841?vs=6995&id=7159

REVISION DETAIL
  https://phab.mercurial-scm.org/D2841

AFFECTED FILES
  mercurial/debugcommands.py
  tests/test-http-protocol.t

CHANGE DETAILS




To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel

Patch

diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t
--- a/tests/test-http-protocol.t
+++ b/tests/test-http-protocol.t
@@ -226,4 +226,39 @@ 
   s>     phases	
   response: bookmarks	\nnamespaces	\nphases	
 
+Same thing, but with "httprequest" command
+
+  $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
+  > httprequest GET ?cmd=listkeys
+  >     accept: application/mercurial-0.1
+  >     user-agent: mercurial/proto-1.0 (Mercurial 42)
+  >     x-hgarg-1: namespace=namespaces
+  > EOF
+  using raw connection to peer
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=listkeys HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     user-agent: mercurial/proto-1.0 (Mercurial 42)\r\n (glob)
+  s>     x-hgarg-1: namespace=namespaces\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     \r\n
+  s> makefile('rb', None)
+  s> readline() -> 36:
+  s>     HTTP/1.1 200 Script output follows\r\n
+  s> readline() -> 28:
+  s>     Server: testing stub value\r\n
+  s> readline() -> *: (glob)
+  s>     Date: $HTTP_DATE$\r\n
+  s> readline() -> 41:
+  s>     Content-Type: application/mercurial-0.1\r\n
+  s> readline() -> 20:
+  s>     Content-Length: 30\r\n
+  s> readline() -> 2:
+  s>     \r\n
+  s> read(30) -> 30:
+  s>     bookmarks	\n
+  s>     namespaces	\n
+  s>     phases	
+
   $ killdaemons.py
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -14,6 +14,7 @@ 
 import operator
 import os
 import random
+import re
 import socket
 import ssl
 import stat
@@ -2692,6 +2693,24 @@ 
 
     This action MUST be paired with a ``batchbegin`` action.
 
+    httprequest <method> <path>
+    ---------------------------
+
+    (HTTP peer only)
+
+    Send an HTTP request to the peer.
+
+    The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
+
+    Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
+    headers to add to the request. e.g. ``Accept: foo``.
+
+    The following arguments are special:
+
+    ``BODYFILE``
+        The content of the file defined as the value to this argument will be
+        transferred verbatim as the HTTP request body.
+
     close
     -----
 
@@ -2754,6 +2773,7 @@ 
     stdin = None
     stdout = None
     stderr = None
+    opener = None
 
     if opts['localssh']:
         # We start the SSH server in its own process so there is process
@@ -2909,6 +2929,42 @@ 
                 ui.status(_('response #%d: %s\n') % (i, util.escapedata(chunk)))
 
             batchedcommands = None
+
+        elif action.startswith('httprequest '):
+            if not opener:
+                raise error.Abort(_('cannot use httprequest without an HTTP '
+                                    'peer'))
+
+            request = action.split(' ', 2)
+            if len(request) != 3:
+                raise error.Abort(_('invalid httprequest: expected format is '
+                                    '"httprequest <method> <path>'))
+
+            method, httppath = request[1:]
+            headers = {}
+            body = None
+            for line in lines:
+                line = line.lstrip()
+                m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
+                if m:
+                    headers[m.group(1)] = m.group(2)
+                    continue
+
+                if line.startswith(b'BODYFILE '):
+                    with open(line.split(b' ', 1), 'rb') as fh:
+                        body = fh.read()
+                else:
+                    raise error.Abort(_('unknown argument to httprequest: %s') %
+                                      line)
+
+            url = path + httppath
+            req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
+
+            try:
+                opener.open(req).read()
+            except util.urlerr.urlerror as e:
+                e.read()
+
         elif action == 'close':
             peer.close()
         elif action == 'readavailable':