D2850: wireproto: define content negotiation for HTTPv2
indygreg (Gregory Szorc)
phabricator at mercurial-scm.org
Wed Mar 14 02:49:21 UTC 2018
indygreg updated this revision to Diff 7016.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D2850?vs=7013&id=7016
REVISION DETAIL
https://phab.mercurial-scm.org/D2850
AFFECTED FILES
mercurial/help/internals/wireprotocol.txt
mercurial/wireprotoserver.py
tests/test-http-api-httpv2.t
CHANGE DETAILS
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
@@ -1,4 +1,5 @@
$ HTTPV2=exp-http-v2-0001
+ $ MEDIATYPE=application/mercurial-tbd
$ send() {
> hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/
@@ -45,27 +46,6 @@
$ hg -R server serve -p $HGPORT -d --pid-file hg.pid
$ cat hg.pid > $DAEMON_PIDS
-Request to read-only command works out of the box
-
- $ send << EOF
- > httprequest POST api/$HTTPV2/ro/capabilities
- > user-agent: test
- > EOF
- using raw connection to peer
- s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
- s> Accept-Encoding: identity\r\n
- s> user-agent: test\r\n
- s> host: $LOCALIP:$HGPORT\r\n (glob)
- s> \r\n
- s> makefile('rb', None)
- s> HTTP/1.1 200 OK\r\n
- s> Server: testing stub value\r\n
- s> Date: $HTTP_DATE$\r\n
- s> Content-Type: text/plain\r\n
- s> Content-Length: 16\r\n
- s> \r\n
- s> ro/capabilities\n
-
Request to unknown command yields 404
$ send << EOF
@@ -108,6 +88,100 @@
s> \r\n
s> commands require POST requests
+Missing Accept header results in 406
+
+ $ send << EOF
+ > httprequest POST api/$HTTPV2/ro/capabilities
+ > user-agent: test
+ > EOF
+ using raw connection to peer
+ s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
+ s> Accept-Encoding: identity\r\n
+ s> user-agent: test\r\n
+ s> host: $LOCALIP:$HGPORT\r\n (glob)
+ s> \r\n
+ s> makefile('rb', None)
+ s> HTTP/1.1 406 Not Acceptable\r\n
+ s> Server: testing stub value\r\n
+ s> Date: $HTTP_DATE$\r\n
+ s> Content-Type: text/plain\r\n
+ s> Content-Length: 72\r\n
+ s> \r\n
+ s> client MUST specify Accept header with value: application/mercurial-tbd\n
+
+Bad Accept header results in 406
+
+ $ send << EOF
+ > httprequest POST api/$HTTPV2/ro/capabilities
+ > accept: invalid
+ > user-agent: test
+ > EOF
+ using raw connection to peer
+ s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
+ s> Accept-Encoding: identity\r\n
+ s> accept: invalid\r\n
+ s> user-agent: test\r\n
+ s> host: $LOCALIP:$HGPORT\r\n (glob)
+ s> \r\n
+ s> makefile('rb', None)
+ s> HTTP/1.1 406 Not Acceptable\r\n
+ s> Server: testing stub value\r\n
+ s> Date: $HTTP_DATE$\r\n
+ s> Content-Type: text/plain\r\n
+ s> Content-Length: 72\r\n
+ s> \r\n
+ s> client MUST specify Accept header with value: application/mercurial-tbd\n
+
+Bad Content-Type header results in 415
+
+ $ send << EOF
+ > httprequest POST api/$HTTPV2/ro/capabilities
+ > accept: $MEDIATYPE
+ > user-agent: test
+ > content-type: badmedia
+ > EOF
+ using raw connection to peer
+ s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
+ s> Accept-Encoding: identity\r\n
+ s> accept: application/mercurial-tbd\r\n
+ s> content-type: badmedia\r\n
+ s> user-agent: test\r\n
+ s> host: $LOCALIP:$HGPORT\r\n (glob)
+ s> \r\n
+ s> makefile('rb', None)
+ s> HTTP/1.1 415 Unsupported Media Type\r\n
+ s> Server: testing stub value\r\n
+ s> Date: $HTTP_DATE$\r\n
+ s> Content-Type: text/plain\r\n
+ s> Content-Length: 75\r\n
+ s> \r\n
+ s> client MUST send Content-Type header with value: application/mercurial-tbd\n
+
+Request to read-only command works out of the box
+
+ $ send << EOF
+ > httprequest POST api/$HTTPV2/ro/capabilities
+ > accept: $MEDIATYPE
+ > content-type: $MEDIATYPE
+ > user-agent: test
+ > EOF
+ using raw connection to peer
+ s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
+ s> Accept-Encoding: identity\r\n
+ s> accept: application/mercurial-tbd\r\n
+ s> content-type: application/mercurial-tbd\r\n
+ s> user-agent: test\r\n
+ s> host: $LOCALIP:$HGPORT\r\n (glob)
+ s> \r\n
+ s> makefile('rb', None)
+ s> HTTP/1.1 200 OK\r\n
+ s> Server: testing stub value\r\n
+ s> Date: $HTTP_DATE$\r\n
+ s> Content-Type: text/plain\r\n
+ s> Content-Length: 16\r\n
+ s> \r\n
+ s> ro/capabilities\n
+
Request to read-write command fails because server is read-only by default
GET to read-write request yields 405
@@ -192,10 +266,14 @@
$ send << EOF
> httprequest POST api/$HTTPV2/rw/capabilities
> user-agent: test
+ > accept: $MEDIATYPE
+ > content-type: $MEDIATYPE
> EOF
using raw connection to peer
s> POST /api/exp-http-v2-0001/rw/capabilities HTTP/1.1\r\n
s> Accept-Encoding: identity\r\n
+ s> accept: application/mercurial-tbd\r\n
+ s> content-type: application/mercurial-tbd\r\n
s> user-agent: test\r\n
s> host: $LOCALIP:$HGPORT\r\n (glob)
s> \r\n
@@ -213,10 +291,12 @@
$ send << EOF
> httprequest POST api/$HTTPV2/rw/badcommand
> user-agent: test
+ > accept: $MEDIATYPE
> EOF
using raw connection to peer
s> POST /api/exp-http-v2-0001/rw/badcommand HTTP/1.1\r\n
s> Accept-Encoding: identity\r\n
+ s> accept: application/mercurial-tbd\r\n
s> user-agent: test\r\n
s> host: $LOCALIP:$HGPORT\r\n (glob)
s> \r\n
diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -32,6 +32,7 @@
HGTYPE = 'application/mercurial-0.1'
HGTYPE2 = 'application/mercurial-0.2'
HGERRTYPE = 'application/hg-error'
+HTTPV2TYPE = 'application/mercurial-tbd'
HTTPV2 = wireprototypes.HTTPV2
SSHV1 = wireprototypes.SSHV1
@@ -335,6 +336,23 @@
res.setbodybytes(_('invalid wire protocol command: %s') % command)
return
+ if req.headers.get(b'Accept') != HTTPV2TYPE:
+ res.status = b'406 Not Acceptable'
+ res.headers[b'Content-Type'] = b'text/plain'
+ res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
+ % HTTPV2TYPE)
+ return
+
+ if (b'Content-Type' in req.headers
+ and req.headers[b'Content-Type'] != HTTPV2TYPE):
+ res.status = b'415 Unsupported Media Type'
+ # TODO we should send a response with appropriate media type,
+ # since client does Accept it.
+ res.headers[b'Content-Type'] = b'text/plain'
+ res.setbodybytes(_('client MUST send Content-Type header with '
+ 'value: %s\n') % HTTPV2TYPE)
+ return
+
# We don't do anything meaningful yet.
res.status = b'200 OK'
res.headers[b'Content-Type'] = b'text/plain'
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
@@ -187,6 +187,19 @@
Requests to unknown commands or URLS result in an HTTP 404.
TODO formally define response type, how error is communicated, etc.
+HTTP request and response bodies use the *TBD Protocol* for media exchange.
+
+Clients and servers MUST advertise the ``TBD`` media type via the
+``Content-Type`` request and response headers. In addition, clients MUST
+advertise this media type value in their ``Accept`` request header in all
+requests.
+
+Servers receiving requests without an ``Accept`` header SHOULD respond with
+an HTTP 406.
+
+Servers receiving requests with an invalid ``Content-Type`` header SHOULD
+respond with an HTTP 415.
+
SSH Protocol
============
To: indygreg, #hg-reviewers
Cc: mercurial-devel
More information about the Mercurial-devel
mailing list