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 ============ 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/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