.spawn_pending used for the *whole* window, from request to responsive (added to proxy)
.waiting_for_response is just used for the window between Spawner.start returning (process started, http endpoint known) and http endpoint becoming responsive
.waiting_for_response will never be True while .spawn_pending is False
We already added running users, but we didn't handle removing users from the proxy
if the user's server was stopped (e.g. while the Hub was restarting).
check_routes checks for missing routes for running users.
This is meant for when the proxy has been relaunched outside the Hub.
If spawners are slow to start, it's possible for check_routes to fire in the middle of spawning,
triggering addition of the user's server (which has no defined location yet) to the proxy before it's up.
If the spawning fails, the route will remain indefinitely (because it never should have been added in the first place), and the user will see 503 until their server is launched manually again.
Checking `spawn_pending` in user.running prevents this.
relies on CHP's host-based routing (a feature I didn't add!)
requires wildcard DNS and wildcard SSL for a proper setup
still lots to workout and cleanup in terms of cookies and where to use host, domain, path, but it works locally.
moves `spawn_pending` flag to only around start, not the HTTP wait.
Some Spawners may not know how to poll until start has finished (DockerSpawner).
Let's not require that they do.
Usernames that have an `@'-separated domain component
break JupyterHub when the server expects to see query
strings that contain an `@', when browsers and other
clients send `%40'.
If Spawner.options_form is specified, a form providing input controls is shown to the user prior to launch.
Spawners access the result via the `self.user_options` dict.
The default spawners offer no form.