| Index: services/python/mojo_url_redirector/__mojo__.py
|
| diff --git a/services/python/mojo_url_redirector/__mojo__.py b/services/python/mojo_url_redirector/__mojo__.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3028bb9b11c4f7c67092412043fb0fc264699a1e
|
| --- /dev/null
|
| +++ b/services/python/mojo_url_redirector/__mojo__.py
|
| @@ -0,0 +1,174 @@
|
| +# Copyright 2015 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +"""Application that serves requests for Mojo apps and responds with redirects
|
| +to the locations of the most recent versions of these apps."""
|
| +
|
| +import logging
|
| +import os
|
| +
|
| +import http_request_mojom
|
| +import http_response_mojom
|
| +import http_server_mojom
|
| +import http_server_factory_mojom
|
| +import net_address_mojom
|
| +import network_service_mojom
|
| +import service_provider_mojom
|
| +import url_loader_mojom
|
| +
|
| +from mojo_application import application_delegate
|
| +from mojo_application import application_impl
|
| +from mojo_application import application_runner
|
| +
|
| +from mojo_bindings import promise
|
| +import mojo_system
|
| +from mojo_utils import data_pipe_utils
|
| +
|
| +
|
| +def _HttpResponseWithStatusCode(status_code):
|
| + response = http_response_mojom.HttpResponse()
|
| + response.status_code = status_code
|
| + return response
|
| +
|
| +
|
| +def _HttpBadRequestResponse():
|
| + return _HttpResponseWithStatusCode(400)
|
| +
|
| +
|
| +def _HttpNotFoundResponse():
|
| + return _HttpResponseWithStatusCode(404)
|
| +
|
| +
|
| +def _HttpInternalServerErrorResponse():
|
| + return _HttpResponseWithStatusCode(500)
|
| +
|
| +
|
| +def _HttpRedirectResponse(new_location):
|
| + response = _HttpResponseWithStatusCode(302)
|
| + custom_headers = {}
|
| + custom_headers["location"] = new_location
|
| + response.custom_headers = custom_headers
|
| + return response
|
| +
|
| +
|
| +def _RequestIdentifier(requested_app, requested_platform):
|
| + return "[Request: %s on %s]" % (requested_app, requested_platform)
|
| +
|
| +
|
| +def _LogMessageForRequest(request_identifier, message, log=logging.info,
|
| + exc_info=None):
|
| + log("%s %s" % (request_identifier, message), exc_info=exc_info)
|
| +
|
| +
|
| +class MojoUrlRedirector(http_server_mojom.HttpHandler):
|
| + def __init__(self, network_service):
|
| + self.network_service = network_service
|
| +
|
| + def HandleRequest(self, request):
|
| + # Parse the components of the request.
|
| + relative_url_components = request.relative_url.split("/")
|
| +
|
| + # The request must have a component for the platform and for the app.
|
| + if len(relative_url_components) != 3:
|
| + return _HttpBadRequestResponse()
|
| +
|
| + requested_platform = relative_url_components[1]
|
| + requested_app = relative_url_components[2]
|
| +
|
| + def OnRedirectToAppRejected(error):
|
| + request_identifier = _RequestIdentifier(requested_app, requested_platform)
|
| + _LogMessageForRequest(request_identifier,
|
| + "Error in redirecting to current app location",
|
| + log=logging.error,
|
| + exc_info=getattr(error, "__traceback__", True))
|
| + return _HttpInternalServerErrorResponse()
|
| +
|
| + return self.RedirectToCurrentAppLocation(requested_platform,
|
| + requested_app).Catch(
|
| + OnRedirectToAppRejected)
|
| +
|
| + def RedirectToCurrentAppLocation(self, requested_platform, requested_app):
|
| + # Construct a URLRequest to fetch the app location file...
|
| + app_location_request = url_loader_mojom.UrlRequest()
|
| + mojo_services_url = "https://storage.googleapis.com/mojo/services"
|
| + app_name, _ = os.path.splitext(requested_app)
|
| + app_location_request.url = "%s/%s/%s_location" % (mojo_services_url,
|
| + requested_platform,
|
| + app_name)
|
| + app_location_request.auto_follow_redirects = True
|
| +
|
| + # ...and start a URLLoader to fetch it.
|
| + url_loader_proxy, request = url_loader_mojom.UrlLoader.manager.NewRequest()
|
| + self.network_service.CreateUrlLoader(request)
|
| +
|
| + return self.ProcessAppLocationResponse(
|
| + url_loader_proxy.Start(app_location_request),
|
| + _RequestIdentifier(requested_app, requested_platform),
|
| + url_loader_proxy)
|
| +
|
| + @promise.async
|
| + def ProcessAppLocationResponse(self, app_location_response,
|
| + request_identifier, url_loader_proxy):
|
| + error_message = None
|
| + if app_location_response.error:
|
| + error_message = "Network error from app location fetch: %d" % (
|
| + app_location_response.error)
|
| + elif app_location_response.status_code != 200:
|
| + error_message = "Unexpected http status from app location fetch: %s" % (
|
| + app_location_response.status_code)
|
| +
|
| + if error_message:
|
| + _LogMessageForRequest(request_identifier, error_message,
|
| + log=logging.error)
|
| + return _HttpNotFoundResponse()
|
| +
|
| + return self.ProcessAppLocationResponseBody(
|
| + data_pipe_utils.CopyFromDataPipe(app_location_response.body,
|
| + 30 * 10**6),
|
| + request_identifier)
|
| +
|
| + @promise.async
|
| + def ProcessAppLocationResponseBody(self, app_location_body,
|
| + request_identifier):
|
| + app_location = app_location_body.decode("utf-8")
|
| + _LogMessageForRequest(request_identifier,
|
| + "Redirecting to %s" % app_location)
|
| + return _HttpRedirectResponse(app_location)
|
| +
|
| +
|
| +class MojoUrlRedirectorApp(application_delegate.ApplicationDelegate):
|
| + def Initialize(self, shell, application):
|
| + server_address = net_address_mojom.NetAddress()
|
| + server_address.family = net_address_mojom.NetAddressFamily.IPV4
|
| + server_address.ipv4 = net_address_mojom.NetAddressIPv4()
|
| + server_address.ipv4.addr = [0, 0, 0, 0]
|
| + server_address.ipv4.port = 80
|
| +
|
| + # Parse args if given.
|
| + if application.args:
|
| + assert len(application.args) == 2
|
| + server_address_arg = application.args[1]
|
| + server_address_str, server_port_str = server_address_arg.split(":")
|
| + server_address.ipv4.addr = [int(n) for n in server_address_str.split(".")]
|
| + server_address.ipv4.port = int(server_port_str)
|
| +
|
| + # Connect to HttpServer.
|
| + http_server_factory = application.ConnectToService("mojo:http_server",
|
| + http_server_factory_mojom.HttpServerFactory)
|
| + self.http_server, request = (
|
| + http_server_mojom.HttpServer.manager.NewRequest())
|
| + http_server_factory.CreateHttpServer(request, server_address)
|
| +
|
| + # Connect to NetworkService.
|
| + self.network_service = application.ConnectToService("mojo:network_service",
|
| + network_service_mojom.NetworkService)
|
| +
|
| + # Construct a MojoUrlRedirector and add that as a handler to the server.
|
| + self.app_request_handler = MojoUrlRedirector(self.network_service)
|
| + self.http_server.SetHandler("/.*", self.app_request_handler)
|
| +
|
| +
|
| +def MojoMain(app_request_handle):
|
| + application_runner.RunMojoApplication(MojoUrlRedirectorApp(),
|
| + app_request_handle)
|
|
|