2012-03-05 7 views
3

Я пытаюсь создать небольшой тестовый сервер для Bugzilla, чтобы я мог проверить изменения, которые я делаю, прежде чем они будут развернуты на главном сервере на базе Apache. Я больше всего знаком с Python, и я хотел, чтобы встроенный HTTP-сервер Python запускал CGI-программы Bugzilla.Как запустить скрипт CGI из обработчика WSGI?

К сожалению, у Bugzilla есть намного больше, чем приложения CGI. У него есть куча css и другие данные, которые подаются напрямую. Это означает, что обработчик также должен иметь дело с ними. Я хотел бы настроить обработчик WSGI, который просматривает URL-адрес запроса и соответствующим образом направляет запрос на один из сценариев CGI Bugzilla или вытаскивает данные непосредственно из файловой системы.

Есть ли лучший способ выполнить то, что я хочу сделать? Если этого не происходит, есть ли там приложение WSGI, которое установит среду CGI и вызовет приложение CGI через модульPython?

+1

Возможно, гораздо проще просто настроить небольшой файл конфигурации для httpd, который делает то, что вам нужно. –

+0

@ IgnacioVazquez-Abrams - Я не понимаю, как это было бы проще. Apache всегда казался очень мучительным зверю, чтобы вообще бежать. Все веб-приложения, над которыми я работал, были приятными, если бы был крошечный веб-сервер, который вы могли бы запустить для целей разработки. – Omnifarious

+0

Если вы настраиваете Apache, вы можете попробовать [xampp] (http://www.apachefriends.org/en/xampp.html). –

ответ

5

Вот решение, которое работает, хотя это довольно некрасиво и вид медленно. Он требует отдельного объекта CGIApplication для каждого скрипта CGI, который вы хотите запустить. Поэтому, если у вас есть полный каталог, вам необходимо создать экземпляр другого объекта CGIApplication для каждого из них. Когда вы его создаете, конечно, зависит от вас. Вы можете создавать новые экземпляры для каждого запроса, но вы, скорее всего, сохраните немного времени, если вы каким-то образом избегаете этого.

import os 
import os.path as _osp 
import re 
import subprocess 
import io 
import email.parser 

env_forward = re.compile('^[A-Z][A-Z0-9_]*$') 
header_match = re.compile(b'^(.*?\\n[ \\t\\r]*\\n)(.*)$', re.M | re.S) 
env_whitelist = frozenset(('AUTH_TYPE', 'CONTENT_LENGTH', 'CONTENT_TYPE', 
          'DOCUMENT_ROOT', 'QUERY_STRING', 'PATH_INFO', 
          'PATH_TRANSLATED', 'REMOTE_ADDR', 'REMOTE_PORT', 
          'REMOTE_IDENT', 'REMOTE_USER', 'REQUEST_METHOD', 
          'REQUEST_URI', 'SCRIPT_NAME', 
          'SERVER_ADDR', 'SERVER_ADMIN', 'SERVER_NAME', 
          'SERVER_PORT', 'SERVER_PROTOCOL', 
          'SERVER_SIGNATURE', 'SERVER_SOFTWARE')) 

class CGIApplication(object): 
    def __init__(self, appfname): 
     self._appfname = _osp.abspath(appfname) 

    def __call__(self, environ, start_respose): 
     appenv = {item[0]: item[1] \ 
         for item in environ.items() \ 
         if ((item[0] in env_whitelist) or 
          item[0].startswith('HTTP_'))} 
     appenv['GATEWAY_INTERFACE'] = 'CGI/1.1' 
     appenv['PATH'] = '/usr/local/bin:/usr/bin:/bin' 
     appenv['SCRIPT_FILENAME'] = self._appfname 
     nbytes_for_cgi = appenv.get('CONTENT_LENGTH', '') 
     nbytes_for_cgi = (int(nbytes_for_cgi) if nbytes_for_cgi != '' else 0) 

     args = [self._appfname] 
     query = environ.get('QUERY_STRING', None) 
     query = query.replace('+', ' ') 
     if '=' not in query: 
      args.append(query) 
     proc = subprocess.Popen(args, 
           stdin=subprocess.PIPE, 
           stdout=subprocess.PIPE, 
           stderr=subprocess.PIPE, 
           env = appenv, 
           cwd = _osp.dirname(self._appfname)) 
     bytes_read = 0 
     data_for_cgi = io.BytesIO() 
     while bytes_read < nbytes_for_cgi: 
      data = environ['wsgi.input'].read(nbytes_for_cgi - bytes_read) 
      bytes_read += len(data) 
      data_for_cgi.write(data) 
      data = None 
     data_for_cgi = data_for_cgi.getvalue() 
     output, errdata = proc.communicate(data_for_cgi) 
     data_for_cgi = None 
     proc.stdin.close() 
     proc.stdout.close() 
     proc.stderr.close() 
     try: 
      errdata = errdata.decode('utf-8') 
     except UnicodeDecodeError: 
      errdata = errdata.decode('iso8859-1') 
     environ['wsgi.errors'].write(errdata) 
     errdata = None 
     if proc.returncode != 0: 
      start_respose('500 Internal Server Error', 
          [('Content-Type', 'text/plain')]) 
      return (b"CGI application died with non-zero return code.\n",) 
     else: 
      output_hdr = header_match.match(output) 
      output_hdr, output = output_hdr.groups() 
      parser = email.parser.HeaderParser() 
      headers = parser.parsestr(output_hdr.decode('iso8859-1')) 
      status = headers.get_all('Status', ['200 OK'])[-1] 
      del headers['Status'] 
      start_respose(status, list(headers.items())) 
      return (output,) 
+0

На самом деле это не ответ, но это единственное, что решило мою проблему. Если я сам напишу шлюз, я задержу его здесь. – Omnifarious

+0

И я сам написал шлюз. – Omnifarious

1

Вы используете pybugz? http://www.liquidx.net/pybugz/

http://code.google.com/p/pybugz/

Кроме того, настройка WSGI через Django и AppEngine очень легко. Довольно быстро установить и, возможно, стоит использовать в качестве работы. Это было бы получить вам тестовый сервер, который должен быть в состоянии справиться с CGI Bugzilla с сотовыми и т.д.

удачи

+0

Пока нет, но я бы не хотел переписывать весь пользовательский интерфейс Bugzilla в терминах pybugz в любом случае. И я хочу, чтобы общий шлюз WSGI-> CGI был специально, потому что большое количество различных небольших веб-серверов Python предназначено для обслуживания WSGI. Я не хочу, чтобы определенный веб-сервер Python мог обслуживать WSGI и CGI. Мне нужен шлюз, поэтому у меня есть выбор веб-серверов. – Omnifarious

Смежные вопросы