server: give old 0.4.0 senders a "you must upgrade" error

Without this, old senders will throw a messy 404 traceback when talking
to a modern server.

Unfortunately 0.4.0 receivers don't make API calls in the right order,
so they throw a 404 before seeing our "you need to upgrade" message.
This commit is contained in:
Brian Warner 2015-11-10 21:02:44 -08:00
parent ca5f79233c
commit b83062701d
3 changed files with 71 additions and 0 deletions

View File

@ -1,6 +1,13 @@
User-visible changes in "magic-wormhole":
## Release ?? (??)
* Arrange for 0.4.0 senders to print an error message when connecting to a
current (0.5.0) server, instead of an ugly stack trace. Unfortunately 0.4.0
receivers still display the traceback, since they don't check the welcome
message before using a missing API.
## Release 0.5.0 (07-Oct-2015)
* Change the CLI to merge send-file with send-text, and receive-file with

View File

@ -63,6 +63,9 @@ class ChannelLister(resource.Resource):
self._relay = relay
def render_GET(self, request):
if b"appid" not in request.args:
e = NeedToUpgradeErrorResource(self._relay.welcome)
return e.get_message()
appid = request.args[b"appid"][0].decode("utf-8")
#print("LIST", appid)
app = self._relay.get_app(appid)
@ -95,6 +98,29 @@ class Allocator(resource.Resource):
"channelid": channelid}
return (json.dumps(data)+"\n").encode("utf-8")
def getChild(self, path, req):
# wormhole-0.4.0 "send" started with "POST /allocate/SIDE".
# wormhole-0.5.0 changed that to "POST /allocate". We catch the old
# URL here to deliver a nicer error message (with upgrade
# instructions) than an ugly 404.
return NeedToUpgradeErrorResource(self._relay.welcome)
class NeedToUpgradeErrorResource(resource.Resource):
def __init__(self, welcome):
resource.Resource.__init__(self)
w = welcome.copy()
w["error"] = "Sorry, you must upgrade your client to use this server."
message = {"welcome": w}
self._message = (json.dumps(message)+"\n").encode("utf-8")
def get_message(self):
return self._message
def render_POST(self, request):
return self._message
def render_GET(self, request):
return self._message
def getChild(self, path, req):
return self
class Adder(resource.Resource):
def __init__(self, relay):
resource.Resource.__init__(self)
@ -311,6 +337,15 @@ class Relay(resource.Resource, service.MultiService):
self.putChild(b"get", Getter(self))
self.putChild(b"deallocate", Deallocator(self))
def getChild(self, path, req):
# 0.4.0 used "POST /CID/SIDE/post/MSGNUM"
# 0.5.0 replaced it with "POST /add (json body)"
# give a nicer error message to old clients
if (len(req.postpath) >= 2
and req.postpath[1] in (b"post", b"poll", b"deallocate")):
return NeedToUpgradeErrorResource(self.welcome)
return resource.NoResource("No such child resource.")
def get_app(self, appid):
assert isinstance(appid, type(u""))
if not appid in self._apps:

View File

@ -165,6 +165,35 @@ class API(ServerBase, unittest.TestCase):
return d
UPGRADE_ERROR = "Sorry, you must upgrade your client to use this server."
def test_old_allocate(self):
# 0.4.0 used "POST /allocate/SIDE".
# 0.5.0 replaced it with "POST /allocate".
# test that an old client gets a useful error message, not a 404.
d = self.post("allocate/abc", {})
def _check(data):
self.failUnlessEqual(data["welcome"]["error"], self.UPGRADE_ERROR)
d.addCallback(_check)
return d
def test_old_list(self):
# 0.4.0 used "GET /list".
# 0.5.0 replaced it with "GET /list?appid="
d = self.get("list", {}) # no appid
def _check(data):
self.failUnlessEqual(data["welcome"]["error"], self.UPGRADE_ERROR)
d.addCallback(_check)
return d
def test_old_post(self):
# 0.4.0 used "POST /CID/SIDE/post/MSGNUM"
# 0.5.0 replaced it with "POST /add (json body)"
d = self.post("1/abc/post/pake", {})
def _check(data):
self.failUnlessEqual(data["welcome"]["error"], self.UPGRADE_ERROR)
d.addCallback(_check)
return d
def add_message(self, message, side="abc", phase="1"):
return self.post("add",
{"appid": "app1",