[Jython-checkins] jython (merge 2.5 -> default): merge w/2.5: Fixing issue 1754: changing the implementation of the modjy
alan.kennedy
jython-checkins at python.org
Sun Nov 4 15:37:31 CET 2012
http://hg.python.org/jython/rev/7ebb51401f54
changeset: 6885:7ebb51401f54
parent: 6883:4b061dc82e97
parent: 6884:4c3155645812
user: Alan Kennedy <alan at xhaus.com>
date: Sun Nov 04 14:32:26 2012 +0000
summary:
merge w/2.5: Fixing issue 1754: changing the implementation of the modjy sgi.input object
files:
Lib/modjy/modjy_input.py | 167 ++++++++++
Lib/modjy/modjy_wsgi.py | 5 +-
tests/modjy/java/com/xhaus/modjy/ModjyTestPostData.java | 4 +-
tests/modjy/java/com/xhaus/modjy/ModjyTestWSGIStreams.java | 47 ++-
tests/modjy/test_apps_dir/stream_tests.py | 8 +
5 files changed, 223 insertions(+), 8 deletions(-)
diff --git a/Lib/modjy/modjy_input.py b/Lib/modjy/modjy_input.py
new file mode 100644
--- /dev/null
+++ b/Lib/modjy/modjy_input.py
@@ -0,0 +1,167 @@
+###
+#
+# 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
+#
+###
+
+#
+# This code adapted from the socket._fileobject class
+#
+
+import jarray
+
+class modjy_input_object(object):
+
+ def __init__(self, servlet_inputstream, bufsize=8192):
+ self.istream = servlet_inputstream
+ self.buffer_size = bufsize
+ self.buffer = ""
+
+ def istream_read(self, n):
+ data = jarray.zeros(n, 'b')
+ m = self.istream.read(data)
+ if m == -1: # indicates EOF has been reached, so we just return the empty string
+ return ""
+ elif m <= 0:
+ return ""
+ if m < n:
+ data = data[:m]
+ return data.tostring()
+
+ def read(self, size=-1):
+ data = self.buffer
+ if size < 0:
+ # Read until EOF
+ buffers = []
+ if data:
+ buffers.append(data)
+ self.buffer = ""
+ recv_size = self.buffer_size
+ while True:
+ data = self.istream_read(recv_size)
+ if not data:
+ break
+ buffers.append(data)
+ return "".join(buffers)
+ else:
+ # Read until size bytes or EOF seen, whichever comes first
+ buf_len = len(data)
+ if buf_len >= size:
+ self.buffer = data[size:]
+ return data[:size]
+ buffers = []
+ if data:
+ buffers.append(data)
+ self.buffer = ""
+ while True:
+ left = size - buf_len
+ recv_size = max(self.buffer_size, left)
+ data = self.istream_read(recv_size)
+ if not data:
+ break
+ buffers.append(data)
+ n = len(data)
+ if n >= left:
+ self.buffer = data[left:]
+ buffers[-1] = data[:left]
+ break
+ buf_len += n
+ return "".join(buffers)
+
+ def readline(self, size=-1):
+ data = self.buffer
+ if size < 0:
+ # Read until \n or EOF, whichever comes first
+ nl = data.find('\n')
+ if nl >= 0:
+ nl += 1
+ self.buffer = data[nl:]
+ return data[:nl]
+ buffers = []
+ if data:
+ buffers.append(data)
+ self.buffer = ""
+ while True:
+ data = self.istream_read(self.buffer_size)
+ if not data:
+ break
+ buffers.append(data)
+ nl = data.find('\n')
+ if nl >= 0:
+ nl += 1
+ self.buffer = data[nl:]
+ buffers[-1] = data[:nl]
+ break
+ return "".join(buffers)
+ else:
+ # Read until size bytes or \n or EOF seen, whichever comes first
+ nl = data.find('\n', 0, size)
+ if nl >= 0:
+ nl += 1
+ self.buffer = data[nl:]
+ return data[:nl]
+ buf_len = len(data)
+ if buf_len >= size:
+ self.buffer = data[size:]
+ return data[:size]
+ buffers = []
+ if data:
+ buffers.append(data)
+ self.buffer = ""
+ while True:
+ data = self.istream_read(self.buffer_size)
+ if not data:
+ break
+ buffers.append(data)
+ left = size - buf_len
+ nl = data.find('\n', 0, left)
+ if nl >= 0:
+ nl += 1
+ self.buffer = data[nl:]
+ buffers[-1] = data[:nl]
+ break
+ n = len(data)
+ if n >= left:
+ self.buffer = data[left:]
+ buffers[-1] = data[:left]
+ break
+ buf_len += n
+ return "".join(buffers)
+
+ def readlines(self, sizehint=0):
+ total = 0
+ list = []
+ while True:
+ line = self.readline()
+ if not line:
+ break
+ list.append(line)
+ total += len(line)
+ if sizehint and total >= sizehint:
+ break
+ return list
+
+ # Iterator protocols
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ line = self.readline()
+ if not line:
+ raise StopIteration
+ return line
diff --git a/Lib/modjy/modjy_wsgi.py b/Lib/modjy/modjy_wsgi.py
--- a/Lib/modjy/modjy_wsgi.py
+++ b/Lib/modjy/modjy_wsgi.py
@@ -28,6 +28,7 @@
create_py_file = PyFile
from modjy_exceptions import *
+from modjy_input import modjy_input_object
server_name = "modjy"
server_param_prefix = "%s.param" % server_name
@@ -125,8 +126,8 @@
def set_wsgi_streams(self, req, resp, dict):
try:
- dict["wsgi.input"] = create_py_file(req.getInputStream(), "rb")
- dict["wsgi.errors"] = create_py_file(System.err)
+ dict["wsgi.input"] = modjy_input_object(req.getInputStream())
+ dict["wsgi.errors"] = create_py_file(System.err)
except IOException, iox:
raise ModjyIOException(iox)
diff --git a/tests/modjy/java/com/xhaus/modjy/ModjyTestPostData.java b/tests/modjy/java/com/xhaus/modjy/ModjyTestPostData.java
--- a/tests/modjy/java/com/xhaus/modjy/ModjyTestPostData.java
+++ b/tests/modjy/java/com/xhaus/modjy/ModjyTestPostData.java
@@ -27,7 +27,7 @@
setAppFile("post_data_tests.py");
}
- public void doHeaderTest(String appName, String postData) throws Exception {
+ public void doPostTest(String appName, String postData) throws Exception {
postDataTestSetUp();
setMethod("POST");
setAppName(appName);
@@ -40,7 +40,7 @@
public void testPostDataLineEndsNotTranslated() throws Exception {
String testData = "this\r\ndata\r\ncontains\r\ncarriage\r\nreturns\r\n";
String expectedData = "'"+testData.replace("\r", "\\r").replace("\n", "\\n")+"'";
- doHeaderTest("test_return_post_data", testData);
+ doPostTest("test_return_post_data", testData);
assertEquals("Wrong post data returned >>" + getOutput() + "<< != >>"+expectedData+"<<", expectedData, getOutput());
}
diff --git a/tests/modjy/java/com/xhaus/modjy/ModjyTestWSGIStreams.java b/tests/modjy/java/com/xhaus/modjy/ModjyTestWSGIStreams.java
--- a/tests/modjy/java/com/xhaus/modjy/ModjyTestWSGIStreams.java
+++ b/tests/modjy/java/com/xhaus/modjy/ModjyTestWSGIStreams.java
@@ -63,6 +63,14 @@
doInputTest(appName, bodyContent, expectedContent, expectedLength, 0);
}
+ protected String buildStringWithContents(int count, String contents) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0 ; i < count ; i++) {
+ builder.append(contents);
+ };
+ return builder.toString();
+ }
+
public void testEmptyInput() throws Exception {
doInputTest("test_read_input_stream", "", "", 0);
}
@@ -81,6 +89,14 @@
}
}
+ public void testAsciiInputWithReadSizeLargeInput() throws Exception {
+ String one_k = buildStringWithContents(1024, "X");
+ String testData = buildStringWithContents(64, one_k);
+ for (int i = 64; i <= 65536; i=i*2) {
+ doInputTest("test_read_input_stream", testData, testData, testData.length(), i);
+ }
+ }
+
public void testAsciiInputReadline() throws Exception {
doInputTest("test_readline_input_stream", "Hello\nWorld!\n", "Hello\n", 6);
doInputTest("test_readline_input_stream", "Hello", "Hello", 5);
@@ -88,17 +104,40 @@
public void testAsciiInputReadlineWithSize() throws Exception {
// Let's test this: although PEP-333 says it's not supported, modjy can do it
- doInputTest("test_readline_input_stream", "Hello\nWorld!\n", "Hello", 5, 5);
+ doInputTest("test_readline_input_stream", "Hello\nWorld!\n", "Hello\n", 6, 6);
+ }
+
+ public void testAsciiInputReadlineWithSizeLessThanOneLine() throws Exception {
+ // Test where the size given is too small to actually reach a line end and
+ // a truncated line should be returned.
+ doInputTest("test_readline_input_stream", "Hello\nWorld!\n", "Hel", 3, 3);
+ }
+
+ public void testAsciiInputReadlineWithSizeLongerThanOneLine() throws Exception {
+ // Test where the size given is long enough to take in a whole line
+ // and part of the next line.
+ doInputTest("test_readline_input_stream", "Hello\nWorld!\n", "Hello\n", 6, 10);
+ }
+
+ public void testAsciiInputReadlineWithSizeLongerThanTwoLines() throws Exception {
+ // Test where the size given is long enough to take in a whole line
+ // and part of the next line.
+ doInputTest("test_readline_input_stream", "Hello\nWorld!\n", "Hello\n", 6, 32);
}
public void testAsciiInputWithReadlines() throws Exception {
+ doInputTest("test_readlines_input_stream", "Hello", "Hello", 5);
+ doInputTest("test_readlines_input_stream", "Hello\n", "Hello\n", 6);
doInputTest("test_readlines_input_stream", "Hello\nWorld!\n", "Hello\n$World!\n", 14);
- doInputTest("test_readlines_input_stream", "Hello", "Hello", 5);
}
public void testAsciiInputWithReadlinesWithHint() throws Exception {
- // Let's leave this for now
- // doInputTest("test_readlines_input_stream", "Hello\nWorld!\n", "Hello\n", 6, 5);
+ doInputTest("test_readlines_input_stream", "Hello\nWorld!\n", "Hello\n", 6, 5);
+ doInputTest("test_readlines_input_stream", "Hello\nWorld!\n", "Hello\n$World!\n", 14, 32);
+ }
+
+ public void testInputIterator() throws Exception {
+ doInputTest("test_iter_input_stream", "Hello\nWorld!\n", "Hello\n$World!\n", 14);
}
public void testError() throws Exception {
diff --git a/tests/modjy/test_apps_dir/stream_tests.py b/tests/modjy/test_apps_dir/stream_tests.py
--- a/tests/modjy/test_apps_dir/stream_tests.py
+++ b/tests/modjy/test_apps_dir/stream_tests.py
@@ -83,6 +83,14 @@
writer(repr(output_dict))
return []
+def test_iter_input_stream(environ, start_response):
+ writer = start_response("200 OK", [])
+ wsgi_input = environ['wsgi.input']
+ data = "$".join([line for line in wsgi_input])
+ output_dict = {'data': data}
+ writer(repr(output_dict))
+ return []
+
def test_error_stream(environ, start_response):
writer = start_response("200 OK", [])
wsgi_errors = environ['wsgi.errors']
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list