files: #!/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.
  #
  
  
  
  
  """An apiproxy stub that calls a remote handler via HTTP.
  
  This allows easy remote access to the App Engine datastore, and potentially any
  of the other App Engine APIs, using the same interface you use when accessing
  the service locally.
  
  An example Python script:
  ---
  from google.appengine.ext import db
  from google.appengine.ext.remote_api import remote_api_stub
  from myapp import models
  import getpass
  
  def auth_func():
    return (raw_input('Username:'), getpass.getpass('Password:'))
  
  remote_api_stub.ConfigureRemoteApi(None, '/_ah/remote_api', auth_func,
                                     'my-app.appspot.com')
  
  # Now you can access the remote datastore just as if your code was running on
  # App Engine!
  
  houses = models.House.all().fetch(100)
  for a_house in q:
    a_house.doors += 1
  db.put(houses)
  ---
  
  A few caveats:
  - Where possible, avoid iterating over queries. Fetching as many results as you
    will need is faster and more efficient. If you don't know how many results
    you need, or you need 'all of them', iterating is fine.
  - Likewise, it's a good idea to put entities in batches. Instead of calling put
    for each individual entity, accumulate them and put them in batches using
    db.put(), if you can.
  - Requests and responses are still limited to 1MB each, so if you have large
    entities or try and fetch or put many of them at once, your requests may fail.
  """
  
  
  
  
  
  
  
  
  
  import google
  import imp
  import os
  import pickle
  import random
  import sys
  import thread
  import threading
  import yaml
  import hashlib
  
  
  if os.environ.get('APPENGINE_RUNTIME') == 'python27':
    from google.appengine.api import apiproxy_rpc
    from google.appengine.api import apiproxy_stub_map
    from google.appengine.datastore import datastore_pb
    from google.appengine.ext.remote_api import remote_api_pb
    from google.appengine.ext.remote_api import remote_api_services
    from google.appengine.runtime import apiproxy_errors
  else:
    from google.appengine.api import apiproxy_rpc
    from google.appengine.api import apiproxy_stub_map
    from google.appengine.datastore import datastore_pb
    from google.appengine.ext.remote_api import remote_api_pb
    from google.appengine.ext.remote_api import remote_api_services
    from google.appengine.runtime import apiproxy_errors
  
  from google.appengine.tools import appengine_rpc
  
  
  _REQUEST_ID_HEADER = 'HTTP_X_APPENGINE_REQUEST_ID'
  
  
  class Error(Exception):
    """Base class for exceptions in this module."""
  
  
  class ConfigurationError(Error):
    """Exception for configuration errors."""
  
  
  class UnknownJavaServerError(Error):
    """Exception for exceptions returned from a Java remote_api handler."""
  
  
  def GetUserAgent():
    """Determines the value of the 'User-agent' header to use for HTTP requests.
  
    Returns:
      String containing the 'user-agent' header value, which includes the SDK
      version, the platform information, and the version of Python;
      e.g., "remote_api/1.0.1 Darwin/9.2.0 Python/2.5.2".
    """
    product_tokens = []
  
    product_tokens.append("Google-remote_api/1.0")
  
  
    product_tokens.append(appengine_rpc.GetPlatformToken())
  
  
    python_version = ".".join(str(i) for i in sys.version_info)
    product_tokens.append("Python/%s" % python_version)
  
    return " ".join(product_tokens)
  
  
  def GetSourceName():
    return "Google-remote_api-1.0"
  
  
  def HashEntity(entity):
    """Return a very-likely-unique hash of an entity."""
    return hashlib.sha1(entity.Encode()).digest()
  
  
  class TransactionData(object):
    """Encapsulates data about an individual transaction."""
  
    def __init__(self, thread_id, is_xg):
  
  
      self.thread_id = thread_id
  
  
  
      self.preconditions = {}
  
  
  
  
      self.entities = {}
  
      self.is_xg = is_xg
  
  
  class RemoteStub(object):
    """A stub for calling services on a remote server over HTTP.
  
    You can use this to stub out any service that the remote server supports.
    """
  
  
    _local = threading.local()
  
    def __init__(self, server, path, _test_stub_map=None):
      """Constructs a new RemoteStub that communicates with the specified server.
  
      Args:
        server: An instance of a subclass of
          google.appengine.tools.appengine_rpc.AbstractRpcServer.
        path: The path to the handler this stub should send requests to.
      """
  
  
      self._server = server
      self._path = path
      self._test_stub_map = _test_stub_map
  
    def _PreHookHandler(self, service, call, request, response):
      pass
  
    def _PostHookHandler(self, service, call, request, response):
      pass
  
    def MakeSyncCall(self, service, call, request, response):
      self._PreHookHandler(service, call, request, response)
      try:
        test_stub = self._test_stub_map and self._test_stub_map.GetStub(service)
        if test_stub:
  
          test_stub.MakeSyncCall(service, call, request, response)
        else:
          self._MakeRealSyncCall(service, call, request, response)
      finally:
        self._PostHookHandler(service, call, request, response)
  
    @classmethod
    def _GetRequestId(cls):
      """Returns the id of the request associated with the current thread."""
      try:
        return cls._local.request_id
      except AttributeError:
        return None
  
    @classmethod
    def _SetRequestId(cls, request_id):
      """Set the id of the request associated with the current thread."""
      cls._local.request_id = request_id
  
    def _MakeRealSyncCall(self, service, call, request, response):
      request_pb = remote_api_pb.Request()
      request_pb.set_service_name(service)
      request_pb.set_method(call)
      request_pb.set_request(request.Encode())
      if hasattr(self._local, 'request_id'):
  
  
        request_pb.set_request_id(self._local.request_id)
  
      response_pb = remote_api_pb.Response()
      encoded_request = request_pb.Encode()
      encoded_response = self._server.Send(self._path, encoded_request)
      response_pb.ParseFromString(encoded_response)
  
      if response_pb.has_application_error():
        error_pb = response_pb.application
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/ext/remote_api/remote_api_stub.py
files: #!/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.
  #
  
  
  
  
  """An apiproxy stub that calls a remote handler via HTTP.
  
  This allows easy remote access to the App Engine datastore, and potentially any
  of the other App Engine APIs, using the same interface you use when accessing
  the service locally.
  
  An example Python script:
  ---
  from google.appengine.ext import db
  from google.appengine.ext.remote_api import remote_api_stub
  from myapp import models
  import getpass
  
  def auth_func():
    return (raw_input('Username:'), getpass.getpass('Password:'))
  
  remote_api_stub.ConfigureRemoteApi(None, '/_ah/remote_api', auth_func,
                                     'my-app.appspot.com')
  
  # Now you can access the remote datastore just as if your code was running on
  # App Engine!
  
  houses = models.House.all().fetch(100)
  for a_house in q:
    a_house.doors += 1
  db.put(houses)
  ---
  
  A few caveats:
  - Where possible, avoid iterating over queries. Fetching as many results as you
    will need is faster and more efficient. If you don't know how many results
    you need, or you need 'all of them', iterating is fine.
  - Likewise, it's a good idea to put entities in batches. Instead of calling put
    for each individual entity, accumulate them and put them in batches using
    db.put(), if you can.
  - Requests and responses are still limited to 1MB each, so if you have large
    entities or try and fetch or put many of them at once, your requests may fail.
  """
  
  
  
  
  
  
  
  
  
  import google
  import imp
  import os
  import pickle
  import random
  import sys
  import thread
  import threading
  import yaml
  import hashlib
  
  
  if os.environ.get('APPENGINE_RUNTIME') == 'python27':
    from google.appengine.api import apiproxy_rpc
    from google.appengine.api import apiproxy_stub_map
    from google.appengine.datastore import datastore_pb
    from google.appengine.ext.remote_api import remote_api_pb
    from google.appengine.ext.remote_api import remote_api_services
    from google.appengine.runtime import apiproxy_errors
  else:
    from google.appengine.api import apiproxy_rpc
    from google.appengine.api import apiproxy_stub_map
    from google.appengine.datastore import datastore_pb
    from google.appengine.ext.remote_api import remote_api_pb
    from google.appengine.ext.remote_api import remote_api_services
    from google.appengine.runtime import apiproxy_errors
  
  from google.appengine.tools import appengine_rpc
  
  
  _REQUEST_ID_HEADER = 'HTTP_X_APPENGINE_REQUEST_ID'
  
  
  class Error(Exception):
    """Base class for exceptions in this module."""
  
  
  class ConfigurationError(Error):
    """Exception for configuration errors."""
  
  
  class UnknownJavaServerError(Error):
    """Exception for exceptions returned from a Java remote_api handler."""
  
  
  def GetUserAgent():
    """Determines the value of the 'User-agent' header to use for HTTP requests.
  
    Returns:
      String containing the 'user-agent' header value, which includes the SDK
      version, the platform information, and the version of Python;
      e.g., "remote_api/1.0.1 Darwin/9.2.0 Python/2.5.2".
    """
    product_tokens = []
  
    product_tokens.append("Google-remote_api/1.0")
  
  
    product_tokens.append(appengine_rpc.GetPlatformToken())
  
  
    python_version = ".".join(str(i) for i in sys.version_info)
    product_tokens.append("Python/%s" % python_version)
  
    return " ".join(product_tokens)
  
  
  def GetSourceName():
    return "Google-remote_api-1.0"
  
  
  def HashEntity(entity):
    """Return a very-likely-unique hash of an entity."""
    return hashlib.sha1(entity.Encode()).digest()
  
  
  class TransactionData(object):
    """Encapsulates data about an individual transaction."""
  
    def __init__(self, thread_id, is_xg):
  
  
      self.thread_id = thread_id
  
  
  
      self.preconditions = {}
  
  
  
  
      self.entities = {}
  
      self.is_xg = is_xg
  
  
  class RemoteStub(object):
    """A stub for calling services on a remote server over HTTP.
  
    You can use this to stub out any service that the remote server supports.
    """
  
  
    _local = threading.local()
  
    def __init__(self, server, path, _test_stub_map=None):
      """Constructs a new RemoteStub that communicates with the specified server.
  
      Args:
        server: An instance of a subclass of
          google.appengine.tools.appengine_rpc.AbstractRpcServer.
        path: The path to the handler this stub should send requests to.
      """
  
  
      self._server = server
      self._path = path
      self._test_stub_map = _test_stub_map
  
    def _PreHookHandler(self, service, call, request, response):
      pass
  
    def _PostHookHandler(self, service, call, request, response):
      pass
  
    def MakeSyncCall(self, service, call, request, response):
      self._PreHookHandler(service, call, request, response)
      try:
        test_stub = self._test_stub_map and self._test_stub_map.GetStub(service)
        if test_stub:
  
          test_stub.MakeSyncCall(service, call, request, response)
        else:
          self._MakeRealSyncCall(service, call, request, response)
      finally:
        self._PostHookHandler(service, call, request, response)
  
    @classmethod
    def _GetRequestId(cls):
      """Returns the id of the request associated with the current thread."""
      try:
        return cls._local.request_id
      except AttributeError:
        return None
  
    @classmethod
    def _SetRequestId(cls, request_id):
      """Set the id of the request associated with the current thread."""
      cls._local.request_id = request_id
  
    def _MakeRealSyncCall(self, service, call, request, response):
      request_pb = remote_api_pb.Request()
      request_pb.set_service_name(service)
      request_pb.set_method(call)
      request_pb.set_request(request.Encode())
      if hasattr(self._local, 'request_id'):
  
  
        request_pb.set_request_id(self._local.request_id)
  
      response_pb = remote_api_pb.Response()
      encoded_request = request_pb.Encode()
      encoded_response = self._server.Send(self._path, encoded_request)
      response_pb.ParseFromString(encoded_response)
  
      if response_pb.has_application_error():
        error_pb = response_pb.application
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/ext/remote_api/remote_api_stub.py
files: #!/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.
  #
  """The main entry point for the new development server."""
  
  
  import argparse
  import errno
  import getpass
  import itertools
  import logging
  import os
  import sys
  import tempfile
  import time
  
  from google.appengine.datastore import datastore_stub_util
  from google.appengine.tools import boolean_action
  from google.appengine.tools.devappserver2.admin import admin_server
  from google.appengine.tools.devappserver2 import api_server
  from google.appengine.tools.devappserver2 import application_configuration
  from google.appengine.tools.devappserver2 import dispatcher
  from google.appengine.tools.devappserver2 import login
  from google.appengine.tools.devappserver2 import runtime_config_pb2
  from google.appengine.tools.devappserver2 import shutdown
  from google.appengine.tools.devappserver2 import update_checker
  from google.appengine.tools.devappserver2 import wsgi_request_info
  
  from appscale.common import appscale_info
  
  # Initialize logging early -- otherwise some library packages may
  # pre-empt our log formatting.  NOTE: the level is provisional; it may
  # be changed in main() based on the --debug flag.
  logging.basicConfig(
      level=logging.INFO,
      format='%(levelname)-8s %(asctime)s %(filename)s:%(lineno)s] %(message)s')
  
  # Valid choices for --log_level and their corresponding constants in
  # runtime_config_pb2.Config.stderr_log_level.
  _LOG_LEVEL_TO_RUNTIME_CONSTANT = {
      'debug': 0,
      'info': 1,
      'warning': 2,
      'error': 3,
      'critical': 4,
  }
  
  # Valid choices for --dev_appserver_log_level and their corresponding Python
  # logging levels
  _LOG_LEVEL_TO_PYTHON_CONSTANT = {
      'debug': logging.DEBUG,
      'info': logging.INFO,
      'warning': logging.WARNING,
      'error': logging.ERROR,
      'critical': logging.CRITICAL,
  }
  
  
  def _generate_storage_paths(app_id):
    """Yield an infinite sequence of possible storage paths."""
    if sys.platform == 'win32':
      # The temp directory is per-user on Windows so there is no reason to add
      # the username to the generated directory name.
      user_format = ''
    else:
      try:
        user_name = getpass.getuser()
      except Exception:  # The possible set of exceptions is not documented.
        user_format = ''
      else:
        user_format = '.%s' % user_name
  
    tempdir = tempfile.gettempdir()
    yield os.path.join(tempdir, 'appengine.%s%s' % (app_id, user_format))
    for i in itertools.count(1):
      yield os.path.join(tempdir, 'appengine.%s%s.%d' % (app_id, user_format, i))
  
  
  def _get_storage_path(path, app_id):
    """Returns a path to the directory where stub data can be stored."""
    _, _, app_id = app_id.replace(':', '_').rpartition('~')
    if path is None:
      for path in _generate_storage_paths(app_id):
        try:
          os.mkdir(path, 0700)
        except OSError, e:
          if e.errno == errno.EEXIST:
            # Check that the directory is only accessable by the current user to
            # protect against an attacker creating the directory in advance in
            # order to access any created files. Windows has per-user temporary
            # directories and st_mode does not include per-user permission
            # information so assume that it is safe.
            if sys.platform == 'win32' or (
                (os.stat(path).st_mode & 0777) == 0700 and os.path.isdir(path)):
              return path
            else:
              continue
          raise
        else:
          return path
    elif not os.path.exists(path):
      os.mkdir(path)
      return path
    elif not os.path.isdir(path):
      raise IOError('the given storage path %r is a file, a directory was '
                    'expected' % path)
    else:
      return path
  
  
  class PortParser(object):
    """A parser for ints that represent ports."""
  
    def __init__(self, allow_port_zero=True):
      self._min_port = 0 if allow_port_zero else 1
  
    def __call__(self, value):
      try:
        port = int(value)
      except ValueError:
        raise argparse.ArgumentTypeError('Invalid port: %r' % value)
      if port < self._min_port or port >= (1 << 16):
        raise argparse.ArgumentTypeError('Invalid port: %d' % port)
      return port
  
  
  def parse_max_module_instances(value):
    """Returns the parsed value for the --max_module_instances flag.
  
    Args:
      value: A str containing the flag value for parse. The format should follow
          one of the following examples:
            1. "5" - All modules are limited to 5 instances.
            2. "default:3,backend:20" - The default module can have 3 instances,
               "backend" can have 20 instances and all other modules are
                unaffected.
    """
    if ':' not in value:
      try:
        max_module_instances = int(value)
      except ValueError:
        raise argparse.ArgumentTypeError('Invalid instance count: %r' % value)
      else:
        if not max_module_instances:
          raise argparse.ArgumentTypeError(
              'Cannot specify zero instances for all modules')
        return max_module_instances
    else:
      module_to_max_instances = {}
      for module_instance_max in value.split(','):
        try:
          module_name, max_instances = module_instance_max.split(':')
          max_instances = int(max_instances)
        except ValueError:
          raise argparse.ArgumentTypeError(
              'Expected "module:max_instances": %r' % module_instance_max)
        else:
          module_name = module_name.strip()
          if module_name in module_to_max_instances:
            raise argparse.ArgumentTypeError(
                'Duplicate max instance value: %r' % module_name)
          module_to_max_instances[module_name] = max_instances
      return module_to_max_instances
  
  
  def create_command_line_parser():
    """Returns an argparse.ArgumentParser to parse command line arguments."""
    # TODO: Add more robust argument validation. Consider what flags
    # are actually needed.
  
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('yaml_files', nargs='+')
  
    common_group = parser.add_argument_group('Common')
   
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/devappserver2.py
files: #!/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.
  #
  """The main entry point for the new development server."""
  
  
  import argparse
  import errno
  import getpass
  import itertools
  import logging
  import os
  import sys
  import tempfile
  import time
  
  from google.appengine.datastore import datastore_stub_util
  from google.appengine.tools import boolean_action
  from google.appengine.tools.devappserver2.admin import admin_server
  from google.appengine.tools.devappserver2 import api_server
  from google.appengine.tools.devappserver2 import application_configuration
  from google.appengine.tools.devappserver2 import dispatcher
  from google.appengine.tools.devappserver2 import login
  from google.appengine.tools.devappserver2 import runtime_config_pb2
  from google.appengine.tools.devappserver2 import shutdown
  from google.appengine.tools.devappserver2 import update_checker
  from google.appengine.tools.devappserver2 import wsgi_request_info
  
  from appscale.common import appscale_info
  
  # Initialize logging early -- otherwise some library packages may
  # pre-empt our log formatting.  NOTE: the level is provisional; it may
  # be changed in main() based on the --debug flag.
  logging.basicConfig(
      level=logging.INFO,
      format='%(levelname)-8s %(asctime)s %(filename)s:%(lineno)s] %(message)s')
  
  # Valid choices for --log_level and their corresponding constants in
  # runtime_config_pb2.Config.stderr_log_level.
  _LOG_LEVEL_TO_RUNTIME_CONSTANT = {
      'debug': 0,
      'info': 1,
      'warning': 2,
      'error': 3,
      'critical': 4,
  }
  
  # Valid choices for --dev_appserver_log_level and their corresponding Python
  # logging levels
  _LOG_LEVEL_TO_PYTHON_CONSTANT = {
      'debug': logging.DEBUG,
      'info': logging.INFO,
      'warning': logging.WARNING,
      'error': logging.ERROR,
      'critical': logging.CRITICAL,
  }
  
  
  def _generate_storage_paths(app_id):
    """Yield an infinite sequence of possible storage paths."""
    if sys.platform == 'win32':
      # The temp directory is per-user on Windows so there is no reason to add
      # the username to the generated directory name.
      user_format = ''
    else:
      try:
        user_name = getpass.getuser()
      except Exception:  # The possible set of exceptions is not documented.
        user_format = ''
      else:
        user_format = '.%s' % user_name
  
    tempdir = tempfile.gettempdir()
    yield os.path.join(tempdir, 'appengine.%s%s' % (app_id, user_format))
    for i in itertools.count(1):
      yield os.path.join(tempdir, 'appengine.%s%s.%d' % (app_id, user_format, i))
  
  
  def _get_storage_path(path, app_id):
    """Returns a path to the directory where stub data can be stored."""
    _, _, app_id = app_id.replace(':', '_').rpartition('~')
    if path is None:
      for path in _generate_storage_paths(app_id):
        try:
          os.mkdir(path, 0700)
        except OSError, e:
          if e.errno == errno.EEXIST:
            # Check that the directory is only accessable by the current user to
            # protect against an attacker creating the directory in advance in
            # order to access any created files. Windows has per-user temporary
            # directories and st_mode does not include per-user permission
            # information so assume that it is safe.
            if sys.platform == 'win32' or (
                (os.stat(path).st_mode & 0777) == 0700 and os.path.isdir(path)):
              return path
            else:
              continue
          raise
        else:
          return path
    elif not os.path.exists(path):
      os.mkdir(path)
      return path
    elif not os.path.isdir(path):
      raise IOError('the given storage path %r is a file, a directory was '
                    'expected' % path)
    else:
      return path
  
  
  class PortParser(object):
    """A parser for ints that represent ports."""
  
    def __init__(self, allow_port_zero=True):
      self._min_port = 0 if allow_port_zero else 1
  
    def __call__(self, value):
      try:
        port = int(value)
      except ValueError:
        raise argparse.ArgumentTypeError('Invalid port: %r' % value)
      if port < self._min_port or port >= (1 << 16):
        raise argparse.ArgumentTypeError('Invalid port: %d' % port)
      return port
  
  
  def parse_max_module_instances(value):
    """Returns the parsed value for the --max_module_instances flag.
  
    Args:
      value: A str containing the flag value for parse. The format should follow
          one of the following examples:
            1. "5" - All modules are limited to 5 instances.
            2. "default:3,backend:20" - The default module can have 3 instances,
               "backend" can have 20 instances and all other modules are
                unaffected.
    """
    if ':' not in value:
      try:
        max_module_instances = int(value)
      except ValueError:
        raise argparse.ArgumentTypeError('Invalid instance count: %r' % value)
      else:
        if not max_module_instances:
          raise argparse.ArgumentTypeError(
              'Cannot specify zero instances for all modules')
        return max_module_instances
    else:
      module_to_max_instances = {}
      for module_instance_max in value.split(','):
        try:
          module_name, max_instances = module_instance_max.split(':')
          max_instances = int(max_instances)
        except ValueError:
          raise argparse.ArgumentTypeError(
              'Expected "module:max_instances": %r' % module_instance_max)
        else:
          module_name = module_name.strip()
          if module_name in module_to_max_instances:
            raise argparse.ArgumentTypeError(
                'Duplicate max instance value: %r' % module_name)
          module_to_max_instances[module_name] = max_instances
      return module_to_max_instances
  
  
  def create_command_line_parser():
    """Returns an argparse.ArgumentParser to parse command line arguments."""
    # TODO: Add more robust argument validation. Consider what flags
    # are actually needed.
  
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('yaml_files', nargs='+')
  
    common_group = parser.add_argument_group('Common')
   
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/devappserver2.py
files: #!/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.
  #
  """Manage the lifecycle of modules and dispatch requests to them."""
  
  import collections
  import logging
  import os
  import threading
  import time
  import urlparse
  import wsgiref.headers
  
  from google.appengine.api import request_info
  from google.appengine.tools.devappserver2 import constants
  from google.appengine.tools.devappserver2 import instance
  from google.appengine.tools.devappserver2 import scheduled_executor
  from google.appengine.tools.devappserver2 import module
  from google.appengine.tools.devappserver2 import start_response_utils
  from google.appengine.tools.devappserver2 import thread_executor
  from google.appengine.tools.devappserver2 import wsgi_server
  
  _THREAD_POOL = thread_executor.ThreadExecutor()
  
  ResponseTuple = collections.namedtuple('ResponseTuple',
                                         ['status', 'headers', 'content'])
  
  
  class PortRegistry(object):
    def __init__(self):
      self._ports = {}
      self._ports_lock = threading.RLock()
  
    def add(self, port, _module, inst):
      with self._ports_lock:
        self._ports[port] = (_module, inst)
  
    def get(self, port):
      with self._ports_lock:
        return self._ports[port]
  
  
  class Dispatcher(request_info.Dispatcher):
    """A devappserver2 implementation of request_info.Dispatcher.
  
    In addition to the request_info.Dispatcher interface, it owns modules and
    manages their lifetimes.
    """
  
    def __init__(self,
                 configuration,
                 host,
                 port,
                 auth_domain,
                 runtime_stderr_loglevel,
                 php_executable_path,
                 enable_php_remote_debugging,
                 python_config,
                 cloud_sql_config,
                 module_to_max_instances,
                 use_mtime_file_watcher,
                 automatic_restart,
                 allow_skipped_files,
                 external_api_port=None):
      """Initializer for Dispatcher.
  
      Args:
        configuration: An application_configuration.ApplicationConfiguration
            instance storing the configuration data for the app.
        host: A string containing the host that any HTTP servers should bind to
            e.g. "localhost".
        port: An int specifying the first port where servers should listen.
        auth_domain: A string containing the auth domain to set in the environment
            variables.
        runtime_stderr_loglevel: An int reprenting the minimum logging level at
            which runtime log messages should be written to stderr. See
            devappserver2.py for possible values.
        php_executable_path: A string containing the path to PHP execution e.g.
            "/usr/bin/php-cgi".
        enable_php_remote_debugging: A boolean indicating whether the PHP
            interpreter should be started with XDebug remote debugging enabled.
        python_config: A runtime_config_pb2.PythonConfig instance containing
            Python runtime-specific configuration. If None then defaults are
            used.
        cloud_sql_config: A runtime_config_pb2.CloudSQL instance containing the
            required configuration for local Google Cloud SQL development. If None
            then Cloud SQL will not be available.
        module_to_max_instances: A mapping between a module name and the maximum
            number of instances that can be created (this overrides the settings
            found in the configuration argument) e.g.
            {'default': 10, 'backend': 15}.
        use_mtime_file_watcher: A bool containing whether to use mtime polling to
            monitor file changes even if other options are available on the
            current platform.
        automatic_restart: If True then instances will be restarted when a
            file or configuration change that effects them is detected.
        allow_skipped_files: If True then all files in the application's directory
            are readable, even if they appear in a static handler or "skip_files"
            directive.
        external_api_port: An integer specifying the location of an external API
            server.
      """
      self._configuration = configuration
      self._php_executable_path = php_executable_path
      self._enable_php_remote_debugging = enable_php_remote_debugging
      self._python_config = python_config
      self._cloud_sql_config = cloud_sql_config
      self._request_data = None
      self._api_port = None
      self._external_api_port = external_api_port
      self._running_modules = []
      self._module_configurations = {}
      self._host = host
      self._port = port
      self._auth_domain = auth_domain
      self._runtime_stderr_loglevel = runtime_stderr_loglevel
      self._module_name_to_module = {}
      self._dispatch_server = None
      self._quit_event = threading.Event()  # Set when quit() has been called.
      self._update_checking_thread = threading.Thread(
          target=self._loop_checking_for_updates)
      self._module_to_max_instances = module_to_max_instances or {}
      self._use_mtime_file_watcher = use_mtime_file_watcher
      self._automatic_restart = automatic_restart
      self._allow_skipped_files = allow_skipped_files
      self._executor = scheduled_executor.ScheduledExecutor(_THREAD_POOL)
      self._port_registry = PortRegistry()
  
    def start(self, api_port, request_data):
      """Starts the configured modules.
  
      Args:
        api_port: The port that APIServer listens for RPC requests on.
        request_data: A wsgi_request_info.WSGIRequestInfo that will be provided
            with request information for use by API stubs.
      """
      self._api_port = api_port
      self._request_data = request_data
      port = self._port
      self._executor.start()
      if self._configuration.dispatch:
        self._dispatch_server = wsgi_server.WsgiServer((self._host, port), self)
        self._dispatch_server.start()
        logging.info('Starting dispatcher running at: http://%s:%s', self._host,
                     self._dispatch_server.port)
        self._update_checking_thread.start()
        if port:
          port += 100
        self._port_registry.add(self._dispatch_server.port, None, None)
      for module_configuration in self._configuration.modules:
        self._module_configurations[
            module_configuration.module_name] = module_configuration
        _module, port = self._create_module(module_configuration, port,
                                            self._external_api_port)
        _module.start()
        self._module_name_to_module[module_configuration.module_name] = _module
        logging.info('Starting module "%s" running at: http://%s',
                     module_configuration.module_name, _module.balanced_address)
  
    @property
    def dispatch_port(self):
      """The
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/dispatcher.py
files: #!/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.
  #
  """Manage the lifecycle of modules and dispatch requests to them."""
  
  import collections
  import logging
  import os
  import threading
  import time
  import urlparse
  import wsgiref.headers
  
  from google.appengine.api import request_info
  from google.appengine.tools.devappserver2 import constants
  from google.appengine.tools.devappserver2 import instance
  from google.appengine.tools.devappserver2 import scheduled_executor
  from google.appengine.tools.devappserver2 import module
  from google.appengine.tools.devappserver2 import start_response_utils
  from google.appengine.tools.devappserver2 import thread_executor
  from google.appengine.tools.devappserver2 import wsgi_server
  
  _THREAD_POOL = thread_executor.ThreadExecutor()
  
  ResponseTuple = collections.namedtuple('ResponseTuple',
                                         ['status', 'headers', 'content'])
  
  
  class PortRegistry(object):
    def __init__(self):
      self._ports = {}
      self._ports_lock = threading.RLock()
  
    def add(self, port, _module, inst):
      with self._ports_lock:
        self._ports[port] = (_module, inst)
  
    def get(self, port):
      with self._ports_lock:
        return self._ports[port]
  
  
  class Dispatcher(request_info.Dispatcher):
    """A devappserver2 implementation of request_info.Dispatcher.
  
    In addition to the request_info.Dispatcher interface, it owns modules and
    manages their lifetimes.
    """
  
    def __init__(self,
                 configuration,
                 host,
                 port,
                 auth_domain,
                 runtime_stderr_loglevel,
                 php_executable_path,
                 enable_php_remote_debugging,
                 python_config,
                 cloud_sql_config,
                 module_to_max_instances,
                 use_mtime_file_watcher,
                 automatic_restart,
                 allow_skipped_files):
      """Initializer for Dispatcher.
  
      Args:
        configuration: An application_configuration.ApplicationConfiguration
            instance storing the configuration data for the app.
        host: A string containing the host that any HTTP servers should bind to
            e.g. "localhost".
        port: An int specifying the first port where servers should listen.
        auth_domain: A string containing the auth domain to set in the environment
            variables.
        runtime_stderr_loglevel: An int reprenting the minimum logging level at
            which runtime log messages should be written to stderr. See
            devappserver2.py for possible values.
        php_executable_path: A string containing the path to PHP execution e.g.
            "/usr/bin/php-cgi".
        enable_php_remote_debugging: A boolean indicating whether the PHP
            interpreter should be started with XDebug remote debugging enabled.
        python_config: A runtime_config_pb2.PythonConfig instance containing
            Python runtime-specific configuration. If None then defaults are
            used.
        cloud_sql_config: A runtime_config_pb2.CloudSQL instance containing the
            required configuration for local Google Cloud SQL development. If None
            then Cloud SQL will not be available.
        module_to_max_instances: A mapping between a module name and the maximum
            number of instances that can be created (this overrides the settings
            found in the configuration argument) e.g.
            {'default': 10, 'backend': 15}.
        use_mtime_file_watcher: A bool containing whether to use mtime polling to
            monitor file changes even if other options are available on the
            current platform.
        automatic_restart: If True then instances will be restarted when a
            file or configuration change that effects them is detected.
        allow_skipped_files: If True then all files in the application's directory
            are readable, even if they appear in a static handler or "skip_files"
            directive.
      """
      self._configuration = configuration
      self._php_executable_path = php_executable_path
      self._enable_php_remote_debugging = enable_php_remote_debugging
      self._python_config = python_config
      self._cloud_sql_config = cloud_sql_config
      self._request_data = None
      self._api_port = None
      self._running_modules = []
      self._module_configurations = {}
      self._host = host
      self._port = port
      self._auth_domain = auth_domain
      self._runtime_stderr_loglevel = runtime_stderr_loglevel
      self._module_name_to_module = {}
      self._dispatch_server = None
      self._quit_event = threading.Event()  # Set when quit() has been called.
      self._update_checking_thread = threading.Thread(
          target=self._loop_checking_for_updates)
      self._module_to_max_instances = module_to_max_instances or {}
      self._use_mtime_file_watcher = use_mtime_file_watcher
      self._automatic_restart = automatic_restart
      self._allow_skipped_files = allow_skipped_files
      self._executor = scheduled_executor.ScheduledExecutor(_THREAD_POOL)
      self._port_registry = PortRegistry()
  
    def start(self, api_port, request_data):
      """Starts the configured modules.
  
      Args:
        api_port: The port that APIServer listens for RPC requests on.
        request_data: A wsgi_request_info.WSGIRequestInfo that will be provided
            with request information for use by API stubs.
      """
      self._api_port = api_port
      self._request_data = request_data
      port = self._port
      self._executor.start()
      if self._configuration.dispatch:
        self._dispatch_server = wsgi_server.WsgiServer((self._host, port), self)
        self._dispatch_server.start()
        logging.info('Starting dispatcher running at: http://%s:%s', self._host,
                     self._dispatch_server.port)
        self._update_checking_thread.start()
        if port:
          port += 100
        self._port_registry.add(self._dispatch_server.port, None, None)
      for module_configuration in self._configuration.modules:
        self._module_configurations[
            module_configuration.module_name] = module_configuration
        _module, port = self._create_module(module_configuration, port)
        _module.start()
        self._module_name_to_module[module_configuration.module_name] = _module
        logging.info('Starting module "%s" running at: http://%s',
                     module_configuration.module_name, _module.balanced_address)
  
    @property
    def dispatch_port(self):
      """The port that the dispatch HTTP server for the Module is listening on."""
      assert self._dispatch_server, 'dispatch server not running'
      assert self._dispatch_server.ready, 'dispatch server not ready'
     
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/dispatcher.py
files: #!/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.
  #
  """Manage the lifecycle of runtime processes and dispatch requests to them."""
  
  
  import collections
  import cStringIO
  import functools
  import httplib
  import logging
  import math
  import os
  import os.path
  import random
  import re
  import string
  import struct
  import threading
  import time
  import urllib
  import urlparse
  import wsgiref.headers
  
  from google.appengine.api import api_base_pb
  from google.appengine.api import apiproxy_stub_map
  from google.appengine.api import appinfo
  from google.appengine.api import request_info
  from google.appengine.api.logservice import log_service_pb
  from google.appengine.tools.devappserver2 import application_configuration
  from google.appengine.tools.devappserver2 import blob_image
  from google.appengine.tools.devappserver2 import blob_upload
  from google.appengine.tools.devappserver2 import channel
  from google.appengine.tools.devappserver2 import constants
  
  from google.appengine.tools.devappserver2 import endpoints
  from google.appengine.tools.devappserver2 import errors
  from google.appengine.tools.devappserver2 import file_watcher
  from google.appengine.tools.devappserver2 import go_runtime
  from google.appengine.tools.devappserver2 import http_runtime_constants
  from google.appengine.tools.devappserver2 import instance
  from google.appengine.tools.devappserver2 import login
  from google.appengine.tools.devappserver2 import php_runtime
  from google.appengine.tools.devappserver2 import python_runtime
  from google.appengine.tools.devappserver2 import request_rewriter
  from google.appengine.tools.devappserver2 import runtime_config_pb2
  from google.appengine.tools.devappserver2 import start_response_utils
  from google.appengine.tools.devappserver2 import static_files_handler
  from google.appengine.tools.devappserver2 import thread_executor
  from google.appengine.tools.devappserver2 import url_handler
  from google.appengine.tools.devappserver2 import util
  from google.appengine.tools.devappserver2 import wsgi_handler
  from google.appengine.tools.devappserver2 import wsgi_server
  
  
  _LOWER_HEX_DIGITS = string.hexdigits.lower()
  _UPPER_HEX_DIGITS = string.hexdigits.upper()
  _REQUEST_ID_HASH_LENGTH = 8
  
  _THREAD_POOL = thread_executor.ThreadExecutor()
  _RESTART_INSTANCES_CONFIG_CHANGES = frozenset(
      [application_configuration.NORMALIZED_LIBRARIES_CHANGED,
       application_configuration.SKIP_FILES_CHANGED,
       application_configuration.NOBUILD_FILES_CHANGED,
       # The server must be restarted when the handlers change because files
       # appearing in static content handlers make them unavailable to the
       # runtime.
       application_configuration.HANDLERS_CHANGED,
       application_configuration.ENV_VARIABLES_CHANGED])
  
  _REQUEST_LOGGING_BLACKLIST_RE = re.compile(
      r'^/_ah/(?:channel/(?:dev|jsapi)|img|login|upload)')
  
  # Fake arguments for _handle_script_request for request types that don't use
  # user-specified handlers.
  _EMPTY_MATCH = re.match('', '')
  _DUMMY_URLMAP = appinfo.URLMap(script='/')
  _SHUTDOWN_TIMEOUT = 30
  
  
  def _static_files_regex_from_handlers(handlers):
    patterns = []
    for url_map in handlers:
      handler_type = url_map.GetHandlerType()
      if url_map.application_readable:
        continue
      if handler_type == appinfo.STATIC_FILES:
        patterns.append(r'(%s)' % url_map.upload)
      elif handler_type == appinfo.STATIC_DIR:
        patterns.append('(%s%s%s)' % (url_map.static_dir.rstrip(os.path.sep),
                                      re.escape(os.path.sep), r'.*'))
    return r'^%s$' % '|'.join(patterns)
  
  
  class InteractiveCommandError(errors.Error):
    pass
  
  
  class _ScriptHandler(url_handler.UserConfiguredURLHandler):
    """A URL handler that will cause the request to be dispatched to an instance.
  
    This handler is special in that it does not have a working handle() method
    since the Module's dispatch logic is used to select the appropriate Instance.
    """
  
    def __init__(self, url_map):
      """Initializer for _ScriptHandler.
  
      Args:
        url_map: An appinfo.URLMap instance containing the configuration for this
            handler.
      """
      try:
        url_pattern = re.compile('%s$' % url_map.url)
      except re.error, e:
        raise errors.InvalidAppConfigError(
            'invalid url %r in script handler: %s' % (url_map.url, e))
  
      super(_ScriptHandler, self).__init__(url_map, url_pattern)
      self.url_map = url_map
  
    def handle(self, match, environ, start_response):
      """This is a dummy method that should never be called."""
      raise NotImplementedError()
  
  
  class Module(object):
    """The abstract base for all instance pool implementations."""
  
    _RUNTIME_INSTANCE_FACTORIES = {
  
        'go': go_runtime.GoRuntimeInstanceFactory,
        'php': php_runtime.PHPRuntimeInstanceFactory,
        'python': python_runtime.PythonRuntimeInstanceFactory,
        'python27': python_runtime.PythonRuntimeInstanceFactory,
    }
  
    def _create_instance_factory(self,
                                 module_configuration):
      """Create an instance.InstanceFactory.
  
      Args:
        module_configuration: An application_configuration.ModuleConfiguration
            instance storing the configuration data for a module.
  
      Returns:
        A instance.InstanceFactory subclass that can be used to create instances
        with the provided configuration.
  
      Raises:
        RuntimeError: if the configuration specifies an unknown runtime.
      """
      # TODO: a bad runtime should be caught before we get here.
      if module_configuration.runtime not in self._RUNTIME_INSTANCE_FACTORIES:
        raise RuntimeError(
            'Unknown runtime %r; supported runtimes are %s.' %
            (module_configuration.runtime,
             ', '.join(
                 sorted(repr(k) for k in self._RUNTIME_INSTANCE_FACTORIES))))
      instance_factory = self._RUNTIME_INSTANCE_FACTORIES[
          module_configuration.runtime]
      return instance_factory(
          request_data=self._request_data,
          runtime_config_getter=self._get_runtime_config,
          module_configuration=module_configuration)
  
    def _create_url_handlers(self):
      """Constructs URLHandlers based on the module configuration.
  
      Returns:
        A list of url_handler.URLHand
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/module.py
files: #!/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.
  #
  """Manage the lifecycle of runtime processes and dispatch requests to them."""
  
  
  import collections
  import cStringIO
  import functools
  import httplib
  import logging
  import math
  import os
  import os.path
  import random
  import re
  import string
  import threading
  import time
  import urllib
  import urlparse
  import wsgiref.headers
  
  from google.appengine.api import api_base_pb
  from google.appengine.api import apiproxy_stub_map
  from google.appengine.api import appinfo
  from google.appengine.api import request_info
  from google.appengine.api.logservice import log_service_pb
  from google.appengine.tools.devappserver2 import application_configuration
  from google.appengine.tools.devappserver2 import blob_image
  from google.appengine.tools.devappserver2 import blob_upload
  from google.appengine.tools.devappserver2 import channel
  from google.appengine.tools.devappserver2 import constants
  
  from google.appengine.tools.devappserver2 import endpoints
  from google.appengine.tools.devappserver2 import errors
  from google.appengine.tools.devappserver2 import file_watcher
  from google.appengine.tools.devappserver2 import go_runtime
  from google.appengine.tools.devappserver2 import http_runtime_constants
  from google.appengine.tools.devappserver2 import instance
  from google.appengine.tools.devappserver2 import login
  from google.appengine.tools.devappserver2 import php_runtime
  from google.appengine.tools.devappserver2 import python_runtime
  from google.appengine.tools.devappserver2 import request_rewriter
  from google.appengine.tools.devappserver2 import runtime_config_pb2
  from google.appengine.tools.devappserver2 import start_response_utils
  from google.appengine.tools.devappserver2 import static_files_handler
  from google.appengine.tools.devappserver2 import thread_executor
  from google.appengine.tools.devappserver2 import url_handler
  from google.appengine.tools.devappserver2 import util
  from google.appengine.tools.devappserver2 import wsgi_handler
  from google.appengine.tools.devappserver2 import wsgi_server
  
  
  _LOWER_HEX_DIGITS = string.hexdigits.lower()
  _UPPER_HEX_DIGITS = string.hexdigits.upper()
  _REQUEST_ID_HASH_LENGTH = 8
  
  _THREAD_POOL = thread_executor.ThreadExecutor()
  _RESTART_INSTANCES_CONFIG_CHANGES = frozenset(
      [application_configuration.NORMALIZED_LIBRARIES_CHANGED,
       application_configuration.SKIP_FILES_CHANGED,
       application_configuration.NOBUILD_FILES_CHANGED,
       # The server must be restarted when the handlers change because files
       # appearing in static content handlers make them unavailable to the
       # runtime.
       application_configuration.HANDLERS_CHANGED,
       application_configuration.ENV_VARIABLES_CHANGED])
  
  _REQUEST_LOGGING_BLACKLIST_RE = re.compile(
      r'^/_ah/(?:channel/(?:dev|jsapi)|img|login|upload)')
  
  # Fake arguments for _handle_script_request for request types that don't use
  # user-specified handlers.
  _EMPTY_MATCH = re.match('', '')
  _DUMMY_URLMAP = appinfo.URLMap(script='/')
  _SHUTDOWN_TIMEOUT = 30
  
  
  def _static_files_regex_from_handlers(handlers):
    patterns = []
    for url_map in handlers:
      handler_type = url_map.GetHandlerType()
      if url_map.application_readable:
        continue
      if handler_type == appinfo.STATIC_FILES:
        patterns.append(r'(%s)' % url_map.upload)
      elif handler_type == appinfo.STATIC_DIR:
        patterns.append('(%s%s%s)' % (url_map.static_dir.rstrip(os.path.sep),
                                      re.escape(os.path.sep), r'.*'))
    return r'^%s$' % '|'.join(patterns)
  
  
  class InteractiveCommandError(errors.Error):
    pass
  
  
  class _ScriptHandler(url_handler.UserConfiguredURLHandler):
    """A URL handler that will cause the request to be dispatched to an instance.
  
    This handler is special in that it does not have a working handle() method
    since the Module's dispatch logic is used to select the appropriate Instance.
    """
  
    def __init__(self, url_map):
      """Initializer for _ScriptHandler.
  
      Args:
        url_map: An appinfo.URLMap instance containing the configuration for this
            handler.
      """
      try:
        url_pattern = re.compile('%s$' % url_map.url)
      except re.error, e:
        raise errors.InvalidAppConfigError(
            'invalid url %r in script handler: %s' % (url_map.url, e))
  
      super(_ScriptHandler, self).__init__(url_map, url_pattern)
      self.url_map = url_map
  
    def handle(self, match, environ, start_response):
      """This is a dummy method that should never be called."""
      raise NotImplementedError()
  
  
  class Module(object):
    """The abstract base for all instance pool implementations."""
  
    _RUNTIME_INSTANCE_FACTORIES = {
  
        'go': go_runtime.GoRuntimeInstanceFactory,
        'php': php_runtime.PHPRuntimeInstanceFactory,
        'python': python_runtime.PythonRuntimeInstanceFactory,
        'python27': python_runtime.PythonRuntimeInstanceFactory,
    }
  
    def _create_instance_factory(self,
                                 module_configuration):
      """Create an instance.InstanceFactory.
  
      Args:
        module_configuration: An application_configuration.ModuleConfiguration
            instance storing the configuration data for a module.
  
      Returns:
        A instance.InstanceFactory subclass that can be used to create instances
        with the provided configuration.
  
      Raises:
        RuntimeError: if the configuration specifies an unknown runtime.
      """
      # TODO: a bad runtime should be caught before we get here.
      if module_configuration.runtime not in self._RUNTIME_INSTANCE_FACTORIES:
        raise RuntimeError(
            'Unknown runtime %r; supported runtimes are %s.' %
            (module_configuration.runtime,
             ', '.join(
                 sorted(repr(k) for k in self._RUNTIME_INSTANCE_FACTORIES))))
      instance_factory = self._RUNTIME_INSTANCE_FACTORIES[
          module_configuration.runtime]
      return instance_factory(
          request_data=self._request_data,
          runtime_config_getter=self._get_runtime_config,
          module_configuration=module_configuration)
  
    def _create_url_handlers(self):
      """Constructs URLHandlers based on the module configuration.
  
      Returns:
        A list of url_handler.URLHandlers corresponding that
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/module.py
files: #!/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.
  #
  """A Python devappserver2 runtime."""
  
  
  import base64
  import os
  import struct
  import sys
  import time
  import traceback
  
  import google
  
  from google.appengine.api import rdbms_mysqldb
  from google.appengine.ext.remote_api import remote_api_stub
  from google.appengine.tools.devappserver2 import request_rewriter
  from google.appengine.tools.devappserver2 import runtime_config_pb2
  from google.appengine.tools.devappserver2 import wsgi_server
  from google.appengine.tools.devappserver2.python import sandbox
  
  
  _STARTUP_FAILURE_TEMPLATE = """
  <!DOCTYPE html>
  <html>
  <head>
  <title>Startup Script Failure</title>
  </head>
  
  <body>
  <b>Debugger startup failed: {exception_message}</b>
  <details>
    <summary>Configuration</summary>
    <pre><code>{config}</code></pre>
  </details>
  <details>
    <summary>Traceback</summary>
    <pre><code>{traceback}</code></pre>
  </details>
  </body>
  </html>"""
  
  
  def setup_stubs(config, external_api_port=None):
    """Sets up API stubs using remote API."""
    if external_api_port is None:
      external_api_server = None
    else:
      external_api_server = 'localhost:{}'.format(external_api_port)
  
    remote_api_stub.ConfigureRemoteApi(config.app_id, '/', lambda: ('', ''),
                                       'localhost:%d' % config.api_port,
                                       use_remote_datastore=False,
                                       use_async_rpc=True,
                                       external_api_server=external_api_server)
  
    if config.HasField('cloud_sql_config'):
      # Connect the RDBMS API to MySQL.
      sys.modules['google.appengine.api.rdbms'] = rdbms_mysqldb
      google.appengine.api.rdbms = rdbms_mysqldb
  
      connect_kwargs = dict(host=config.cloud_sql_config.mysql_host,
                            port=config.cloud_sql_config.mysql_port,
                            user=config.cloud_sql_config.mysql_user,
                            passwd=config.cloud_sql_config.mysql_password)
  
      if config.cloud_sql_config.mysql_socket:
        connect_kwargs['unix_socket'] = config.cloud_sql_config.mysql_socket
      elif (os.name == 'posix' and
            config.cloud_sql_config.mysql_host == 'localhost'):
        # From http://dev.mysql.com/doc/refman/5.0/en/connecting.html:
        # "On Unix, MySQL programs treat the host name localhost specially,
        # in a way that is likely different from what you expect compared to
        # other network-based programs. For connections to localhost, MySQL
        # programs attempt to connect to the local server by using a Unix socket
        # file. This occurs even if a --port or -P option is given to specify a
        # port number."
        #
        # This logic is duplicated in rdbms_mysqldb.connect but FindUnixSocket
        # will not worked in devappserver2 when rdbms_mysqldb.connect is called
        # because os.access is replaced in the sandboxed environment.
        #
        # A warning is not logged if FindUnixSocket returns None because it would
        # appear for all users, not just those who call connect.
        connect_kwargs['unix_socket'] = rdbms_mysqldb.FindUnixSocket()
  
      rdbms_mysqldb.SetConnectKwargs(**connect_kwargs)
  
  
  class StartupScriptFailureApplication(object):
    """A PEP-333 application that displays startup script failure information."""
  
    def __init__(self, config, exception_message, formatted_traceback):
      self._config = config
      self._exception_message = exception_message
      self._formatted_traceback = formatted_traceback
  
    def __call__(self, environ, start_response):
      start_response('500 Internal Server Error',
                     [('Content-Type', 'text/html')])
      yield _STARTUP_FAILURE_TEMPLATE.format(
          exception_message=self._exception_message,
          config=str(self._config),
          traceback=self._formatted_traceback)
  
  
  def expand_user(path):
    """Fake implementation of os.path.expanduser(path)."""
    return path
  
  
  def main():
    config = runtime_config_pb2.Config()
    config.ParseFromString(base64.b64decode(sys.stdin.read()))
  
    # AppScale: The external port is packed in the same field as the API port.
    external_api_port = None
    if config.api_port > 65535:
      port_bytes = struct.pack('I', config.api_port)
      config.api_port, external_api_port = struct.unpack('HH', port_bytes)
  
    debugging_app = None
    if config.python_config and config.python_config.startup_script:
      global_vars = {'config': config}
      try:
        execfile(config.python_config.startup_script, global_vars)
      except Exception, e:
        debugging_app = StartupScriptFailureApplication(config,
                                                        str(e),
                                                        traceback.format_exc())
  
    my_ip_address = None
    with open('/etc/appscale/my_private_ip') as file_handle:
      my_ip_address = file_handle.read().strip()
  
    nginx_host = None
    with open('/etc/appscale/login_ip') as file_handle:
      raw_ips = file_handle.read()
      ips = raw_ips.split('\n')
      nginx_host = ips[0]
  
    if debugging_app:
      server = wsgi_server.WsgiServer(
          ('localhost', 0),
          debugging_app)
    else:
      setup_stubs(config, external_api_port)
      sandbox.enable_sandbox(config)
      os.path.expanduser = expand_user
      # This import needs to be after enabling the sandbox so the runtime
      # implementation imports the sandboxed version of the logging module.
      from google.appengine.tools.devappserver2.python import request_handler
  
      os.environ['MY_IP_ADDRESS'] = my_ip_address
      os.environ['NGINX_HOST'] = nginx_host
      server = wsgi_server.WsgiServer(
          ('localhost', 0),
          request_rewriter.runtime_rewriter_middleware(
              request_handler.RequestHandler(config)))
    server.start()
    print server.port
    sys.stdout.close()
    sys.stdout = sys.stderr
    try:
      while True:
        time.sleep(1)
    except KeyboardInterrupt:
      pass
    finally:
      server.quit()
  
  
  if __name__ == '__main__':
    main()
  
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/python/runtime.py
files: #!/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.
  #
  """A Python devappserver2 runtime."""
  
  
  import base64
  import os
  import sys
  import time
  import traceback
  
  import google
  
  from google.appengine.api import rdbms_mysqldb
  from google.appengine.ext.remote_api import remote_api_stub
  from google.appengine.tools.devappserver2 import request_rewriter
  from google.appengine.tools.devappserver2 import runtime_config_pb2
  from google.appengine.tools.devappserver2 import wsgi_server
  from google.appengine.tools.devappserver2.python import sandbox
  
  
  _STARTUP_FAILURE_TEMPLATE = """
  <!DOCTYPE html>
  <html>
  <head>
  <title>Startup Script Failure</title>
  </head>
  
  <body>
  <b>Debugger startup failed: {exception_message}</b>
  <details>
    <summary>Configuration</summary>
    <pre><code>{config}</code></pre>
  </details>
  <details>
    <summary>Traceback</summary>
    <pre><code>{traceback}</code></pre>
  </details>
  </body>
  </html>"""
  
  
  def setup_stubs(config):
    """Sets up API stubs using remote API."""
    remote_api_stub.ConfigureRemoteApi(config.app_id, '/', lambda: ('', ''),
                                       'localhost:%d' % config.api_port,
                                       use_remote_datastore=False,
                                       use_async_rpc=True)
  
    if config.HasField('cloud_sql_config'):
      # Connect the RDBMS API to MySQL.
      sys.modules['google.appengine.api.rdbms'] = rdbms_mysqldb
      google.appengine.api.rdbms = rdbms_mysqldb
  
      connect_kwargs = dict(host=config.cloud_sql_config.mysql_host,
                            port=config.cloud_sql_config.mysql_port,
                            user=config.cloud_sql_config.mysql_user,
                            passwd=config.cloud_sql_config.mysql_password)
  
      if config.cloud_sql_config.mysql_socket:
        connect_kwargs['unix_socket'] = config.cloud_sql_config.mysql_socket
      elif (os.name == 'posix' and
            config.cloud_sql_config.mysql_host == 'localhost'):
        # From http://dev.mysql.com/doc/refman/5.0/en/connecting.html:
        # "On Unix, MySQL programs treat the host name localhost specially,
        # in a way that is likely different from what you expect compared to
        # other network-based programs. For connections to localhost, MySQL
        # programs attempt to connect to the local server by using a Unix socket
        # file. This occurs even if a --port or -P option is given to specify a
        # port number."
        #
        # This logic is duplicated in rdbms_mysqldb.connect but FindUnixSocket
        # will not worked in devappserver2 when rdbms_mysqldb.connect is called
        # because os.access is replaced in the sandboxed environment.
        #
        # A warning is not logged if FindUnixSocket returns None because it would
        # appear for all users, not just those who call connect.
        connect_kwargs['unix_socket'] = rdbms_mysqldb.FindUnixSocket()
  
      rdbms_mysqldb.SetConnectKwargs(**connect_kwargs)
  
  
  class StartupScriptFailureApplication(object):
    """A PEP-333 application that displays startup script failure information."""
  
    def __init__(self, config, exception_message, formatted_traceback):
      self._config = config
      self._exception_message = exception_message
      self._formatted_traceback = formatted_traceback
  
    def __call__(self, environ, start_response):
      start_response('500 Internal Server Error',
                     [('Content-Type', 'text/html')])
      yield _STARTUP_FAILURE_TEMPLATE.format(
          exception_message=self._exception_message,
          config=str(self._config),
          traceback=self._formatted_traceback)
  
  
  def expand_user(path):
    """Fake implementation of os.path.expanduser(path)."""
    return path
  
  
  def main():
    config = runtime_config_pb2.Config()
    config.ParseFromString(base64.b64decode(sys.stdin.read()))
    debugging_app = None
    if config.python_config and config.python_config.startup_script:
      global_vars = {'config': config}
      try:
        execfile(config.python_config.startup_script, global_vars)
      except Exception, e:
        debugging_app = StartupScriptFailureApplication(config,
                                                        str(e),
                                                        traceback.format_exc())
  
    my_ip_address = None
    with open('/etc/appscale/my_private_ip') as file_handle:
      my_ip_address = file_handle.read().strip()
  
    nginx_host = None
    with open('/etc/appscale/login_ip') as file_handle:
      raw_ips = file_handle.read()
      ips = raw_ips.split('\n')
      nginx_host = ips[0]
  
    if debugging_app:
      server = wsgi_server.WsgiServer(
          ('localhost', 0),
          debugging_app)
    else:
      setup_stubs(config)
      sandbox.enable_sandbox(config)
      os.path.expanduser = expand_user
      # This import needs to be after enabling the sandbox so the runtime
      # implementation imports the sandboxed version of the logging module.
      from google.appengine.tools.devappserver2.python import request_handler
  
      os.environ['MY_IP_ADDRESS'] = my_ip_address
      os.environ['NGINX_HOST'] = nginx_host
      server = wsgi_server.WsgiServer(
          ('localhost', 0),
          request_rewriter.runtime_rewriter_middleware(
              request_handler.RequestHandler(config)))
    server.start()
    print server.port
    sys.stdout.close()
    sys.stdout = sys.stderr
    try:
      while True:
        time.sleep(1)
    except KeyboardInterrupt:
      pass
    finally:
      server.quit()
  
  
  if __name__ == '__main__':
    main()
  
  
  [... the rest is omitted ...]
files: AppServer/google/appengine/tools/devappserver2/python/runtime.py