summaryrefslogtreecommitdiffstats
path: root/simple/simple-http/src/test/java/org/simpleframework/http/core
diff options
context:
space:
mode:
Diffstat (limited to 'simple/simple-http/src/test/java/org/simpleframework/http/core')
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/AccumulatorTest.java99
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/ChunkedProducerTest.java43
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/Chunker.java52
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/Client.java264
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/Connector.java9
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/ConversationTest.java126
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/DribbleCursor.java62
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/FixedConsumerTest.java80
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/FixedProducerTest.java50
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MessageTest.java72
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockChannel.java57
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockController.java55
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockEntity.java49
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockObserver.java62
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockPart.java49
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockProxyRequest.java67
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockRequest.java202
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockResponse.java95
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockSender.java75
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/MockSocket.java42
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/PayloadTest.java97
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/ProducerExceptionTest.java23
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/QueryBuilderTest.java35
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorProcessorTest.java247
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorTest.java178
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/RequestConsumerTest.java138
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/RequestTest.java144
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/Result.java37
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/StopTest.java176
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/StreamCursor.java74
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java183
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/Ticket.java22
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/TicketProcessor.java28
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/TransferTest.java195
-rw-r--r--simple/simple-http/src/test/java/org/simpleframework/http/core/WebSocketUpgradeTest.java126
35 files changed, 3313 insertions, 0 deletions
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/AccumulatorTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/AccumulatorTest.java
new file mode 100644
index 0000000..70db4a3
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/AccumulatorTest.java
@@ -0,0 +1,99 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class AccumulatorTest extends TestCase {
+
+ public void testAccumulator() throws IOException {
+ MockChannel channel = new MockChannel(null);
+ MockObserver monitor = new MockObserver();
+ MockRequest request = new MockRequest();
+ MockResponse response = new MockResponse();
+ Conversation support = new Conversation(request, response);
+ ResponseBuffer buffer = new ResponseBuffer(monitor, response, support, channel);
+
+ byte[] content = { 'T', 'E', 'S', 'T' };
+
+ // Start a HTTP/1.1 conversation
+ request.setMajor(1);
+ request.setMinor(1);
+
+ // Write to a zero capacity buffer
+ buffer.expand(0);
+ buffer.write(content, 0, content.length);
+
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertEquals(response.getValue("Transfer-Encoding"), "chunked");
+ assertEquals(response.getValue("Content-Length"), null);
+ assertEquals(response.getContentLength(), -1);
+ assertTrue(response.isCommitted());
+
+ channel = new MockChannel(null);
+ monitor = new MockObserver();
+ request = new MockRequest();
+ response = new MockResponse();
+ support = new Conversation(request, response);
+ buffer = new ResponseBuffer(monitor, response, support, channel);
+
+ // Start a HTTP/1.0 conversation
+ request.setMajor(1);
+ request.setMinor(0);
+
+ // Write to a zero capacity buffer
+ buffer.expand(0);
+ buffer.write(content, 0, content.length);
+
+ assertEquals(response.getValue("Connection"), "close");
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getValue("Content-Length"), null);
+ assertEquals(response.getContentLength(), -1);
+ assertTrue(response.isCommitted());
+
+ channel = new MockChannel(null);
+ monitor = new MockObserver();
+ request = new MockRequest();
+ response = new MockResponse();
+ support = new Conversation(request, response);
+ buffer = new ResponseBuffer(monitor, response, support, channel);
+
+ // Start a HTTP/1.1 conversation
+ request.setMajor(1);
+ request.setMinor(1);
+
+ // Write to a large capacity buffer
+ buffer.expand(1024);
+ buffer.write(content, 0, content.length);
+
+ assertEquals(response.getValue("Connection"), null);
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getValue("Content-Length"), null);
+ assertEquals(response.getContentLength(), -1);
+ assertFalse(response.isCommitted());
+ assertFalse(monitor.isReady());
+ assertFalse(monitor.isClose());
+ assertFalse(monitor.isError());
+
+ // Flush the buffer
+ buffer.close();
+
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getValue("Content-Length"), "4");
+ assertEquals(response.getContentLength(), 4);
+ assertTrue(response.isCommitted());
+ assertTrue(monitor.isReady());
+ assertFalse(monitor.isClose());
+ assertFalse(monitor.isError());
+
+ boolean catchOverflow = false;
+
+ try {
+ buffer.write(content, 0, content.length);
+ } catch(Exception e) {
+ catchOverflow = true;
+ }
+ assertTrue(catchOverflow);
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/ChunkedProducerTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/ChunkedProducerTest.java
new file mode 100644
index 0000000..9f7a6bb
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/ChunkedProducerTest.java
@@ -0,0 +1,43 @@
+package org.simpleframework.http.core;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.buffer.ArrayAllocator;
+import org.simpleframework.http.message.ChunkedConsumer;
+import org.simpleframework.transport.ByteCursor;
+
+public class ChunkedProducerTest extends TestCase {
+
+ public void testChunk() throws Exception {
+ testChunk(1024, 1);
+ testChunk(1024, 2);
+ testChunk(512, 20);
+ testChunk(64, 64);
+ }
+
+ public void testChunk(int chunkSize, int count) throws Exception {
+ MockSender sender = new MockSender((chunkSize * count) + 1024);
+ MockObserver monitor = new MockObserver();
+ ChunkedConsumer validator = new ChunkedConsumer(new ArrayAllocator());
+ ChunkedEncoder producer = new ChunkedEncoder(monitor, sender);
+ byte[] chunk = new byte[chunkSize];
+
+ for(int i = 0; i < chunk.length; i++) {
+ chunk[i] = (byte)String.valueOf(i).charAt(0);
+ }
+ for(int i = 0; i < count; i++) {
+ producer.encode(chunk, 0, chunkSize);
+ }
+ producer.close();
+
+ System.err.println(sender.getBuffer().encode("UTF-8"));
+
+ ByteCursor cursor = sender.getCursor();
+
+ while(!validator.isFinished()) {
+ validator.consume(cursor);
+ }
+ assertEquals(cursor.ready(), -1);
+ assertTrue(monitor.isReady());
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/Chunker.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/Chunker.java
new file mode 100644
index 0000000..8f5ef13
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/Chunker.java
@@ -0,0 +1,52 @@
+
+package org.simpleframework.http.core;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Chunker extends FilterOutputStream {
+
+
+ private byte[] size = {'0', '0', '0', '0', '0',
+ '0', '0', '0', 13, 10};
+
+
+ private byte[] index = {'0', '1', '2', '3', '4', '5','6', '7',
+ '8', '9', 'a', 'b', 'c', 'd','e', 'f'};
+
+
+ private byte[] zero = {'0', 13, 10, 13, 10};
+
+
+ public Chunker(OutputStream out){
+ super(out);
+ }
+
+ public void write(int octet) throws IOException {
+ byte[] swap = new byte[1];
+ swap[0] = (byte)octet;
+ write(swap);
+ }
+
+
+ public void write(byte[] buf, int off, int len) throws IOException {
+ int pos = 7;
+
+ if(len > 0) {
+ for(int num = len; num > 0; num >>>= 4){
+ size[pos--] = index[num & 0xf];
+ }
+ String text = String.format("%s; %s\r\n", Integer.toHexString(len), len);
+
+ out.write(text.getBytes("ISO-8859-1"));
+ out.write(buf, off, len);
+ out.write(size, 8, 2);
+ }
+ }
+
+ public void close() throws IOException {
+ out.write(zero);
+ out.close();
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/Client.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/Client.java
new file mode 100644
index 0000000..13d2f30
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/Client.java
@@ -0,0 +1,264 @@
+package org.simpleframework.http.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.X509TrustManager;
+
+
+public class Client {
+
+
+ private static final byte[] CERTIFICATE = {
+ (byte)254,(byte)237,(byte)254,(byte)237,(byte)0, (byte)0, (byte)0, (byte)2, (byte)0, (byte)0,
+ (byte)0, (byte)1, (byte)0, (byte)0, (byte)0, (byte)1, (byte)0, (byte)3, (byte)107,(byte)101,
+ (byte)121,(byte)0, (byte)0, (byte)1, (byte)26, (byte)105,(byte)38, (byte)187,(byte)170,(byte)0,
+ (byte)0, (byte)2, (byte)187,(byte)48, (byte)130,(byte)2, (byte)183,(byte)48, (byte)14, (byte)6,
+ (byte)10, (byte)43, (byte)6, (byte)1, (byte)4, (byte)1, (byte)42, (byte)2, (byte)17, (byte)1,
+ (byte)1, (byte)5, (byte)0, (byte)4, (byte)130,(byte)2, (byte)163,(byte)138,(byte)122,(byte)194,
+ (byte)218,(byte)31, (byte)101,(byte)210,(byte)131,(byte)160,(byte)37, (byte)111,(byte)187,(byte)43,
+ (byte)192,(byte)67, (byte)244,(byte)136,(byte)120,(byte)166,(byte)171,(byte)204,(byte)87, (byte)156,
+ (byte)50, (byte)58, (byte)153,(byte)37, (byte)180,(byte)248,(byte)60, (byte)73, (byte)16, (byte)110,
+ (byte)176,(byte)84, (byte)239,(byte)247,(byte)113,(byte)133,(byte)193,(byte)239,(byte)94, (byte)107,
+ (byte)126,(byte)141,(byte)199,(byte)243,(byte)243,(byte)25, (byte)179,(byte)181,(byte)201,(byte)100,
+ (byte)194,(byte)146,(byte)114,(byte)162,(byte)124,(byte)96, (byte)198,(byte)248,(byte)232,(byte)162,
+ (byte)143,(byte)170,(byte)120,(byte)106,(byte)171,(byte)128,(byte)32, (byte)18, (byte)134,(byte)69,
+ (byte)2, (byte)230,(byte)204,(byte)18, (byte)191,(byte)212,(byte)236,(byte)130,(byte)76, (byte)24,
+ (byte)24, (byte)131,(byte)210,(byte)150,(byte)209,(byte)205,(byte)174,(byte)25, (byte)175,(byte)45,
+ (byte)39, (byte)223,(byte)17, (byte)57, (byte)129,(byte)6, (byte)195,(byte)116,(byte)197,(byte)143,
+ (byte)14, (byte)160,(byte)120,(byte)249,(byte)220,(byte)48, (byte)71, (byte)109,(byte)122,(byte)64,
+ (byte)195,(byte)139,(byte)61, (byte)206,(byte)83, (byte)159,(byte)78, (byte)137,(byte)160,(byte)88,
+ (byte)252,(byte)120,(byte)217,(byte)251,(byte)254,(byte)151,(byte)94, (byte)242,(byte)170,(byte)0,
+ (byte)247,(byte)170,(byte)53, (byte)197,(byte)34, (byte)253,(byte)96, (byte)47, (byte)248,(byte)194,
+ (byte)230,(byte)62, (byte)121,(byte)117,(byte)163,(byte)35, (byte)80, (byte)15, (byte)113,(byte)203,
+ (byte)71, (byte)202,(byte)36, (byte)187,(byte)163,(byte)78, (byte)228,(byte)31, (byte)3, (byte)53,
+ (byte)214,(byte)149,(byte)170,(byte)214,(byte)161,(byte)180,(byte)53, (byte)207,(byte)158,(byte)150,
+ (byte)161,(byte)37, (byte)59, (byte)150,(byte)107,(byte)161,(byte)9, (byte)195,(byte)79, (byte)254,
+ (byte)62, (byte)231,(byte)13, (byte)195,(byte)173,(byte)139,(byte)15, (byte)153,(byte)62, (byte)20,
+ (byte)204,(byte)111,(byte)64, (byte)89, (byte)180,(byte)201,(byte)58, (byte)64, (byte)15, (byte)195,
+ (byte)18, (byte)29, (byte)29, (byte)44, (byte)5, (byte)101,(byte)132,(byte)113,(byte)204,(byte)251,
+ (byte)225,(byte)3, (byte)82, (byte)52, (byte)62, (byte)86, (byte)142,(byte)43, (byte)240,(byte)201,
+ (byte)26, (byte)226,(byte)143,(byte)162,(byte)9, (byte)97, (byte)96, (byte)185,(byte)59, (byte)85,
+ (byte)54, (byte)115,(byte)135,(byte)199,(byte)26, (byte)58, (byte)185,(byte)100,(byte)118,(byte)48,
+ (byte)119,(byte)110,(byte)203,(byte)115,(byte)74, (byte)152,(byte)144,(byte)137,(byte)13, (byte)18,
+ (byte)192,(byte)82, (byte)101,(byte)163,(byte)8, (byte)128,(byte)57, (byte)68, (byte)183,(byte)225,
+ (byte)79, (byte)6, (byte)143,(byte)94, (byte)203,(byte)203,(byte)121,(byte)52, (byte)128,(byte)94,
+ (byte)184,(byte)223,(byte)107,(byte)217,(byte)68, (byte)118,(byte)145,(byte)164,(byte)13, (byte)220,
+ (byte)135,(byte)11, (byte)74, (byte)193,(byte)48, (byte)7, (byte)95, (byte)190,(byte)17, (byte)0,
+ (byte)69, (byte)109,(byte)6, (byte)64, (byte)86, (byte)80, (byte)93, (byte)82, (byte)20, (byte)106,
+ (byte)191,(byte)201,(byte)13, (byte)91, (byte)132,(byte)102,(byte)47, (byte)188,(byte)123,(byte)79,
+ (byte)209,(byte)43, (byte)180,(byte)152,(byte)128,(byte)20, (byte)182,(byte)148,(byte)19, (byte)24,
+ (byte)230,(byte)249,(byte)42, (byte)51, (byte)197,(byte)176,(byte)113,(byte)44, (byte)100,(byte)95,
+ (byte)59, (byte)91, (byte)78, (byte)226,(byte)184,(byte)224,(byte)72, (byte)233,(byte)133,(byte)154,
+ (byte)42, (byte)221,(byte)32, (byte)165,(byte)41, (byte)156,(byte)165,(byte)247,(byte)86, (byte)115,
+ (byte)183,(byte)22, (byte)89, (byte)17, (byte)165,(byte)215,(byte)148,(byte)32, (byte)199,(byte)64,
+ (byte)139,(byte)171,(byte)236,(byte)43, (byte)5, (byte)36, (byte)35, (byte)223,(byte)35, (byte)247,
+ (byte)255,(byte)112,(byte)27, (byte)215,(byte)57, (byte)251,(byte)236,(byte)128,(byte)168,(byte)219,
+ (byte)146,(byte)235,(byte)241,(byte)68, (byte)213,(byte)127,(byte)63, (byte)231,(byte)236,(byte)176,
+ (byte)166,(byte)121,(byte)203,(byte)114,(byte)33, (byte)19, (byte)200,(byte)167,(byte)155,(byte)27,
+ (byte)38, (byte)109,(byte)133,(byte)1, (byte)184,(byte)173,(byte)253,(byte)198,(byte)122,(byte)98,
+ (byte)196,(byte)43, (byte)145,(byte)86, (byte)182,(byte)208,(byte)78, (byte)246,(byte)234,(byte)249,
+ (byte)229,(byte)202,(byte)75, (byte)66, (byte)108,(byte)134,(byte)81, (byte)134,(byte)90, (byte)251,
+ (byte)137,(byte)155,(byte)209,(byte)11, (byte)249,(byte)87, (byte)164,(byte)98, (byte)242,(byte)51,
+ (byte)184,(byte)162,(byte)35, (byte)20, (byte)248,(byte)14, (byte)224,(byte)76, (byte)31, (byte)132,
+ (byte)125,(byte)44, (byte)83, (byte)15, (byte)221,(byte)43, (byte)62, (byte)187,(byte)211,(byte)176,
+ (byte)41, (byte)70, (byte)187,(byte)3, (byte)48, (byte)150,(byte)206,(byte)54, (byte)38, (byte)33,
+ (byte)94, (byte)133,(byte)145,(byte)148,(byte)58, (byte)219,(byte)252,(byte)124,(byte)251,(byte)46,
+ (byte)72, (byte)35, (byte)244,(byte)33, (byte)97, (byte)50, (byte)21, (byte)207,(byte)163,(byte)3,
+ (byte)226,(byte)225,(byte)252,(byte)149,(byte)214,(byte)200,(byte)132,(byte)65, (byte)224,(byte)121,
+ (byte)205,(byte)241,(byte)107,(byte)155,(byte)252,(byte)158,(byte)64, (byte)40, (byte)252,(byte)143,
+ (byte)76, (byte)71, (byte)227,(byte)13, (byte)176,(byte)50, (byte)250,(byte)115,(byte)198,(byte)64,
+ (byte)174,(byte)146,(byte)108,(byte)106,(byte)66, (byte)98, (byte)78, (byte)196,(byte)126,(byte)118,
+ (byte)51, (byte)65, (byte)251,(byte)8, (byte)28, (byte)75, (byte)123,(byte)92, (byte)5, (byte)125,
+ (byte)16, (byte)127,(byte)250,(byte)65, (byte)178,(byte)54, (byte)169,(byte)109,(byte)94, (byte)171,
+ (byte)97, (byte)154,(byte)232,(byte)24, (byte)196,(byte)91, (byte)103,(byte)90, (byte)217,(byte)75,
+ (byte)126,(byte)76, (byte)129,(byte)240,(byte)67, (byte)131,(byte)147,(byte)178,(byte)29, (byte)234,
+ (byte)150,(byte)91, (byte)78, (byte)165,(byte)76, (byte)200,(byte)99, (byte)175,(byte)240,(byte)3,
+ (byte)76, (byte)151,(byte)111,(byte)167,(byte)220,(byte)162,(byte)7, (byte)249,(byte)12, (byte)201,
+ (byte)171,(byte)58, (byte)170,(byte)26, (byte)149,(byte)224,(byte)135,(byte)201,(byte)186,(byte)201,
+ (byte)253,(byte)153,(byte)248,(byte)148,(byte)171,(byte)197,(byte)70, (byte)179,(byte)127,(byte)210,
+ (byte)30, (byte)172,(byte)207,(byte)179,(byte)140,(byte)240,(byte)244,(byte)2, (byte)24, (byte)156,
+ (byte)116,(byte)6, (byte)237,(byte)42, (byte)221,(byte)201,(byte)244,(byte)207,(byte)123,(byte)19,
+ (byte)189,(byte)58, (byte)189,(byte)107,(byte)223,(byte)44, (byte)230,(byte)114,(byte)115,(byte)194,
+ (byte)189,(byte)163,(byte)189,(byte)224,(byte)161,(byte)221,(byte)40, (byte)29, (byte)73, (byte)244,
+ (byte)231,(byte)213,(byte)139,(byte)178,(byte)248,(byte)84, (byte)137,(byte)65, (byte)124,(byte)98,
+ (byte)248,(byte)62, (byte)229,(byte)86, (byte)128,(byte)57, (byte)106,(byte)38, (byte)193,(byte)185,
+ (byte)10, (byte)162,(byte)0, (byte)0, (byte)0, (byte)1, (byte)0, (byte)5, (byte)88, (byte)46,
+ (byte)53, (byte)48, (byte)57, (byte)0, (byte)0, (byte)2, (byte)72, (byte)48, (byte)130,(byte)2,
+ (byte)68, (byte)48, (byte)130,(byte)1, (byte)173,(byte)2, (byte)4, (byte)72, (byte)76, (byte)18,
+ (byte)25, (byte)48, (byte)13, (byte)6, (byte)9, (byte)42, (byte)134,(byte)72, (byte)134,(byte)247,
+ (byte)13, (byte)1, (byte)1, (byte)4, (byte)5, (byte)0, (byte)48, (byte)105,(byte)49, (byte)16,
+ (byte)48, (byte)14, (byte)6, (byte)3, (byte)85, (byte)4, (byte)6, (byte)19, (byte)7, (byte)67,
+ (byte)111,(byte)117,(byte)110,(byte)116,(byte)114,(byte)121,(byte)49, (byte)17, (byte)48, (byte)15,
+ (byte)6, (byte)3, (byte)85, (byte)4, (byte)7, (byte)19, (byte)8, (byte)76, (byte)111,(byte)99,
+ (byte)97, (byte)116,(byte)105,(byte)111,(byte)110,(byte)49, (byte)28, (byte)48, (byte)26, (byte)6,
+ (byte)3, (byte)85, (byte)4, (byte)11, (byte)19, (byte)19, (byte)79, (byte)114,(byte)103,(byte)97,
+ (byte)110,(byte)105,(byte)122,(byte)97, (byte)116,(byte)105,(byte)111,(byte)110,(byte)97, (byte)108,
+ (byte)32, (byte)85, (byte)110,(byte)105,(byte)116,(byte)49, (byte)21, (byte)48, (byte)19, (byte)6,
+ (byte)3, (byte)85, (byte)4, (byte)10, (byte)19, (byte)12, (byte)79, (byte)114,(byte)103,(byte)97,
+ (byte)110,(byte)105,(byte)122,(byte)97, (byte)116,(byte)105,(byte)111,(byte)110,(byte)49, (byte)13,
+ (byte)48, (byte)11, (byte)6, (byte)3, (byte)85, (byte)4, (byte)3, (byte)19, (byte)4, (byte)78,
+ (byte)97, (byte)109,(byte)101,(byte)48, (byte)30, (byte)23, (byte)13, (byte)48, (byte)56, (byte)48,
+ (byte)54, (byte)48, (byte)56, (byte)49, (byte)55, (byte)48, (byte)56, (byte)52, (byte)49, (byte)90,
+ (byte)23, (byte)13, (byte)48, (byte)57, (byte)48, (byte)54, (byte)48, (byte)56, (byte)49, (byte)55,
+ (byte)48, (byte)56, (byte)52, (byte)49, (byte)90, (byte)48, (byte)105,(byte)49, (byte)16, (byte)48,
+ (byte)14, (byte)6, (byte)3, (byte)85, (byte)4, (byte)6, (byte)19, (byte)7, (byte)67, (byte)111,
+ (byte)117,(byte)110,(byte)116,(byte)114,(byte)121,(byte)49, (byte)17, (byte)48, (byte)15, (byte)6,
+ (byte)3, (byte)85, (byte)4, (byte)7, (byte)19, (byte)8, (byte)76, (byte)111,(byte)99, (byte)97,
+ (byte)116,(byte)105,(byte)111,(byte)110,(byte)49, (byte)28, (byte)48, (byte)26, (byte)6, (byte)3,
+ (byte)85, (byte)4, (byte)11, (byte)19, (byte)19, (byte)79, (byte)114,(byte)103,(byte)97, (byte)110,
+ (byte)105,(byte)122,(byte)97, (byte)116,(byte)105,(byte)111,(byte)110,(byte)97, (byte)108,(byte)32,
+ (byte)85, (byte)110,(byte)105,(byte)116,(byte)49, (byte)21, (byte)48, (byte)19, (byte)6, (byte)3,
+ (byte)85, (byte)4, (byte)10, (byte)19, (byte)12, (byte)79, (byte)114,(byte)103,(byte)97, (byte)110,
+ (byte)105,(byte)122,(byte)97, (byte)116,(byte)105,(byte)111,(byte)110,(byte)49, (byte)13, (byte)48,
+ (byte)11, (byte)6, (byte)3, (byte)85, (byte)4, (byte)3, (byte)19, (byte)4, (byte)78, (byte)97,
+ (byte)109,(byte)101,(byte)48, (byte)129,(byte)159,(byte)48, (byte)13, (byte)6, (byte)9, (byte)42,
+ (byte)134,(byte)72, (byte)134,(byte)247,(byte)13, (byte)1, (byte)1, (byte)1, (byte)5, (byte)0,
+ (byte)3, (byte)129,(byte)141,(byte)0, (byte)48, (byte)129,(byte)137,(byte)2, (byte)129,(byte)129,
+ (byte)0, (byte)137,(byte)239,(byte)22, (byte)193,(byte)171,(byte)79, (byte)177,(byte)85, (byte)159,
+ (byte)210,(byte)81, (byte)174,(byte)63, (byte)210,(byte)57, (byte)43, (byte)172,(byte)130,(byte)205,
+ (byte)144,(byte)207,(byte)100,(byte)16, (byte)69, (byte)78, (byte)72, (byte)22, (byte)155,(byte)44,
+ (byte)146,(byte)252,(byte)202,(byte)119,(byte)199,(byte)69, (byte)38, (byte)48, (byte)38, (byte)39,
+ (byte)46, (byte)119,(byte)219,(byte)200,(byte)105,(byte)216,(byte)188,(byte)162,(byte)175,(byte)74,
+ (byte)43, (byte)175,(byte)6, (byte)148,(byte)131,(byte)125,(byte)226,(byte)198,(byte)239,(byte)115,
+ (byte)204,(byte)196,(byte)28, (byte)189,(byte)108,(byte)236,(byte)29, (byte)132,(byte)72, (byte)207,
+ (byte)238,(byte)3, (byte)97, (byte)223,(byte)227,(byte)82, (byte)115,(byte)202,(byte)134,(byte)43,
+ (byte)242,(byte)83, (byte)70, (byte)226,(byte)172,(byte)162,(byte)177,(byte)183,(byte)128,(byte)126,
+ (byte)164,(byte)233,(byte)250,(byte)230,(byte)18, (byte)177,(byte)126,(byte)40, (byte)36, (byte)30,
+ (byte)169,(byte)124,(byte)126,(byte)203,(byte)23, (byte)252,(byte)38, (byte)55, (byte)250,(byte)181,
+ (byte)232,(byte)168,(byte)84, (byte)232,(byte)140,(byte)85, (byte)119,(byte)163,(byte)255,(byte)117,
+ (byte)133,(byte)174,(byte)51, (byte)195,(byte)8, (byte)174,(byte)200,(byte)142,(byte)43, (byte)2,
+ (byte)3, (byte)1, (byte)0, (byte)1, (byte)48, (byte)13, (byte)6, (byte)9, (byte)42, (byte)134,
+ (byte)72, (byte)134,(byte)247,(byte)13, (byte)1, (byte)1, (byte)4, (byte)5, (byte)0, (byte)3,
+ (byte)129,(byte)129,(byte)0, (byte)9, (byte)240,(byte)8, (byte)65, (byte)178,(byte)238,(byte)119,
+ (byte)127,(byte)249,(byte)164,(byte)9, (byte)159,(byte)110,(byte)132,(byte)177,(byte)76, (byte)239,
+ (byte)164,(byte)27, (byte)130,(byte)174,(byte)97, (byte)100,(byte)2, (byte)154,(byte)231,(byte)44,
+ (byte)217,(byte)30, (byte)210,(byte)42, (byte)221,(byte)225,(byte)114,(byte)205,(byte)165,(byte)152,
+ (byte)188,(byte)232,(byte)1, (byte)128,(byte)143,(byte)116,(byte)113,(byte)128,(byte)50, (byte)199,
+ (byte)80, (byte)16, (byte)172,(byte)112,(byte)129,(byte)236,(byte)34, (byte)189,(byte)106,(byte)79,
+ (byte)152,(byte)67, (byte)233,(byte)61, (byte)114,(byte)137,(byte)40, (byte)157,(byte)233,(byte)83,
+ (byte)123,(byte)28, (byte)138,(byte)168,(byte)46, (byte)151,(byte)36, (byte)177,(byte)7, (byte)22,
+ (byte)148,(byte)253,(byte)80, (byte)144,(byte)122,(byte)52, (byte)104,(byte)196,(byte)15, (byte)225,
+ (byte)148,(byte)136,(byte)193,(byte)68, (byte)133,(byte)113,(byte)48, (byte)244,(byte)8, (byte)64,
+ (byte)117,(byte)110,(byte)115,(byte)80, (byte)110,(byte)105,(byte)56, (byte)20, (byte)170,(byte)125,
+ (byte)182,(byte)159,(byte)190,(byte)4, (byte)173,(byte)193,(byte)200,(byte)153,(byte)246,(byte)155,
+ (byte)249,(byte)33, (byte)180,(byte)233,(byte)48, (byte)109,(byte)55, (byte)208,(byte)209,(byte)196,
+ (byte)16, (byte)23, (byte)172,(byte)125,(byte)207,(byte)94, (byte)238,(byte)23, (byte)38, (byte)60,
+ (byte)58, (byte)92, (byte)244,(byte)100,(byte)145,(byte)44, (byte)204,(byte)92, (byte)21, (byte)136,
+ (byte)39, };
+
+
+ public static class AnonymousTrustManager implements X509TrustManager {
+
+ public boolean isClientTrusted(X509Certificate[] cert) {
+ return true;
+ }
+
+ public boolean isServerTrusted(X509Certificate[] cert) {
+ return true;
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+
+ public void checkClientTrusted(X509Certificate[] arg0, String arg1)
+ throws CertificateException {
+ }
+
+ public void checkServerTrusted(X509Certificate[] arg0, String arg1)
+ throws CertificateException {
+ }
+ }
+
+ private static SSLContext sslContext;
+ private static SocketFactory factory;
+
+ static {
+ try {
+ KeyStore store = KeyStore.getInstance("JKS");
+ KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("SunX509");
+ sslContext = SSLContext.getInstance("TLS");//SSLv3");
+ InputStream stream = new ByteArrayInputStream(CERTIFICATE);
+ X509TrustManager trustManager = new AnonymousTrustManager();
+ X509TrustManager[] trustManagers = new X509TrustManager[]{trustManager};
+
+ store.load(stream, "password".toCharArray());
+ keyFactory.init(store, "password".toCharArray());
+ sslContext.init(keyFactory.getKeyManagers(), trustManagers, null);
+
+ factory = sslContext.getSocketFactory();
+ }catch(Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+
+ public SSLContext getServerSSLContext() {
+ return sslContext;
+ }
+
+ public SocketFactory getClientSocketFactory() {
+ return factory;
+ }
+
+ public static void main(String[] list) throws Exception {
+ FileOutputStream out = new FileOutputStream("c:\\client");
+ final PrintStream console = System.out;
+ OutputStream dup = new FilterOutputStream(out) {
+ public void write(int off) throws IOException {
+ console.write(off);
+ out.write(off);
+ }
+ public void write(byte[] b, int off, int len) throws IOException {
+ out.write(b, off, len);
+ console.write(b, off, len);
+ }
+ public void flush() throws IOException {
+ out.flush();
+ console.flush();
+ }
+ public void close() throws IOException {
+ out.close();
+ }
+ };
+ PrintStream p = new PrintStream(dup, true);
+
+ System.setOut(p);
+ System.setErr(p);
+ Socket socket = factory.createSocket("localhost", 9091);
+ OutputStream sockOut = socket.getOutputStream();
+ sockOut.write("GET /tmp/amazon.htm HTTP/1.1\r\nConnection: keep-alive\r\n\r\n".getBytes("ISO-8859-1"));
+ sockOut.flush();
+ InputStream in = socket.getInputStream();
+ byte[] buf = new byte[1024];
+ int all = 0;
+ int count = 0;
+ while((count = in.read(buf)) != -1) {
+ all += count;
+ if(all >= 564325) {
+ break;
+ }
+ System.out.write(buf, 0, count);
+ System.out.flush();
+ }
+ console.println(">>>>>>>>>>>>>> ALL=["+all+"]");
+ System.err.println("FINISHED READING");
+ Thread.sleep(10000);
+
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/Connector.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/Connector.java
new file mode 100644
index 0000000..d002c86
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/Connector.java
@@ -0,0 +1,9 @@
+package org.simpleframework.http.core;
+
+import java.net.Socket;
+
+public interface Connector {
+
+ public Socket getSocket() throws Exception;
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/ConversationTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/ConversationTest.java
new file mode 100644
index 0000000..00855c2
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/ConversationTest.java
@@ -0,0 +1,126 @@
+package org.simpleframework.http.core;
+
+import org.simpleframework.http.core.Conversation;
+
+import junit.framework.TestCase;
+
+public class ConversationTest extends TestCase {
+
+ private MockRequest request;
+ private MockResponse response;
+ private Conversation support;
+
+ public void setUp() {
+ request = new MockRequest();
+ response = new MockResponse();
+ support = new Conversation(request, response);
+ }
+
+ public void testWebSocket() {
+ request.setMajor(1);
+ request.setMinor(1);
+ response.setValue("Connection", "upgrade");
+
+ assertFalse(support.isWebSocket());
+ assertFalse(support.isTunnel());
+ assertTrue(support.isKeepAlive());
+
+ request.setValue("Upgrade", "WebSocket");
+
+ assertFalse(support.isWebSocket());
+ assertFalse(support.isTunnel());
+ assertTrue(support.isKeepAlive());
+
+ response.setCode(101);
+ response.setValue("Upgrade", "websocket");
+
+ assertTrue(support.isWebSocket());
+ assertTrue(support.isTunnel());
+ assertTrue(support.isKeepAlive());
+ }
+
+ public void testConnectTunnel() {
+ request.setMajor(1);
+ request.setMinor(1);
+ response.setCode(404);
+ request.setMethod("CONNECT");
+
+ assertFalse(support.isWebSocket());
+ assertFalse(support.isTunnel());
+ assertTrue(support.isKeepAlive());
+
+ response.setCode(200);
+
+ assertFalse(support.isWebSocket());
+ assertTrue(support.isTunnel());
+ assertTrue(support.isKeepAlive());
+ }
+
+ public void testResponse() {
+ request.setMajor(1);
+ request.setMinor(1);
+ response.setValue("Content-Length", "10");
+ response.setValue("Connection", "close");
+
+ assertFalse(support.isKeepAlive());
+ assertTrue(support.isPersistent());
+ assertEquals(support.getContentLength(), 10);
+ assertEquals(support.isChunkedEncoded(), false);
+
+ request.setMinor(0);
+
+ assertFalse(support.isKeepAlive());
+ assertFalse(support.isPersistent());
+
+ response.setValue("Connection", "keep-alive");
+
+ assertTrue(support.isKeepAlive());
+ assertFalse(support.isPersistent());
+
+ response.setValue("Transfer-Encoding", "chunked");
+
+ assertTrue(support.isChunkedEncoded());
+ assertTrue(support.isKeepAlive());
+ }
+
+ public void testConversation() {
+ request.setMajor(1);
+ request.setMinor(1);
+ support.setChunkedEncoded();
+
+ assertEquals(response.getValue("Transfer-Encoding"), "chunked");
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertTrue(support.isKeepAlive());
+ assertTrue(support.isPersistent());
+
+ request.setMinor(0);
+ support.setChunkedEncoded();
+
+ assertEquals(response.getValue("Connection"), "close");
+ assertFalse(support.isKeepAlive());
+
+ request.setMajor(1);
+ request.setMinor(1);
+ response.setValue("Content-Length", "10");
+ response.setValue("Connection", "close");
+
+ assertFalse(support.isKeepAlive());
+ assertTrue(support.isPersistent());
+ assertEquals(support.getContentLength(), 10);
+
+ request.setMinor(0);
+
+ assertFalse(support.isKeepAlive());
+ assertFalse(support.isPersistent());
+
+ response.setValue("Connection", "keep-alive");
+
+ assertTrue(support.isKeepAlive());
+ assertFalse(support.isPersistent());
+
+ response.setValue("Transfer-Encoding", "chunked");
+
+ assertTrue(support.isChunkedEncoded());
+ assertTrue(support.isKeepAlive());
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/DribbleCursor.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/DribbleCursor.java
new file mode 100644
index 0000000..14f2768
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/DribbleCursor.java
@@ -0,0 +1,62 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import org.simpleframework.transport.ByteCursor;
+
+public class DribbleCursor implements ByteCursor {
+
+ private ByteCursor cursor;
+ private byte[] swap;
+ private int dribble;
+
+ public DribbleCursor(ByteCursor cursor, int dribble) {
+ this.cursor = cursor;
+ this.dribble = dribble;
+ this.swap = new byte[1];
+ }
+
+ public boolean isOpen() throws IOException {
+ return true;
+ }
+
+ public boolean isReady() throws IOException {
+ return cursor.isReady();
+ }
+
+ public int ready() throws IOException {
+ int ready = cursor.ready();
+
+ return Math.min(ready, dribble);
+ }
+
+ public int read() throws IOException {
+ if(read(swap) > 0) {
+ return swap[0] & 0xff;
+ }
+ return 0;
+ }
+
+
+ public int read(byte[] data) throws IOException {
+ return read(data, 0, data.length);
+ }
+
+ public int read(byte[] data, int off, int len) throws IOException {
+ int size = Math.min(len, dribble);
+
+ return cursor.read(data, off, size);
+ }
+
+ public int reset(int len) throws IOException {
+ return cursor.reset(len);
+ }
+
+ public void push(byte[] data) throws IOException {
+ cursor.push(data);
+ }
+
+ public void push(byte[] data, int off, int len) throws IOException {
+ cursor.push(data, off, len);
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/FixedConsumerTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/FixedConsumerTest.java
new file mode 100644
index 0000000..f0011ce
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/FixedConsumerTest.java
@@ -0,0 +1,80 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.buffer.Allocator;
+import org.simpleframework.common.buffer.ArrayAllocator;
+import org.simpleframework.common.buffer.Buffer;
+import org.simpleframework.http.message.FixedLengthConsumer;
+import org.simpleframework.transport.ByteCursor;
+
+public class FixedConsumerTest extends TestCase implements Allocator {
+
+ private Buffer buffer;
+
+ public Buffer allocate() {
+ return buffer;
+ }
+
+ public Buffer allocate(long size) {
+ return buffer;
+ }
+
+ public void testConsumer() throws Exception {
+ testConsumer(10, 10, 10);
+ testConsumer(1024, 10, 1024);
+ testConsumer(1024, 1024, 1024);
+ testConsumer(1024, 1024, 1023);
+ testConsumer(1024, 1, 1024);
+ testConsumer(1, 1, 1);
+ testConsumer(2, 2, 2);
+ testConsumer(3, 1, 2);
+ }
+
+ public void testConsumer(int entitySize, int dribble, int limitSize) throws Exception {
+ StringBuffer buf = new StringBuffer();
+
+ // Ensure that we dont try read forever
+ limitSize = Math.min(entitySize, limitSize);
+
+ for(int i = 0, line = 0; i < entitySize; i++) {
+ String text = "["+String.valueOf(i)+"]";
+
+ line += text.length();
+ buf.append(text);
+
+ if(line >= 48) {
+ buf.append("\n");
+ line = 0;
+ }
+
+ }
+ buffer = new ArrayAllocator().allocate();
+
+ String requestBody = buf.toString();
+ FixedLengthConsumer consumer = new FixedLengthConsumer(this, limitSize);
+ ByteCursor cursor = new DribbleCursor(new StreamCursor(requestBody), dribble);
+ byte[] requestBytes = requestBody.getBytes("UTF-8");
+
+ while(!consumer.isFinished()) {
+ consumer.consume(cursor);
+ }
+ byte[] consumedBytes = buffer.encode("UTF-8").getBytes("UTF-8");
+
+ assertEquals(buffer.encode("UTF-8").length(), limitSize);
+
+ for(int i = 0; i < limitSize; i++) {
+ if(consumedBytes[i] != requestBytes[i]) {
+ throw new IOException("Fixed consumer modified the request!");
+ }
+ }
+ }
+
+ public void close() throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/FixedProducerTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/FixedProducerTest.java
new file mode 100644
index 0000000..f7b8f33
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/FixedProducerTest.java
@@ -0,0 +1,50 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import org.simpleframework.http.core.FixedLengthEncoder;
+
+import junit.framework.TestCase;
+
+public class FixedProducerTest extends TestCase {
+
+ public void testContent() throws IOException {
+ testContent(1024, 1);
+ testContent(1024, 2);
+ testContent(512, 20);
+ testContent(64, 64);
+ }
+
+ public void testContent(int chunkSize, int count) throws IOException {
+ MockSender sender = new MockSender((chunkSize * count) + chunkSize);
+ MockObserver monitor = new MockObserver();
+ FixedLengthEncoder producer = new FixedLengthEncoder(monitor, sender, chunkSize * count);
+ byte[] chunk = new byte[chunkSize];
+
+ for(int i = 0; i < chunk.length; i++) {
+ chunk[i] = (byte)String.valueOf(i).charAt(0);
+ }
+ for(int i = 0; i < count; i++) {
+ producer.encode(chunk, 0, chunkSize);
+ }
+ producer.close();
+
+ System.err.println(sender.getBuffer().encode());
+
+ assertTrue(monitor.isReady());
+ assertFalse(monitor.isError());
+ assertFalse(monitor.isClose());
+
+ sender = new MockSender((chunkSize * count) + chunkSize);
+ monitor = new MockObserver();
+ producer = new FixedLengthEncoder(monitor, sender, chunkSize * count);
+
+ for(int i = 0; i < count; i++) {
+ producer.encode(chunk, 0, chunkSize);
+ }
+ producer.close();
+
+ assertFalse(monitor.isError());
+ assertTrue(monitor.isReady());
+ }
+} \ No newline at end of file
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MessageTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MessageTest.java
new file mode 100644
index 0000000..b972f03
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MessageTest.java
@@ -0,0 +1,72 @@
+package org.simpleframework.http.core;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.simpleframework.http.message.MessageHeader;
+
+import junit.framework.TestCase;
+
+public class MessageTest extends TestCase {
+
+ public void testMessage() {
+ MessageHeader message = new MessageHeader();
+
+ message.addValue("Content-Length", "10");
+ message.addValue("Connection", "keep-alive");
+ message.addValue("Accept", "image/gif, image/jpeg, */*");
+ message.addValue("Set-Cookie", "a=b");
+ message.addValue("Set-Cookie", "b=c");
+
+ assertEquals(message.getValue("CONTENT-LENGTH"), "10");
+ assertEquals(message.getValue("Content-Length"), "10");
+ assertEquals(message.getValue("CONTENT-length"), "10");
+ assertEquals(message.getValue("connection"), "keep-alive");
+ assertEquals(message.getValue("CONNECTION"), "keep-alive");
+
+ assertTrue(message.getValues("CONNECTION") != null);
+ assertEquals(message.getValues("connection").size(), 1);
+
+ assertTrue(message.getValues("set-cookie") != null);
+ assertEquals(message.getValues("set-cookie").size(), 2);
+ assertTrue(message.getValues("SET-COOKIE").contains("a=b"));
+ assertTrue(message.getValues("SET-COOKIE").contains("b=c"));
+
+ assertTrue(message.getNames().contains("Content-Length"));
+ assertFalse(message.getNames().contains("CONTENT-LENGTH"));
+ assertTrue(message.getNames().contains("Connection"));
+ assertFalse(message.getNames().contains("CONNECTION"));
+ assertTrue(message.getNames().contains("Set-Cookie"));
+ assertFalse(message.getNames().contains("SET-COOKIE"));
+
+ message.setValue("Set-Cookie", "d=e");
+
+ assertTrue(message.getValues("set-cookie") != null);
+ assertEquals(message.getValues("set-cookie").size(), 1);
+ assertFalse(message.getValues("SET-COOKIE").contains("a=b"));
+ assertFalse(message.getValues("SET-COOKIE").contains("b=c"));
+ assertTrue(message.getValues("SET-COOKIE").contains("d=e"));
+ }
+
+ public void testDates() {
+ MessageHeader message = new MessageHeader();
+ DateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
+ TimeZone zone = TimeZone.getTimeZone("GMT");
+ long time = System.currentTimeMillis();
+ Date date = new Date(time);
+
+ format.setTimeZone(zone);
+ message.setValue("Date", format.format(date));
+
+ assertEquals(format.format(date), message.getValue("date"));
+ assertEquals(new Date(message.getDate("DATE")).toString(), date.toString());
+
+ message.setDate("Date", time);
+
+ assertEquals(format.format(date), message.getValue("date"));
+ assertEquals(new Date(message.getDate("DATE")).toString(), date.toString());
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockChannel.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockChannel.java
new file mode 100644
index 0000000..92a4f5d
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockChannel.java
@@ -0,0 +1,57 @@
+package org.simpleframework.http.core;
+
+import java.nio.channels.SocketChannel;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simpleframework.common.lease.Lease;
+import org.simpleframework.http.MockTrace;
+import org.simpleframework.transport.Certificate;
+import org.simpleframework.transport.Channel;
+import org.simpleframework.transport.ByteCursor;
+import org.simpleframework.transport.ByteWriter;
+import org.simpleframework.transport.trace.Trace;
+
+
+public class MockChannel implements Channel {
+
+ private ByteCursor cursor;
+
+ public MockChannel(ByteCursor cursor) {
+ this.cursor = cursor;
+ }
+
+ public boolean isSecure() {
+ return false;
+ }
+
+ public Trace getTrace(){
+ return new MockTrace();
+ }
+
+ public Lease getLease() {
+ return null;
+ }
+
+ public Certificate getCertificate() {
+ return null;
+ }
+
+ public ByteCursor getCursor() {
+ return cursor;
+ }
+
+ public ByteWriter getWriter() {
+ return new MockSender();
+ }
+
+ public Map getAttributes() {
+ return new HashMap();
+ }
+
+ public void close() {}
+
+ public SocketChannel getSocket() {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockController.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockController.java
new file mode 100644
index 0000000..b631803
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockController.java
@@ -0,0 +1,55 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import org.simpleframework.transport.Channel;
+
+public class MockController implements Controller {
+
+ private boolean ready;
+ private boolean sleep;
+ private boolean start;
+ private boolean initiated;
+ private boolean stop;
+
+ public void start(Channel channel) throws IOException {
+ initiated = true;
+ }
+
+ public void ready(Collector collector) throws IOException {
+ ready = true;
+ }
+
+ public void select(Collector collector) throws IOException {
+ sleep = true;
+ }
+
+ public void start(Collector collector) throws IOException {
+ start = true;
+ }
+
+ public void stop() throws IOException {
+ stop = true;
+ }
+
+ public boolean isStopped() {
+ return stop;
+ }
+
+ public boolean isInitiated() {
+ return initiated;
+ }
+
+ public boolean isReady() {
+ return ready;
+ }
+
+ public boolean isSleep() {
+ return sleep;
+ }
+
+ public boolean isStart() {
+ return start;
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockEntity.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockEntity.java
new file mode 100644
index 0000000..e0ec896
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockEntity.java
@@ -0,0 +1,49 @@
+
+package org.simpleframework.http.core;
+
+import org.simpleframework.http.message.Body;
+import org.simpleframework.http.message.Entity;
+import org.simpleframework.http.message.Header;
+import org.simpleframework.transport.Channel;
+
+
+public class MockEntity implements Entity {
+
+ private Body body;
+ private Header header;
+
+ public MockEntity() {
+ super();
+ }
+
+ public MockEntity(Body body) {
+ this.body = body;
+ }
+
+ public MockEntity(Body body, Header header) {
+ this.body = body;
+ this.header = header;
+ }
+
+ public long getTime() {
+ return 0;
+ }
+
+ public Body getBody() {
+ return body;
+ }
+
+ public Header getHeader() {
+ return header;
+ }
+
+ public Channel getChannel() {
+ return null;
+ }
+
+ public void close() {}
+
+ public long getStart() {
+ return 0;
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockObserver.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockObserver.java
new file mode 100644
index 0000000..cb4b41e
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockObserver.java
@@ -0,0 +1,62 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import org.simpleframework.transport.ByteWriter;
+
+
+public class MockObserver implements BodyObserver {
+
+ private boolean close;
+
+ private boolean error;
+
+ private boolean ready;
+
+ private boolean commit;
+
+ public MockObserver() {
+ super();
+ }
+
+ public void close(ByteWriter sender) {
+ close = true;
+ }
+
+ public boolean isClose() {
+ return close;
+ }
+
+ public boolean isError() {
+ return error;
+ }
+
+ public void ready(ByteWriter sender) {
+ ready = true;
+ }
+
+ public boolean isReady() {
+ return ready;
+ }
+
+ public void error(ByteWriter sender) {
+ error = true;
+ }
+
+ public boolean isClosed() {
+ return close || error;
+ }
+
+ public long getTime() {
+ return 0;
+ }
+
+ public void commit(ByteWriter sender) {
+ this.commit = commit;
+ }
+
+ public boolean isCommitted() {
+ return commit;
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockPart.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockPart.java
new file mode 100644
index 0000000..614a7aa
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockPart.java
@@ -0,0 +1,49 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import org.simpleframework.http.ContentDisposition;
+import org.simpleframework.http.ContentType;
+import org.simpleframework.http.Part;
+import org.simpleframework.http.message.MockBody;
+
+public class MockPart extends MockBody implements Part {
+
+ private String name;
+ private boolean file;
+
+ public MockPart(String name, String body, boolean file) {
+ super(body);
+ this.file = file;
+ this.name = name;
+ }
+
+ public String getContent() throws IOException {
+ return body;
+ }
+
+ public ContentType getContentType() {
+ return null;
+ }
+
+ public ContentDisposition getDisposition() {
+ return null;
+ }
+
+ public String getHeader(String name) {
+ return null;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isFile() {
+ return file;
+ }
+
+ public String getFileName() {
+ return null;
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockProxyRequest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockProxyRequest.java
new file mode 100644
index 0000000..a7f12b6
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockProxyRequest.java
@@ -0,0 +1,67 @@
+package org.simpleframework.http.core;
+
+import java.util.List;
+
+import org.simpleframework.http.ContentType;
+import org.simpleframework.http.Cookie;
+import org.simpleframework.http.Path;
+import org.simpleframework.http.Query;
+import org.simpleframework.http.RequestHeader;
+
+public class MockProxyRequest extends MockRequest {
+
+ private RequestHeader header;
+
+ public MockProxyRequest(RequestHeader header) {
+ this.header = header;
+ }
+
+ public long getContentLength() {
+ return header.getContentLength();
+ }
+
+ public ContentType getContentType() {
+ return header.getContentType();
+ }
+
+ public String getValue(String name) {
+ return header.getValue(name);
+ }
+
+ public List<String> getValues(String name) {
+ return header.getValues(name);
+ }
+
+ public int getMajor() {
+ return header.getMajor();
+ }
+
+ public String getMethod() {
+ return header.getMethod();
+ }
+
+ public int getMinor() {
+ return header.getMajor();
+ }
+
+ public Path getPath() {
+ return header.getPath();
+ }
+
+ public Query getQuery() {
+ return header.getQuery();
+ }
+
+ public String getTarget() {
+ return header.getTarget();
+ }
+
+
+ public String getParameter(String name) {
+ return header.getQuery().get(name);
+ }
+
+ public Cookie getCookie(String name) {
+ return header.getCookie(name);
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockRequest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockRequest.java
new file mode 100644
index 0000000..f382a32
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockRequest.java
@@ -0,0 +1,202 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.nio.channels.ReadableByteChannel;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.simpleframework.http.ContentDisposition;
+import org.simpleframework.http.ContentType;
+import org.simpleframework.http.Cookie;
+import org.simpleframework.http.Part;
+import org.simpleframework.http.Path;
+import org.simpleframework.http.Query;
+import org.simpleframework.http.Request;
+import org.simpleframework.http.message.MessageHeader;
+import org.simpleframework.http.message.RequestConsumer;
+import org.simpleframework.http.parse.AddressParser;
+import org.simpleframework.http.parse.ContentDispositionParser;
+import org.simpleframework.http.parse.ContentTypeParser;
+import org.simpleframework.transport.Certificate;
+import org.simpleframework.transport.Channel;
+
+public class MockRequest extends RequestMessage implements Request {
+
+ private MessageHeader message;
+ private Channel channel;
+ private String target;
+ private String method = "GET";
+ private String content;
+ private String type;
+ private int major = 1;
+ private int minor = 1;
+
+ public MockRequest() {
+ this.header = new RequestConsumer();
+ this.message = new MessageHeader();
+ this.channel = new MockChannel(null);
+ }
+
+ public void setValue(String name, String value) {
+ message.setValue(name, value);
+ }
+
+ public void add(String name, String value) {
+ message.addValue(name, value);
+ }
+
+ public boolean isSecure(){
+ return false;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setContentType(String value) {
+ type = value;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ public Path getPath() {
+ return new AddressParser(target).getPath();
+ }
+
+ public Query getQuery() {
+ return new AddressParser(target).getQuery();
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public void setMajor(int major) {
+ this.major = major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public void setMinor(int minor) {
+ this.minor = minor;
+ }
+
+ public Certificate getClientCertificate() {
+ return null;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public InputStream getInputStream() {
+ return null;
+ }
+
+ public Part getPart(String name) {
+ return null;
+ }
+
+ public List<Part> getParts() {
+ return Collections.emptyList();
+ }
+
+ public int size() {
+ return 0;
+ }
+
+ public Cookie getCookie(String name) {
+ return null;
+ }
+
+ public String getParameter(String name) {
+ return null;
+ }
+
+ public Map getAttributes() {
+ return null;
+ }
+
+
+ public ContentType getContentType() {
+ return new ContentTypeParser(type);
+ }
+
+ public long getContentLength() {
+ String value = getValue("Content-Length");
+
+ if(value != null) {
+ return new Long(value);
+ }
+ return -1;
+ }
+
+ public String getTransferEncoding() {
+ List<String> list = getValues("Transfer-Encoding");
+
+ if(list.size() > 0) {
+ return list.get(0);
+ }
+ return null;
+ }
+
+ public ContentDisposition getDisposition() {
+ String value = getValue("Content-Disposition");
+
+ if(value == null) {
+ return null;
+ }
+ return new ContentDispositionParser(value);
+ }
+
+ public List<String> getValues(String name) {
+ return message.getValues(name);
+ }
+
+ public String getValue(String name) {
+ return message.getValue(name);
+ }
+
+ public Object getAttribute(Object key) {
+ return null;
+ }
+
+ public boolean isKeepAlive() {
+ return true;
+ }
+
+ public InetSocketAddress getClientAddress() {
+ return null;
+ }
+
+ public ReadableByteChannel getByteChannel() throws IOException {
+ return null;
+ }
+
+ public long getRequestTime() {
+ return 0;
+ }
+
+ public Channel getChannel() {
+ return channel;
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockResponse.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockResponse.java
new file mode 100644
index 0000000..43c0b86
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockResponse.java
@@ -0,0 +1,95 @@
+package org.simpleframework.http.core;
+
+import static org.simpleframework.http.Protocol.CLOSE;
+import static org.simpleframework.http.Protocol.CONNECTION;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.channels.WritableByteChannel;
+import java.util.Map;
+
+import org.simpleframework.http.Response;
+import org.simpleframework.http.core.ResponseMessage;
+
+public class MockResponse extends ResponseMessage implements Response {
+
+ private boolean committed;
+
+ public MockResponse() {
+ super();
+ }
+
+ public OutputStream getOutputStream() {
+ return System.out;
+ }
+
+ public boolean isKeepAlive() {
+ String value = getValue(CONNECTION);
+
+ if(value != null) {
+ return value.equalsIgnoreCase(CLOSE);
+ }
+ return true;
+ }
+
+ public boolean isCommitted() {
+ return committed;
+ }
+
+ public void commit() {
+ committed = true;
+ }
+
+ public void reset() {
+ return;
+ }
+
+ public void close() {
+ return;
+ }
+
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ public Map getAttributes() {
+ return null;
+ }
+
+ public OutputStream getOutputStream(int size) throws IOException {
+ return null;
+ }
+
+ public PrintStream getPrintStream() throws IOException {
+ return null;
+ }
+
+ public PrintStream getPrintStream(int size) throws IOException {
+ return null;
+ }
+
+ public void setContentLength(long length) {
+ setValue("Content-Length", String.valueOf(length));
+ }
+
+ public WritableByteChannel getByteChannel() throws IOException {
+ return null;
+ }
+
+ public WritableByteChannel getByteChannel(int size) throws IOException {
+ return null;
+ }
+
+ public boolean isEmpty() {
+ return false;
+ }
+
+ public long getResponseTime() {
+ return 0;
+ }
+
+ public void setContentType(String type) {
+ setValue("Content-Type", type);
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockSender.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockSender.java
new file mode 100644
index 0000000..eb20930
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockSender.java
@@ -0,0 +1,75 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.simpleframework.common.buffer.ArrayBuffer;
+import org.simpleframework.common.buffer.Buffer;
+import org.simpleframework.transport.ByteCursor;
+import org.simpleframework.transport.ByteWriter;
+
+public class MockSender implements ByteWriter {
+
+ private Buffer buffer;
+
+ public MockSender() {
+ this(1024);
+ }
+
+ public MockSender(int size) {
+ this.buffer = new ArrayBuffer(size);
+ }
+
+ public Buffer getBuffer() {
+ return buffer;
+ }
+
+ public ByteCursor getCursor() throws IOException {
+ return new StreamCursor(buffer.encode("UTF-8"));
+ }
+
+ public void write(byte[] array) throws IOException {
+ buffer.append(array);
+ }
+
+ public void write(byte[] array, int off, int len) throws IOException {
+ buffer.append(array, off, len);
+ }
+
+ public void flush() throws IOException {
+ return;
+ }
+
+ public void close() throws IOException {
+ return;
+ }
+
+ public String toString() {
+ return buffer.toString();
+ }
+
+ public boolean isOpen() throws Exception {
+ return true;
+ }
+
+ public void write(ByteBuffer source) throws IOException {
+ int mark = source.position();
+ int limit = source.limit();
+
+ byte[] array = new byte[limit - mark];
+ source.get(array, 0, array.length);
+ buffer.append(array);
+ }
+
+ public void write(ByteBuffer source, int off, int len) throws IOException {
+ int mark = source.position();
+ int limit = source.limit();
+
+ if(limit - mark < len) {
+ len = limit - mark;
+ }
+ byte[] array = new byte[len];
+ source.get(array, 0, len);
+ buffer.append(array);
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/MockSocket.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockSocket.java
new file mode 100644
index 0000000..5ac7a14
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/MockSocket.java
@@ -0,0 +1,42 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+
+public class MockSocket extends Socket {
+
+ private Socket socket;
+
+ private OutputStream out;
+
+ public MockSocket(Socket socket) {
+ this(socket, System.err);
+ }
+
+ public MockSocket(Socket socket, OutputStream out){
+ this.socket = socket;
+ this.out = out;
+ }
+
+ @Override
+ public void setSoTimeout(int delay) throws SocketException {
+ socket.setSoTimeout(delay);
+ }
+
+ @Override
+ public int getSoTimeout() throws SocketException {
+ return socket.getSoTimeout();
+ }
+
+
+ public InputStream getInputStream() throws IOException {
+ return socket.getInputStream();
+ }
+
+ public OutputStream getOutputStream() {
+ return out;
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/PayloadTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/PayloadTest.java
new file mode 100644
index 0000000..6b23fab
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/PayloadTest.java
@@ -0,0 +1,97 @@
+package org.simpleframework.http.core;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.buffer.ArrayAllocator;
+import org.simpleframework.http.Part;
+import org.simpleframework.http.message.Header;
+import org.simpleframework.transport.Channel;
+import org.simpleframework.transport.ByteCursor;
+
+public class PayloadTest extends TestCase {
+
+ private static final String PAYLOAD =
+ "POST /index.html HTTP/1.0\r\n"+
+ "Content-Type: multipart/form-data; boundary=AaB03x\r\n"+
+ "Accept: image/gif;q=1.0,\r\n image/jpeg;q=0.8,\r\n"+
+ " \t\t image/png;\t\r\n\t"+
+ " q=1.0,*;q=0.1\r\n"+
+ "Accept-Language: fr;q=0.1, en-us;q=0.4, en-gb; q=0.8, en;q=0.7\r\n"+
+ "Host: some.host.com \r\n"+
+ "Cookie: $Version=1; UID=1234-5678; $Path=/; $Domain=.host.com\r\n"+
+ "Cookie: $Version=1; NAME=\"Niall Gallagher\"; $path=\"/\"\r\n"+
+ "\r\n" +
+ "--AaB03x\r\n"+
+ "Content-Disposition: form-data; name='pics'; filename='file1.txt'\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file1.txt\r\n"+
+ "--AaB03x\r\n"+
+ "Content-Type: multipart/mixed; boundary=BbC04y\r\n\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: form-data; name='pics'; filename='file2.txt'\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file3.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: form-data; name='pics'; filename='file3.txt'\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file4.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: form-data; name='pics'; filename='file4.txt'\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file4.txt ...\r\n"+
+ "--BbC04y--\r\n"+
+ "--AaB03x--\r\n";
+
+
+ public void testPayload() throws Exception {
+ for(int i = 1; i < 4096; i++) {
+ testPayload(i);
+ }
+ }
+
+ public void testPayload(int dribble) throws Exception {
+ ByteCursor cursor = new DribbleCursor(new StreamCursor(PAYLOAD), 10);
+ Channel channel = new MockChannel(cursor);
+ MockController selector = new MockController();
+ Collector body = new RequestCollector(new ArrayAllocator(), channel);
+ long time = System.currentTimeMillis();
+
+ while(!selector.isReady()) {
+ body.collect(selector);
+ }
+ System.err.println("Time taken to parse payload "+(System.currentTimeMillis() - time)+" ms");
+
+ Header header = body.getHeader();
+ List<Part> list = body.getBody().getParts();
+
+ assertEquals(header.getTarget(), "/index.html");
+ assertEquals(header.getMethod(), "POST");
+ assertEquals(header.getMajor(), 1);
+ assertEquals(header.getMinor(), 0);
+ assertEquals(header.getContentType().getPrimary(), "multipart");
+ assertEquals(header.getContentType().getSecondary(), "form-data");
+ assertEquals(header.getValue("Host"), "some.host.com");
+ assertEquals(header.getValues("Accept").size(), 4);
+ assertEquals(header.getValues("Accept").get(0), "image/gif");
+ assertEquals(header.getValues("Accept").get(1), "image/png");
+ assertEquals(header.getValues("Accept").get(2), "image/jpeg");
+ assertEquals(header.getValues("Accept").get(3), "*");
+ assertEquals(list.size(), 4);
+ assertEquals(list.get(0).getContentType().getPrimary(), "text");
+ assertEquals(list.get(0).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(0).getHeader("Content-Disposition"), "form-data; name='pics'; filename='file1.txt'");
+ assertEquals(list.get(1).getContentType().getPrimary(), "text");
+ assertEquals(list.get(1).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(1).getHeader("Content-Disposition"), "form-data; name='pics'; filename='file2.txt'");
+ assertEquals(list.get(2).getContentType().getPrimary(), "text");
+ assertEquals(list.get(2).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(2).getHeader("Content-Disposition"), "form-data; name='pics'; filename='file3.txt'");
+ assertEquals(list.get(3).getContentType().getPrimary(), "text");
+ assertEquals(list.get(3).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(3).getHeader("Content-Disposition"), "form-data; name='pics'; filename='file4.txt'");
+ assertEquals(cursor.ready(), -1);
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/ProducerExceptionTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/ProducerExceptionTest.java
new file mode 100644
index 0000000..d81370e
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/ProducerExceptionTest.java
@@ -0,0 +1,23 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class ProducerExceptionTest extends TestCase {
+
+ public void testException() {
+ try {
+ throw new IOException("Error");
+ }catch(Exception main) {
+ try {
+ throw new BodyEncoderException("Wrapper", main);
+ }catch(Exception cause) {
+ cause.printStackTrace();
+
+ assertEquals(cause.getCause(), main);
+ }
+ }
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/QueryBuilderTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/QueryBuilderTest.java
new file mode 100644
index 0000000..92c9d64
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/QueryBuilderTest.java
@@ -0,0 +1,35 @@
+package org.simpleframework.http.core;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.http.Query;
+import org.simpleframework.http.message.MockBody;
+import org.simpleframework.http.message.MockHeader;
+
+public class QueryBuilderTest extends TestCase{
+
+ public void testBuilder() throws Exception {
+ MockRequest request = new MockRequest();
+
+ request.setContentType("application/x-www-form-urlencoded");
+ request.setContent("a=post_A&c=post_C&e=post_E");
+
+ MockBody body = new MockBody();
+ MockHeader header = new MockHeader("/path?a=query_A&b=query_B&c=query_C&d=query_D");
+ MockEntity entity = new MockEntity(body, header);
+ QueryBuilder builder = new QueryBuilder(request, entity);
+
+ Query form = builder.build();
+
+ assertEquals(form.getAll("a").size(), 2);
+ assertEquals(form.getAll("b").size(), 1);
+ assertEquals(form.getAll("c").size(), 2);
+ assertEquals(form.getAll("e").size(), 1);
+
+ assertEquals(form.get("a"), "query_A");
+ assertEquals(form.get("b"), "query_B");
+ assertEquals(form.get("c"), "query_C");
+ assertEquals(form.get("e"), "post_E");
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorProcessorTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorProcessorTest.java
new file mode 100644
index 0000000..9b0bdcd
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorProcessorTest.java
@@ -0,0 +1,247 @@
+package org.simpleframework.http.core;
+
+import java.nio.channels.SocketChannel;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.buffer.ArrayAllocator;
+import org.simpleframework.http.MockTrace;
+import org.simpleframework.http.Part;
+import org.simpleframework.http.Request;
+import org.simpleframework.http.Response;
+import org.simpleframework.http.core.ReactorTest.TestChannel;
+import org.simpleframework.transport.Certificate;
+import org.simpleframework.transport.Channel;
+import org.simpleframework.transport.ByteCursor;
+import org.simpleframework.transport.ByteWriter;
+import org.simpleframework.transport.trace.Trace;
+
+public class ReactorProcessorTest extends TestCase implements Container {
+
+ private static final int ITERATIONS = 20000;
+
+ private static final String MINIMAL =
+ "HEAD /MINIMAL/%s HTTP/1.0\r\n" +
+ "Accept-Language: fr;q=0.1, en-us;q=0.4, en-gb; q=0.8, en;q=0.7\r\n"+
+ "Host: some.host.com \r\n"+
+ "\r\n";
+
+ private static final String SIMPLE =
+ "GET /SIMPLE/%s HTTP/1.0\r\n" +
+ "Accept: image/gif;q=1.0,\r\n image/jpeg;q=0.8,\r\n"+
+ " \t\t image/png;\t\r\n\t"+
+ " q=1.0,*;q=0.1\r\n"+
+ "Accept-Language: fr;q=0.1, en-us;q=0.4, en-gb; q=0.8, en;q=0.7\r\n"+
+ "Host: some.host.com \r\n"+
+ "Cookie: $Version=1; UID=1234-5678; $Path=/; $Domain=.host.com\r\n"+
+ "Cookie: $Version=1; NAME=\"Niall Gallagher\"; $path=\"/\"\r\n"+
+ "\r\n";
+
+ private static final String UPLOAD =
+ "POST /UPLOAD/%s HTTP/1.0\r\n" +
+ "Content-Type: multipart/form-data; boundary=AaB03x\r\n"+
+ "Accept: image/gif;q=1.0,\r\n image/jpeg;q=0.8,\r\n"+
+ " \t\t image/png;\t\r\n\t"+
+ " q=1.0,*;q=0.1\r\n"+
+ "Accept-Language: fr;q=0.1, en-us;q=0.4, en-gb; q=0.8, en;q=0.7\r\n"+
+ "Host: some.host.com \r\n"+
+ "Cookie: $Version=1; UID=1234-5678; $Path=/; $Domain=.host.com\r\n"+
+ "Cookie: $Version=1; NAME=\"Niall Gallagher\"; $path=\"/\"\r\n"+
+ "\r\n" +
+ "--AaB03x\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file1.txt\"; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file1.txt\r\n"+
+ "--AaB03x\r\n"+
+ "Content-Type: multipart/mixed; boundary=BbC04y\r\n\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file2.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file3.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file3.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file4.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file4.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file4.txt ...\r\n"+
+ "--BbC04y--\r\n"+
+ "--AaB03x--\r\n";
+
+ private static class StopWatch {
+
+ private long duration;
+
+ private long start;
+
+ public StopWatch() {
+ this.start = System.currentTimeMillis();
+ }
+
+ public long time() {
+ return duration;
+ }
+
+ public void stop() {
+ duration = System.currentTimeMillis() - start;
+ }
+ }
+
+ public static class MockChannel implements Channel {
+
+ private ByteCursor cursor;
+
+ public MockChannel(StreamCursor cursor, int dribble) {
+ this.cursor = new DribbleCursor(cursor, dribble);
+ }
+ public boolean isSecure() {
+ return false;
+ }
+
+ public Trace getTrace() {
+ return new MockTrace();
+ }
+
+ public Certificate getCertificate() {
+ return null;
+ }
+
+ public ByteCursor getCursor() {
+ return cursor;
+ }
+
+ public ByteWriter getWriter() {
+ return null;
+ }
+
+ public Map getAttributes() {
+ return null;
+ }
+
+ public void close() {}
+
+ public SocketChannel getSocket() {
+ return null;
+ }
+ }
+
+ private ConcurrentHashMap<String, StopWatch> timers = new ConcurrentHashMap<String, StopWatch>();
+
+ private LinkedBlockingQueue<StopWatch> finished = new LinkedBlockingQueue<StopWatch>();
+
+ public void testMinimal() throws Exception {
+ Controller handler = new ContainerController(this, new ArrayAllocator(), 10, 2);
+
+ testRequest(handler, "/MINIMAL/%s", MINIMAL, "MINIMAL");
+ testRequest(handler, "/SIMPLE/%s", SIMPLE, "SIMPLE");
+ testRequest(handler, "/UPLOAD/%s", UPLOAD, "UPLOAD");
+ }
+
+ public void testRequest(Controller handler, String target, String payload, String name) throws Exception {
+ long start = System.currentTimeMillis();
+
+ for(int i = 0; i < ITERATIONS; i++) {
+ String request = String.format(payload, i);
+ StopWatch stopWatch = new StopWatch();
+
+ timers.put(String.format(target, i), stopWatch);
+ testHandler(handler, request, 2048);
+ }
+ double sum = 0;
+
+ for(int i = 0; i < ITERATIONS; i++) {
+ StopWatch stopWatch = finished.take();
+ sum += stopWatch.time();
+ }
+ double total = (System.currentTimeMillis() - start);
+ double count = ITERATIONS;
+
+ System.err.println(String.format("%s total=[%s] for=[%s] average=[%s] time-per-request=[%s] request-per-millisecond=[%s] request-per-second=[%s]",
+ name, total, count, sum / count, total / count, count / total + 1, count / (total / 1000)));
+ }
+
+ public void testHandler(Controller handler, String payload, int dribble) throws Exception {
+ StreamCursor cursor = new StreamCursor(payload);
+ Channel channel = new TestChannel(cursor, dribble);
+
+ handler.start(channel);
+ }
+
+
+ public void handle(Request request, Response response) {
+ try {
+ process(request, response);
+ }catch(Exception e) {
+ e.printStackTrace();
+ assertTrue(false);
+ }
+ }
+
+ public void process(Request request, Response response) throws Exception {
+ List<Part> list = request.getParts();
+ String method = request.getMethod();
+
+ if(method.equals("HEAD")) {
+ assertEquals(request.getMajor(), 1);
+ assertEquals(request.getMinor(), 0);
+ assertEquals(request.getValue("Host"), "some.host.com");
+ } else if(method.equals("GET")) {
+ assertEquals(request.getMajor(), 1);
+ assertEquals(request.getMinor(), 0);
+ assertEquals(request.getValue("Host"), "some.host.com");
+ assertEquals(request.getValues("Accept").size(), 4);
+ assertEquals(request.getValues("Accept").get(0), "image/gif");
+ assertEquals(request.getValues("Accept").get(1), "image/png");
+ assertEquals(request.getValues("Accept").get(2), "image/jpeg");
+ assertEquals(request.getValues("Accept").get(3), "*");
+ } else {
+ assertEquals(request.getMajor(), 1);
+ assertEquals(request.getMinor(), 0);
+ assertEquals(request.getContentType().getPrimary(), "multipart");
+ assertEquals(request.getContentType().getSecondary(), "form-data");
+ assertEquals(request.getValue("Host"), "some.host.com");
+ assertEquals(request.getValues("Accept").size(), 4);
+ assertEquals(request.getValues("Accept").get(0), "image/gif");
+ assertEquals(request.getValues("Accept").get(1), "image/png");
+ assertEquals(request.getValues("Accept").get(2), "image/jpeg");
+ assertEquals(request.getValues("Accept").get(3), "*");
+ assertEquals(list.size(), 4);
+ assertEquals(list.get(0).getContentType().getPrimary(), "text");
+ assertEquals(list.get(0).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(0).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file1.txt\"; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"");
+ assertEquals(list.get(0).getName(), "pics");
+ assertEquals(list.get(0).getFileName(), "file1.txt");
+ assertEquals(list.get(0).isFile(), true);
+ assertEquals(list.get(1).getContentType().getPrimary(), "text");
+ assertEquals(list.get(1).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(1).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file2.txt\"");
+ assertEquals(list.get(1).getContentType().getPrimary(), "text");
+ assertEquals(list.get(1).getName(), "pics");
+ assertEquals(list.get(1).getFileName(), "file2.txt");
+ assertEquals(list.get(1).isFile(), true);
+ assertEquals(list.get(2).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(2).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file3.txt\"");
+ assertEquals(list.get(2).getName(), "pics");
+ assertEquals(list.get(2).getFileName(), "file3.txt");
+ assertEquals(list.get(2).isFile(), true);
+ assertEquals(list.get(3).getContentType().getPrimary(), "text");
+ assertEquals(list.get(3).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(3).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file4.txt\"");
+ assertEquals(list.get(3).getName(), "pics");
+ assertEquals(list.get(3).getFileName(), "file4.txt");
+ assertEquals(list.get(3).isFile(), true);
+ }
+ StopWatch stopWatch = timers.get(request.getTarget());
+ stopWatch.stop();
+ finished.offer(stopWatch);
+ }
+
+ public static void main(String[] list) throws Exception {
+ new ReactorProcessorTest().testMinimal();
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorTest.java
new file mode 100644
index 0000000..b0aae80
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/ReactorTest.java
@@ -0,0 +1,178 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+import java.nio.channels.SocketChannel;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.buffer.ArrayAllocator;
+import org.simpleframework.common.lease.Lease;
+import org.simpleframework.http.MockTrace;
+import org.simpleframework.http.Part;
+import org.simpleframework.http.message.Body;
+import org.simpleframework.http.message.Entity;
+import org.simpleframework.http.message.Header;
+import org.simpleframework.transport.Certificate;
+import org.simpleframework.transport.Channel;
+import org.simpleframework.transport.ByteCursor;
+import org.simpleframework.transport.ByteWriter;
+import org.simpleframework.transport.trace.Trace;
+
+public class ReactorTest extends TestCase implements Controller {
+
+ private static final String SOURCE =
+ "POST /index.html HTTP/1.0\r\n"+
+ "Content-Type: multipart/form-data; boundary=AaB03x\r\n"+
+ "Accept: image/gif;q=1.0,\r\n image/jpeg;q=0.8,\r\n"+
+ " \t\t image/png;\t\r\n\t"+
+ " q=1.0,*;q=0.1\r\n"+
+ "Accept-Language: fr;q=0.1, en-us;q=0.4, en-gb; q=0.8, en;q=0.7\r\n"+
+ "Host: some.host.com \r\n"+
+ "Cookie: $Version=1; UID=1234-5678; $Path=/; $Domain=.host.com\r\n"+
+ "Cookie: $Version=1; NAME=\"Niall Gallagher\"; $path=\"/\"\r\n"+
+ "\r\n" +
+ "--AaB03x\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file1.txt\"; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file1.txt\r\n"+
+ "--AaB03x\r\n"+
+ "Content-Type: multipart/mixed; boundary=BbC04y\r\n\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file2.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file3.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file3.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file4.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"pics\"; filename=\"file4.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file4.txt ...\r\n"+
+ "--BbC04y--\r\n"+
+ "--AaB03x--\r\n";
+
+ public static class TestChannel implements Channel {
+
+ private ByteCursor cursor;
+
+ public TestChannel(StreamCursor cursor, int dribble) {
+ this.cursor = new DribbleCursor(cursor, dribble);
+ }
+
+ public boolean isSecure() {
+ return false;
+ }
+
+ public Trace getTrace() {
+ return new MockTrace();
+ }
+
+ public Certificate getCertificate() {
+ return null;
+ }
+
+ public Lease getLease() {
+ return null;
+ }
+
+ public ByteCursor getCursor() {
+ return cursor;
+ }
+
+ public ByteWriter getWriter() {
+ return null;
+ }
+
+ public Map getAttributes() {
+ return null;
+ }
+
+ public void close() {}
+
+ public SocketChannel getSocket() {
+ return null;
+ }
+ }
+
+ public void testHandler() throws Exception {
+ testHandler(1024);
+
+ for(int i = 10; i < 2048; i++) {
+ testHandler(i);
+ }
+ }
+
+ public void testHandler(int dribble) throws Exception {
+ StreamCursor cursor = new StreamCursor(SOURCE);
+ Channel channel = new TestChannel(cursor, dribble);
+
+ start(channel);
+
+ assertEquals(cursor.ready(), -1);
+ }
+
+ public void start(Channel channel) throws IOException {
+ start(new RequestCollector(new ArrayAllocator(), channel));
+ }
+
+ public void start(Collector collector) throws IOException {
+ collector.collect(this);
+ }
+
+ public void select(Collector collector) throws IOException {
+ collector.collect(this);
+ }
+
+ public void ready(Collector collector) throws IOException {
+ Entity entity = collector;
+ Channel channel = entity.getChannel();
+ ByteCursor cursor = channel.getCursor();
+ Header header = entity.getHeader();
+ Body body = entity.getBody();
+ List<Part> list = body.getParts();
+
+ assertEquals(header.getTarget(), "/index.html");
+ assertEquals(header.getMethod(), "POST");
+ assertEquals(header.getMajor(), 1);
+ assertEquals(header.getMinor(), 0);
+ assertEquals(header.getContentType().getPrimary(), "multipart");
+ assertEquals(header.getContentType().getSecondary(), "form-data");
+ assertEquals(header.getValue("Host"), "some.host.com");
+ assertEquals(header.getValues("Accept").size(), 4);
+ assertEquals(header.getValues("Accept").get(0), "image/gif");
+ assertEquals(header.getValues("Accept").get(1), "image/png");
+ assertEquals(header.getValues("Accept").get(2), "image/jpeg");
+ assertEquals(header.getValues("Accept").get(3), "*");
+ assertEquals(list.size(), 4);
+ assertEquals(list.get(0).getContentType().getPrimary(), "text");
+ assertEquals(list.get(0).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(0).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file1.txt\"; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"");
+ assertEquals(list.get(0).getName(), "pics");
+ assertEquals(list.get(0).getFileName(), "file1.txt");
+ assertEquals(list.get(0).isFile(), true);
+ assertEquals(list.get(1).getContentType().getPrimary(), "text");
+ assertEquals(list.get(1).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(1).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file2.txt\"");
+ assertEquals(list.get(1).getContentType().getPrimary(), "text");
+ assertEquals(list.get(1).getName(), "pics");
+ assertEquals(list.get(1).getFileName(), "file2.txt");
+ assertEquals(list.get(1).isFile(), true);
+ assertEquals(list.get(2).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(2).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file3.txt\"");
+ assertEquals(list.get(2).getName(), "pics");
+ assertEquals(list.get(2).getFileName(), "file3.txt");
+ assertEquals(list.get(2).isFile(), true);
+ assertEquals(list.get(3).getContentType().getPrimary(), "text");
+ assertEquals(list.get(3).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(3).getHeader("Content-Disposition"), "file; name=\"pics\"; filename=\"file4.txt\"");
+ assertEquals(list.get(3).getName(), "pics");
+ assertEquals(list.get(3).getFileName(), "file4.txt");
+ assertEquals(list.get(3).isFile(), true);
+ assertEquals(cursor.ready(), -1);
+ }
+
+ public void stop() throws IOException {}
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/RequestConsumerTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/RequestConsumerTest.java
new file mode 100644
index 0000000..ae9672f
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/RequestConsumerTest.java
@@ -0,0 +1,138 @@
+package org.simpleframework.http.core;
+
+import org.simpleframework.http.message.RequestConsumer;
+import org.simpleframework.transport.ByteCursor;
+
+import junit.framework.TestCase;
+
+public class RequestConsumerTest extends TestCase {
+
+ private static final byte[] SOURCE_1 =
+ ("POST /index.html HTTP/1.0\r\n"+
+ "Content-Type: application/x-www-form-urlencoded\r\n"+
+ "Content-Length: 42\r\n"+
+ "Transfer-Encoding: chunked\r\n"+
+ "Accept: image/gif;q=1.0,\r\n image/jpeg;q=0.8,\r\n"+
+ " \t\t image/png;\t\r\n\t"+
+ " q=1.0,*;q=0.1\r\n"+
+ "Accept-Language: fr;q=0.1, en-us;q=0.4, en-gb; q=0.8, en;q=0.7\r\n"+
+ "Host: some.host.com \r\n"+
+ "Cookie: $Version=1; UID=1234-5678; $Path=/; $Domain=.host.com\r\n"+
+ "Cookie: $Version=1; NAME=\"Niall Gallagher\"; $path=\"/\"\r\n"+
+ "\r\n").getBytes();
+
+ private static final byte[] SOURCE_2 =
+ ("GET /tmp/amazon_files/21lP7I1XB5L.jpg HTTP/1.1\r\n"+
+ "Accept-Encoding: gzip, deflate\r\n"+
+ "Connection: keep-alive\r\n"+
+ "Referer: http://localhost:9090/tmp/amazon.htm\r\n"+
+ "Cache-Control: max-age=0\r\n"+
+ "Host: localhost:9090\r\n"+
+ "Accept-Language: en-US\r\n"+
+ "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13\r\n"+
+ "Accept: */*\r\n" +
+ "\r\n").getBytes();
+
+ private static final byte[] SOURCE_3 =
+ ("GET /tmp/amazon_files/in-your-city-blue-large._V256095983_.gif HTTP/1.1Accept-Encoding: gzip, deflate\r\n"+
+ "Connection: keep-alive\r\n"+
+ "Referer: http://localhost:9090/tmp/amazon.htm\r\n"+
+ "Cache-Control: max-age=0\r\n"+
+ "Host: localhost:9090\r\n"+
+ "Accept-Language: en-US\r\n"+
+ "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13\r\n"+
+ "Accept: */*\r\n"+
+ "\r\n").getBytes();
+
+ private static final byte[] SOURCE_4 =
+ ("GET /tmp/amazon_files/narrowtimer_transparent._V47062518_.gif HTTP/1.1\r\n"+
+ "Accept-Encoding: gzip, deflate\r\n"+
+ "Connection: keep-alive\r\n"+
+ "Referer: http://localhost:9090/tmp/amazon.htm\r\n"+
+ "Cache-Control: max-age=0\r\n"+
+ "Host: localhost:9090\r\n"+
+ "Accept-Language: en-US\r\n"+
+ "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13\r\n"+
+ "Accept: */*\r\n"+
+ "\r\n").getBytes();
+
+ public void testPerformance() throws Exception {
+ testPerformance(SOURCE_1, "/index.html");
+ testPerformance(SOURCE_2, "/tmp/amazon_files/21lP7I1XB5L.jpg");
+ testPerformance(SOURCE_3, "/tmp/amazon_files/in-your-city-blue-large._V256095983_.gif");
+ testPerformance(SOURCE_4, "/tmp/amazon_files/narrowtimer_transparent._V47062518_.gif");
+ }
+
+ public void testPerformance(byte[] request, String path) throws Exception {
+ long start = System.currentTimeMillis();
+
+ for(int i = 0; i < 10000; i++) {
+ RequestConsumer header = new RequestConsumer();
+ ByteCursor cursor = new StreamCursor(request);
+
+ while(!header.isFinished()) {
+ header.consume(cursor);
+ }
+
+ assertEquals(cursor.ready(), -1);
+ assertEquals(header.getPath().getPath(), path);
+ }
+ System.err.printf("%s time=%s%n", path, (System.currentTimeMillis() - start));
+ }
+
+ public void testHeader() throws Exception {
+ long start = System.currentTimeMillis();
+
+ for(int i = 0; i < 10000; i++) {
+ RequestConsumer header = new RequestConsumer();
+ ByteCursor cursor = new StreamCursor(SOURCE_1);
+
+ while(!header.isFinished()) {
+ header.consume(cursor);
+ }
+
+ assertEquals(cursor.ready(), -1);
+ assertEquals(header.getTarget(), "/index.html");
+ assertEquals(header.getMethod(), "POST");
+ assertEquals(header.getMajor(), 1);
+ assertEquals(header.getMinor(), 0);
+ assertEquals(header.getValue("Content-Length"), "42");
+ assertEquals(header.getValue("Content-Type"), "application/x-www-form-urlencoded");
+ assertEquals(header.getValue("Host"), "some.host.com");
+ assertEquals(header.getValues("Accept").size(), 4);
+ assertEquals(header.getValues("Accept").get(0), "image/gif");
+ assertEquals(header.getValues("Accept").get(1), "image/png");
+ assertEquals(header.getValues("Accept").get(2), "image/jpeg");
+ assertEquals(header.getValues("Accept").get(3), "*");
+ assertEquals(header.getContentType().getPrimary(), "application");
+ assertEquals(header.getContentType().getSecondary(), "x-www-form-urlencoded");
+ assertEquals(header.getTransferEncoding(), "chunked");
+ }
+ System.err.printf("time=%s%n", (System.currentTimeMillis() - start));
+ }
+
+ public void testDribble() throws Exception {
+ RequestConsumer header = new RequestConsumer();
+ ByteCursor cursor = new DribbleCursor(new StreamCursor(SOURCE_1), 1);
+
+ while(!header.isFinished()) {
+ header.consume(cursor);
+ }
+ assertEquals(cursor.ready(), -1);
+ assertEquals(header.getTarget(), "/index.html");
+ assertEquals(header.getMethod(), "POST");
+ assertEquals(header.getMajor(), 1);
+ assertEquals(header.getMinor(), 0);
+ assertEquals(header.getValue("Content-Length"), "42");
+ assertEquals(header.getValue("Content-Type"), "application/x-www-form-urlencoded");
+ assertEquals(header.getValue("Host"), "some.host.com");
+ assertEquals(header.getValues("Accept").size(), 4);
+ assertEquals(header.getValues("Accept").get(0), "image/gif");
+ assertEquals(header.getValues("Accept").get(1), "image/png");
+ assertEquals(header.getValues("Accept").get(2), "image/jpeg");
+ assertEquals(header.getValues("Accept").get(3), "*");
+ assertEquals(header.getContentType().getPrimary(), "application");
+ assertEquals(header.getContentType().getSecondary(), "x-www-form-urlencoded");
+ assertEquals(header.getTransferEncoding(), "chunked");
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/RequestTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/RequestTest.java
new file mode 100644
index 0000000..47cbf35
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/RequestTest.java
@@ -0,0 +1,144 @@
+package org.simpleframework.http.core;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.buffer.ArrayAllocator;
+import org.simpleframework.http.Part;
+import org.simpleframework.http.Request;
+import org.simpleframework.transport.Channel;
+import org.simpleframework.transport.ByteCursor;
+
+public class RequestTest extends TestCase {
+
+ private static final String HEADER =
+ "POST /index.html?a=b&c=d&e=f&g=h&a=1 HTTP/1.0\r\n"+
+ "Content-Type: multipart/form-data; boundary=AaB03x\r\n"+
+ "Accept: image/gif;q=1.0,\r\n image/jpeg;q=0.8,\r\n"+
+ " \t\t image/png;\t\r\n\t"+
+ " q=1.0,*;q=0.1\r\n"+
+ "Accept-Language: fr;q=0.1, en-us;q=0.4, en-gb; q=0.8, en;q=0.7\r\n"+
+ "Host: some.host.com \r\n"+
+ "Cookie: $Version=1; UID=1234-5678; $Path=/; $Domain=.host.com\r\n"+
+ "Cookie: $Version=1; NAME=\"Niall Gallagher\"; $path=\"/\"\r\n"+
+ "\r\n";
+
+ private static final String BODY =
+ "--AaB03x\r\n"+
+ "Content-Disposition: file; name=\"file1\"; filename=\"file1.txt\"; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file1.txt\r\n"+
+ "--AaB03x\r\n"+
+ "Content-Type: multipart/mixed; boundary=BbC04y\r\n\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"file2\"; filename=\"file2.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file2.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"file3\"; filename=\"file3.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file3.txt ...\r\n"+
+ "--BbC04y\r\n"+
+ "Content-Disposition: file; name=\"file4\"; filename=\"file4.txt\"\r\n"+
+ "Content-Type: text/plain\r\n\r\n"+
+ "example contents of file4.txt ...\r\n"+
+ "--BbC04y--\r\n"+
+ "--AaB03x--\r\n";
+
+ private static final byte[] PAYLOAD = (HEADER + BODY).getBytes();
+
+ public void testPayload() throws Exception {
+ long start = System.currentTimeMillis();
+
+ for(int i = 1; i < 8192; i++) {
+ testPayload(i);
+ }
+ System.err.printf("time=%s%n",(System.currentTimeMillis() - start));
+ }
+
+ public void testPerformance() throws Exception {
+ long start = System.currentTimeMillis();
+
+ for(int i = 1; i < 10000; i++) {
+ testPayload(8192);
+ }
+ System.err.printf("time=%s%n",(System.currentTimeMillis() - start));
+ }
+
+ public void testPayload(int dribble) throws Exception {
+ System.out.println("Testing dribbling cursor of "+dribble+" ...");
+ ByteCursor cursor = new StreamCursor(PAYLOAD);
+
+ if(dribble < PAYLOAD.length) {
+ cursor = new DribbleCursor(cursor, dribble);
+ }
+ Channel channel = new MockChannel(cursor);
+ MockController selector = new MockController();
+ Collector body = new RequestCollector(new ArrayAllocator(), channel);
+
+ while(!selector.isReady()) {
+ body.collect(selector);
+ }
+ Request request = new RequestEntity(null, body);
+ List<Part> list = request.getParts();
+
+ assertEquals(request.getParameter("a"), "b");
+ assertEquals(request.getParameter("c"), "d");
+ assertEquals(request.getParameter("e"), "f");
+ assertEquals(request.getParameter("g"), "h");
+ assertEquals(request.getTarget(), "/index.html?a=b&c=d&e=f&g=h&a=1");
+ assertEquals(request.getMethod(), "POST");
+ assertEquals(request.getMajor(), 1);
+ assertEquals(request.getMinor(), 0);
+ assertEquals(request.getContentType().getPrimary(), "multipart");
+ assertEquals(request.getContentType().getSecondary(), "form-data");
+ assertEquals(request.getValue("Host"), "some.host.com");
+ assertEquals(request.getValues("Accept").size(), 4);
+ assertEquals(request.getValues("Accept").get(0), "image/gif");
+ assertEquals(request.getValues("Accept").get(1), "image/png");
+ assertEquals(request.getValues("Accept").get(2), "image/jpeg");
+ assertEquals(request.getValues("Accept").get(3), "*");
+ assertEquals(request.getCookie("UID").getValue(), "1234-5678");
+ assertEquals(request.getCookie("UID").getPath(), "/");
+ assertEquals(request.getCookie("UID").getDomain(), ".host.com");
+ assertEquals(request.getCookie("NAME").getValue(), "Niall Gallagher");
+ assertEquals(request.getCookie("NAME").getPath(), "/");
+ assertEquals(request.getCookie("NAME").getDomain(), null);
+ assertEquals(list.size(), 4);
+ assertEquals(list.get(0).getContentType().getPrimary(), "text");
+ assertEquals(list.get(0).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(0).getHeader("Content-Disposition"), "file; name=\"file1\"; filename=\"file1.txt\"; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"");
+ assertEquals(list.get(0).getName(), "file1");
+ assertEquals(list.get(0).getFileName(), "file1.txt");
+ assertEquals(list.get(0).isFile(), true);
+ assertEquals(list.get(0).getContent(), "example contents of file1.txt");
+ assertEquals(request.getPart("file1").getContent(), "example contents of file1.txt");
+ assertEquals(list.get(1).getContentType().getPrimary(), "text");
+ assertEquals(list.get(1).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(1).getHeader("Content-Disposition"), "file; name=\"file2\"; filename=\"file2.txt\"");
+ assertEquals(list.get(1).getContentType().getPrimary(), "text");
+ assertEquals(list.get(1).getName(), "file2");
+ assertEquals(list.get(1).getFileName(), "file2.txt");
+ assertEquals(list.get(1).isFile(), true);
+ assertEquals(list.get(1).getContent(), "example contents of file2.txt ...");
+ assertEquals(request.getPart("file2").getContent(), "example contents of file2.txt ...");
+ assertEquals(list.get(2).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(2).getHeader("Content-Disposition"), "file; name=\"file3\"; filename=\"file3.txt\"");
+ assertEquals(list.get(2).getName(), "file3");
+ assertEquals(list.get(2).getFileName(), "file3.txt");
+ assertEquals(list.get(2).isFile(), true);
+ assertEquals(list.get(2).getContent(), "example contents of file3.txt ...");
+ assertEquals(request.getPart("file3").getContent(), "example contents of file3.txt ...");
+ assertEquals(list.get(3).getContentType().getPrimary(), "text");
+ assertEquals(list.get(3).getContentType().getSecondary(), "plain");
+ assertEquals(list.get(3).getHeader("Content-Disposition"), "file; name=\"file4\"; filename=\"file4.txt\"");
+ assertEquals(list.get(3).getName(), "file4");
+ assertEquals(list.get(3).getFileName(), "file4.txt");
+ assertEquals(list.get(3).isFile(), true);
+ assertEquals(list.get(3).getContent(), "example contents of file4.txt ...");
+ assertEquals(request.getPart("file4").getContent(), "example contents of file4.txt ...");
+ assertEquals(cursor.ready(), -1);
+ assertEquals(request.getContent(), BODY);
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/Result.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/Result.java
new file mode 100644
index 0000000..c48b248
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/Result.java
@@ -0,0 +1,37 @@
+package org.simpleframework.http.core;
+
+import java.util.List;
+import java.util.Map;
+
+import org.simpleframework.http.Cookie;
+
+class Result {
+
+ private List<Cookie> cookies;
+ private String response;
+ private byte[] body;
+ private Map map;
+
+ public Result(String response, byte[] body, Map map, List<Cookie> cookies) {
+ this.cookies = cookies;
+ this.response = response;
+ this.body = body;
+ this.map = map;
+ }
+
+ public List<Cookie> getCookies() {
+ return cookies;
+ }
+
+ public byte[] getBody() {
+ return body;
+ }
+
+ public String getResponse() throws Exception {
+ return response;
+ }
+
+ public Map getMap() {
+ return map;
+ }
+} \ No newline at end of file
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/StopTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/StopTest.java
new file mode 100644
index 0000000..67751b8
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/StopTest.java
@@ -0,0 +1,176 @@
+package org.simpleframework.http.core;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.thread.ConcurrentExecutor;
+import org.simpleframework.http.Request;
+import org.simpleframework.http.Response;
+import org.simpleframework.transport.connect.Connection;
+import org.simpleframework.transport.connect.SocketConnection;
+
+public class StopTest extends TestCase {
+
+ private static final int ITERATIONS = 20;
+
+ public void testStop() throws Exception {
+ ThreadDumper dumper = new ThreadDumper();
+
+ dumper.start();
+ dumper.waitUntilStarted();
+
+ ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+ int initialThreads = threadBean.getThreadCount();
+
+ for(int i = 0; i < ITERATIONS; i++) {
+ try {
+ ServerCriteria criteria = createServer();
+ InetSocketAddress address = criteria.getAddress();
+ Connection connection = criteria.getConnection();
+ Client client = createClient(address, String.format("[%s of %s]", i, ITERATIONS));
+
+ Thread.sleep(2000); // allow some requests to execute
+ connection.close();
+ Thread.sleep(100); // ensure client keeps executing
+ client.close();
+ Thread.sleep(1000); // wait for threads to terminate
+ }catch(Exception e) {
+ e.printStackTrace();
+ }
+ //assertEquals(initialThreads, threadBean.getThreadCount());
+ }
+ dumper.kill();
+ }
+
+ public static Client createClient(InetSocketAddress address, String tag) throws Exception {
+ ConcurrentExecutor executor = new ConcurrentExecutor(Runnable.class, 20);
+ int port = address.getPort();
+ Client client = new Client(executor, port, tag);
+
+ client.start();
+ return client;
+ }
+
+ public static ServerCriteria createServer() throws Exception {
+ Container container = new Container() {
+ public void handle(Request request, Response response) {
+ try {
+ PrintStream out = response.getPrintStream();
+ response.setValue("Content-Type", "text/plain");
+ response.setValue("Connection", "close");
+
+ out.print("TEST " + new Date());
+ response.close();
+ }catch(Exception e) {
+ e.printStackTrace();
+ try {
+ response.close();
+ }catch(Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ };
+ ContainerSocketProcessor server = new ContainerSocketProcessor(container);
+ Connection connection = new SocketConnection(server);
+ InetSocketAddress address = (InetSocketAddress)connection.connect(null); // ephemeral port
+
+ return new ServerCriteria(connection, address);
+ }
+
+ private static class Client extends Thread implements Closeable {
+
+ private ConcurrentExecutor executor;
+ private RequestTask task;
+ private volatile boolean dead;
+
+ public Client(ConcurrentExecutor executor, int port, String tag) {
+ this.task = new RequestTask(this, port, tag);
+ this.executor = executor;
+ }
+
+ public boolean isDead() {
+ return dead;
+ }
+
+ public void run() {
+ try {
+ while(!dead) {
+ executor.execute(task);
+ Thread.sleep(100);
+ }
+ }catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void close() {
+ dead = true;
+ executor.stop();
+ }
+ }
+
+ private static class RequestTask implements Runnable {
+
+ private Client client;
+ private String tag;
+ private int port;
+
+ public RequestTask(Client client, int port, String tag) {
+ this.client = client;
+ this.port = port;
+ this.tag = tag;
+ }
+
+ public void run() {
+ try {
+ if(!client.isDead()) {
+ URL target = new URL("http://localhost:"+port+"/");
+ URLConnection connection = target.openConnection();
+
+ // set a timeout
+ connection.setConnectTimeout(10000);
+ connection.setReadTimeout(10000);
+
+ InputStream stream = connection.getInputStream();
+ StringBuilder builder = new StringBuilder();
+ int octet = 0;
+
+ while((octet = stream.read()) != -1) {
+ builder.append((char)octet);
+ }
+ stream.close();
+ System.out.println(tag + " " + Thread.currentThread() + ": " + builder);
+ }
+ }catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static class ServerCriteria {
+
+ private Connection connection;
+ private InetSocketAddress address;
+
+ public ServerCriteria(Connection connection, InetSocketAddress address){
+ this.connection = connection;
+ this.address = address;
+ }
+ public Connection getConnection() {
+ return connection;
+ }
+ public InetSocketAddress getAddress() {
+ return address;
+ }
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/StreamCursor.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/StreamCursor.java
new file mode 100644
index 0000000..d6f6a09
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/StreamCursor.java
@@ -0,0 +1,74 @@
+package org.simpleframework.http.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.simpleframework.http.StreamTransport;
+import org.simpleframework.transport.ByteCursor;
+import org.simpleframework.transport.Transport;
+import org.simpleframework.transport.TransportCursor;
+
+public class StreamCursor implements ByteCursor {
+
+ private TransportCursor cursor;
+ private Transport transport;
+ private byte[] swap;
+
+ public StreamCursor(String source) throws IOException {
+ this(source.getBytes("UTF-8"));
+ }
+
+ public StreamCursor(byte[] data) throws IOException {
+ this(new ByteArrayInputStream(data));
+ }
+
+ public StreamCursor(InputStream source) throws IOException {
+ this.transport = new StreamTransport(source, new OutputStream() {
+ public void write(int octet){}
+ });
+ this.cursor = new TransportCursor(transport);
+ this.swap = new byte[1];
+ }
+
+ // TODO investigate this
+ public boolean isOpen() throws IOException {
+ return true;
+ }
+
+ public boolean isReady() throws IOException {
+ return cursor.isReady();
+ }
+
+ public int ready() throws IOException {
+ return cursor.ready();
+ }
+
+ public int read() throws IOException {
+ if(read(swap) > 0) {
+ return swap[0] & 0xff;
+ }
+ return 0;
+ }
+
+ public int read(byte[] data) throws IOException {
+ return read(data, 0, data.length);
+ }
+
+ public int read(byte[] data, int off, int len) throws IOException {
+ return cursor.read(data, off, len);
+ }
+
+ public int reset(int len) throws IOException {
+ return cursor.reset(len);
+ }
+
+ public void push(byte[] data) throws IOException {
+ push(data, 0, data.length);
+ }
+
+ public void push(byte[] data, int off, int len) throws IOException {
+ cursor.push(data, off, len);
+ }
+} \ No newline at end of file
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java
new file mode 100644
index 0000000..85960ed
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/ThreadDumper.java
@@ -0,0 +1,183 @@
+package org.simpleframework.http.core;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+
+public class ThreadDumper extends Thread {
+
+ private static String INDENT = " ";
+ private CountDownLatch latch;
+ private volatile boolean dead;
+ private int wait;
+
+ public ThreadDumper() {
+ this(10000);
+ }
+
+ public ThreadDumper(int wait) {
+ this.latch = new CountDownLatch(1);
+ this.wait = wait;
+ }
+
+ public void waitUntilStarted() throws InterruptedException{
+ latch.await();
+ }
+
+ public void kill(){
+ try {
+ Thread.sleep(1000);
+ dead = true;
+ dumpThreadInfo();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ public void run() {
+ while(!dead) {
+ try{
+ latch.countDown();
+ dumpThreadInfo();
+ findDeadlock();
+ Thread.sleep(wait);
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ }
+ public String dumpThreads() {
+ Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces();
+ return generateDump(stackTraces);
+ }
+
+ public static String dumpCurrentThread() {
+ Thread currentThread = Thread.currentThread();
+ StackTraceElement[] stackTrace = currentThread.getStackTrace();
+ Map<Thread, StackTraceElement[]> stackTraces = Collections.singletonMap(currentThread, stackTrace);
+ return generateDump(stackTraces);
+
+ }
+
+ private static String generateDump(Map<Thread, StackTraceElement[]> stackTraces) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("<pre>");
+ builder.append("<b>Full Java thread dump</b>");
+ builder.append("\n");
+
+ Set<Thread> threads = stackTraces.keySet();
+
+ for (Thread thread : threads) {
+ StackTraceElement[] stackElements = stackTraces.get(thread);
+
+ generateDescription(thread, builder);
+ generateStackFrames(stackElements, builder);
+ }
+ builder.append("</pre>");
+ return builder.toString();
+ }
+
+ private static void generateStackFrames(StackTraceElement[] stackElements, StringBuilder builder) {
+ for (StackTraceElement stackTraceElement : stackElements) {
+ builder.append(" at ");
+ builder.append(stackTraceElement);
+ builder.append("\n");
+ }
+ }
+
+ private static void generateDescription(Thread thread, StringBuilder builder) {
+ Thread.State threadState = thread.getState();
+ String threadName = thread.getName();
+ long threadId = thread.getId();
+
+ builder.append("\n");
+ builder.append("<b>");
+ builder.append(threadName);
+ builder.append("</b> Id=");
+ builder.append(threadId);
+ builder.append(" in ");
+ builder.append(threadState);
+ builder.append("\n");
+ }
+
+ /**
+ * Prints the thread dump information to System.out.
+ */
+ public static void dumpThreadInfo(){
+ System.out.println(getThreadInfo());
+ }
+
+ public static String getThreadInfo() {
+ ThreadMXBean tmbean = ManagementFactory.getThreadMXBean();
+ long[] tids = tmbean.getAllThreadIds();
+ ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
+ StringWriter str = new StringWriter();
+ PrintWriter log = new PrintWriter(str);
+ log.println("Full Java thread dump");
+
+ for (ThreadInfo ti : tinfos) {
+ printThreadInfo(ti, log);
+ }
+ log.flush();
+ return str.toString();
+ }
+
+ private static void printThreadInfo(ThreadInfo ti, PrintWriter log) {
+ if(ti != null) {
+ StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" +
+ " Id=" + ti.getThreadId() +
+ " in " + ti.getThreadState());
+ if (ti.getLockName() != null) {
+ sb.append(" on lock=" + ti.getLockName());
+ }
+ if (ti.isSuspended()) {
+ sb.append(" (suspended)");
+ }
+ if (ti.isInNative()) {
+ sb.append(" (running in native)");
+ }
+ log.println(sb.toString());
+ if (ti.getLockOwnerName() != null) {
+ log.println(INDENT + " owned by " + ti.getLockOwnerName() +
+ " Id=" + ti.getLockOwnerId());
+ }
+ for (StackTraceElement ste : ti.getStackTrace()) {
+ log.println(INDENT + "at " + ste.toString());
+ }
+ log.println();
+ }
+ }
+
+ /**
+ * Checks if any threads are deadlocked. If any, print
+ * the thread dump information.
+ */
+ public static boolean findDeadlock() {
+ ThreadMXBean tmbean = ManagementFactory.getThreadMXBean();
+ long[] tids = tmbean.findMonitorDeadlockedThreads();
+ if (tids == null) {
+ return false;
+ } else {
+ StringWriter str = new StringWriter();
+ PrintWriter log = new PrintWriter(str);
+
+ tids = tmbean.getAllThreadIds();
+ System.out.println("Deadlock found :-");
+ ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
+ for (ThreadInfo ti : tinfos) {
+ printThreadInfo(ti, log);
+ }
+ log.flush();
+ System.out.println(str.toString());
+ return true;
+ }
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/Ticket.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/Ticket.java
new file mode 100644
index 0000000..60fcb5c
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/Ticket.java
@@ -0,0 +1,22 @@
+package org.simpleframework.http.core;
+
+public class Ticket {
+
+ public static final Class KEY = Ticket.class;
+
+ private final String ticket;
+ private final int port;
+ public Ticket(int port) {
+ this.ticket = String.valueOf(port);
+ this.port = port;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public String getTicket() {
+ return ticket;
+ }
+
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/TicketProcessor.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/TicketProcessor.java
new file mode 100644
index 0000000..4636cc7
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/TicketProcessor.java
@@ -0,0 +1,28 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+import java.nio.channels.SocketChannel;
+
+import org.simpleframework.transport.SocketProcessor;
+import org.simpleframework.transport.Socket;
+
+class TicketProcessor implements SocketProcessor {
+
+ private SocketProcessor delegate;
+
+ public TicketProcessor(SocketProcessor delegate) {
+ this.delegate = delegate;
+ }
+
+ public void process(Socket pipe) throws IOException {
+ SocketChannel channel = pipe.getChannel();
+ int port = channel.socket().getPort();
+
+ pipe.getAttributes().put(Ticket.KEY,new Ticket(port));
+ delegate.process(pipe);
+ }
+
+ public void stop() throws IOException {
+ delegate.stop();
+ }
+} \ No newline at end of file
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/TransferTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/TransferTest.java
new file mode 100644
index 0000000..0d0d73d
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/TransferTest.java
@@ -0,0 +1,195 @@
+package org.simpleframework.http.core;
+
+import java.io.IOException;
+
+import org.simpleframework.http.core.Conversation;
+import org.simpleframework.http.core.ResponseEncoder;
+
+import junit.framework.TestCase;
+
+public class TransferTest extends TestCase {
+
+ public void testTransferEncoding() throws IOException {
+ MockChannel channel = new MockChannel(null);
+ MockObserver monitor = new MockObserver();
+ MockRequest request = new MockRequest();
+ MockResponse response = new MockResponse();
+ Conversation support = new Conversation(request, response);
+ ResponseEncoder transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ // Start a HTTP/1.1 conversation
+ request.setMajor(1);
+ request.setMinor(1);
+ transfer.start();
+
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertEquals(response.getValue("Transfer-Encoding"), "chunked");
+ assertEquals(response.getValue("Content-Length"), null);
+ assertEquals(response.getContentLength(), -1);
+ assertTrue(response.isCommitted());
+
+ channel = new MockChannel(null);
+ monitor = new MockObserver();
+ request = new MockRequest();
+ response = new MockResponse();
+ support = new Conversation(request, response);
+ transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ // Start a HTTP/1.0 conversation
+ request.setMajor(1);
+ request.setMinor(0);
+ transfer.start();
+
+ assertEquals(response.getValue("Connection"), "close");
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getValue("Content-Length"), null);
+ assertEquals(response.getContentLength(), -1);
+ assertTrue(response.isCommitted());
+ }
+
+ public void testContentLength() throws IOException {
+ MockChannel channel = new MockChannel(null);
+ MockObserver monitor = new MockObserver();
+ MockRequest request = new MockRequest();
+ MockResponse response = new MockResponse();
+ Conversation support = new Conversation(request, response);
+ ResponseEncoder transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ // Start a HTTP/1.1 conversation
+ request.setMajor(1);
+ request.setMinor(1);
+ transfer.start(1024);
+
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertEquals(response.getValue("Content-Length"), "1024");
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getContentLength(), 1024);
+ assertTrue(response.isCommitted());
+
+ channel = new MockChannel(null);
+ monitor = new MockObserver();
+ request = new MockRequest();
+ response = new MockResponse();
+ support = new Conversation(request, response);
+ transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ // Start a HTTP/1.0 conversation
+ request.setMajor(1);
+ request.setMinor(0);
+ transfer.start(1024);
+
+ assertEquals(response.getValue("Connection"), "close");
+ assertEquals(response.getValue("Content-Length"), "1024");
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getContentLength(), 1024);
+ assertTrue(response.isCommitted());
+
+ channel = new MockChannel(null);
+ monitor = new MockObserver();
+ request = new MockRequest();
+ response = new MockResponse();
+ support = new Conversation(request, response);
+ transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ // Start a HTTP/1.0 conversation
+ request.setMajor(1);
+ request.setMinor(1);
+ response.setValue("Content-Length", "2048");
+ response.setValue("Connection", "close");
+ response.setValue("Transfer-Encoding", "chunked");
+ transfer.start(1024);
+
+ assertEquals(response.getValue("Connection"), "close");
+ assertEquals(response.getValue("Content-Length"), "1024"); // should be 1024
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getContentLength(), 1024);
+ assertTrue(response.isCommitted());
+ }
+
+ public void testHeadMethodWithConnectionClose() throws IOException {
+ MockChannel channel = new MockChannel(null);
+ MockObserver monitor = new MockObserver();
+ MockRequest request = new MockRequest();
+ MockResponse response = new MockResponse();
+ Conversation support = new Conversation(request, response);
+ ResponseEncoder transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ request.setMajor(1);
+ request.setMinor(0);
+ request.setMethod("HEAD");
+ request.setValue("Connection", "keep-alive");
+ response.setContentLength(1024);
+ response.setValue("Connection", "close");
+
+ transfer.start();
+
+ assertEquals(response.getValue("Connection"), "close");
+ assertEquals(response.getValue("Content-Length"), "1024"); // should be 1024
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getContentLength(), 1024);
+ }
+
+ public void testHeadMethodWithSomethingWritten() throws IOException {
+ MockChannel channel = new MockChannel(null);
+ MockObserver monitor = new MockObserver();
+ MockRequest request = new MockRequest();
+ MockResponse response = new MockResponse();
+ Conversation support = new Conversation(request, response);
+ ResponseEncoder transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ request.setMajor(1);
+ request.setMinor(1);
+ request.setMethod("HEAD");
+ request.setValue("Connection", "keep-alive");
+ response.setContentLength(1024);
+
+ transfer.start(512);
+
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertEquals(response.getValue("Content-Length"), "512"); // should be 512
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getContentLength(), 512);
+ }
+
+ public void testHeadMethodWithNoContentLength() throws IOException {
+ MockChannel channel = new MockChannel(null);
+ MockObserver monitor = new MockObserver();
+ MockRequest request = new MockRequest();
+ MockResponse response = new MockResponse();
+ Conversation support = new Conversation(request, response);
+ ResponseEncoder transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ request.setMajor(1);
+ request.setMinor(1);
+ request.setMethod("HEAD");
+ request.setValue("Connection", "keep-alive");
+
+ transfer.start();
+
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertEquals(response.getValue("Content-Length"), null);
+ assertEquals(response.getValue("Transfer-Encoding"), "chunked");
+ assertEquals(response.getContentLength(), -1);
+ }
+
+ public void testHeadMethodWithNoContentLengthAndSomethingWritten() throws IOException {
+ MockChannel channel = new MockChannel(null);
+ MockObserver monitor = new MockObserver();
+ MockRequest request = new MockRequest();
+ MockResponse response = new MockResponse();
+ Conversation support = new Conversation(request, response);
+ ResponseEncoder transfer = new ResponseEncoder(monitor, response, support, channel);
+
+ request.setMajor(1);
+ request.setMinor(1);
+ request.setMethod("HEAD");
+ request.setValue("Connection", "keep-alive");
+
+ transfer.start(32);
+
+ assertEquals(response.getValue("Connection"), "keep-alive");
+ assertEquals(response.getValue("Content-Length"), "32");
+ assertEquals(response.getValue("Transfer-Encoding"), null);
+ assertEquals(response.getContentLength(), 32);
+ }
+}
diff --git a/simple/simple-http/src/test/java/org/simpleframework/http/core/WebSocketUpgradeTest.java b/simple/simple-http/src/test/java/org/simpleframework/http/core/WebSocketUpgradeTest.java
new file mode 100644
index 0000000..ea6e313
--- /dev/null
+++ b/simple/simple-http/src/test/java/org/simpleframework/http/core/WebSocketUpgradeTest.java
@@ -0,0 +1,126 @@
+package org.simpleframework.http.core;
+
+import java.io.OutputStream;
+import java.nio.channels.SocketChannel;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+import org.simpleframework.common.buffer.Allocator;
+import org.simpleframework.common.buffer.ArrayAllocator;
+import org.simpleframework.http.MockTrace;
+import org.simpleframework.http.Request;
+import org.simpleframework.http.Response;
+import org.simpleframework.transport.Certificate;
+import org.simpleframework.transport.Channel;
+import org.simpleframework.transport.ByteCursor;
+import org.simpleframework.transport.ByteWriter;
+import org.simpleframework.transport.trace.Trace;
+
+public class WebSocketUpgradeTest extends TestCase implements Container {
+
+ private static final String OPEN_HANDSHAKE =
+ "GET /chat HTTP/1.1\r\n"+
+ "Host: server.example.com\r\n"+
+ "Upgrade: websocket\r\n"+
+ "Connection: Upgrade\r\n"+
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"+
+ "Origin: http://example.com\r\n"+
+ "Sec-WebSocket-Protocol: chat, superchat\r\n"+
+ "Sec-WebSocket-Version: 14\r\n" +
+ "\r\n";
+
+ public static class MockChannel implements Channel {
+
+ private ByteCursor cursor;
+
+ public MockChannel(StreamCursor cursor, int dribble) {
+ this.cursor = new DribbleCursor(cursor, dribble);
+ }
+ public boolean isSecure() {
+ return false;
+ }
+
+ public Trace getTrace() {
+ return new MockTrace();
+ }
+
+ public Certificate getCertificate() {
+ return null;
+ }
+
+ public ByteCursor getCursor() {
+ return cursor;
+ }
+
+ public ByteWriter getWriter() {
+ return new MockSender();
+ }
+
+ public Map getAttributes() {
+ return null;
+ }
+
+ public void close() {}
+
+ public SocketChannel getSocket() {
+ return null;
+ }
+ }
+
+ private final BlockingQueue<Response> responses = new LinkedBlockingQueue<Response>();
+
+ public void testWebSocketUpgrade() throws Exception {
+ Allocator allocator = new ArrayAllocator();
+ Controller handler = new ContainerController(this, allocator, 10, 2);
+ StreamCursor cursor = new StreamCursor(OPEN_HANDSHAKE);
+ Channel channel = new MockChannel(cursor, 10);
+
+ handler.start(channel);
+
+ Response response = responses.poll(5000, TimeUnit.MILLISECONDS);
+
+ assertEquals(response.getValue("Connection"), "Upgrade");
+ assertEquals(response.getValue("Upgrade"), "websocket");
+ assertTrue(response.isCommitted());
+ assertTrue(response.isKeepAlive());
+ }
+
+ public void handle(Request request, Response response) {
+ try {
+ process(request, response);
+ responses.offer(response);
+ }catch(Exception e) {
+ e.printStackTrace();
+ assertTrue(false);
+ }
+ }
+
+ public void process(Request request, Response response) throws Exception {
+ String method = request.getMethod();
+
+ assertEquals(method, "GET");
+ assertEquals(request.getValue("Upgrade"), "websocket");
+ assertEquals(request.getValue("Connection"), "Upgrade");
+ assertEquals(request.getValue("Sec-WebSocket-Key"), "dGhlIHNhbXBsZSBub25jZQ==");
+
+ response.setCode(101);
+ response.setValue("Connection", "close");
+ response.setValue("Upgrade", "websocket");
+
+ OutputStream out = response.getOutputStream();
+
+ out.write(10); // force commit
+
+ assertTrue(response.isCommitted());
+ assertTrue(response.isKeepAlive());
+ }
+
+ public static void main(String[] list) throws Exception {
+ new ReactorProcessorTest().testMinimal();
+ }
+
+}