blob: 056877496867ddbfc485bb75d004ef0e5500a62f [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Associates request state, derived from a WSGI environ, with a unique id."""
import contextlib
import random
import string
import threading
import wsgiref.util
from google.appengine.api import request_info
def _choose_request_id():
return ''.join(random.choice(string.ascii_letters) for _ in range(10))
class WSGIRequestInfo(request_info.RequestInfo):
"""Associates request state, derived from a WSGI environ, with a unique id."""
def __init__(self, dispatcher):
"""Initializer for WSGIRequestInfo.
Args:
dispatcher: A request_info.Dispatcher instance to provide to API stubs.
"""
super(WSGIRequestInfo, self).__init__()
self._request_wsgi_environ = {}
self._request_id_to_module_configuration = {}
self._request_id_to_instance = {}
self._lock = threading.Lock()
self._dispatcher = dispatcher
@contextlib.contextmanager
def request(self, environ, module_configuration):
"""A context manager that consumes a WSGI environ and returns a request id.
with request_information.request(environ, app_info_external) as request_id:
# Stubs will have access to the state associated with request_id only in
# this context.
send_request_to_runtime(request_id, ...)
Args:
environ: An environ dict for the request as defined in PEP-333.
module_configuration: An application_configuration.ModuleConfiguration
instance respresenting the current module configuration.
Returns:
A unique string id that will be associated with the request.
"""
request_id = self.start_request(environ, module_configuration)
yield request_id
self.end_request(request_id)
def start_request(self, environ, module_configuration):
"""Adds the WSGI to the state of the class and returns a request id.
Args:
environ: An environ dict for the request as defined in PEP-333.
module_configuration: An application_configuration.ModuleConfiguration
instance respresenting the current module configuration.
Returns:
A unique string id that will be associated with the request.
"""
with self._lock:
request_id = _choose_request_id()
self._request_wsgi_environ[request_id] = environ
self._request_id_to_module_configuration[
request_id] = module_configuration
return request_id
def end_request(self, request_id):
"""Removes the information associated with given request_id."""
with self._lock:
del self._request_wsgi_environ[request_id]
del self._request_id_to_module_configuration[request_id]
if request_id in self._request_id_to_instance:
del self._request_id_to_instance[request_id]
def set_request_instance(self, request_id, instance):
with self._lock:
self._request_id_to_instance[request_id] = instance
def get_request_url(self, request_id):
"""Returns the URL the request e.g. 'http://localhost:8080/foo?bar=baz'.
Args:
request_id: The string id of the request making the API call.
Returns:
The URL of the request as a string.
"""
with self._lock:
environ = self._request_wsgi_environ[request_id]
return wsgiref.util.request_uri(environ)
def get_request_environ(self, request_id):
"""Returns a dict containing the WSGI environ for the request."""
with self._lock:
return self._request_wsgi_environ[request_id]
def get_dispatcher(self):
"""Returns the Dispatcher.
Returns:
The Dispatcher instance.
"""
return self._dispatcher
def get_module(self, request_id):
"""Returns the name of the module serving this request.
Args:
request_id: The string id of the request making the API call.
Returns:
A str containing the module name.
"""
with self._lock:
return self._request_id_to_module_configuration[request_id].module_name
def get_version(self, request_id):
"""Returns the version of the module serving this request.
Args:
request_id: The string id of the request making the API call.
Returns:
A str containing the version.
"""
with self._lock:
return self._request_id_to_module_configuration[request_id].major_version
def get_instance(self, request_id):
"""Returns the instance serving this request.
Args:
request_id: The string id of the request making the API call.
Returns:
The instance.Instance serving this request or None if no instance is
serving it.
"""
with self._lock:
return self._request_id_to_instance.get(request_id, None)