diff --git a/mercurial/help/internals/wireprotocol.txt b/mercurial/help/internals/wireprotocol.txt --- a/mercurial/help/internals/wireprotocol.txt +++ b/mercurial/help/internals/wireprotocol.txt @@ -152,11 +152,14 @@ Version 2 of the HTTP protocol is exposed under the ``/api/*`` URL space. It's final API name is not yet formalized. -Commands are triggered by sending HTTP requests against URLs of the +Commands are triggered by sending HTTP POST requests against URLs of the form ``/``, where ```` is ``ro`` or ``rw``, meaning read-only and read-write, respectively and ```` is a named wire protocol command. +Non-POST request methods MUST be rejected by the server with an HTTP +405 response. + Commands that modify repository state in meaningful ways MUST NOT be exposed under the ``ro`` URL prefix. All available commands MUST be available under the ``rw`` URL prefix. diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py --- a/mercurial/wireprotoserver.py +++ b/mercurial/wireprotoserver.py @@ -299,6 +299,12 @@ res.setbodybytes(_('unknown permission: %s') % permission) return + if req.method != 'POST': + res.status = b'405 Method Not Allowed' + res.headers[b'Allow'] = b'POST' + res.setbodybytes(_('commands require POST requests')) + return + # At some point we'll want to use our own API instead of recycling the # behavior of version 1 of the wire protocol... # TODO return reasonable responses - not responses that overload the diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -32,7 +32,7 @@ Request to read-only command works out of the box - $ get-with-headers.py $LOCALIP:$HGPORT api/$HTTPV2/ro/known - + $ get-with-headers.py --method POST $LOCALIP:$HGPORT api/$HTTPV2/ro/known - 200 OK content-length: 9 content-type: text/plain @@ -41,7 +41,7 @@ Request to unknown command yields 404 - $ get-with-headers.py $LOCALIP:$HGPORT api/$HTTPV2/ro/badcommand - + $ get-with-headers.py --method POST $LOCALIP:$HGPORT api/$HTTPV2/ro/badcommand - 404 Not Found content-length: 42 content-type: text/plain @@ -49,24 +49,36 @@ unknown wire protocol command: badcommand [1] +Only POST is allowed + + $ get-with-headers.py --method GET $LOCALIP:$HGPORT api/$HTTPV2/ro/known - + 405 Method Not Allowed + allow: POST + content-length: 30 + + commands require POST requests (no-eol) + [1] + Request to read-write command fails because server is read-only by default GET request not allowed $ get-with-headers.py $LOCALIP:$HGPORT api/$HTTPV2/rw/known - - 405 push requires POST request - content-length: 17 + 405 Method Not Allowed + allow: POST + content-length: 30 - permission denied (no-eol) + commands require POST requests (no-eol) [1] Even for unknown commands $ get-with-headers.py $LOCALIP:$HGPORT api/$HTTPV2/rw/badcommand - - 405 push requires POST request - content-length: 17 + 405 Method Not Allowed + allow: POST + content-length: 30 - permission denied (no-eol) + commands require POST requests (no-eol) [1]