Beispiel #1
0
    def test_connection_error_process_quit(self):
        self.proxy = http_runtime.HttpRuntimeProxy(['/runtime'],
                                                   self.runtime_config_getter,
                                                   appinfo.AppInfoExternal())
        self.proxy._process = self.mox.CreateMockAnything()
        self.proxy._port = 123
        login.get_user_info(None).AndReturn(('', False, ''))
        httplib.HTTPConnection.connect().AndRaise(socket.error())
        self.proxy._process.poll().AndReturn(1)
        shutdown.async_quit()
        httplib.HTTPConnection.close()

        self.mox.ReplayAll()
        expected_headers = {
            'Content-Type': 'text/plain',
            'Content-Length': '110',
        }
        expected_content = (
            'the runtime process for the instance running on port '
            '123 has unexpectedly quit; exiting the development '
            'server')
        self.assertResponse('500 Internal Server Error',
                            expected_headers,
                            expected_content,
                            self.proxy.handle, {'PATH_INFO': '/'},
                            url_map=self.url_map,
                            match=re.match(self.url_map.url, '/get%20error'),
                            request_id='request id',
                            request_type=instance.NORMAL_REQUEST)
        self.mox.VerifyAll()
Beispiel #2
0
 def start(self):
   """Starts the runtime process and waits until it is ready to serve."""
   runtime_config = self._runtime_config_getter()
   serialized_config = base64.b64encode(runtime_config.SerializeToString())
   # TODO: Use a different process group to isolate the child process
   # from signals sent to the parent. Only available in subprocess in
   # Python 2.7.
   with self._process_lock:
     assert not self._process, 'start() can only be called once'
     self._process = safe_subprocess.start_process(
         self._args,
         serialized_config,
         stdout=subprocess.PIPE,
         env=self._env,
         cwd=self._server_configuration.application_root)
   line = self._process.stdout.readline()
   try:
     self._port = int(line)
   except ValueError:
     # The development server is in a bad state. Log an error message and quit.
     logging.error('unexpected port response from runtime [%r]; '
                   'exiting the development server',
                   line)
     shutdown.async_quit()
   else:
     self._check_serving()
  def test_connection_error_process_quit(self):
    self.proxy = http_runtime.HttpRuntimeProxy(
        ['/runtime'], self.runtime_config_getter, appinfo.AppInfoExternal())
    self.proxy._process = self.mox.CreateMockAnything()
    self.proxy._port = 123
    login.get_user_info(None).AndReturn(('', False, ''))
    httplib.HTTPConnection.connect().AndRaise(socket.error())
    self.proxy._process.poll().AndReturn(1)
    shutdown.async_quit()
    httplib.HTTPConnection.close()

    self.mox.ReplayAll()
    expected_headers = {
        'Content-Type': 'text/plain',
        'Content-Length': '110',
    }
    expected_content = ('the runtime process for the instance running on port '
                        '123 has unexpectedly quit; exiting the development '
                        'server')
    self.assertResponse('500 Internal Server Error',
                        expected_headers,
                        expected_content,
                        self.proxy.handle,
                        {'PATH_INFO': '/'},
                        url_map=self.url_map,
                        match=re.match(self.url_map.url, '/get%20error'),
                        request_id='request id',
                        request_type=instance.NORMAL_REQUEST)
    self.mox.VerifyAll()
    self.mox.VerifyAll()
Beispiel #4
0
  def _check_serving(self):
    """Checks if the runtime can serve requests.

    Quits the development server if the runtime cannot serve.
    """
    if not self._can_connect():
      logging.error('cannot connect to runtime running on port %r; '
                    'exiting the development server',
                    self._port)
      shutdown.async_quit()
Beispiel #5
0
  def test_start_bad_port(self):
    safe_subprocess.start_process(
        ['/runtime'],
        base64.b64encode(self.runtime_config.SerializeToString()),
        stdout=subprocess.PIPE,
        env={'foo': 'bar'},
        cwd=self.tmpdir).AndReturn(self.process)
    self.process.stdout.readline().AndReturn('hello 34567')
    shutdown.async_quit()

    self.mox.ReplayAll()
    self.proxy.start()
    self.mox.VerifyAll()
Beispiel #6
0
  def test_start_and_not_serving(self):
    safe_subprocess.start_process(
        ['/runtime'],
        base64.b64encode(self.runtime_config.SerializeToString()),
        stdout=subprocess.PIPE,
        env={'foo': 'bar'},
        cwd=self.tmpdir).AndReturn(self.process)
    self.process.stdout.readline().AndReturn('34567')

    httplib.HTTPConnection.connect().AndRaise(socket.error)
    httplib.HTTPConnection.close()
    shutdown.async_quit()

    self.mox.ReplayAll()
    self.proxy.start()
    self.mox.VerifyAll()
Beispiel #7
0
 def quit_and_raise(*_):
     shutdown.async_quit()
     raise IOError
Beispiel #8
0
 def test_wait_until_shutdown(self):
     self.mox.StubOutWithMock(time, 'sleep')
     time.sleep(1).WithSideEffects(lambda _: shutdown.async_quit())
     self.mox.ReplayAll()
     shutdown.wait_until_shutdown()
     self.mox.VerifyAll()
Beispiel #9
0
 def test_async_quit(self):
     self.mox.ReplayAll()
     shutdown.async_quit()
     self.assertTrue(shutdown._shutting_down)
     self.mox.VerifyAll()
 def quit_and_raise(*_):
   shutdown.async_quit()
   raise IOError
 def test_wait_until_shutdown(self):
   self.mox.StubOutWithMock(time, 'sleep')
   time.sleep(1).WithSideEffects(lambda _: shutdown.async_quit())
   self.mox.ReplayAll()
   shutdown.wait_until_shutdown()
   self.mox.VerifyAll()
 def test_async_quit(self):
   self.mox.ReplayAll()
   shutdown.async_quit()
   self.assertTrue(shutdown._shutting_down)
   self.mox.VerifyAll()
Beispiel #13
0
  def handle(self, environ, start_response, url_map, match, request_id,
             request_type):
    """Serves this request by forwarding it to the runtime process.

    Args:
      environ: An environ dict for the request as defined in PEP-333.
      start_response: A function with semantics defined in PEP-333.
      url_map: An appinfo.URLMap instance containing the configuration for the
          handler matching this request.
      match: A re.MatchObject containing the result of the matched URL pattern.
      request_id: A unique string id associated with the request.
      request_type: The type of the request. See instance.*_REQUEST module
          constants.

    Yields:
      A sequence of strings containing the body of the HTTP response.
    """
    environ[http_runtime_constants.SCRIPT_HEADER] = match.expand(url_map.script)
    if request_type == instance.BACKGROUND_REQUEST:
      environ[http_runtime_constants.REQUEST_TYPE_HEADER] = 'background'
    elif request_type == instance.SHUTDOWN_REQUEST:
      environ[http_runtime_constants.REQUEST_TYPE_HEADER] = 'shutdown'
    elif request_type == instance.INTERACTIVE_REQUEST:
      environ[http_runtime_constants.REQUEST_TYPE_HEADER] = 'interactive'

    for name in http_runtime_constants.ENVIRONS_TO_PROPAGATE:
      if http_runtime_constants.INTERNAL_ENVIRON_PREFIX + name not in environ:
        value = environ.get(name, None)
        if value is not None:
          environ[
              http_runtime_constants.INTERNAL_ENVIRON_PREFIX + name] = value
    headers = util.get_headers_from_environ(environ)
    if environ.get('QUERY_STRING'):
      url = '%s?%s' % (urllib.quote(environ['PATH_INFO']),
                       environ['QUERY_STRING'])
    else:
      url = urllib.quote(environ['PATH_INFO'])
    if 'CONTENT_LENGTH' in environ:
      headers['CONTENT-LENGTH'] = environ['CONTENT_LENGTH']
      data = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
    else:
      data = ''

    cookies = environ.get('HTTP_COOKIE')
    user_email, admin, user_id = login.get_user_info(cookies)
    if user_email:
      nickname, organization = user_email.split('@', 1)
    else:
      nickname = ''
      organization = ''
    headers[http_runtime_constants.REQUEST_ID_HEADER] = request_id
    headers[http_runtime_constants.INTERNAL_HEADER_PREFIX + 'User-Id'] = (
        user_id)
    headers[http_runtime_constants.INTERNAL_HEADER_PREFIX + 'User-Email'] = (
        user_email)
    headers[
        http_runtime_constants.INTERNAL_HEADER_PREFIX + 'User-Is-Admin'] = (
            str(int(admin)))
    headers[
        http_runtime_constants.INTERNAL_HEADER_PREFIX + 'User-Nickname'] = (
            nickname)
    headers[
        http_runtime_constants.INTERNAL_HEADER_PREFIX + 'User-Organization'] = (
            organization)
    headers['X-AppEngine-Country'] = 'ZZ'
    connection = httplib.HTTPConnection(self._host, self._port)
    with contextlib.closing(connection):
      try:
        connection.connect()
        connection.request(environ.get('REQUEST_METHOD', 'GET'),
                           url,
                           data,
                           dict(headers.items()))
        response = connection.getresponse()

        # Ensures that we avoid merging repeat headers into a single header,
        # allowing use of multiple Set-Cookie headers.
        headers = []
        for name in response.msg:
          for value in response.msg.getheaders(name):
            headers.append((name, value))

        response_headers = wsgiref.headers.Headers(headers)

        error_file = self._get_error_file()
        if (error_file and
            http_runtime_constants.ERROR_CODE_HEADER in response_headers):
          try:
            with open(error_file) as f:
              content = f.read()
          except IOError:
            content = 'Failed to load error handler'
            logging.exception('failed to load error file: %s', error_file)
          start_response('500 Internal Server Error',
                         [('Content-Type', 'text/html'),
                          ('Content-Length', str(len(content)))])
          yield content
          return
        del response_headers[http_runtime_constants.ERROR_CODE_HEADER]
        start_response('%s %s' % (response.status, response.reason),
                       response_headers.items())

        # Yield the response body in small blocks.
        block = response.read(512)
        while block:
          yield block
          block = response.read(512)
      except Exception:
        with self._process_lock:
          if self._process and self._process.poll() is not None:
            # The development server is in a bad state. Log and return an error
            # message and quit.
            message = ('the runtime process for the instance running on port '
                       '%d has unexpectedly quit; exiting the development '
                       'server' % (
                           self._port))
            logging.error(message)
            start_response('500 Internal Server Error',
                           [('Content-Type', 'text/plain'),
                            ('Content-Length', str(len(message)))])
            shutdown.async_quit()
            yield message
          else:
            raise
Beispiel #14
0
 def get(self):
     super(QuitHandler, self).get()
     self.response.status_int = 200
     self.response.content_type = 'text/plain'
     self.response.write('devappserver2 quitting')
     shutdown.async_quit()
Beispiel #15
0
 def get(self):
   super(QuitHandler, self).get()
   self.response.status_int = 200
   self.response.content_type = 'text/plain'
   self.response.write('devappserver2 quitting')
   shutdown.async_quit()