wcs/wcs/compat.py

142 lines
5.2 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2013 Entr'ouvert
#
# 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, see <http://www.gnu.org/licenses/>.
import ConfigParser
import os
from threading import Lock
from quixote import get_publisher
from quixote.errors import PublishError
from quixote.http_request import Upload
from django.http import HttpResponse
from django.conf import settings
from .qommon import template
from .qommon.publisher import get_cfg, set_publisher_class
from .publisher import WcsPublisher
from .qommon.http_request import HTTPRequest
from .qommon.http_response import HTTPResponse
def init_publisher_if_needed():
if get_publisher() is not None:
return
# initialize publisher in first request
config = ConfigParser.ConfigParser()
if settings.WCS_LEGACY_CONFIG_FILE:
config.read(settings.WCS_LEGACY_CONFIG_FILE)
if hasattr(settings, 'WCS_EXTRA_MODULES') and settings.WCS_EXTRA_MODULES:
if not config.has_section('extra'):
config.add_section('extra')
for i, extra in enumerate(settings.WCS_EXTRA_MODULES):
config.set('extra', 'cmd_line_extra_%d' % i, extra)
CompatWcsPublisher.configure(config)
class CompatHTTPRequest(HTTPRequest):
def __init__(self, request):
self.django_request = request
self.response = None
request.environ['SCRIPT_NAME'] = str(request.environ['SCRIPT_NAME'])
request.environ['PATH_INFO'] = str(request.environ['PATH_INFO'])
self.META = self.django_request.META
HTTPRequest.__init__(self, None, request.environ)
self.scheme = str(self.django_request.scheme)
def _process_urlencoded(self, length, params):
return self._process_multipart(length, params)
def _process_multipart(self, length, params):
# Make sure request.form doesn't contain unicode strings, converting
# them all to strings in the site charset; it would contain unicode
# strings when the user agent specifies a charset in a mime content
# part, such a behaviour appears with some Nokia phones (6020, 6300)
site_charset = get_publisher().site_charset
# parse multipart data with the charset of the website
if 'charset' not in params:
params['charset'] = site_charset
if not self.form:
self.form = {}
for k, v in self.django_request.POST.items():
if type(v) is unicode:
self.form[str(k)] = v.encode(site_charset)
else:
self.form[str(k)] = v
for k, upload_file in self.django_request.FILES.items():
upload = Upload(upload_file.name.encode('utf-8'),
upload_file.content_type.encode('utf-8'),
upload_file.charset)
upload.fp = upload_file.file
self.form[str(k)] = upload
def build_absolute_uri(self):
return self.django_request.build_absolute_uri()
class CompatWcsPublisher(WcsPublisher):
def filter_output(self, request, output):
response = self.get_request().response
if response.status_code == 304:
# clients don't like to receive content with a 304
return ''
if response.content_type != 'text/html':
return output
if not hasattr(response, 'filter') or not response.filter:
return output
return self.render_response(output)
def process_request(self, request):
self._set_request(request)
try:
self.parse_request(request)
output = self.try_publish(request)
except PublishError, exc:
output = self.finish_interrupted_request(exc)
except Exception, exc:
output = self.finish_failed_request()
response = request.response
output = self.filter_output(request, output)
content = output
django_response = HttpResponse(content,
content_type=response.content_type,
status=response.status_code,
reason=response.reason_phrase)
for name, value in response.generate_headers():
if name == 'Content-Length':
continue
django_response[name] = value
self._clear_request()
return django_response
# keep a lock during quixote processing as it's not meant to work with threads;
# the publisher instance can't be shared for concurrent requests.
quixote_lock = Lock()
def quixote(request):
with quixote_lock:
pub = get_publisher()
compat_request = CompatHTTPRequest(request)
return pub.process_request(compat_request)
set_publisher_class(CompatWcsPublisher)