diff options
Diffstat (limited to 'simple/simple-http/src/test/java/org/simpleframework/http/core')
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(); + } + +} |