def test_connection_error_process_quit(self):
    self.proxy = http_proxy.HttpProxy(
        host='localhost', port=123,
        instance_died_unexpectedly=lambda: True,
        instance_logs_getter=get_instance_logs,
        error_handler_file=None)
    login.get_user_info(None).AndReturn(('', False, ''))
    http.client.HTTPConnection.connect().AndRaise(socket.error())
    http.client.HTTPConnection.close()

    self.mox.ReplayAll()
    expected_headers = {
        'Content-Type': 'text/plain',
        'Content-Length': '78',
    }
    expected_content = ('the runtime process for the instance running on port '
                        '123 has unexpectedly quit')
    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()
  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)
    self.proxy._stderr_tee = FakeTee('')
    httplib.HTTPConnection.close()

    self.mox.ReplayAll()
    expected_headers = {
        'Content-Type': 'text/plain',
        'Content-Length': '78',
    }
    expected_content = ('the runtime process for the instance running on port '
                        '123 has unexpectedly quit')
    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()
  def test_handle_with_error(self):
    error_handler_file = os.path.join(self.tmpdir, 'error.html')
    with open(error_handler_file, 'w') as f:
      f.write('error')

    self.proxy = http_proxy.HttpProxy(
        host='localhost', port=23456,
        instance_died_unexpectedly=lambda: False,
        instance_logs_getter=get_instance_logs,
        error_handler_file=error_handler_file)

    response = FakeHttpResponse(
        500, 'Internal Server Error',
        [(http_runtime_constants.ERROR_CODE_HEADER, '1')], '')
    login.get_user_info(None).AndReturn(('', False, ''))
    http.client.HTTPConnection.connect()
    http.client.HTTPConnection.request(
        'GET', '/get%20error', '',
        {'HEADER': 'value',
         http_runtime_constants.REQUEST_ID_HEADER: 'request id',
         'X-AppEngine-Country': 'ZZ',
         'X-Appengine-User-Email': '',
         'X-Appengine-User-Id': '',
         'X-Appengine-User-Is-Admin': '0',
         'X-Appengine-User-Nickname': '',
         'X-Appengine-User-Organization': '',
         'X-APPENGINE-DEV-SCRIPT': 'get.py',
         'X-APPENGINE-SERVER-NAME': 'localhost',
         'X-APPENGINE-SERVER-PORT': '8080',
         'X-APPENGINE-SERVER-PROTOCOL': 'HTTP/1.1',
        })
    http.client.HTTPConnection.getresponse().AndReturn(response)
    http.client.HTTPConnection.close()
    environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get error',
               'QUERY_STRING': '',
               'HTTP_X_APPENGINE_USER_ID': '123',
               'SERVER_NAME': 'localhost',
               'SERVER_PORT': '8080',
               'SERVER_PROTOCOL': 'HTTP/1.1',
              }
    self.mox.ReplayAll()
    expected_headers = {
        'Content-Type': 'text/html',
        'Content-Length': '5',
    }
    self.assertResponse('500 Internal Server Error', expected_headers, 'error',
                        self.proxy.handle, environ,
                        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()
  def test_http_response_early_failure(self):
    header = ('the runtime process gave a bad HTTP response: '
              'IncompleteRead(0 bytes read)\n\n')
    def dave_message():
      return "I'm sorry, Dave. I'm afraid I can't do that.\n"

    self.proxy = http_proxy.HttpProxy(
        host='localhost', port=23456,
        instance_died_unexpectedly=lambda: False,
        instance_logs_getter=dave_message,
        error_handler_file=None)

    login.get_user_info(None).AndReturn(('', False, ''))
    http.client.HTTPConnection.connect()
    http.client.HTTPConnection.request(
        'GET', '/get%20request?key=value', '',
        {'HEADER': 'value',
         http_runtime_constants.REQUEST_ID_HEADER: 'request id',
         'X-AppEngine-Country': 'ZZ',
         'X-Appengine-User-Email': '',
         'X-Appengine-User-Id': '',
         'X-Appengine-User-Is-Admin': '0',
         'X-Appengine-User-Nickname': '',
         'X-Appengine-User-Organization': '',
         'X-APPENGINE-DEV-SCRIPT': 'get.py',
         'X-APPENGINE-SERVER-NAME': 'localhost',
         'X-APPENGINE-SERVER-PORT': '8080',
         'X-APPENGINE-SERVER-PROTOCOL': 'HTTP/1.1',
        })
    http.client.HTTPConnection.getresponse().AndRaise(http.client.IncompleteRead(''))
    http.client.HTTPConnection.close()
    environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get request',
               'QUERY_STRING': 'key=value',
               'HTTP_X_APPENGINE_USER_ID': '123',
               'SERVER_NAME': 'localhost',
               'SERVER_PORT': '8080',
               'SERVER_PROTOCOL': 'HTTP/1.1',
              }
    self.mox.ReplayAll()
    expected_headers = {
        'Content-Type': 'text/plain',
        'Content-Length': '%d' % (len(header) + len(dave_message()))
    }

    self.assertResponse('500 Internal Server Error', expected_headers,
                        header + dave_message(),
                        self.proxy.handle, environ,
                        url_map=self.url_map,
                        match=re.match(self.url_map.url, '/get%20request'),
                        request_id='request id',
                        request_type=instance.NORMAL_REQUEST)
    self.mox.VerifyAll()
  def test_connection_error(self):
    login.get_user_info(None).AndReturn(('', False, ''))
    http.client.HTTPConnection.connect().AndRaise(socket.error())
    http.client.HTTPConnection.close()

    self.mox.ReplayAll()
    self.assertRaises(socket.error,
                      self.proxy.handle(
                          {'PATH_INFO': '/'},
                          start_response=None,  # Not used.
                          url_map=self.url_map,
                          match=re.match(self.url_map.url, '/get%20error'),
                          request_id='request id',
                          request_type=instance.NORMAL_REQUEST).__next__)
    self.mox.VerifyAll()
  def test_http_response_late_failure(self):
    line0 = "I know I've made some very poor decisions recently...\n"
    def dave_message():
      return "I'm afraid. I'm afraid, Dave.\n"

    self.proxy = http_proxy.HttpProxy(
        host='localhost', port=23456,
        instance_died_unexpectedly=lambda: False,
        instance_logs_getter=dave_message,
        error_handler_file=None)

    response = FakeHttpResponse(200, 'OK', [], line0)
    response.partial_read_error = http.client.IncompleteRead('')
    login.get_user_info(None).AndReturn(('', False, ''))
    http.client.HTTPConnection.connect()
    http.client.HTTPConnection.request(
        'GET', '/get%20request?key=value', '',
        {'HEADER': 'value',
         http_runtime_constants.REQUEST_ID_HEADER: 'request id',
         'X-AppEngine-Country': 'ZZ',
         'X-Appengine-User-Email': '',
         'X-Appengine-User-Id': '',
         'X-Appengine-User-Is-Admin': '0',
         'X-Appengine-User-Nickname': '',
         'X-Appengine-User-Organization': '',
         'X-APPENGINE-DEV-SCRIPT': 'get.py',
         'X-APPENGINE-SERVER-NAME': 'localhost',
         'X-APPENGINE-SERVER-PORT': '8080',
         'X-APPENGINE-SERVER-PROTOCOL': 'HTTP/1.1',
        })
    http.client.HTTPConnection.getresponse().AndReturn(response)
    http.client.HTTPConnection.close()
    environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get request',
               'QUERY_STRING': 'key=value',
               'HTTP_X_APPENGINE_USER_ID': '123',
               'SERVER_NAME': 'localhost',
               'SERVER_PORT': '8080',
               'SERVER_PROTOCOL': 'HTTP/1.1',
              }
    self.mox.ReplayAll()
    self.assertResponse('200 OK', {},
                        line0,
                        self.proxy.handle, environ,
                        url_map=self.url_map,
                        match=re.match(self.url_map.url, '/get%20request'),
                        request_id='request id',
                        request_type=instance.NORMAL_REQUEST)
    self.mox.VerifyAll()
Пример #7
0
  def test_get_user_info_does_not_exist(self):
    """Tests the get_user_info function when the cookie is not present."""
    http_cookie = 'one=two; three=four'
    email, admin, user_id = login.get_user_info(http_cookie,
                                                cookie_name=COOKIE_NAME)

    self.assertEqual('', email)
    self.assertFalse(admin)
Пример #8
0
 def test_handle_post(self):
   response = FakeHttpResponse(200, 'OK', [('Foo', 'Bar')], 'response')
   login.get_user_info('cookie').AndReturn(('*****@*****.**', True, '12345'))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'POST', '/post', 'post data',
       {'HEADER': 'value',
        'COOKIE': 'cookie',
        'CONTENT-TYPE': 'text/plain',
        'CONTENT-LENGTH': '9',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-Internal-Datacenter': 'us1',
        'X-Appengine-Internal-User-Email': '*****@*****.**',
        'X-Appengine-Internal-User-Id': '12345',
        'X-Appengine-Internal-User-Is-Admin': '1',
        'X-Appengine-Internal-User-Nickname': 'user',
        'X-Appengine-Internal-User-Organization': 'example.com',
        'X-APPENGINE-INTERNAL-SCRIPT': 'post.py',
        'X-APPENGINE-INTERNAL-SERVER-NAME': 'localhost',
        'X-APPENGINE-INTERNAL-SERVER-PORT': '8080',
        'X-APPENGINE-INTERNAL-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/post',
              'wsgi.input': cStringIO.StringIO('post data'),
              'CONTENT_LENGTH': '9',
              'CONTENT_TYPE': 'text/plain',
              'REQUEST_METHOD': 'POST',
              'HTTP_COOKIE': 'cookie',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   expected_headers = {
       'Foo': 'Bar',
   }
   self.assertResponse('200 OK', expected_headers, 'response',
                       self.proxy.handle, environ,
                       url_map=self.url_map,
                       match=re.match(self.url_map.url, '/post'),
                       request_id='request id',
                       request_type=instance.NORMAL_REQUEST)
   self.mox.VerifyAll()
 def test_http_response_early_failure(self):
   header = ('the runtime process gave a bad HTTP response: '
             'IncompleteRead(0 bytes read)\n\n')
   stderr0 = "I'm sorry, Dave. I'm afraid I can't do that.\n"
   self.proxy._stderr_tee = FakeTee(stderr0)
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'GET', '/get%20request?key=value', '',
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-Internal-User-Email': '',
        'X-Appengine-Internal-User-Id': '',
        'X-Appengine-Internal-User-Is-Admin': '0',
        'X-Appengine-Internal-User-Nickname': '',
        'X-Appengine-Internal-User-Organization': '',
        'X-APPENGINE-INTERNAL-SCRIPT': 'get.py',
        'X-APPENGINE-INTERNAL-SERVER-NAME': 'localhost',
        'X-APPENGINE-INTERNAL-SERVER-PORT': '8080',
        'X-APPENGINE-INTERNAL-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndRaise(httplib.IncompleteRead(''))
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get request',
              'QUERY_STRING': 'key=value',
              'HTTP_X_APPENGINE_INTERNAL_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   expected_headers = {
       'Content-Type': 'text/plain',
       'Content-Length': '121',#str(len(header) + len(stderr0)),
   }
   self.assertResponse('500 Internal Server Error', expected_headers,
                       header + stderr0,
                       self.proxy.handle, environ,
                       url_map=self.url_map,
                       match=re.match(self.url_map.url, '/get%20request'),
                       request_id='request id',
                       request_type=instance.NORMAL_REQUEST)
   self.mox.VerifyAll()
  def test_connection_error(self):
    self.proxy = http_runtime.HttpRuntimeProxy(
        ['/runtime'], self.runtime_config_getter, appinfo.AppInfoExternal())
    self.proxy._process = self.mox.CreateMockAnything()
    login.get_user_info(None).AndReturn(('', False, ''))
    httplib.HTTPConnection.connect().AndRaise(socket.error())
    self.proxy._process.poll().AndReturn(None)
    httplib.HTTPConnection.close()

    self.mox.ReplayAll()
    self.assertRaises(socket.error,
                      self.proxy.handle(
                          {'PATH_INFO': '/'},
                          start_response=None,  # Not used.
                          url_map=self.url_map,
                          match=re.match(self.url_map.url, '/get%20error'),
                          request_id='request id',
                          request_type=instance.NORMAL_REQUEST).next)
    self.mox.VerifyAll()
Пример #11
0
  def test_get_user_info_not_admin(self):
    """Tests the get_user_info function when the admin field is False."""
    cookie_value = self.get_cookie_value(EMAIL, NICKNAME, False)

    http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
    email, admin, user_id = login.get_user_info(http_cookie,
                                                cookie_name=COOKIE_NAME)

    self.assertEqual(EMAIL, email)
    self.assertFalse(admin)
Пример #12
0
 def test_handle_with_error_missing_error_handler(self):
   response = FakeHttpResponse(
       500, 'Internal Server Error',
       [(http_runtime_constants.ERROR_CODE_HEADER, '1')], '')
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'GET', '/get%20error', '',
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-Internal-Datacenter': 'us1',
        'X-Appengine-Internal-User-Email': '',
        'X-Appengine-Internal-User-Id': '',
        'X-Appengine-Internal-User-Is-Admin': '0',
        'X-Appengine-Internal-User-Nickname': '',
        'X-Appengine-Internal-User-Organization': '',
        'X-APPENGINE-INTERNAL-SCRIPT': 'get.py',
        'X-APPENGINE-INTERNAL-SERVER-NAME': 'localhost',
        'X-APPENGINE-INTERNAL-SERVER-PORT': '8080',
        'X-APPENGINE-INTERNAL-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get error',
              'QUERY_STRING': '',
              'HTTP_X_APPENGINE_INTERNAL_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   expected_headers = {
       'Content-Type': 'text/html',
       'Content-Length': '28',
   }
   self.assertResponse('500 Internal Server Error', expected_headers,
                       'Failed to load error handler', self.proxy.handle,
                       environ, 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()
 def test_http_response_late_failure(self):
   line0 = "I know I've made some very poor decisions recently...\n"
   line1 = "I'm afraid. I'm afraid, Dave.\n"
   line2 = "Dave, my mind is going. I can feel it.\n"
   response = FakeHttpResponse(200, 'OK', [], line0)
   response.partial_read_error = httplib.IncompleteRead('')
   self.proxy._stderr_tee = FakeTee(line1 + line2)
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'GET', '/get%20request?key=value', '',
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-Internal-User-Email': '',
        'X-Appengine-Internal-User-Id': '',
        'X-Appengine-Internal-User-Is-Admin': '0',
        'X-Appengine-Internal-User-Nickname': '',
        'X-Appengine-Internal-User-Organization': '',
        'X-APPENGINE-INTERNAL-SCRIPT': 'get.py',
        'X-APPENGINE-INTERNAL-SERVER-NAME': 'localhost',
        'X-APPENGINE-INTERNAL-SERVER-PORT': '8080',
        'X-APPENGINE-INTERNAL-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get request',
              'QUERY_STRING': 'key=value',
              'HTTP_X_APPENGINE_INTERNAL_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   self.assertResponse('200 OK', {},
                       line0,
                       self.proxy.handle, environ,
                       url_map=self.url_map,
                       match=re.match(self.url_map.url, '/get%20request'),
                       request_id='request id',
                       request_type=instance.NORMAL_REQUEST)
   self.mox.VerifyAll()
Пример #14
0
 def test_handle_ssl(self):
   response = FakeHttpResponse(200,
                               'OK',
                               [('Foo', 'a'), ('Foo', 'b'), ('Var', 'c')],
                               'response')
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()  # pylint: disable=no-value-for-parameter
   httplib.HTTPConnection.request(
       'GET', '/get%20request?key=value', None,
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-User-Email': '',
        'X-Appengine-User-Id': '',
        'X-Appengine-User-Is-Admin': '0',
        'X-Appengine-User-Nickname': '',
        'X-Appengine-User-Organization': '',
        'X-Appengine-Dev-LocalSSL': '1',
        'X-APPENGINE-DEV-SCRIPT': 'get.py',
        'X-APPENGINE-SERVER-NAME': 'localhost',
        'X-APPENGINE-SERVER-PORT': '8080',
        'X-APPENGINE-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)  # pylint: disable=no-value-for-parameter
   httplib.HTTPConnection.close()  # pylint: disable=no-value-for-parameter
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get request',
              'QUERY_STRING': 'key=value',
              'HTTP_X_APPENGINE_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
              'wsgi.url_scheme': 'https',
             }
   self.mox.ReplayAll()
   expected_headers = [('Foo', 'a'), ('Foo', 'b'), ('Var', 'c')]
   self.assertResponse('200 OK', expected_headers, 'response',
                       self.proxy.handle, environ,
                       url_map=self.url_map,
                       match=re.match(self.url_map.url, '/get%20request'),
                       request_id='request id',
                       request_type=instance.NORMAL_REQUEST)
   self.mox.VerifyAll()
Пример #15
0
  def test_get_user_info_not_admin(self):
    """Tests the get_user_info function when the admin field is False."""
    cookie_value = '%s:False:%s' % (EMAIL, USER_ID)

    http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
    email, admin, user_id = login.get_user_info(http_cookie,
                                                cookie_name=COOKIE_NAME)

    self.assertEqual(EMAIL, email)
    self.assertFalse(admin)
    self.assertEqual(USER_ID, user_id)
Пример #16
0
  def test_get_user_info_invalid_email(self):
    """Tests the get_user_info function when the admin field is False."""
    cookie_value = 'foo:True:%s' % USER_ID

    http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
    email, admin, user_id = login.get_user_info(http_cookie,
                                                cookie_name=COOKIE_NAME)

    self.assertEqual('', email)
    self.assertFalse(admin)
    self.assertEqual('', user_id)
Пример #17
0
  def test_get_user_info_admin(self):
    """Tests the get_user_info function when the admin field is True."""
    cookie_value = '%s:True:%s' % (EMAIL, USER_ID)

    http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
    email, admin, user_id = login.get_user_info(http_cookie,
                                                cookie_name=COOKIE_NAME)

    self.assertEqual(EMAIL, email)
    self.assertTrue(admin)
    self.assertEqual(USER_ID, user_id)
Пример #18
0
  def handle_authorization(self, environ, start_response):
    """Handles the response if the user is not authorized to access this URL.

    The authorization check is based on the 'login' setting for this handler,
    configured by the supplied url_map.

    Args:
      environ: An environ dict for the current request as defined in PEP-333.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      An iterable over strings containing the body of an HTTP response, if the
      authorization check fails or the login UI must be displayed. None if the
      user is authorized to access the resource.
    """
    admin_only = self._url_map.login == appinfo.LOGIN_ADMIN
    requires_login = self._url_map.login == appinfo.LOGIN_REQUIRED or admin_only
    auth_fail_action = self._url_map.auth_fail_action

    cookies = environ.get('HTTP_COOKIE')
    email_addr, admin, _ = login.get_user_info(cookies)

    # AppScale: Here we check to see if our secret hash is in the header which
    # authenticates that the task was created from an AppScale deployment and
    # not an unauthorized party.
    if (constants.FAKE_IS_ADMIN_HEADER in environ and
            self._secret_hash == environ[constants.FAKE_IS_ADMIN_HEADER]):
      admin = True

    if constants.FAKE_LOGGED_IN_HEADER in environ:
      email_addr = 'Fake User'

    # admin has an effect only with login: admin (not login: required).
    if requires_login and not email_addr and not (admin and admin_only):
      if auth_fail_action == appinfo.AUTH_FAIL_ACTION_REDIRECT:
        logging.debug('login required, redirecting user')
        return login.login_redirect(wsgiref.util.application_uri(environ),
                                    wsgiref.util.request_uri(environ),
                                    start_response)
      elif auth_fail_action == appinfo.AUTH_FAIL_ACTION_UNAUTHORIZED:
        logging.debug('login required, user unauthorized')
        start_response('401 Not authorized', [('Content-Type', 'text/html'),
                                              ('Cache-Control', 'no-cache')])
        return ['Login required to view page.']
    elif admin_only and not admin:
      logging.debug('admin required, user unauthorized')
      start_response('401 Not authorized', [('Content-Type', 'text/html'),
                                            ('Cache-Control', 'no-cache')])
      return ['Current logged in user %s is not '
              'authorized to view this page.'
              % email_addr]

    # Authorization check succeeded
    return None
Пример #19
0
  def test_get_user_info_invalid_email(self):
    """Tests the get_user_info function when the admin field is False."""
    cookie_value = 'foo:True:%s' % USER_ID

    http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
    email, admin, user_id = login.get_user_info(http_cookie,
                                                cookie_name=COOKIE_NAME)

    self.assertEqual('', email)
    self.assertFalse(admin)
    self.assertEqual('', user_id)
Пример #20
0
    def test_get_user_info_bad_cookie(self):
        """Tests the get_user_info function when the cookie is malformed."""
        cookie_name = 'SinaRot/g/get'  # seen in the wild
        cookie_value = 'blah'

        http_cookie = '%s=%s' % (cookie_name, cookie_value)
        email, admin, user_id = login.get_user_info(http_cookie,
                                                    cookie_name=cookie_name)

        self.assertEqual('', email)
        self.assertFalse(admin)
Пример #21
0
    def test_get_user_info_admin(self):
        """Tests the get_user_info function when the admin field is True."""
        cookie_value = self.get_cookie_value(EMAIL, NICKNAME, True)

        http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME,
                                                      cookie_value)
        email, admin, _ = login.get_user_info(http_cookie,
                                              cookie_name=COOKIE_NAME)

        self.assertEqual(EMAIL, email)
        self.assertTrue(admin)
Пример #22
0
  def test_get_user_info_bad_cookie(self):
    """Tests the get_user_info function when the cookie is malformed."""
    cookie_name = 'SinaRot/g/get'  # seen in the wild
    cookie_value = 'blah'

    http_cookie = '%s=%s' % (cookie_name, cookie_value)
    email, admin, user_id = login.get_user_info(http_cookie,
                                                cookie_name=cookie_name)

    self.assertEqual('', email)
    self.assertFalse(admin)
 def test_handle_with_error_no_error_handler(self):
   self.proxy = http_runtime.HttpRuntimeProxy(
       ['/runtime'], self.runtime_config_getter, appinfo.AppInfoExternal())
   self.proxy._port = 23456
   response = FakeHttpResponse(
       500, 'Internal Server Error',
       [(http_runtime_constants.ERROR_CODE_HEADER, '1')], '')
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'GET', '/get%20error', '',
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-Internal-User-Email': '',
        'X-Appengine-Internal-User-Id': '',
        'X-Appengine-Internal-User-Is-Admin': '0',
        'X-Appengine-Internal-User-Nickname': '',
        'X-Appengine-Internal-User-Organization': '',
        'X-APPENGINE-INTERNAL-SCRIPT': 'get.py',
        'X-APPENGINE-INTERNAL-SERVER-NAME': 'localhost',
        'X-APPENGINE-INTERNAL-SERVER-PORT': '8080',
        'X-APPENGINE-INTERNAL-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get error',
              'QUERY_STRING': '',
              'HTTP_X_APPENGINE_INTERNAL_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   self.assertResponse('500 Internal Server Error', {}, '',
                       self.proxy.handle, environ,
                       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()
Пример #24
0
 def test_handle_background_thread(self):
   response = FakeHttpResponse(200, 'OK', [('Foo', 'Bar')], 'response')
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'GET', '/get%20request?key=value', '',
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-Internal-Datacenter': 'us1',
        'X-Appengine-Internal-User-Email': '',
        'X-Appengine-Internal-User-Id': '',
        'X-Appengine-Internal-User-Is-Admin': '0',
        'X-Appengine-Internal-User-Nickname': '',
        'X-Appengine-Internal-User-Organization': '',
        'X-APPENGINE-INTERNAL-SCRIPT': 'get.py',
        'X-APPENGINE-INTERNAL-REQUEST-TYPE': 'background',
        'X-APPENGINE-INTERNAL-SERVER-NAME': 'localhost',
        'X-APPENGINE-INTERNAL-SERVER-PORT': '8080',
        'X-APPENGINE-INTERNAL-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get request',
              'QUERY_STRING': 'key=value',
              'HTTP_X_APPENGINE_INTERNAL_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   expected_headers = {
       'Foo': 'Bar',
   }
   self.assertResponse('200 OK', expected_headers, 'response',
                       self.proxy.handle, environ,
                       url_map=self.url_map,
                       match=re.match(self.url_map.url, '/get%20request'),
                       request_id='request id',
                       request_type=instance.BACKGROUND_REQUEST)
   self.mox.VerifyAll()
Пример #25
0
    def handle_authorization(self, environ, start_response):
        """Handles the response if the user is not authorized to access this URL.

    The authorization check is based on the 'login' setting for this handler,
    configured by the supplied url_map.

    Args:
      environ: An environ dict for the current request as defined in PEP-333.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      An iterable over strings containing the body of an HTTP response, if the
      authorization check fails or the login UI must be displayed. None if the
      user is authorized to access the resource.
    """
        admin_only = self._url_map.login == appinfo.LOGIN_ADMIN
        requires_login = self._url_map.login == appinfo.LOGIN_REQUIRED or admin_only
        auth_fail_action = self._url_map.auth_fail_action

        cookies = environ.get('HTTP_COOKIE')
        email_addr, admin, _ = login.get_user_info(cookies)

        if constants.FAKE_IS_ADMIN_HEADER in environ:
            admin = True

        if constants.FAKE_LOGGED_IN_HEADER in environ:
            email_addr = 'Fake User'

        # admin has an effect only with login: admin (not login: required).
        if requires_login and not email_addr and not (admin and admin_only):
            if auth_fail_action == appinfo.AUTH_FAIL_ACTION_REDIRECT:
                logging.debug('login required, redirecting user')
                return login.login_redirect(
                    wsgiref.util.application_uri(environ),
                    wsgiref.util.request_uri(environ), start_response)
            elif auth_fail_action == appinfo.AUTH_FAIL_ACTION_UNAUTHORIZED:
                logging.debug('login required, user unauthorized')
                start_response('401 Not authorized',
                               [('Content-Type', 'text/html'),
                                ('Cache-Control', 'no-cache')])
                return ['Login required to view page.']
        elif admin_only and not admin:
            logging.debug('admin required, user unauthorized')
            start_response('401 Not authorized',
                           [('Content-Type', 'text/html'),
                            ('Cache-Control', 'no-cache')])
            return [
                'Current logged in user %s is not '
                'authorized to view this page.' % email_addr
            ]

        # Authorization check succeeded
        return None
Пример #26
0
 def test_handle_with_error_no_error_handler(self):
   self.proxy = http_runtime.HttpRuntimeProxy(
       ['/runtime'], self.runtime_config_getter, appinfo.AppInfoExternal())
   response = FakeHttpResponse(
       500, 'Internal Server Error',
       [(http_runtime_constants.ERROR_CODE_HEADER, '1')], '')
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'GET', '/get%20error', '',
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-Internal-User-Email': '',
        'X-Appengine-Internal-User-Id': '',
        'X-Appengine-Internal-User-Is-Admin': '0',
        'X-Appengine-Internal-User-Nickname': '',
        'X-Appengine-Internal-User-Organization': '',
        'X-APPENGINE-INTERNAL-SCRIPT': 'get.py',
        'X-APPENGINE-INTERNAL-SERVER-NAME': 'localhost',
        'X-APPENGINE-INTERNAL-SERVER-PORT': '8080',
        'X-APPENGINE-INTERNAL-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get error',
              'QUERY_STRING': '',
              'HTTP_X_APPENGINE_INTERNAL_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   self.assertResponse('500 Internal Server Error', {}, '',
                       self.proxy.handle, environ,
                       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()
Пример #27
0
 def test_handle_background_thread(self):
   response = FakeHttpResponse(200, 'OK', [('Foo', 'Bar')], 'response')
   login.get_user_info(None).AndReturn(('', False, ''))
   httplib.HTTPConnection.connect()
   httplib.HTTPConnection.request(
       'GET', '/get%20request?key=value', '',
       {'HEADER': 'value',
        http_runtime_constants.REQUEST_ID_HEADER: 'request id',
        'X-AppEngine-Country': 'ZZ',
        'X-Appengine-User-Email': '',
        'X-Appengine-User-Id': '',
        'X-Appengine-User-Is-Admin': '0',
        'X-Appengine-User-Nickname': '',
        'X-Appengine-User-Organization': '',
        'X-APPENGINE-DEV-SCRIPT': 'get.py',
        'X-APPENGINE-DEV-REQUEST-TYPE': 'background',
        'X-APPENGINE-SERVER-NAME': 'localhost',
        'X-APPENGINE-SERVER-PORT': '8080',
        'X-APPENGINE-SERVER-PROTOCOL': 'HTTP/1.1',
       })
   httplib.HTTPConnection.getresponse().AndReturn(response)
   httplib.HTTPConnection.close()
   environ = {'HTTP_HEADER': 'value', 'PATH_INFO': '/get request',
              'QUERY_STRING': 'key=value',
              'HTTP_X_APPENGINE_USER_ID': '123',
              'SERVER_NAME': 'localhost',
              'SERVER_PORT': '8080',
              'SERVER_PROTOCOL': 'HTTP/1.1',
             }
   self.mox.ReplayAll()
   expected_headers = {
       'Foo': 'Bar',
   }
   self.assertResponse('200 OK', expected_headers, 'response',
                       self.proxy.handle, environ,
                       url_map=self.url_map,
                       match=re.match(self.url_map.url, '/get%20request'),
                       request_id='request id',
                       request_type=instance.BACKGROUND_REQUEST)
   self.mox.VerifyAll()
Пример #28
0
    def test_connection_error(self):
        self.proxy = http_runtime.HttpRuntimeProxy(['/runtime'],
                                                   self.runtime_config_getter,
                                                   appinfo.AppInfoExternal())
        self.proxy._process = self.mox.CreateMockAnything()
        login.get_user_info(None).AndReturn(('', False, ''))
        httplib.HTTPConnection.connect().AndRaise(socket.error())
        self.proxy._process.poll().AndReturn(None)
        httplib.HTTPConnection.close()

        self.mox.ReplayAll()
        self.assertRaises(
            socket.error,
            self.proxy.handle(
                {
                    'PATH_INFO': '/'
                },
                start_response=None,  # Not used.
                url_map=self.url_map,
                match=re.match(self.url_map.url, '/get%20error'),
                request_id='request id',
                request_type=instance.NORMAL_REQUEST).next)
        self.mox.VerifyAll()
Пример #29
0
    def handle_authorization(self, environ, start_response):
        """Handles the response if the user is not authorized to access this URL.

    The authorization check is based on the 'login' setting for this handler,
    configured by the supplied url_map.

    Args:
      environ: An environ dict for the current request as defined in PEP-333.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      An iterable over strings containing the body of an HTTP response, if the
      authorization check fails or the login UI must be displayed. None if the
      user is authorized to access the resource.
    """
        admin_only = self._url_map.login == appinfo.LOGIN_ADMIN
        requires_login = self._url_map.login == appinfo.LOGIN_REQUIRED or admin_only
        auth_fail_action = self._url_map.auth_fail_action

        cookies = environ.get("HTTP_COOKIE")
        email_addr, admin, _ = login.get_user_info(cookies)

        if constants.FAKE_IS_ADMIN_HEADER in environ:
            admin = True

        if constants.FAKE_LOGGED_IN_HEADER in environ:
            email_addr = "Fake User"

        # admin has an effect only with login: admin (not login: required).
        if requires_login and not email_addr and not (admin and admin_only):
            if auth_fail_action == appinfo.AUTH_FAIL_ACTION_REDIRECT:
                logging.debug("login required, redirecting user")
                return login.login_redirect(
                    wsgiref.util.application_uri(environ), wsgiref.util.request_uri(environ), start_response
                )
            elif auth_fail_action == appinfo.AUTH_FAIL_ACTION_UNAUTHORIZED:
                logging.debug("login required, user unauthorized")
                start_response("401 Not authorized", [("Content-Type", "text/html"), ("Cache-Control", "no-cache")])
                return ["Login required to view page."]
        elif admin_only and not admin:
            logging.debug("admin required, user unauthorized")
            start_response("401 Not authorized", [("Content-Type", "text/html"), ("Cache-Control", "no-cache")])
            return ["Current logged in user %s is not " "authorized to view this page." % email_addr]

        # Authorization check succeeded
        return None
Пример #30
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

        prefix = http_runtime_constants.INTERNAL_HEADER_PREFIX

        # The Go runtime from the 1.9.48 SDK looks for different headers.
        if self._module_configuration.runtime == 'go':
            headers['X-Appengine-Dev-Request-Id'] = request_id
            prefix = 'X-Appengine-'

        headers[prefix + 'User-Id'] = (user_id)
        headers[prefix + 'User-Email'] = (user_email)
        headers[prefix + 'User-Is-Admin'] = (str(int(admin)))
        headers[prefix + 'User-Nickname'] = (nickname)
        headers[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
Пример #31
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.
    """
        if self._prior_error:
            yield self._handle_error(self._prior_error, start_response)
            return

        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()))

                try:
                    response = connection.getresponse()
                except httplib.HTTPException as e:
                    # The runtime process has written a bad HTTP response. For example,
                    # a Go runtime process may have crashed in app-specific code.
                    yield self._handle_error(
                        'the runtime process gave a bad HTTP response: %s' % e,
                        start_response)
                    return

                # 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.
                while True:
                    try:
                        block = response.read(512)
                        if not block:
                            break
                        yield block
                    except httplib.HTTPException:
                        # The runtime process has encountered a problem, but has not
                        # necessarily crashed. For example, a Go runtime process' HTTP
                        # handler may have panicked in app-specific code (which the http
                        # package will recover from, so the process as a whole doesn't
                        # crash). At this point, we have already proxied onwards the HTTP
                        # header, so we cannot retroactively serve a 500 Internal Server
                        # Error. We silently break here; the runtime process has presumably
                        # already written to stderr (via the Tee).
                        break
            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.
                        self._prior_error = (
                            'the runtime process for the instance running '
                            'on port %d has unexpectedly quit' % (self._port))
                        yield self._handle_error(self._prior_error,
                                                 start_response)
                    else:
                        raise
Пример #32
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 = wsgiref.headers.Headers([])
    for header, value in environ.iteritems():
      if header.startswith('HTTP_'):
        headers[header[5:].replace('_', '-')] = value
    # Content-Type is special; it does not start with 'HTTP_'.
    if 'CONTENT_TYPE' in environ:
      headers['CONTENT-TYPE'] = environ['CONTENT_TYPE']
    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 + 'Datacenter'] = 'us1'
    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):
      connection.connect()
      connection.request(environ.get('REQUEST_METHOD', 'GET'),
                         url,
                         data,
                         dict(headers.items()))
      response = connection.getresponse()
      response_headers = wsgiref.headers.Headers(response.getheaders())

      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)
Пример #33
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.
    """

    if self._prior_error:
      logging.error(self._prior_error)
      yield self._respond_with_error(self._prior_error, start_response)
      return

    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.APPENGINE_ENVIRON_PREFIX + name not in environ:
        value = environ.get(name, None)
        if value is not None:
          environ[
              http_runtime_constants.APPENGINE_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 = None

    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[self.request_id_header_name] = request_id
    headers[http_runtime_constants.APPENGINE_HEADER_PREFIX + 'User-Id'] = (
        user_id)
    headers[http_runtime_constants.APPENGINE_HEADER_PREFIX + 'User-Email'] = (
        user_email)
    headers[
        http_runtime_constants.APPENGINE_HEADER_PREFIX + 'User-Is-Admin'] = (
            str(int(admin)))
    headers[
        http_runtime_constants.APPENGINE_HEADER_PREFIX + 'User-Nickname'] = (
            nickname)
    headers[http_runtime_constants.APPENGINE_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()))

        try:
          response = connection.getresponse()
        except httplib.HTTPException as e:
          # The runtime process has written a bad HTTP response. For example,
          # a Go runtime process may have crashed in app-specific code.
          yield self._respond_with_error(
              'the runtime process gave a bad HTTP response: %s' % e,
              start_response)
          return

        # 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)

        if self._error_handler_file and (
            http_runtime_constants.ERROR_CODE_HEADER in response_headers):
          try:
            with open(self._error_handler_file) as f:
              content = f.read()
          except IOError:
            content = 'Failed to load error handler'
            logging.exception('failed to load error file: %s',
                              self._error_handler_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.
        while True:
          try:
            block = response.read(512)
            if not block:
              break
            yield block
          except httplib.HTTPException:
            # The runtime process has encountered a problem, but has not
            # necessarily crashed. For example, a Go runtime process' HTTP
            # handler may have panicked in app-specific code (which the http
            # package will recover from, so the process as a whole doesn't
            # crash). At this point, we have already proxied onwards the HTTP
            # header, so we cannot retroactively serve a 500 Internal Server
            # Error. We silently break here; the runtime process has presumably
            # already written to stderr (via the Tee).
            break
      except Exception:
        if self._instance_died_unexpectedly():
          yield self._respond_with_error(
              'the runtime process for the instance running on port %d has '
              'unexpectedly quit' % self._port, start_response)
        else:
          raise
Пример #34
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