2012-11-14 357 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'的東西。 –