Lib.modjy.modjy_response.py Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython Show documentation
Show all versions of jython Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
###
#
# Copyright Alan Kennedy.
#
# You may contact the copyright holder at this uri:
#
# http://www.xhaus.com/contact/modjy
#
# The licence under which this code is released is the Apache License v2.0.
#
# The terms and conditions of this license are listed in a file contained
# in the distribution that also contained this file, under the name
# LICENSE.txt.
#
# You may also read a copy of the license at the following web address.
#
# http://modjy.xhaus.com/LICENSE.txt
#
###
import types
from java.lang import System
from modjy_exceptions import *
from modjy_write import write_object
# From: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
hop_by_hop_headers = {
'connection': None,
'keep-alive': None,
'proxy-authenticate': None,
'proxy-authorization': None,
'te': None,
'trailers': None,
'transfer-encoding': None,
'upgrade': None,
}
class start_response_object:
def __init__(self, req, resp):
self.http_req = req
self.http_resp = resp
self.write_callable = None
self.called = 0
self.content_length = None
# I'm doing the parameters this way to facilitate porting back to java
def __call__(self, *args, **keywords):
if len(args) < 2 or len(args) > 3:
raise BadArgument("Start response callback requires either two or three arguments: got %s" % str(args))
if len(args) == 3:
exc_info = args[2]
try:
try:
self.http_resp.reset()
except IllegalStateException, isx:
raise exc_info[0], exc_info[1], exc_info[2]
finally:
exc_info = None
else:
if self.called > 0:
raise StartResponseCalledTwice("Start response callback may only be called once, without exception information.")
status_str = args[0]
headers_list = args[1]
if not isinstance(status_str, types.StringType):
raise BadArgument("Start response callback requires string as first argument")
if not isinstance(headers_list, types.ListType):
raise BadArgument("Start response callback requires list as second argument")
try:
status_code, status_message_str = status_str.split(" ", 1)
self.http_resp.setStatus(int(status_code))
except ValueError:
raise BadArgument("Status string must be of the form ' '")
self.make_write_object()
try:
for header_name, header_value in headers_list:
header_name_lower = header_name.lower()
if hop_by_hop_headers.has_key(header_name_lower):
raise HopByHopHeaderSet("Under WSGI, it is illegal to set hop-by-hop headers, i.e. '%s'" % header_name)
if header_name_lower == "content-length":
try:
self.set_content_length(int(header_value))
except ValueError, v:
raise BadArgument("Content-Length header value must be a string containing an integer, not '%s'" % header_value)
else:
final_value = header_value.encode('latin-1')
# Here would be the place to check for control characters, whitespace, etc
self.http_resp.addHeader(header_name, final_value)
except (AttributeError, TypeError), t:
raise BadArgument("Start response callback headers must contain a list of (,) tuples")
except UnicodeError, u:
raise BadArgument("Encoding error: header values may only contain latin-1 characters, not '%s'" % repr(header_value))
except ValueError, v:
raise BadArgument("Headers list must contain 2-tuples")
self.called += 1
return self.write_callable
def set_content_length(self, length):
if self.write_callable.num_writes == 0:
self.content_length = length
self.http_resp.setContentLength(length)
else:
raise ResponseCommitted("Cannot set content-length: response is already commited.")
def make_write_object(self):
try:
self.write_callable = write_object(self.http_resp.getOutputStream())
except IOException, iox:
raise IOError(iox)
return self.write_callable