2012-11-14 309 views
3

在我的一项作业实践中,我必须启动一个web服务器,当我访问web服务器的根目录时,它会执行一个CGI脚本。CGI脚本不可执行

但是当我打开本地主机:8080,出现此错误消息:

Error code 403. 

Message: CGI script is not executable ('/cgi-bin/todolist.cgi'). 

Error code explanation: 403 = Request forbidden -- authorization will not help. 

我的服务器代码:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import os 
import sys 
import getopt 
import logging 
import BaseHTTPServer 
from CGIHTTPServer import CGIHTTPRequestHandler 
import json 
from DBBackend import TodoDao 

# CRUD to REST conventions 
# POST Create 
# GET Retrieve 
# PUT Update 
# DELETE Delete 

""" 
API REST del servidor. 

GET /todos  - Recupera la lista de tareas (ToDos) 
DELETE /todos/id - Elimina la tarea con el id especificado 
POST /todos  - Añade una nueva tarea con los valores especificados como parámetros 
PUT /todos/id  - Actualiza los valores espcificados en los parámetros para la tarea con 
        el id dado 

Tanto los parámetros (en el cuerpo de la petición) como las respuestas son en formato JSON. 
""" 

logging.basicConfig(level=logging.DEBUG) 

class RESTHTTPRequestHandler(CGIHTTPRequestHandler): 

    dao = TodoDao() 
    res_string = dao.tableName 
    res_path = "/" + res_string 

    def _GET(self): 
     if self.path == self.res_path: 
      tasks = self.dao.findTasks() 
      return {'code': 'ok', 'data': tasks} 
     else: 
      _,res,id = self.path.split("/") 
      int(id) 
      assert(res==self.res_string) 
      data = self.dao.retrieveTask(id) 
      return {'code': 'ok', 'data': data} 

    def _POST(self): 
     assert(self.path == self.res_path) 
     if 'Content-length' in self.headers: 
      data = json.loads(self.rfile.read(int(self.headers['Content-length']))) 
     else: 
      data = json.load(self.rfile) 
     self.dao.createTask(data) 
     return {'code': 'ok'} 


    def _PUT(self): 
     _,res,id = self.path.split("/") 
     int(id) 
     assert(res==self.res_string) 
     if 'Content-length' in self.headers: 
      data = json.loads(self.rfile.read(int(self.headers['Content-length']))) 
     else: 
      data = json.load(self.rfile) 
     self.dao.updateTask(id, data) 
     return {'code': 'ok'} 


    def _DELETE(self): 
     _,res,id = self.path.split("/") 
     int(id) 
     assert(res==self.res_string) 
     self.dao.deleteTask(id) 
     return {'code': 'ok'} 


    def _send(self, data): 
     response = json.dumps(data) 
     self.send_response(200) 
     self.send_header("Content-type", "application/json") 
     self.send_header("Content-Length", len(response)) 
     self.end_headers() 
     self.wfile.write(response) 


    # El BaseHTTPRequestHandler no está pensado para ésto :(
    def do_POST(self): 
     self._reroute() 
    def do_PUT(self): 
     self._reroute() 
    def do_GET(self): 
     self._reroute() 
    def do_DELETE(self): 
     self._reroute() 
    def _reroute(self): 
     try: 
      if self.path.startswith(self.res_path): 
       method_name = '_' + self.command 
       method = getattr(self, method_name) 
       try: 
        self._send(method()) 
       except (ValueError, AssertionError): 
        self.send_error(400, "Invalid request") 
       except: 
        logging.exception("Database access error") 
        self.send_error(500, "DDBB error") 
      else: 
       if self.path == "/" or self.path == "/index.html": 
        self.path = "/cgi-bin/todolist.cgi" 
       method_name = 'do_' + self.command 
       method = getattr(CGIHTTPRequestHandler, method_name) 
       method(self) 
     except AttributeError: 
      self.send_error(501, "Unsupported method (%r)" % self.command) 


#---- Defaults 
port = "8080" 
basedir = "www/" 
#---- 

#---------------------------------------- 
def usage(): 
    print "Uso: " + os.path.basename(sys.argv[0]) + " -h -p port" 
    print "  -h   Muestra este mensaje" 
    print "  -p port Sirve en el puerto indicado (def={0})".format(port) 
    print "  -d dirname Sirve el contenido del directorio indicado (def={0})".format(basedir) 

#---------------------------------------- 

try: 
    opts, args = getopt.getopt(sys.argv[1:], "hp:d:", ["help", "port=", "dir="]) 
except getopt.GetoptError: 
    usage() 
    sys.exit(2) 

for o, a in opts: 
    if o in ("-h", "--help"): 
     usage() 
     sys.exit() 
    if o in ("-p", "--port"): 
     port = a 
    if o in ("-d", "--dir"): 
     basedir = a 

if (port == None): 
    usage() 
    sys.exit() 

try: 
    address = ('', int(port)) 
except ValueError: 
    usage() 
    sys.exit(2) 

httpd = BaseHTTPServer.HTTPServer(address, 
            RESTHTTPRequestHandler) 
os.chdir(basedir) 
httpd.serve_forever() 

而且我todolist.cgi:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import cgi 
import sys 
import os 
import datetime 
import locale 
# TBD: Usar el locale del cliente 
locale.setlocale(locale.LC_TIME,'') 
date_format = locale.nl_langinfo(locale.D_FMT) 

sys.path.append(os.path.join(os.path.dirname(__file__), "../..")) 
import DBBackend 

print "Content-Type: text/html" 
print "" 
print """ 
<!doctype html> 

<html lang="es"> 

<head> 
<meta charset="utf-8"/> 
<title>[IPM] Lista de tareas</title> 
<meta name="author" content="David Cabrero"/> 
<meta name="HandheldFriendly" content="true"/> 
<meta name="viewport" content="width=device-width, initial-scale=1,maximun-scale=1,user-scalable=no"/> 

<meta http-equiv="X-UA-Compatible" content="IE=ecdge,chrome=1"> 
<!--[if lt IE 9]> 
    <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> 
    <script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script> 
<![endif]--> 

<link rel="stylesheet" type="text/css" href="css/default.css" /> 
<link rel="stylesheet" type="text/css" href="css/wide-screen.css" 
     media="only screen and (min-width : 1024px)" /> 
<script src="js/todolist.js"></script> 
</head> 

<body> 

<header> 
<h1>ToDo</h1> 
</header> 

<ul> 
""" 
fname = os.path.join(os.getcwd(), "../", DBBackend.DATABASEFILENAME) 
li = """ 
    <a href="#dialog"><li data-task-id="{0}"> 
    <p class="desc">{1}</p> 
    <time datetime="{2}">{3}</time> 
    <p class="done" data-task-done="{4}">{5}</p> 
    </li></a> 
""" 
for task in DBBackend.TodoDao(fname).findTasks(): 
    id = str(task['id']) 
    desc = task['desc'].encode('utf-8') 
    deadline = datetime.datetime.strptime(task['deadline'], "%Y-%m-%d") 
    done = task['done'] == 1 
    print li.format(id, desc, deadline.strftime("%Y-%m-%d"), deadline.strftime(date_format), 
        "yes" if done else "no", "Hecho" if done else "Sin hacer") 

print """ 
</ul> 


<div id="updateTask" class="dialog"><div> 
    <h1>Actualizar tarea</h1> 
    <form> 
    <p><input type="text" name="task_desc" placeholder="task description" autofocus="autofocus" /></p> 
    <p><input type="date" name="task_deadline" placeholder="deadline" /></p> 
    <p><input type="checkbox" name="task_done" /></p> 
    <p class="okCancel"> 
     <button name="ok">OK</button> 
     <button name="cancel">Cancel</button> 
    </p> 
    </form> 
</div></div> 

</body> 

</html> 
""" 

print """ 
""" 

所有代码是由老师给出的(我必须做一个web应用程序),所以我不知道如何开始,如果我不能设法获得ser正在工作。我也运行Windows 7和Python for Windows(版本2.7),希望它有帮助!

回答

4

OK,你需要做的,使这项工作在Windows是从todolist.cgi重命名你的脚本todolist.py和改线的服务器代码,它说什么:

self.path = "/cgi-bin/todolist.cgi" 

更改,到:

self.path = "/cgi-bin/todolist.py" 

这应该让它在Windows中工作没有太多的大惊小怪。这一切都与CGIHTTPServer的内部工作以及它如何处理可执行文件有关。我尝试了各种其他技巧(并且像猴子修补CGIHTTPServer.executable一样彻底攻击......)以使其工作,但这似乎是最简单的。

+0

谢谢!我设法正确地执行脚本,但是现在出现了一些与语言环境有关的问题......我想我必须通过它来工作。尽管如此,再次感谢您的回答;) – Shadark

3

该问题不在您的代码中,而是在文件系统权限中。 cgi文件必须标记为可执行。这可以使用chmod a+x todolist.cgi,从cgi-bin目录中的shell中完成。

+3

对于Unix或类Unix系统来说,这是一个很好的答案......但是无论你用键盘敲打你的头脑有多难,Windows 7似乎都无法理解那个'chmod'的东西。 –