Index: editor/filemanager/upload/test.html =================================================================== --- editor/filemanager/upload/test.html (revisión: 387) +++ editor/filemanager/upload/test.html (copia de trabajo) @@ -91,7 +91,8 @@ + Index: editor/filemanager/upload/py/upload.py =================================================================== --- editor/filemanager/upload/py/upload.py (revisión: 0) +++ editor/filemanager/upload/py/upload.py (revisión: 0) @@ -0,0 +1,177 @@ +#!/usr/bin/env python +""" + * FCKeditor - The text editor for Internet - http://www.fckeditor.net + * Copyright (C) 2003-2007 Frederico Caldeira Knabben + * + * == BEGIN LICENSE == + * + * Licensed under the terms of any of the following licenses at your + * choice: + * + * - GNU General Public License Version 2 or later (the "GPL") + * http://www.gnu.org/licenses/gpl.html + * + * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") + * http://www.gnu.org/licenses/lgpl.html + * + * - Mozilla Public License Version 1.1 or later (the "MPL") + * http://www.mozilla.org/MPL/MPL-1.1.html + * + * == END LICENSE == + * + * This is the "File Uploader" for Python (Standalone CGI and WSGI). + * + * Tested with: + * - Apache/2.2.3 (Win32) mod_python/3.2.10 Python/2.5 + * - Apache/2.2.3 (Debian Etch) mod_python/3.2.10 Python/2.4.4 + * + * You shouldn't need to make any change to this file, instead see + * config.py and .htaccess + * +""" +import config as Config + +import cgi +import cgitb; cgitb.enable() +import os, sys, re +try: # Windows needs stdio set for binary mode. + import msvcrt + msvcrt.setmode (0, os.O_BINARY) # stdin = 0 + msvcrt.setmode (1, os.O_BINARY) # stdout = 1 +except ImportError: + pass + +def WSGIApp(environ, start_response): # entry point + + # This is the function that sends the results of the uploading process + # WSGI compilant (generator) + def SendResults( errorNumber, fileUrl = '', fileName = '', customMsg = '' ): + yield """""" % { + 'errorNumber': errorNumber, + 'fileUrl': fileUrl.replace ('"', '\\"'), + 'fileName': fileName.replace ( '"', '\\"' ) , + 'customMsg': customMsg.replace ( '"', '\\"' ), + } + + def GetRootPath(): + # WARNING: this is not be thread safe, and doesn't work w/ VirtualServer/mod_python + # Use Config.UserFilesAbsolutePath instead + if environ.has_key('DOCUMENT_ROOT'): + return environ['DOCUMENT_ROOT'] + else: + sRealPath = os.path.realpath( './' ) + sSelfPath = environ['SCRIPT_FILENAME'] + sSelfPath = sSelfPath [ : sSelfPath.rfind( '/' ) ] + sRealPath = sRealPath [ : len(sRealPath) - len(sSelfPath) ] + return sRealPath + + + # Start WSGI response: + start_response ("200 Ok",[("Content-type","text/html")]) + + # Check if this uploader has been enabled. + if not Config.Enabled: + return SendResults( '1', '', '', 'This file uploader is disabled. Please check the "editor/filemanager/upload/py/config.py" file' ) + + # Get the posted form data + oForm = cgi.FieldStorage(fp=environ['wsgi.input'], + environ=environ, + keep_blank_values=1) + + # Check if the file has been correctly uploaded. + if not oForm.has_key('NewFile') or not oForm['NewFile'].file: + return SendResults( '202' ) + + # Get the posted file. + oFile = oForm['NewFile'] + + # Get the uploaded file name extension. + sFileName = oFile.filename + + # Replace dots in the name with underscores (only one dot can be there... security issue). + if ( Config.ForceSingleExtension ): + sFileName = re.sub( r'\.(?![^.]*$)', '_', sFileName ) + + sFileName = sFileName.replace('\\','/') # convert windows to unix path + sFileName = os.path.basename (sFileName) # strip directories + sOriginalFileName = sFileName ; + + # Get the extension. + sExtension = sFileName[ sFileName.rfind('.') + 1 : ] + sExtension = sExtension.lower + + # The the file type (from the QueryString, by default 'File'). + sType = oForm.has_key('Type') and oForm('Type') or 'File' + + # Check if it is an allowed type. + if not sType in ('File','Image','Flash','Media'): + return SendResults( 1, '', '', 'Invalid type specified' ) + + # Get the allowed and denied extensions arrays. + arAllowed = Config.AllowedExtensions[sType] ; + arDenied = Config.DeniedExtensions[sType] ; + + # Check if it is an allowed extension. + if ( len(arAllowed) > 0 and not sExtension in arAllowed ) or ( len(arDenied) > 0 and sExtension in arDenied ): + return SendResults( '202' ) + + sErrorNumber = '0' ; + sFileUrl = '' ; + + # Initializes the counter used to rename the file, if another one with the same name already exists. + iCounter = 0 + + # Get the target directory. + if ( Config.UserFilesAbsolutePath ): + sServerDir = Config.UserFilesAbsolutePath[sType] + else: + sServerDir = GetRootPath() + Config.UserFilesPath[sType] + + if ( Config.UseFileType ): + sServerDir = sServerDir + sType + '/' + + while True: + # Compose the file path. + sFilePath = sServerDir + sFileName + + # If a file with that name already exists. + if os.path.exists( sFilePath ): + iCounter+=1 + sFileName = sOriginalFileName.replace('.','(%d).' % iCounter ) + sErrorNumber = '201' + else: + # Read file contents and write to the desired path (similar to php's move_uploaded_file) + fout = file(sFilePath, 'wb') + while 1: + chunk = oFile.file.read(100000) + if not chunk: break + fout.write (chunk) + fout.close() + + if os.path.exists ( sFilePath ): + oldumask = os.umask(0) + os.chmod( sFilePath, 0755 ) + os.umask( oldumask ) + + if ( Config.UseFileType ): + sFileUrl = Config.UserFilesPath[sType] + sType + '/' + sFileName + else: + sFileUrl = Config.UserFilesPath[sType] + sFileName + + break + + return SendResults ( sErrorNumber, sFileUrl, sFileName ) ; + + + +# Running from command line (CGI), in case of no mod_python nor wsgi server available +if __name__ == '__main__': + try: + import cgi2wsgi + cgi2wsgi.run(WSGIApp) # (call cgi to wsgi wrapper to execute WSGIApp) + except: + print "Content-Type: text/plain" + print + cgi.print_exception() Index: editor/filemanager/upload/py/config.py =================================================================== --- editor/filemanager/upload/py/config.py (revisión: 0) +++ editor/filemanager/upload/py/config.py (revisión: 0) @@ -0,0 +1,61 @@ +#!/usr/bin/env python +""" + * FCKeditor - The text editor for Internet - http://www.fckeditor.net + * Copyright (C) 2003-2007 Frederico Caldeira Knabben + * + * == BEGIN LICENSE == + * + * Licensed under the terms of any of the following licenses at your + * choice: + * + * - GNU General Public License Version 2 or later (the "GPL") + * http://www.gnu.org/licenses/gpl.html + * + * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") + * http://www.gnu.org/licenses/lgpl.html + * + * - Mozilla Public License Version 1.1 or later (the "MPL") + * http://www.mozilla.org/MPL/MPL-1.1.html + * + * == END LICENSE == + * + * Configuration file for the Python File Uploader. +""" + +# SECURITY: You must explicitelly enable this "uploader". +Enabled = False + +# Set if the file type must be considere in the target path. +# Ex: /userfiles/image/ or /userfiles/file/ +UseFileType = False # deprecated, use UserFilesPath { file_type : file_path } + +# Path to uploaded files relative to the document root: { Type: Path } +UserFilesPath = { 'File':'/files/', + 'Images':'/images/', + 'Flash':'/flash/', + } + +# Fill the following value it you prefer to specify the absolute path for the +# user files directory. Usefull if you are using a virtual directory, symbolic +# link or alias. Examples: 'C:\\MySite\\userfiles\\' or '/root/mysite/userfiles/'. +# Attention: The above 'UserFilesPath' must point to the same directory. +# WARNING: GetRootPath may not work in virtual or mod_python configurations, and +# may not be thread safe. Use this configuration parameter instead. +UserFilesAbsolutePath = { 'File':'/var/www/files/', + 'Images':'/var/www/images/', + 'Flash':'/var/www/flash/', + } + +# Due to security issues with Apache modules, it is reccomended to leave the +# following setting enabled. +ForceSingleExtension = True + +AllowedExtensions={ 'File': [], + 'Image':['jpg','gif','jpeg','png'], + 'Flash':['swf','fla'] + } + +DeniedExtensions={ 'File': ['html','htm','php','php2','php3','php4','php5','phtml','pwml','inc','asp','aspx','ascx','jsp','cfm','cfc','pl','bat','exe','com','dll','vbs','js','reg','cgi','htaccess','asis'], + 'Image': [], + 'Flash': [], + } Index: editor/filemanager/upload/py/.htaccess =================================================================== --- editor/filemanager/upload/py/.htaccess (revisión: 0) +++ editor/filemanager/upload/py/.htaccess (revisión: 0) @@ -0,0 +1,30 @@ +# you must use either wsgi, php-like o cgi functionality + +# php-like functionality (default): +# - calling .../py/upload.py +# - can serve files from the same directory +# - can do automatic reloading of source files +# - no need to specify PythonPath (if wsighandler.py and modpython_gateway.py are already inside PythonPath, in site-pacakges, if not, see PythonPath directive below) + +AddHandler mod_python .py +PythonHandler wsgihandler::handler +PythonOption reload-modules no + + +# wsgi functionality: +# - calling .../py/ executes the script +# - cannot serve files from the same directory +# - no automatic reloading posible +# - you must specify PythonPath to include the script directory + +#SetHandler python-program +#PythonHandler modpython_gateway::handler +#PythonOption application upload::WSGIApp +#PythonPath "['C:/Archivos de programa/Apache Software Foundation/Apache2.2/htdocs/'] + sys.path" + + +# cgi functionality (not recomended, very slow) +#Options +ExecCGI +#AddHandler cgi-script py + +Allow from all Index: editor/filemanager/upload/py/cgi2wsgi.py =================================================================== --- editor/filemanager/upload/py/cgi2wsgi.py (revisión: 0) +++ editor/filemanager/upload/py/cgi2wsgi.py (revisión: 0) @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# taken from http://www.python.org/dev/peps/pep-0333/ + +import os, sys + +def run(wsgi_app): + #if sys.argv.: + # instancedir=sys.argv[1] + #else + instancedir='' + + stream=sys.stdout + + environ = dict(os.environ.items()) + environ['wsgi.input'] = sys.stdin + environ['wsgi.errors'] = sys.stderr + environ['wsgi.version'] = (1, 0) + environ['wsgi.multithread'] = False + environ['wsgi.multiprocess'] = True + environ['wsgi.run_once'] = True + + if environ.get('HTTPS','off') in ('on','1'): + environ['wsgi.url_scheme'] = 'https' + else: + environ['wsgi.url_scheme'] = 'http' + + headers_set = [] + headers_sent = [] + + def write(data): + if not headers_set: + raise AssertionError("write() before start_response()") + + elif not headers_sent: + # Before the first output, send the stored headers + status, response_headers = headers_sent[:] = headers_set + stream.write('Status: %s\r\n' % status) + for header in response_headers: + stream.write('%s: %s\r\n' % header) + stream.write('\r\n') + + stream.write(data) + stream.flush() + + def start_response(status, response_headers, exc_info=None): + if exc_info: + try: + if headers_sent: + # Re-raise original exception if headers sent + raise exc_info[0], exc_info[1], exc_info[2] + finally: + exc_info = None # avoid dangling circular ref + elif headers_set: + raise AssertionError("Headers already set!") + + headers_set[:] = [status, response_headers] + return write + + result = wsgi_app(environ, start_response) + try: + for data in result: + if data: # don't send headers until body appears + write(data) + if not headers_sent: + write('') # send headers now if body was empty + finally: + if hasattr(result,'close'): + result.close() + Index: editor/filemanager/upload/py/modpython_gateway.py =================================================================== --- editor/filemanager/upload/py/modpython_gateway.py (revisión: 0) +++ editor/filemanager/upload/py/modpython_gateway.py (revisión: 0) @@ -0,0 +1,212 @@ +""" +WSGI wrapper for mod_python. Requires Python 2.2 or greater. + + +Example httpd.conf section for a CherryPy app called "mcontrol": + + + SetHandler python-program + PythonFixupHandler mcontrol.cherry::startup + PythonHandler modpython_gateway::handler + PythonOption wsgi.application cherrypy._cpwsgi::wsgiApp + + +Some WSGI implementations assume that the SCRIPT_NAME environ variable will +always be equal to "the root URL of the app"; Apache probably won't act as +you expect in that case. You can add another PythonOption directive to tell +modpython_gateway to force that behavior: + + PythonOption SCRIPT_NAME /mcontrol + +Some WSGI applications need to be cleaned up when Apache exits. You can +register a cleanup handler with yet another PythonOption directive: + + PythonOption wsgi.cleanup module::function + +The module.function will be called with no arguments on server shutdown, +once for each child process or thread. +""" + +import traceback + +from mod_python import apache + + +class InputWrapper(object): + + def __init__(self, req): + self.req = req + + def close(self): + pass + + def read(self, size=-1): + return self.req.read(size) + + def readline(self, size=-1): + return self.req.readline(size) + + def readlines(self, hint=-1): + return self.req.readlines(hint) + + def __iter__(self): + line = self.readline() + while line: + yield line + # Notice this won't prefetch the next line; it only + # gets called if the generator is resumed. + line = self.readline() + + +class ErrorWrapper(object): + + def __init__(self, req): + self.req = req + + def flush(self): + pass + + def write(self, msg): + self.req.log_error(msg) + + def writelines(self, seq): + self.write(''.join(seq)) + + +bad_value = ("You must provide a PythonOption '%s', either 'on' or 'off', " + "when running a version of mod_python < 3.1") + + +class Handler: + + def __init__(self, req): + self.started = False + + options = req.get_options() + + # Threading and forking + try: + q = apache.mpm_query + threaded = q(apache.AP_MPMQ_IS_THREADED) + forked = q(apache.AP_MPMQ_IS_FORKED) + except AttributeError: + threaded = options.get('multithread', '').lower() + if threaded == 'on': + threaded = True + elif threaded == 'off': + threaded = False + else: + raise ValueError(bad_value % "multithread") + + forked = options.get('multiprocess', '').lower() + if forked == 'on': + forked = True + elif forked == 'off': + forked = False + else: + raise ValueError(bad_value % "multiprocess") + + env = self.environ = dict(apache.build_cgi_env(req)) + + if 'SCRIPT_NAME' in options: + # Override SCRIPT_NAME and PATH_INFO if requested. + env['SCRIPT_NAME'] = options['SCRIPT_NAME'] + env['PATH_INFO'] = req.uri[len(options['SCRIPT_NAME']):] + + env['wsgi.input'] = InputWrapper(req) + env['wsgi.errors'] = ErrorWrapper(req) + env['wsgi.version'] = (1,0) + env['wsgi.run_once'] = False + if env.get("HTTPS") in ('yes', 'on', '1'): + env['wsgi.url_scheme'] = 'https' + else: + env['wsgi.url_scheme'] = 'http' + env['wsgi.multithread'] = threaded + env['wsgi.multiprocess'] = forked + + self.request = req + + def run(self, application): + # 20070226: DISABLE Exception Handling to be directy handled by wsgihandler + #try: + result = application(self.environ, self.start_response) + for data in result: + self.write(data) + if not self.started: + self.request.set_content_length(0) + if hasattr(result, 'close'): + result.close() + #except: + # traceback.print_exc(None, self.environ['wsgi.errors']) + # if not self.started: + # self.request.status = 500 + # self.request.content_type = 'text/plain' + # data = "A server error occurred. Please contact the administrator." + # self.request.set_content_length(len(data)) + # self.request.write(data) + + def start_response(self, status, headers, exc_info=None): + if exc_info: + try: + if self.started: + raise exc_info[0], exc_info[1], exc_info[2] + finally: + exc_info = None + + self.request.status = int(status[:3]) + + for key, val in headers: + if key.lower() == 'content-length': + self.request.set_content_length(int(val)) + elif key.lower() == 'content-type': + self.request.content_type = val + else: + self.request.headers_out.add(key, val) + + return self.write + + def write(self, data): + if not self.started: + self.started = True + self.request.write(data) + + +startup = None +cleanup = None + +def handler(req): + # Run a startup function if requested. + global startup + if not startup: + func = req.get_options().get('wsgi.startup') + if func: + module_name, object_str = func.split('::', 1) + module = __import__(module_name, globals(), locals(), ['']) + startup = apache.resolve_object(module, object_str) + startup(req) + + # Register a cleanup function if requested. + global cleanup + if not cleanup: + func = req.get_options().get('wsgi.cleanup') + if func: + module_name, object_str = func.split('::', 1) + module = __import__(module_name, globals(), locals(), ['']) + cleanup = apache.resolve_object(module, object_str) + def cleaner(data): + cleanup() + try: + # apache.register_cleanup wasn't available until 3.1.4. + apache.register_cleanup(cleaner) + except AttributeError: + req.server.register_cleanup(req, cleaner) + + # Import the wsgi 'application' callable and pass it to Handler.run + modname, objname = req.get_options()['wsgi.application'].split('::', 1) + module = __import__(modname, globals(), locals(), ['']) + app = getattr(module, objname) + Handler(req).run(app) + + # status was set in Handler; always return apache.OK + return apache.OK + Index: editor/filemanager/upload/py/wsgihandler.py =================================================================== --- editor/filemanager/upload/py/wsgihandler.py (revisión: 0) +++ editor/filemanager/upload/py/wsgihandler.py (revisión: 0) @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +""" + WSGI Handler form Mod Python: + + This module implement cgihandler-like functionality but for WSGI. + It allows to call standalone WSGI script without too much configuration, + and keep serving static files in the same directory (ala PHP) + + Each script (.py) must contain a WSGI compilant callable named WSGIApp + + Use .htaccess: + AddHandler mod_python .py + PythonHandler wsgihandler + + This need either modpywsgi.py or modpython_gateway.py (WSGI gateways) be + present inside python path. + + If this script is stored inside python path (normally site-packages), + no PythonPath directive is needed (script directory is appended to + sys.path), so you could import modules in script directory normally. + + If you cannot install both scripts in site-packages, just modify .htaccess: + AddHandler mod_python .py + PythonHandler wsgihandler + PythonPath "['/your/script/path'] + sys.path" + And copy modpywsgi.py or modpython_gateway.py and wsgihandler.py with your + script. + + license: GNU GPL +""" + +# Copyright (C) 2007 Mariano Reingart + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +import os +import sys +from mod_python import apache + +try: + # first, try to import "official" modpython wsgi gateway + import modpython_gateway + srv=modpython_gateway.Handler +except ImportError: + try: + import modpywsgi + srv=modpywsgi.WSGIServer + except ImportError: + # sorry, no gateway found, raise apache error + raise apache.SERVER_RETURN, apache.HTTP_BAD_GATEWAY + +__author__ = 'Mariano Reingart ' + +# keep original modules, in order to refresh user ones +# (only in development, to prevent restarting apache to apply changes) +original = sys.modules.keys() +# find out the standard library location +stdlib, x = os.path.split(os.__file__) + +def handler(req): + options=req.get_options() + + # this allows make changes to source files and get them imported without + # restarting apache + if options.get('reload-modules', '').lower()=='yes': + for m in sys.modules.keys(): + if m not in original: + # unless they are part of standard library + mod = sys.modules[m] + if hasattr(mod, "__file__"): + path, x = os.path.split(mod.__file__) + if path != stdlib: + del sys.modules[m] + + # get the filename of the script (copied from cgihandler) + if req.subprocess_env.has_key("script_filename"): + dir, file = os.path.split(req.subprocess_env["script_filename"]) + else: + dir, file = os.path.split(req.filename) + + module_name, ext = os.path.splitext(file) + + # automagically append script directory to sys.path + if dir not in sys.path: + sys.path.append(dir) + + try: + module = __import__(module_name) + except ImportError: + raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND + + app = getattr(module, "WSGIApp") + + try: + # create server and run WSGIApp + if srv.__name__ == 'WSGIServer': + # this is to prevent that modpywsgi alter SCRIPT_NAME + options['untouched_scriptname']='yes' + srv(app).run(req) + elif srv.__name__ == 'Handler': + srv(req).run(app) + except: + # print fancy exception output + import cgitb + req.status = int(200) + req.content_type = "text/html" + req.write(cgitb.html(sys.exc_info())) + + # allways return apache.OK (status was set in Handler) + return apache.OK