D2726: debugcommands: support connecting to HTTP peers

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

D2726: debugcommands: support connecting to HTTP peers

indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Now that we have the plumbing for logging socket activity, let's hook
  it up to `hg debugwireproto` so we can collect low-level activity on
  sockets.
 
  The new code is a bit incomplete. But it is better than nothing:
  `hg debugwireproto` is still heavily evolving.
 
  The added test demonstrates some interesting behavior. For example,
  we're calling socket.makefile() and doing I/O on that. TIL. We're also
  sending an "Accept-Encoding: identity" request header. (This is
  probably not necessary.)
 
  I don't plan on implementing too many HTTP protocol tests at this
  time because they are a bit verbose and the liberal use of ignoring
  variable length fields is annoying. Although, I may evolve
  `hg debugwireproto` to make the output less verbose to facilitate
  testing. I'm still working things out...

REPOSITORY
  rHG Mercurial

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

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

CHANGE DETAILS

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
@@ -161,3 +161,68 @@
   0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
   0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
   0020: 78                                              |x|
+
+  $ killdaemons.py
+  $ cd ..
+
+Test listkeys for listing namespaces
+
+  $ hg init empty
+  $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
+  $ cat hg.pid > $DAEMON_PIDS
+  $ hg --verbose debugwireproto <a href="http://$LOCALIP:$HGPORT">http://$LOCALIP:$HGPORT << EOF
+  > command listkeys
+  >     namespace namespaces
+  > EOF
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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() -> *: (glob)
+  s>     Server: *\r\n (glob)
+  s> readline() -> *: (glob)
+  s>     Date: *\r\n (glob)
+  s> readline() -> 41:
+  s>     Content-Type: application/mercurial-0.1\r\n
+  s> readline() -> 21:
+  s>     Content-Length: *\r\n (glob)
+  s> readline() -> 2:
+  s>     \r\n
+  s> read(*) -> *: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ (glob)
+  sending listkeys command
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=listkeys HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     vary: X-HgArg-1,X-HgProto-1\r\n
+  s>     x-hgarg-1: namespace=namespaces\r\n
+  s>     x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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() -> 36:
+  s>     Server: *\r\n (glob)
+  s> readline() -> *: (glob)
+  s>     Date: *\r\n (glob)
+  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
+  response: bookmarks \nnamespaces \nphases
+
+  $ killdaemons.py
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -47,6 +47,7 @@
     fileset,
     formatter,
     hg,
+    httppeer,
     localrepo,
     lock as lockmod,
     logcmdutil,
@@ -2571,9 +2572,9 @@
         ('', 'peer', '', _('construct a specific version of the peer')),
         ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
     ] + cmdutil.remoteopts,
-    _('[REPO]'),
+    _('[PATH]'),
     optionalrepo=True)
-def debugwireproto(ui, repo, **opts):
+def debugwireproto(ui, repo, path=None, **opts):
     """send wire protocol commands to a server
 
     This command can be used to issue wire protocol commands to remote
@@ -2708,12 +2709,19 @@
         raise error.Abort(_('invalid value for --peer'),
                           hint=_('valid values are "raw", "ssh1", and "ssh2"'))
 
+    if path and opts['localssh']:
+        raise error.Abort(_('cannot specify --localssh with an explicit '
+                            'path'))
+
     if ui.interactive():
         ui.write(_('(waiting for commands on stdin)\n'))
 
     blocks = list(_parsewirelangblocks(ui.fin))
 
     proc = None
+    stdin = None
+    stdout = None
+    stderr = None
 
     if opts['localssh']:
         # We start the SSH server in its own process so there is process
@@ -2761,22 +2769,55 @@
             peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
                                     autoreadstderr=autoreadstderr)
 
+    elif path:
+        # We bypass hg.peer() so we can proxy the sockets.
+        # TODO consider not doing this because we skip
+        # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
+        u = util.url(path)
+        if u.scheme != 'http':
+            raise error.Abort(_('only http:// paths are currently supported'))
+
+        if opts['peer']:
+            raise error.Abort(_('--peer is not supported with HTTP peers'))
+
+        url, authinfo = u.authinfo()
+        openerargs = {}
+
+        # Turn pipes/sockets into observers so we can log I/O.
+        if ui.verbose:
+            openerargs = {
+                r'loggingfh': ui,
+                r'loggingname': b's',
+                r'loggingopts': {
+                    r'logdata': True,
+                },
+            }
+
+        opener = urlmod.opener(ui, authinfo, **openerargs)
+        peer = httppeer.httppeer(ui, path, url, opener)
+        peer._fetchcaps()
+        # We /could/ populate stdin/stdout with sock.makefile()...
     else:
-        raise error.Abort(_('only --localssh is currently supported'))
+        raise error.Abort(_('unsupported connection configuration'))
 
     batchedcommands = None
 
     # Now perform actions based on the parsed wire language instructions.
     for action, lines in blocks:
         if action in ('raw', 'raw+'):
+            if not stdin:
+                raise error.Abort(_('cannot call raw/raw+ on this peer'))
+
             # Concatenate the data together.
             data = ''.join(l.lstrip() for l in lines)
             data = util.unescapestr(data)
             stdin.write(data)
 
             if action == 'raw+':
                 stdin.flush()
         elif action == 'flush':
+            if not stdin:
+                raise error.Abort(_('cannot call flush on this peer'))
             stdin.flush()
         elif action.startswith('command'):
             if not peer:
@@ -2833,6 +2874,9 @@
         elif action == 'close':
             peer.close()
         elif action == 'readavailable':
+            if not stdout or not stderr:
+                raise error.Abort(_('readavailable not available on this peer'))
+
             fds = [stdout.fileno(), stderr.fileno()]
             try:
                 act = util.poll(fds)
@@ -2845,14 +2889,22 @@
             if stderr.fileno() in act:
                 util.readpipe(stderr)
         elif action == 'readline':
+            if not stdout:
+                raise error.Abort(_('readline not available on this peer'))
             stdout.readline()
         elif action == 'ereadline':
+            if not stderr:
+                raise error.Abort(_('ereadline not available on this peer'))
             stderr.readline()
         elif action.startswith('read '):
             count = int(action.split(' ', 1)[1])
+            if not stdout:
+                raise error.Abort(_('read not available on this peer'))
             stdout.read(count)
         elif action.startswith('eread '):
             count = int(action.split(' ', 1)[1])
+            if not stderr:
+                raise error.Abort(_('eread not available on this peer'))
             stderr.read(count)
         else:
             raise error.Abort(_('unknown action: %s') % action)



To: indygreg, #hg-reviewers
Cc: mercurial-devel
_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

D2726: debugcommands: support connecting to HTTP peers

indygreg (Gregory Szorc)
indygreg updated this revision to Diff 6977.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2726?vs=6721&id=6977

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

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

CHANGE DETAILS

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
@@ -161,3 +161,68 @@
   0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
   0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
   0020: 78                                              |x|
+
+  $ killdaemons.py
+  $ cd ..
+
+Test listkeys for listing namespaces
+
+  $ hg init empty
+  $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
+  $ cat hg.pid > $DAEMON_PIDS
+  $ hg --verbose debugwireproto <a href="http://$LOCALIP:$HGPORT">http://$LOCALIP:$HGPORT << EOF
+  > command listkeys
+  >     namespace namespaces
+  > EOF
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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() -> *: (glob)
+  s>     Server: *\r\n (glob)
+  s> readline() -> *: (glob)
+  s>     Date: *\r\n (glob)
+  s> readline() -> 41:
+  s>     Content-Type: application/mercurial-0.1\r\n
+  s> readline() -> 21:
+  s>     Content-Length: *\r\n (glob)
+  s> readline() -> 2:
+  s>     \r\n
+  s> read(*) -> *: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ (glob)
+  sending listkeys command
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=listkeys HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     vary: X-HgArg-1,X-HgProto-1\r\n
+  s>     x-hgarg-1: namespace=namespaces\r\n
+  s>     x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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() -> 36:
+  s>     Server: *\r\n (glob)
+  s> readline() -> *: (glob)
+  s>     Date: *\r\n (glob)
+  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
+  response: bookmarks \nnamespaces \nphases
+
+  $ killdaemons.py
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -48,6 +48,7 @@
     fileset,
     formatter,
     hg,
+    httppeer,
     localrepo,
     lock as lockmod,
     logcmdutil,
@@ -2588,9 +2589,9 @@
         ('', 'peer', '', _('construct a specific version of the peer')),
         ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
     ] + cmdutil.remoteopts,
-    _('[REPO]'),
+    _('[PATH]'),
     optionalrepo=True)
-def debugwireproto(ui, repo, **opts):
+def debugwireproto(ui, repo, path=None, **opts):
     """send wire protocol commands to a server
 
     This command can be used to issue wire protocol commands to remote
@@ -2726,12 +2727,19 @@
         raise error.Abort(_('invalid value for --peer'),
                           hint=_('valid values are "raw", "ssh1", and "ssh2"'))
 
+    if path and opts['localssh']:
+        raise error.Abort(_('cannot specify --localssh with an explicit '
+                            'path'))
+
     if ui.interactive():
         ui.write(_('(waiting for commands on stdin)\n'))
 
     blocks = list(_parsewirelangblocks(ui.fin))
 
     proc = None
+    stdin = None
+    stdout = None
+    stderr = None
 
     if opts['localssh']:
         # We start the SSH server in its own process so there is process
@@ -2779,22 +2787,55 @@
             peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
                                     autoreadstderr=autoreadstderr)
 
+    elif path:
+        # We bypass hg.peer() so we can proxy the sockets.
+        # TODO consider not doing this because we skip
+        # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
+        u = util.url(path)
+        if u.scheme != 'http':
+            raise error.Abort(_('only http:// paths are currently supported'))
+
+        if opts['peer']:
+            raise error.Abort(_('--peer is not supported with HTTP peers'))
+
+        url, authinfo = u.authinfo()
+        openerargs = {}
+
+        # Turn pipes/sockets into observers so we can log I/O.
+        if ui.verbose:
+            openerargs = {
+                r'loggingfh': ui,
+                r'loggingname': b's',
+                r'loggingopts': {
+                    r'logdata': True,
+                },
+            }
+
+        opener = urlmod.opener(ui, authinfo, **openerargs)
+        peer = httppeer.httppeer(ui, path, url, opener)
+        peer._fetchcaps()
+        # We /could/ populate stdin/stdout with sock.makefile()...
     else:
-        raise error.Abort(_('only --localssh is currently supported'))
+        raise error.Abort(_('unsupported connection configuration'))
 
     batchedcommands = None
 
     # Now perform actions based on the parsed wire language instructions.
     for action, lines in blocks:
         if action in ('raw', 'raw+'):
+            if not stdin:
+                raise error.Abort(_('cannot call raw/raw+ on this peer'))
+
             # Concatenate the data together.
             data = ''.join(l.lstrip() for l in lines)
             data = util.unescapestr(data)
             stdin.write(data)
 
             if action == 'raw+':
                 stdin.flush()
         elif action == 'flush':
+            if not stdin:
+                raise error.Abort(_('cannot call flush on this peer'))
             stdin.flush()
         elif action.startswith('command'):
             if not peer:
@@ -2851,18 +2892,30 @@
         elif action == 'close':
             peer.close()
         elif action == 'readavailable':
+            if not stdout or not stderr:
+                raise error.Abort(_('readavailable not available on this peer'))
+
             stdin.close()
             stdout.read()
             stderr.read()
+
         elif action == 'readline':
+            if not stdout:
+                raise error.Abort(_('readline not available on this peer'))
             stdout.readline()
         elif action == 'ereadline':
+            if not stderr:
+                raise error.Abort(_('ereadline not available on this peer'))
             stderr.readline()
         elif action.startswith('read '):
             count = int(action.split(' ', 1)[1])
+            if not stdout:
+                raise error.Abort(_('read not available on this peer'))
             stdout.read(count)
         elif action.startswith('eread '):
             count = int(action.split(' ', 1)[1])
+            if not stderr:
+                raise error.Abort(_('eread not available on this peer'))
             stderr.read(count)
         else:
             raise error.Abort(_('unknown action: %s') % action)



To: indygreg, #hg-reviewers
Cc: mercurial-devel
_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

D2726: debugcommands: support connecting to HTTP peers

indygreg (Gregory Szorc)
In reply to this post by indygreg (Gregory Szorc)
indygreg updated this revision to Diff 6994.
indygreg edited the summary of this revision.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2726?vs=6977&id=6994

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

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

CHANGE DETAILS

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
@@ -161,3 +161,69 @@
   0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
   0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
   0020: 78                                              |x|
+
+  $ killdaemons.py
+  $ cd ..
+
+Test listkeys for listing namespaces
+
+  $ hg init empty
+  $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
+  $ cat hg.pid > $DAEMON_PIDS
+
+  $ hg --verbose debugwireproto <a href="http://$LOCALIP:$HGPORT">http://$LOCALIP:$HGPORT << EOF
+  > command listkeys
+  >     namespace namespaces
+  > EOF
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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() -> 21:
+  s>     Content-Length: *\r\n (glob)
+  s> readline() -> 2:
+  s>     \r\n
+  s> read(*) -> *: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ (glob)
+  sending listkeys command
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=listkeys HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     vary: X-HgArg-1,X-HgProto-1\r\n
+  s>     x-hgarg-1: namespace=namespaces\r\n
+  s>     x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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
+  response: bookmarks \nnamespaces \nphases
+
+  $ killdaemons.py
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -48,6 +48,7 @@
     fileset,
     formatter,
     hg,
+    httppeer,
     localrepo,
     lock as lockmod,
     logcmdutil,
@@ -2588,9 +2589,9 @@
         ('', 'peer', '', _('construct a specific version of the peer')),
         ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
     ] + cmdutil.remoteopts,
-    _('[REPO]'),
+    _('[PATH]'),
     optionalrepo=True)
-def debugwireproto(ui, repo, **opts):
+def debugwireproto(ui, repo, path=None, **opts):
     """send wire protocol commands to a server
 
     This command can be used to issue wire protocol commands to remote
@@ -2726,12 +2727,19 @@
         raise error.Abort(_('invalid value for --peer'),
                           hint=_('valid values are "raw", "ssh1", and "ssh2"'))
 
+    if path and opts['localssh']:
+        raise error.Abort(_('cannot specify --localssh with an explicit '
+                            'path'))
+
     if ui.interactive():
         ui.write(_('(waiting for commands on stdin)\n'))
 
     blocks = list(_parsewirelangblocks(ui.fin))
 
     proc = None
+    stdin = None
+    stdout = None
+    stderr = None
 
     if opts['localssh']:
         # We start the SSH server in its own process so there is process
@@ -2779,22 +2787,61 @@
             peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
                                     autoreadstderr=autoreadstderr)
 
+    elif path:
+        # We bypass hg.peer() so we can proxy the sockets.
+        # TODO consider not doing this because we skip
+        # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
+        u = util.url(path)
+        if u.scheme != 'http':
+            raise error.Abort(_('only http:// paths are currently supported'))
+
+        url, authinfo = u.authinfo()
+        openerargs = {}
+
+        # Turn pipes/sockets into observers so we can log I/O.
+        if ui.verbose:
+            openerargs = {
+                r'loggingfh': ui,
+                r'loggingname': b's',
+                r'loggingopts': {
+                    r'logdata': True,
+                },
+            }
+
+        opener = urlmod.opener(ui, authinfo, **openerargs)
+
+        if opts['peer'] == 'raw':
+            ui.write(_('using raw connection to peer\n'))
+            peer = None
+        elif opts['peer']:
+            raise error.Abort(_('--peer %s not supported with HTTP peers') %
+                              opts['peer'])
+        else:
+            peer = httppeer.httppeer(ui, path, url, opener)
+            peer._fetchcaps()
+
+        # We /could/ populate stdin/stdout with sock.makefile()...
     else:
-        raise error.Abort(_('only --localssh is currently supported'))
+        raise error.Abort(_('unsupported connection configuration'))
 
     batchedcommands = None
 
     # Now perform actions based on the parsed wire language instructions.
     for action, lines in blocks:
         if action in ('raw', 'raw+'):
+            if not stdin:
+                raise error.Abort(_('cannot call raw/raw+ on this peer'))
+
             # Concatenate the data together.
             data = ''.join(l.lstrip() for l in lines)
             data = util.unescapestr(data)
             stdin.write(data)
 
             if action == 'raw+':
                 stdin.flush()
         elif action == 'flush':
+            if not stdin:
+                raise error.Abort(_('cannot call flush on this peer'))
             stdin.flush()
         elif action.startswith('command'):
             if not peer:
@@ -2851,18 +2898,30 @@
         elif action == 'close':
             peer.close()
         elif action == 'readavailable':
+            if not stdout or not stderr:
+                raise error.Abort(_('readavailable not available on this peer'))
+
             stdin.close()
             stdout.read()
             stderr.read()
+
         elif action == 'readline':
+            if not stdout:
+                raise error.Abort(_('readline not available on this peer'))
             stdout.readline()
         elif action == 'ereadline':
+            if not stderr:
+                raise error.Abort(_('ereadline not available on this peer'))
             stderr.readline()
         elif action.startswith('read '):
             count = int(action.split(' ', 1)[1])
+            if not stdout:
+                raise error.Abort(_('read not available on this peer'))
             stdout.read(count)
         elif action.startswith('eread '):
             count = int(action.split(' ', 1)[1])
+            if not stderr:
+                raise error.Abort(_('eread not available on this peer'))
             stderr.read(count)
         else:
             raise error.Abort(_('unknown action: %s') % action)



To: indygreg, #hg-reviewers
Cc: mercurial-devel
_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

D2726: debugcommands: support connecting to HTTP peers

indygreg (Gregory Szorc)
In reply to this post by indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGfc8939825632: debugcommands: support connecting to HTTP peers (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2726?vs=6994&id=7158

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

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

CHANGE DETAILS

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
@@ -161,3 +161,69 @@
   0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
   0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
   0020: 78                                              |x|
+
+  $ killdaemons.py
+  $ cd ..
+
+Test listkeys for listing namespaces
+
+  $ hg init empty
+  $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
+  $ cat hg.pid > $DAEMON_PIDS
+
+  $ hg --verbose debugwireproto <a href="http://$LOCALIP:$HGPORT">http://$LOCALIP:$HGPORT << EOF
+  > command listkeys
+  >     namespace namespaces
+  > EOF
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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() -> 21:
+  s>     Content-Length: *\r\n (glob)
+  s> readline() -> 2:
+  s>     \r\n
+  s> read(*) -> *: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ (glob)
+  sending listkeys command
+  s> sendall(*, 0): (glob)
+  s>     GET /?cmd=listkeys HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     vary: X-HgArg-1,X-HgProto-1\r\n
+  s>     x-hgarg-1: namespace=namespaces\r\n
+  s>     x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$\r\n
+  s>     accept: application/mercurial-0.1\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: mercurial/proto-1.0 (Mercurial *)\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
+  response: bookmarks \nnamespaces \nphases
+
+  $ killdaemons.py
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -48,6 +48,7 @@
     fileset,
     formatter,
     hg,
+    httppeer,
     localrepo,
     lock as lockmod,
     logcmdutil,
@@ -2602,9 +2603,9 @@
         ('', 'peer', '', _('construct a specific version of the peer')),
         ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
     ] + cmdutil.remoteopts,
-    _('[REPO]'),
+    _('[PATH]'),
     optionalrepo=True)
-def debugwireproto(ui, repo, **opts):
+def debugwireproto(ui, repo, path=None, **opts):
     """send wire protocol commands to a server
 
     This command can be used to issue wire protocol commands to remote
@@ -2740,12 +2741,19 @@
         raise error.Abort(_('invalid value for --peer'),
                           hint=_('valid values are "raw", "ssh1", and "ssh2"'))
 
+    if path and opts['localssh']:
+        raise error.Abort(_('cannot specify --localssh with an explicit '
+                            'path'))
+
     if ui.interactive():
         ui.write(_('(waiting for commands on stdin)\n'))
 
     blocks = list(_parsewirelangblocks(ui.fin))
 
     proc = None
+    stdin = None
+    stdout = None
+    stderr = None
 
     if opts['localssh']:
         # We start the SSH server in its own process so there is process
@@ -2793,22 +2801,61 @@
             peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
                                     autoreadstderr=autoreadstderr)
 
+    elif path:
+        # We bypass hg.peer() so we can proxy the sockets.
+        # TODO consider not doing this because we skip
+        # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
+        u = util.url(path)
+        if u.scheme != 'http':
+            raise error.Abort(_('only http:// paths are currently supported'))
+
+        url, authinfo = u.authinfo()
+        openerargs = {}
+
+        # Turn pipes/sockets into observers so we can log I/O.
+        if ui.verbose:
+            openerargs = {
+                r'loggingfh': ui,
+                r'loggingname': b's',
+                r'loggingopts': {
+                    r'logdata': True,
+                },
+            }
+
+        opener = urlmod.opener(ui, authinfo, **openerargs)
+
+        if opts['peer'] == 'raw':
+            ui.write(_('using raw connection to peer\n'))
+            peer = None
+        elif opts['peer']:
+            raise error.Abort(_('--peer %s not supported with HTTP peers') %
+                              opts['peer'])
+        else:
+            peer = httppeer.httppeer(ui, path, url, opener)
+            peer._fetchcaps()
+
+        # We /could/ populate stdin/stdout with sock.makefile()...
     else:
-        raise error.Abort(_('only --localssh is currently supported'))
+        raise error.Abort(_('unsupported connection configuration'))
 
     batchedcommands = None
 
     # Now perform actions based on the parsed wire language instructions.
     for action, lines in blocks:
         if action in ('raw', 'raw+'):
+            if not stdin:
+                raise error.Abort(_('cannot call raw/raw+ on this peer'))
+
             # Concatenate the data together.
             data = ''.join(l.lstrip() for l in lines)
             data = util.unescapestr(data)
             stdin.write(data)
 
             if action == 'raw+':
                 stdin.flush()
         elif action == 'flush':
+            if not stdin:
+                raise error.Abort(_('cannot call flush on this peer'))
             stdin.flush()
         elif action.startswith('command'):
             if not peer:
@@ -2865,18 +2912,30 @@
         elif action == 'close':
             peer.close()
         elif action == 'readavailable':
+            if not stdout or not stderr:
+                raise error.Abort(_('readavailable not available on this peer'))
+
             stdin.close()
             stdout.read()
             stderr.read()
+
         elif action == 'readline':
+            if not stdout:
+                raise error.Abort(_('readline not available on this peer'))
             stdout.readline()
         elif action == 'ereadline':
+            if not stderr:
+                raise error.Abort(_('ereadline not available on this peer'))
             stderr.readline()
         elif action.startswith('read '):
             count = int(action.split(' ', 1)[1])
+            if not stdout:
+                raise error.Abort(_('read not available on this peer'))
             stdout.read(count)
         elif action.startswith('eread '):
             count = int(action.split(' ', 1)[1])
+            if not stderr:
+                raise error.Abort(_('eread not available on this peer'))
             stderr.read(count)
         else:
             raise error.Abort(_('unknown action: %s') % action)



To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel
_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel