def make_php_cgi_environ(self, environ): """Returns a dict of environ for php-cgi based off the wsgi environ.""" user_environ = self.environ_template.copy() environ_utils.propagate_environs(environ, user_environ) user_environ['REQUEST_METHOD'] = environ.get('REQUEST_METHOD', 'GET') user_environ['PATH_INFO'] = environ['PATH_INFO'] user_environ['QUERY_STRING'] = environ['QUERY_STRING'] # Construct the partial URL that PHP expects for REQUEST_URI # (http://php.net/manual/en/reserved.variables.server.php) using part of # the process described in PEP-333 # (http://www.python.org/dev/peps/pep-0333/#url-reconstruction). user_environ['REQUEST_URI'] = urllib.quote(user_environ['PATH_INFO']) if user_environ['QUERY_STRING']: user_environ['REQUEST_URI'] += '?' + user_environ['QUERY_STRING'] # Modify the SCRIPT_FILENAME to specify the setup script that readies the # PHP environment. Put the user script in REAL_SCRIPT_FILENAME. user_environ['REAL_SCRIPT_FILENAME'] = os.path.normpath( os.path.join(self.config.application_root, environ[http_runtime_constants.SCRIPT_HEADER].lstrip('/'))) user_environ['SCRIPT_FILENAME'] = SETUP_PHP_PATH user_environ['REMOTE_REQUEST_ID'] = environ[ http_runtime_constants.REQUEST_ID_ENVIRON] # Pass the APPLICATION_ROOT so we can use it in the setup script. We will # remove it from the environment before we execute the user script. user_environ['APPLICATION_ROOT'] = self.config.application_root if 'CONTENT_TYPE' in environ: user_environ['CONTENT_TYPE'] = environ['CONTENT_TYPE'] user_environ['HTTP_CONTENT_TYPE'] = environ['CONTENT_TYPE'] if 'CONTENT_LENGTH' in environ: user_environ['CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] user_environ['HTTP_CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] # On Windows, in order to run a side-by-side assembly the specified env # must include a valid SystemRoot. if 'SYSTEMROOT' in os.environ: user_environ['SYSTEMROOT'] = os.environ['SYSTEMROOT'] if 'LD_LIBRARY_PATH' in os.environ: user_environ['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] # On Windows, TMP & TEMP environmental variables are used by GetTempPath # http://msdn.microsoft.com/library/windows/desktop/aa364992(v=vs.85).aspx if 'TMP' in os.environ: user_environ['TMP'] = os.environ['TMP'] if 'TEMP' in os.environ: user_environ['TEMP'] = os.environ['TEMP'] if self.config.php_config.enable_debugger: user_environ['XDEBUG_CONFIG'] = environ.get('XDEBUG_CONFIG', '') return user_environ
def make_php_cgi_environ(self, environ): """Returns a dict of environ for php-cgi based off the wsgi environ.""" user_environ = self.environ_template.copy() environ_utils.propagate_environs(environ, user_environ) user_environ['REQUEST_METHOD'] = environ.get('REQUEST_METHOD', 'GET') user_environ['PATH_INFO'] = environ['PATH_INFO'] user_environ['QUERY_STRING'] = environ['QUERY_STRING'] # Construct the partial URL that PHP expects for REQUEST_URI # (http://php.net/manual/en/reserved.variables.server.php) using part of # the process described in PEP-333 # (http://www.python.org/dev/peps/pep-0333/#url-reconstruction). user_environ['REQUEST_URI'] = urllib.quote(user_environ['PATH_INFO']) if user_environ['QUERY_STRING']: user_environ['REQUEST_URI'] += '?' + user_environ['QUERY_STRING'] # Modify the SCRIPT_FILENAME to specify the setup script that readies the # PHP environment. Put the user script in REAL_SCRIPT_FILENAME. user_environ['REAL_SCRIPT_FILENAME'] = os.path.normpath( os.path.join(self.config.application_root, environ[http_runtime_constants.SCRIPT_HEADER].lstrip('/'))) user_environ['SCRIPT_FILENAME'] = SETUP_PHP_PATH user_environ['REMOTE_REQUEST_ID'] = environ[ http_runtime_constants.REQUEST_ID_ENVIRON] # Pass the APPLICATION_ROOT so we can use it in the setup script. We will # remove it from the environment before we execute the user script. user_environ['APPLICATION_ROOT'] = self.config.application_root if 'CONTENT_TYPE' in environ: user_environ['CONTENT_TYPE'] = environ['CONTENT_TYPE'] user_environ['HTTP_CONTENT_TYPE'] = environ['CONTENT_TYPE'] if 'CONTENT_LENGTH' in environ: user_environ['CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] user_environ['HTTP_CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] # On Windows, in order to run a side-by-side assembly the specified env # must include a valid SystemRoot. if 'SYSTEMROOT' in os.environ: user_environ['SYSTEMROOT'] = os.environ['SYSTEMROOT'] # On Windows, TMP & TEMP environmental variables are used by GetTempPath # http://msdn.microsoft.com/library/windows/desktop/aa364992(v=vs.85).aspx if 'TMP' in os.environ: user_environ['TMP'] = os.environ['TMP'] if 'TEMP' in os.environ: user_environ['TEMP'] = os.environ['TEMP'] if self.config.php_config.enable_debugger: user_environ['XDEBUG_CONFIG'] = environ.get('XDEBUG_CONFIG', '') return user_environ
def test_propagate_environs(self): src = { 'LALA': 'will not propagate', 'HTTP_LALA': 'will propagate', 'HTTP_X_APPENGINE_USER_ID': '12345', 'HTTP_X_APPENGINE_DEV_MYENV': 'will not propagate either' } dst = {} environ_utils.propagate_environs(src, dst) self.assertEqual(dst, {'HTTP_LALA': 'will propagate', 'USER_ID': '12345'})
def test_propagate_environs(self): src = { 'LALA': 'will not propagate', 'HTTP_LALA': 'will propagate', 'HTTP_X_APPENGINE_USER_ID': '12345', 'HTTP_X_APPENGINE_DEV_MYENV': 'will not propagate either' } dst = {} environ_utils.propagate_environs(src, dst) self.assertEqual(dst, { 'HTTP_LALA': 'will propagate', 'USER_ID': '12345' })
def get_user_environ(self, environ): """Returns a dict containing the environ to pass to the user's application. Args: environ: A dict containing the request WSGI environ. Returns: A dict containing the environ representing an HTTP request. """ user_environ = self.environ_template.copy() environ_utils.propagate_environs(environ, user_environ) user_environ['REQUEST_METHOD'] = environ.get('REQUEST_METHOD', 'GET') content_type = environ.get('CONTENT_TYPE') if content_type: user_environ['HTTP_CONTENT_TYPE'] = content_type content_length = environ.get('CONTENT_LENGTH') if content_length: user_environ['HTTP_CONTENT_LENGTH'] = content_length return user_environ
def __call__(self, environ, start_response): """Handles an HTTP request for the runtime using a PHP executable. Args: environ: An environ dict for the 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 the HTTP response. """ user_environ = self.environ_template.copy() environ_utils.propagate_environs(environ, user_environ) user_environ['REQUEST_METHOD'] = environ.get('REQUEST_METHOD', 'GET') user_environ['PATH_INFO'] = environ['PATH_INFO'] user_environ['QUERY_STRING'] = environ['QUERY_STRING'] # Construct the partial URL that PHP expects for REQUEST_URI # (http://php.net/manual/en/reserved.variables.server.php) using part of # the process described in PEP-333 # (http://www.python.org/dev/peps/pep-0333/#url-reconstruction). user_environ['REQUEST_URI'] = urllib.quote(user_environ['PATH_INFO']) if user_environ['QUERY_STRING']: user_environ['REQUEST_URI'] += '?' + user_environ['QUERY_STRING'] # Modify the SCRIPT_FILENAME to specify the setup script that readies the # PHP environment. Put the user script in REAL_SCRIPT_FILENAME. user_environ['REAL_SCRIPT_FILENAME'] = os.path.normpath( os.path.join( self.config.application_root, environ[http_runtime_constants.SCRIPT_HEADER].lstrip('/'))) user_environ['SCRIPT_FILENAME'] = SETUP_PHP_PATH user_environ['REMOTE_REQUEST_ID'] = environ[ http_runtime_constants.REQUEST_ID_ENVIRON] # Pass the APPLICATION_ROOT so we can use it in the setup script. We will # remove it from the environment before we execute the user script. user_environ['APPLICATION_ROOT'] = self.config.application_root if 'CONTENT_TYPE' in environ: user_environ['CONTENT_TYPE'] = environ['CONTENT_TYPE'] user_environ['HTTP_CONTENT_TYPE'] = environ['CONTENT_TYPE'] if 'CONTENT_LENGTH' in environ: user_environ['CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] user_environ['HTTP_CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] content = environ['wsgi.input'].read(int( environ['CONTENT_LENGTH'])) else: content = '' # On Windows, in order to run a side-by-side assembly the specified env # must include a valid SystemRoot. if 'SYSTEMROOT' in os.environ: user_environ['SYSTEMROOT'] = os.environ['SYSTEMROOT'] # See http://www.php.net/manual/en/ini.core.php#ini.include-path. include_paths = [self.config.application_root, SDK_PATH] if sys.platform == 'win32': # See https://bugs.php.net/bug.php?id=46034 for quoting requirements. include_path = 'include_path="%s"' % ';'.join(include_paths) else: include_path = 'include_path=%s' % ':'.join(include_paths) args = [self.config.php_config.php_executable_path, '-d', include_path] # Load php.ini from application's root. args.extend(['-c', self.config.application_root]) if self.config.php_config.enable_debugger: args.extend(['-d', 'xdebug.remote_enable="1"']) user_environ['XDEBUG_CONFIG'] = os.environ.get('XDEBUG_CONFIG', '') request_type = environ.pop(http_runtime_constants.REQUEST_TYPE_HEADER, None) if request_type == 'interactive': args.extend(['-d', 'html_errors="0"']) user_environ[ http_runtime_constants.REQUEST_TYPE_HEADER] = request_type try: p = safe_subprocess.start_process(args, input_string=content, env=user_environ, cwd=self.config.application_root, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() except Exception as e: logging.exception('Failure to start PHP with: %s', args) start_response('500 Internal Server Error', [(http_runtime_constants.ERROR_CODE_HEADER, '1')]) return [ 'Failure to start the PHP subprocess with %r:\n%s' % (args, e) ] if p.returncode: if request_type == 'interactive': start_response('200 OK', [('Content-Type', 'text/plain')]) message = httplib.HTTPMessage(cStringIO.StringIO(stdout)) return [message.fp.read()] else: logging.error('php failure (%r) with:\nstdout:\n%sstderr:\n%s', p.returncode, stdout, stderr) start_response( '500 Internal Server Error', [(http_runtime_constants.ERROR_CODE_HEADER, '1')]) message = httplib.HTTPMessage(cStringIO.StringIO(stdout)) return [message.fp.read()] message = httplib.HTTPMessage(cStringIO.StringIO(stdout)) if 'Status' in message: status = message['Status'] del message['Status'] else: status = '200 OK' # Ensures that we avoid merging repeat headers into a single header, # allowing use of multiple Set-Cookie headers. headers = [] for name in message: for value in message.getheaders(name): headers.append((name, value)) start_response(status, headers) return [message.fp.read()]
def __call__(self, environ, start_response): """Handles an HTTP request for the runtime using a PHP executable. Args: environ: An environ dict for the 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 the HTTP response. """ user_environ = self.environ_template.copy() environ_utils.propagate_environs(environ, user_environ) user_environ['REQUEST_METHOD'] = environ.get('REQUEST_METHOD', 'GET') user_environ['PATH_INFO'] = environ['PATH_INFO'] user_environ['QUERY_STRING'] = environ['QUERY_STRING'] # Construct the partial URL that PHP expects for REQUEST_URI # (http://php.net/manual/en/reserved.variables.server.php) using part of # the process described in PEP-333 # (http://www.python.org/dev/peps/pep-0333/#url-reconstruction). user_environ['REQUEST_URI'] = urllib.quote(user_environ['PATH_INFO']) if user_environ['QUERY_STRING']: user_environ['REQUEST_URI'] += '?' + user_environ['QUERY_STRING'] # Modify the SCRIPT_FILENAME to specify the setup script that readies the # PHP environment. Put the user script in REAL_SCRIPT_FILENAME. user_environ['REAL_SCRIPT_FILENAME'] = os.path.normpath( os.path.join(self.config.application_root, environ[http_runtime_constants.SCRIPT_HEADER])) user_environ['SCRIPT_FILENAME'] = SETUP_PHP_PATH user_environ['REMOTE_REQUEST_ID'] = environ[ http_runtime_constants.REQUEST_ID_ENVIRON] # Pass the APPLICATION_ROOT so we can use it in the setup script. We will # remove it from the environment before we execute the user script. user_environ['APPLICATION_ROOT'] = self.config.application_root if 'CONTENT_TYPE' in environ: user_environ['CONTENT_TYPE'] = environ['CONTENT_TYPE'] user_environ['HTTP_CONTENT_TYPE'] = environ['CONTENT_TYPE'] if 'CONTENT_LENGTH' in environ: user_environ['CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] user_environ['HTTP_CONTENT_LENGTH'] = environ['CONTENT_LENGTH'] content = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH'])) else: content = '' # On Windows, in order to run a side-by-side assembly the specified env # must include a valid SystemRoot. if 'SYSTEMROOT' in os.environ: user_environ['SYSTEMROOT'] = os.environ['SYSTEMROOT'] # See http://www.php.net/manual/en/ini.core.php#ini.include-path. include_paths = [self.config.application_root, SDK_PATH] if sys.platform == 'win32': # See https://bugs.php.net/bug.php?id=46034 for quoting requirements. include_path = 'include_path="%s"' % ';'.join(include_paths) else: include_path = 'include_path=%s' % ':'.join(include_paths) args = [self.config.php_config.php_executable_path, '-d', include_path] if self.config.php_config.enable_debugger: args.extend(['-d', 'xdebug.remote_enable="1"']) user_environ['XDEBUG_CONFIG'] = os.environ.get('XDEBUG_CONFIG', '') request_type = environ.pop(http_runtime_constants.REQUEST_TYPE_HEADER, None) if request_type == 'interactive': args.extend(['-d', 'html_errors="0"']) user_environ[http_runtime_constants.REQUEST_TYPE_HEADER] = request_type try: p = safe_subprocess.start_process(args, input_string=content, env=user_environ, cwd=self.config.application_root, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() except Exception as e: logging.exception('Failure to start PHP with: %s', args) start_response('500 Internal Server Error', [(http_runtime_constants.ERROR_CODE_HEADER, '1')]) return ['Failure to start the PHP subprocess with %r:\n%s' % (args, e)] if p.returncode: if request_type == 'interactive': start_response('200 OK', [('Content-Type', 'text/plain')]) message = httplib.HTTPMessage(cStringIO.StringIO(stdout)) return [message.fp.read()] else: logging.error('php failure (%r) with:\nstdout:\n%sstderr:\n%s', p.returncode, stdout, stderr) start_response('500 Internal Server Error', [(http_runtime_constants.ERROR_CODE_HEADER, '1')]) message = httplib.HTTPMessage(cStringIO.StringIO(stdout)) return [message.fp.read()] message = httplib.HTTPMessage(cStringIO.StringIO(stdout)) if 'Status' in message: status = message['Status'] del message['Status'] else: status = '200 OK' # Ensures that we avoid merging repeat headers into a single header, # allowing use of multiple Set-Cookie headers. headers = [] for name in message: for value in message.getheaders(name): headers.append((name, value)) start_response(status, headers) return [message.fp.read()]