1.1 --- a/WebStack/JavaServlet.py Sat Oct 27 21:31:02 2007 +0000
1.2 +++ b/WebStack/JavaServlet.py Sat Oct 27 21:34:37 2007 +0000
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Java Servlet classes.
1.6
1.7 -Copyright (C) 2004, 2005, 2006 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2004, 2005, 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This library is free software; you can redistribute it and/or
1.11 modify it under the terms of the GNU Lesser General Public
1.12 @@ -34,14 +34,15 @@
1.13 import javax.mail
1.14 import java.util
1.15 import java.net
1.16 +import java.io
1.17
1.18 class Stream:
1.19
1.20 """
1.21 - Wrapper around java.io.ServletInputStream.
1.22 + Wrapper around java.io.InputStream.
1.23 """
1.24
1.25 - bufsize = 100
1.26 + bufsize = 1024
1.27
1.28 def __init__(self, stream):
1.29
1.30 @@ -49,31 +50,40 @@
1.31
1.32 self.stream = stream
1.33
1.34 - def read(self):
1.35 + def read(self, limit=None):
1.36
1.37 "Read the entire message, returning it as a string."
1.38
1.39 + bufsize = limit or self.bufsize
1.40 characters = StringIO()
1.41 + a = jarray.zeros(bufsize, 'b')
1.42 while 1:
1.43 - c = self.stream.read()
1.44 - if c == -1:
1.45 + nread = self.stream.read(a, 0, bufsize)
1.46 + if nread != -1:
1.47 + self._copy(a, characters, nread)
1.48 + if nread != bufsize or nread == limit:
1.49 return characters.getvalue()
1.50 - else:
1.51 - characters.write(chr(c))
1.52
1.53 - def readline(self):
1.54 + def readline(self, bufsize=None):
1.55
1.56 "Read a line from the stream, returning it as a string."
1.57
1.58 + bufsize = bufsize or self.bufsize
1.59 characters = StringIO()
1.60 - a = jarray.zeros(self.bufsize, 'b')
1.61 + a = jarray.zeros(bufsize, 'b')
1.62 while 1:
1.63 - nread = self.stream.readLine(a, 0, self.bufsize)
1.64 + nread = self.stream.readLine(a, 0, bufsize)
1.65 if nread != -1:
1.66 self._copy(a, characters, nread)
1.67 - if nread != self.bufsize:
1.68 + if nread != bufsize:
1.69 return characters.getvalue()
1.70
1.71 + def reset(self):
1.72 +
1.73 + "Attempt to reset the stream."
1.74 +
1.75 + self.stream.reset()
1.76 +
1.77 def _unsigned(self, i):
1.78 if i < 0:
1.79 return chr(256 + i)
1.80 @@ -116,6 +126,10 @@
1.81
1.82 self.message_fields = None
1.83
1.84 + # Resource management.
1.85 +
1.86 + self.tempfiles = []
1.87 +
1.88 def commit(self):
1.89
1.90 """
1.91 @@ -124,6 +138,8 @@
1.92 """
1.93
1.94 self.get_response_stream().close()
1.95 + for tempfile in self.tempfiles:
1.96 + tempfile.delete()
1.97
1.98 # Server-related methods.
1.99
1.100 @@ -597,7 +613,7 @@
1.101
1.102 session = javax.mail.Session.getDefaultInstance(java.util.Properties())
1.103
1.104 - # Fake a multipart message.
1.105 + # Fake the headers.
1.106
1.107 str_buffer = java.io.StringWriter()
1.108 fp = self.get_request_stream()
1.109 @@ -607,62 +623,80 @@
1.110 str_buffer.write(fp.read())
1.111 str_buffer.close()
1.112
1.113 - # Re-read that message.
1.114 + # Concatenate the headers with the rest of the stream.
1.115 +
1.116 + header_stream = java.io.StringBufferInputStream(str_buffer.toString())
1.117 + input_stream = self.request.getInputStream()
1.118 + message = javax.mail.internet.MimeMessage(session, java.io.SequenceInputStream(header_stream, input_stream))
1.119
1.120 - input_stream = java.io.StringBufferInputStream(str_buffer.toString())
1.121 - message = javax.mail.internet.MimeMessage(session, input_stream)
1.122 - content = message.getContent()
1.123 - return self._get_fields_from_multipart(content, encoding)
1.124 + # Collect the fields by traversing the message.
1.125
1.126 - def _get_fields_from_multipart(self, content, encoding):
1.127 + fields = {}
1.128 + self._get_fields_from_multipart(fields, message.getContent(), encoding)
1.129 + return fields
1.130 +
1.131 + def _get_fields_from_multipart(self, fields, content, encoding):
1.132
1.133 "Get fields from multipart 'content'."
1.134
1.135 - fields = {}
1.136 for i in range(0, content.getCount()):
1.137 part = content.getBodyPart(i)
1.138 - subcontent = part.getContent()
1.139 + self._get_field_from_multipart(fields, part, encoding)
1.140
1.141 - # Convert input stream content.
1.142 + def _get_field_from_multipart(self, fields, part, encoding):
1.143
1.144 - if isinstance(subcontent, java.io.InputStream):
1.145 - subcontent = Stream(subcontent)
1.146 + "Get a field from the given 'part'."
1.147
1.148 - # Record string content.
1.149 + if not part.getContentType().startswith("multipart"):
1.150 +
1.151 + # Should get: form-data; name="x"
1.152
1.153 - if isinstance(subcontent, (type(""), Stream)):
1.154 + disposition = self.parse_header_value(HeaderValue, part.getHeader("Content-Disposition")[0])
1.155
1.156 - # Should get: form-data; name="x"
1.157 + # Store and optionally convert the field.
1.158
1.159 - disposition = self.parse_header_value(HeaderValue, part.getHeader("Content-Disposition")[0])
1.160 + if disposition.name is not None:
1.161 + field_name = disposition.name[1:-1]
1.162
1.163 - # Store and optionally convert the field.
1.164 + # Test whether the part should be written to a temporary file.
1.165
1.166 - if disposition.name is not None:
1.167 - field_name = disposition.name[1:-1]
1.168 + if part.getHeader("Content-Type") is not None:
1.169
1.170 # Using properly decoded header values.
1.171
1.172 - if part.getHeader("Content-Type") is not None:
1.173 - headers = {}
1.174 - for header in part.getAllHeaders():
1.175 - headers[header.getName()] = self.parse_header_value(HeaderValue, header.getValue())
1.176 - field_value = FileContent(subcontent, headers)
1.177 - else:
1.178 - field_value = self.decode_path(subcontent, encoding)
1.179 + headers = {}
1.180 + for header in part.getAllHeaders():
1.181 + headers[header.getName()] = self.parse_header_value(HeaderValue, header.getValue())
1.182 +
1.183 + # Write to a temporary file and then open that file.
1.184
1.185 - # Store the entry in the fields dictionary.
1.186 + tempfile = java.io.File.createTempFile(str(id(self)), field_name)
1.187 + temp_stream = java.io.FileOutputStream(tempfile)
1.188 + try:
1.189 + part.writeTo(temp_stream)
1.190 + finally:
1.191 + self.tempfiles.append(tempfile)
1.192 +
1.193 + # The file must be treated like a message.
1.194
1.195 - if not fields.has_key(field_name):
1.196 - fields[field_name] = []
1.197 - fields[field_name].append(field_value)
1.198 + temp_part = javax.mail.internet.MimeBodyPart(java.io.FileInputStream(tempfile))
1.199 + field_value = FileContent(Stream(temp_part.getRawInputStream()), headers)
1.200 +
1.201 + else:
1.202 + subcontent = part.getContent()
1.203 + field_value = self.decode_path(subcontent, encoding)
1.204 +
1.205 + # Store the entry in the fields dictionary.
1.206
1.207 - # Otherwise, descend deeper into the multipart hierarchy.
1.208 + if not fields.has_key(field_name):
1.209 + fields[field_name] = []
1.210 + fields[field_name].append(field_value)
1.211
1.212 - else:
1.213 - fields.update(self._get_fields_from_multipart(subcontent, encoding))
1.214 + # Otherwise, descend deeper into the multipart hierarchy.
1.215
1.216 - return fields
1.217 + else:
1.218 + subcontent = part.getContent()
1.219 + fields.update(self._get_fields_from_multipart(subcontent, encoding))
1.220
1.221 class Session:
1.222